79 lines
2.1 KiB
TypeScript
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>
|
|
);
|
|
};
|