109 lines
2.5 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import React, { useEffect } from 'react';
export type ToastType = 'success' | 'error' | 'info' | 'warning';
interface ToastProps {
message: string;
type?: ToastType;
isVisible: boolean;
onClose: () => void;
duration?: number;
}
const toastConfig = {
success: { bg: '#d1fae5', color: '#065f46', icon: '✓' },
error: { bg: '#fee2e2', color: '#991b1b', icon: '✗' },
info: { bg: '#dbeafe', color: '#1e40af', icon: '' },
warning: { bg: '#fef3c7', color: '#92400e', icon: '⚠' },
};
export function Toast({ message, type = 'info', isVisible, onClose, duration = 5000 }: ToastProps) {
useEffect(() => {
if (isVisible && duration > 0) {
const timer = setTimeout(onClose, duration);
return () => clearTimeout(timer);
}
}, [isVisible, duration, onClose]);
if (!isVisible) return null;
const config = toastConfig[type];
return (
<div
style={{
position: 'fixed',
bottom: 'var(--spacing-6)',
right: 'var(--spacing-6)',
background: config.bg,
color: config.color,
padding: 'var(--spacing-4) var(--spacing-5)',
borderRadius: 'var(--border-radius-lg)',
boxShadow: 'var(--shadow-lg)',
display: 'flex',
alignItems: 'center',
gap: 'var(--spacing-3)',
maxWidth: '400px',
zIndex: 2000,
}}
className="animate-slide-up"
>
<span
style={{
fontSize: 'var(--font-size-lg)',
fontWeight: 700,
}}
>
{config.icon}
</span>
<span
style={{
fontSize: 'var(--font-size-sm)',
fontWeight: 600,
flex: 1,
}}
>
{message}
</span>
<button
onClick={onClose}
style={{
background: 'transparent',
border: 'none',
color: config.color,
fontSize: 'var(--font-size-lg)',
cursor: 'pointer',
padding: '0',
lineHeight: 1,
opacity: 0.7,
}}
>
×
</button>
</div>
);
}
// Hook for managing toast state
export function useToast() {
const [toast, setToast] = React.useState<{
message: string;
type: ToastType;
isVisible: boolean;
}>({
message: '',
type: 'info',
isVisible: false,
});
const showToast = (message: string, type: ToastType = 'info') => {
setToast({ message, type, isVisible: true });
};
const hideToast = () => {
setToast((prev) => ({ ...prev, isVisible: false }));
};
return { toast, showToast, hideToast };
}