frontend_nyla/src/components/UiComponents/Toast/Toast.tsx
2026-04-11 00:07:30 +02:00

79 lines
2.1 KiB
TypeScript

import { motion, AnimatePresence } from 'framer-motion';
import { FaCheckCircle, FaExclamationCircle, FaExclamationTriangle, FaInfoCircle, FaTimes } from 'react-icons/fa';
import styles from './Toast.module.css';
import { useLanguage } from '../../../providers/language/LanguageContext';
export type ToastType = 'success' | 'error' | 'warning' | 'info';
export interface ToastData {
id: string;
type: ToastType;
title: string;
message?: string;
duration?: number;
}
interface ToastProps {
toast: ToastData;
onClose: (id: string) => void;
}
const _getIcon = (type: ToastType) => {
switch (type) {
case 'success':
return <FaCheckCircle />;
case 'error':
return <FaExclamationCircle />;
case 'warning':
return <FaExclamationTriangle />;
case 'info':
return <FaInfoCircle />;
}
};
export const Toast: React.FC<ToastProps> = ({ toast, onClose }) => {
const { t } = useLanguage();
return (
<motion.div
className={`${styles.toast} ${styles[toast.type]}`}
initial={{ opacity: 0, x: 100, scale: 0.9 }}
animate={{ opacity: 1, x: 0, scale: 1 }}
exit={{ opacity: 0, x: 100, scale: 0.9 }}
transition={{ type: 'spring', stiffness: 400, damping: 30 }}
layout
>
<div className={`${styles.icon} ${styles[toast.type]}`}>
{_getIcon(toast.type)}
</div>
<div className={styles.content}>
<p className={styles.title}>{toast.title}</p>
{toast.message && <p className={styles.message}>{toast.message}</p>}
</div>
<button
className={styles.closeButton}
onClick={() => onClose(toast.id)}
aria-label={t('Schließen')}
>
<FaTimes />
</button>
</motion.div>
);
};
interface ToastContainerProps {
toasts: ToastData[];
onClose: (id: string) => void;
}
export const ToastContainer: React.FC<ToastContainerProps> = ({ toasts, onClose }) => {
return (
<div className={styles.toastContainer}>
<AnimatePresence mode="popLayout">
{toasts.map((toast) => (
<Toast key={toast.id} toast={toast} onClose={onClose} />
))}
</AnimatePresence>
</div>
);
};