All files / src/components toast.tsx

100% Statements 23/23
100% Branches 12/12
100% Functions 5/5
100% Lines 22/22

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76        4x         24x   24x   10x   4x   4x   5x   1x       4x   24x   24x   10x   4x   4x   5x   1x       4x 37x   37x   18x     24x                         1x                      
import { X, CheckCircle, XCircle, AlertTriangle, Info } from 'lucide-react';
import { useUIStore } from '@/store/ui-store';
import { Text } from '@/components/text';
 
const ToastIcon = ({
  type,
}: {
  type: 'success' | 'error' | 'warning' | 'info';
}) => {
  const iconProps = { size: 20 };
 
  switch (type) {
    case 'success':
      return <CheckCircle {...iconProps} className="text-green-600" />;
    case 'error':
      return <XCircle {...iconProps} className="text-red-600" />;
    case 'warning':
      return <AlertTriangle {...iconProps} className="text-yellow-600" />;
    case 'info':
      return <Info {...iconProps} className="text-blue-600" />;
    default:
      return <Info {...iconProps} className="text-gray-600" />;
  }
};
 
const getToastStyles = (type: 'success' | 'error' | 'warning' | 'info') => {
  const baseStyles =
    'flex items-center gap-3 p-4 rounded-lg shadow-lg border max-w-md';
 
  switch (type) {
    case 'success':
      return `${baseStyles} bg-green-50 border-green-200 text-green-800`;
    case 'error':
      return `${baseStyles} bg-red-50 border-red-200 text-red-800`;
    case 'warning':
      return `${baseStyles} bg-yellow-50 border-yellow-200 text-yellow-800`;
    case 'info':
      return `${baseStyles} bg-blue-50 border-blue-200 text-blue-800`;
    default:
      return `${baseStyles} bg-gray-50 border-gray-200 text-gray-800`;
  }
};
 
export const ToastContainer = () => {
  const { toasts, removeToast } = useUIStore();
 
  if (toasts.length === 0) return null;
 
  return (
    <div className="fixed top-4 right-4 z-50 space-y-2">
      {toasts.map(toast => (
        <div
          key={toast.id}
          className={`${getToastStyles(toast.type)} animate-in slide-in-from-right-full duration-300`}
        >
          <ToastIcon type={toast.type} />
 
          <div className="flex-1">
            <Text size="sm" weight="medium">
              {toast.message}
            </Text>
          </div>
 
          <button
            onClick={() => removeToast(toast.id)}
            className="flex-shrink-0 p-1 rounded-full hover:bg-black/10 transition-colors"
            aria-label="Close notification"
          >
            <X size={16} />
          </button>
        </div>
      ))}
    </div>
  );
};