Files
pdf/frontend/src/components/custom/CustomConfirmationModal.tsx
T
2026-06-10 15:16:20 +05:30

80 lines
3.4 KiB
TypeScript

import React, { useEffect } from 'react';
import { CustomButton } from './CustomButton';
export interface CustomConfirmationOptions {
title: string;
message: string;
confirmLabel?: string;
danger?: boolean;
}
export interface CustomConfirmationModalProps {
state: (CustomConfirmationOptions & { onConfirm: () => void }) | null;
onClose: () => void;
}
export const CustomConfirmationModal: React.FC<CustomConfirmationModalProps> = ({ state, onClose }) => {
useEffect(() => {
if (!state) return;
const onKey = (e: KeyboardEvent) => e.key === 'Escape' && onClose();
document.addEventListener('keydown', onKey);
return () => document.removeEventListener('keydown', onKey);
}, [state, onClose]);
if (!state) return null;
return (
<div className="fixed inset-0 z-[200] flex items-center justify-center p-4" onMouseDown={onClose}>
{/* Backdrop */}
<div
className="absolute inset-0 bg-[#0f172a]/30 backdrop-blur-[2px]"
style={{ animation: 'toastIn 0.2s ease-out' }}
/>
{/* Modal Content */}
<div
style={{ width: 440, animation: 'slideUp 0.25s cubic-bezier(0.16, 1, 0.3, 1)' }}
className="relative flex max-h-[90vh] flex-col overflow-hidden rounded-[16px] bg-[#ffffff] shadow-[0_24px_48px_rgba(16,24,40,0.18)] ring-1 ring-[#ebedf0]"
onMouseDown={(e) => e.stopPropagation()}
>
<div className="flex flex-col gap-2.5 p-7 pb-6">
<div className="flex items-center gap-3">
{state.danger ? (
<div className="flex h-10 w-10 shrink-0 items-center justify-center rounded-full bg-[#fdecec] text-[#dc2626]">
<svg width="22" height="22" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={2}>
<path strokeLinecap="round" strokeLinejoin="round" d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z" />
</svg>
</div>
) : (
<div className="flex h-10 w-10 shrink-0 items-center justify-center rounded-full bg-[#eef4ff] text-[#2563eb]">
<svg width="22" height="22" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={2}>
<path strokeLinecap="round" strokeLinejoin="round" d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" />
</svg>
</div>
)}
<h2 className="text-[17.5px] font-bold tracking-tight text-[#18212e]">{state.title}</h2>
</div>
<p className="pl-[52px] text-[13.5px] leading-relaxed text-[#5b6573]">{state.message}</p>
</div>
<div className="flex items-center justify-end gap-3 bg-[#f6f7f9] px-7 py-5 border-t border-[#ebedf0]">
<CustomButton variant="ghost" onClick={onClose} className="rounded-[8px] font-semibold px-4 text-[#5b6573]">
Cancel
</CustomButton>
<CustomButton
variant={state.danger ? 'danger' : 'primary'}
onClick={() => { state.onConfirm(); onClose(); }}
className={`rounded-[8px] px-5 font-semibold text-white shadow-sm transition-colors ${
state.danger
? 'bg-[#dc2626] hover:bg-[#b91c1c]'
: 'bg-[#2563eb] hover:bg-[#1d4ed8]'
}`}
>
{state.confirmLabel ?? 'Confirm'}
</CustomButton>
</div>
</div>
</div>
);
};