ConfirmModal.tsx 2.3 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182
  1. import { useEffect } from 'react';
  2. import { AlertTriangle } from 'lucide-react';
  3. import { Card, CardContent } from './Card';
  4. import { Button } from './Button';
  5. interface ConfirmModalProps {
  6. title: string;
  7. message: string;
  8. confirmText?: string;
  9. cancelText?: string;
  10. variant?: 'danger' | 'warning' | 'default';
  11. onConfirm: () => void;
  12. onCancel: () => void;
  13. }
  14. export function ConfirmModal({
  15. title,
  16. message,
  17. confirmText = 'Confirm',
  18. cancelText = 'Cancel',
  19. variant = 'default',
  20. onConfirm,
  21. onCancel,
  22. }: ConfirmModalProps) {
  23. // Close on Escape key
  24. useEffect(() => {
  25. const handleKeyDown = (e: KeyboardEvent) => {
  26. if (e.key === 'Escape') onCancel();
  27. };
  28. window.addEventListener('keydown', handleKeyDown);
  29. return () => window.removeEventListener('keydown', handleKeyDown);
  30. }, [onCancel]);
  31. const variantStyles = {
  32. danger: {
  33. icon: 'text-red-400',
  34. button: 'bg-red-500 hover:bg-red-600',
  35. },
  36. warning: {
  37. icon: 'text-yellow-400',
  38. button: 'bg-yellow-500 hover:bg-yellow-600',
  39. },
  40. default: {
  41. icon: 'text-bambu-green',
  42. button: 'bg-bambu-green hover:bg-bambu-green-dark',
  43. },
  44. };
  45. const styles = variantStyles[variant];
  46. return (
  47. <div
  48. className="fixed inset-0 bg-black/50 flex items-center justify-center z-50 p-4"
  49. onClick={onCancel}
  50. >
  51. <Card className="w-full max-w-md" onClick={(e: React.MouseEvent) => e.stopPropagation()}>
  52. <CardContent className="p-6">
  53. <div className="flex items-start gap-4">
  54. <div className={`p-2 rounded-full bg-bambu-dark ${styles.icon}`}>
  55. <AlertTriangle className="w-6 h-6" />
  56. </div>
  57. <div className="flex-1">
  58. <h3 className="text-lg font-semibold text-white mb-2">{title}</h3>
  59. <p className="text-bambu-gray text-sm">{message}</p>
  60. </div>
  61. </div>
  62. <div className="flex gap-3 mt-6">
  63. <Button variant="secondary" onClick={onCancel} className="flex-1">
  64. {cancelText}
  65. </Button>
  66. <Button
  67. onClick={onConfirm}
  68. className={`flex-1 ${styles.button}`}
  69. >
  70. {confirmText}
  71. </Button>
  72. </div>
  73. </CardContent>
  74. </Card>
  75. </div>
  76. );
  77. }