veza/apps/web/src/components/ui/Toast.tsx

104 lines
No EOL
2.6 KiB
TypeScript

import React, { useEffect } from 'react';
import { X, CheckCircle, AlertCircle, Info } from 'lucide-react';
/**
* ToastMessage - Interface pour un message de toast
*
* @interface ToastMessage
*/
export interface ToastMessage {
/**
* Identifiant unique du toast
*/
id: string;
/**
* Type de toast
*
* - `success`: Message de succès (vert/lime)
* - `error`: Message d'erreur (rouge)
* - `info`: Message d'information (cyan)
*/
type: 'success' | 'error' | 'info';
/**
* Message à afficher
*/
message: string;
}
/**
* ToastProps - Propriétés du composant Toast
*
* @interface ToastProps
* @extends ToastMessage
*/
interface ToastProps extends ToastMessage {
/**
* Fonction appelée pour fermer le toast
*
* @param {string} id - Identifiant du toast à fermer
*/
onClose: (id: string) => void;
}
/**
* Toast - Composant de notification toast avec design system Kodo
*
* Composant de notification toast qui s'affiche temporairement et se ferme automatiquement
* après 4 secondes. Supporte trois types : success, error et info.
*
* @example
* ```tsx
* // Toast de succès
* <Toast
* id="1"
* type="success"
* message="Opération réussie"
* onClose={(id) => removeToast(id)}
* />
*
* // Toast d'erreur
* <Toast
* id="2"
* type="error"
* message="Une erreur s'est produite"
* onClose={(id) => removeToast(id)}
* />
* ```
*
* @component
* @param {ToastProps} props - Propriétés du composant
* @returns {JSX.Element} Élément div stylisé comme un toast avec animation
*/
export const Toast: React.FC<ToastProps> = ({ id, type, message, onClose }) => {
useEffect(() => {
const timer = setTimeout(() => {
onClose(id);
}, 4000);
return () => clearTimeout(timer);
}, [id, onClose]);
const styles = {
success: 'border-kodo-lime text-white bg-kodo-ink/90',
error: 'border-kodo-red text-white bg-kodo-ink/90',
info: 'border-kodo-cyan text-white bg-kodo-ink/90',
};
const icons = {
success: <CheckCircle className="w-5 h-5 text-kodo-lime" />,
error: <AlertCircle className="w-5 h-5 text-kodo-red" />,
info: <Info className="w-5 h-5 text-kodo-cyan" />,
};
return (
<div className={`flex items-center gap-3 p-4 rounded-lg border shadow-2xl min-w-[300px] animate-slideInRight backdrop-blur-md mb-3 ${styles[type]}`}>
{icons[type]}
<p className="flex-1 text-sm font-medium">{message}</p>
<button onClick={() => onClose(id)} className="text-gray-400 hover:text-white transition-colors">
<X className="w-4 h-4" />
</button>
</div>
);
};