Files
Hotel-Booking/Frontend/src/shared/components/ConfirmationDialog.tsx
Iliyan Angelov 39fcfff811 update
2025-11-30 22:43:09 +02:00

163 lines
5.5 KiB
TypeScript

import React from 'react';
import { AlertTriangle, X } from 'lucide-react';
interface ConfirmationDialogProps {
isOpen: boolean;
onClose: () => void;
onConfirm: () => void;
title: string;
message: string;
confirmText?: string;
cancelText?: string;
variant?: 'danger' | 'warning' | 'info';
isLoading?: boolean;
}
const ConfirmationDialog: React.FC<ConfirmationDialogProps> = ({
isOpen,
onClose,
onConfirm,
title,
message,
confirmText = 'Confirm',
cancelText = 'Cancel',
variant = 'info',
isLoading = false,
}) => {
if (!isOpen) return null;
return (
<div
className="fixed inset-0 z-50 overflow-y-auto"
aria-labelledby="modal-title"
role="dialog"
aria-modal="true"
>
{}
<div
className="fixed inset-0 bg-black/60 backdrop-blur-sm transition-opacity"
onClick={onClose}
aria-hidden="true"
/>
{}
<div className="flex min-h-full items-end justify-center p-4 text-center sm:items-center sm:p-0">
<div className="relative transform overflow-hidden rounded-sm bg-gradient-to-b from-white to-gray-50 text-left shadow-2xl border border-[#d4af37]/20 transition-all sm:my-8 sm:w-full sm:max-w-lg animate-fade-in">
{}
<button
onClick={onClose}
className="absolute right-4 top-4 text-gray-400 hover:text-[#d4af37] focus:outline-none focus:ring-2 focus:ring-[#d4af37]/50 rounded-sm p-1 transition-colors"
aria-label="Close"
>
<X className="w-5 h-5" />
</button>
<div className="bg-transparent px-4 pb-4 pt-5 sm:p-6 sm:pb-4">
<div className="sm:flex sm:items-start">
<div
className={`mx-auto flex h-12 w-12 flex-shrink-0 items-center justify-center rounded-full ${
variant === 'danger'
? 'bg-red-100 border-2 border-red-200'
: variant === 'warning'
? 'bg-[#d4af37]/20 border-2 border-[#d4af37]/40'
: 'bg-[#d4af37]/20 border-2 border-[#d4af37]/40'
} sm:mx-0 sm:h-10 sm:w-10`}
>
<AlertTriangle
className={`h-6 w-6 ${
variant === 'danger'
? 'text-red-600'
: variant === 'warning'
? 'text-[#d4af37]'
: 'text-[#d4af37]'
}`}
aria-hidden="true"
/>
</div>
<div className="mt-3 text-center sm:ml-4 sm:mt-0 sm:text-left">
<h3
className="text-lg font-serif font-semibold leading-6 text-gray-900 tracking-tight"
id="modal-title"
>
{title}
</h3>
<div className="mt-2">
<p className="text-sm text-gray-600 font-light leading-relaxed">{message}</p>
</div>
</div>
</div>
</div>
<div className="bg-gray-50/50 backdrop-blur-sm px-4 py-4 sm:flex sm:flex-row-reverse sm:px-6 gap-3 border-t border-gray-200">
<button
type="button"
onClick={onConfirm}
disabled={isLoading}
className={`inline-flex w-full justify-center rounded-sm px-4 py-2.5 text-sm font-medium tracking-wide text-white shadow-lg sm:ml-3 sm:w-auto focus:outline-none focus:ring-2 focus:ring-offset-2 disabled:opacity-50 disabled:cursor-not-allowed transition-all ${
variant === 'danger'
? 'bg-red-600 hover:bg-red-700 focus:ring-red-500'
: variant === 'warning'
? 'bg-gradient-to-r from-[#d4af37] to-[#c9a227] hover:from-[#f5d76e] hover:to-[#d4af37] focus:ring-[#d4af37]'
: 'btn-luxury-primary focus:ring-[#d4af37]'
}`}
>
{isLoading ? (
<span className="flex items-center gap-2">
<svg
className="animate-spin h-4 w-4 text-white"
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
>
<circle
className="opacity-25"
cx="12"
cy="12"
r="10"
stroke="currentColor"
strokeWidth="4"
/>
<path
className="opacity-75"
fill="currentColor"
d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"
/>
</svg>
Processing...
</span>
) : (
confirmText
)}
</button>
<button
type="button"
onClick={onClose}
disabled={isLoading}
className="mt-3 inline-flex w-full justify-center rounded-sm bg-white/80 backdrop-blur-sm px-4 py-2.5 text-sm font-medium tracking-wide text-gray-700 shadow-sm border border-gray-300 hover:bg-white hover:border-[#d4af37]/30 hover:text-[#d4af37] sm:mt-0 sm:w-auto disabled:opacity-50 disabled:cursor-not-allowed transition-all"
>
{cancelText}
</button>
</div>
</div>
</div>
</div>
);
};
export default ConfirmationDialog;