import * as React from 'react'; import { Loader2 } from 'lucide-react'; import { cn } from '@/lib/utils'; import { Dialog, DialogContent, DialogHeader, DialogFooter, DialogTitle, DialogDescription, } from '@/components/ui/dialog'; import { Button } from '@/components/ui/button'; type ConfirmVariant = 'default' | 'destructive'; interface ConfirmDialogProps { open: boolean; onOpenChange: (open: boolean) => void; title?: string; description?: React.ReactNode; confirmLabel?: string; cancelLabel?: string; variant?: ConfirmVariant; onConfirm?: () => void | Promise; loading?: boolean; } /* ── ConfirmDialog ────────────────────────────────────────────── Reusable confirmation dialog that replaces window.confirm. */ export function ConfirmDialog({ open, onOpenChange, title, description, confirmLabel = 'Confirm', cancelLabel = 'Cancel', variant = 'default', onConfirm, loading = false, }: ConfirmDialogProps) { const handleConfirm = async () => { await onConfirm?.(); }; const handleCancel = () => { if (!loading) onOpenChange(false); }; return ( {title} {description && ( {description} )} ); } /* ── useConfirm hook ──────────────────────────────────────────── Imperative API for ConfirmDialog. Usage: const { confirm, ConfirmDialogComponent } = useConfirm(); const ok = await confirm({ title, description, confirmLabel, variant }); // Render anywhere in the tree. */ interface ConfirmState { open: boolean; title: string; description: React.ReactNode; confirmLabel: string; cancelLabel: string; variant: ConfirmVariant; loading: boolean; } interface ConfirmOptions { title?: string; description?: React.ReactNode; confirmLabel?: string; cancelLabel?: string; variant?: ConfirmVariant; } export function useConfirm() { const [state, setState] = React.useState({ open: false, title: '', description: '', confirmLabel: 'Confirm', cancelLabel: 'Cancel', variant: 'default', loading: false, }); // Keep a stable ref to the resolve callback so it survives re-renders const resolveRef = React.useRef<((value: boolean) => void) | null>(null); const confirm = React.useCallback( ({ title = 'Are you sure?', description = '', confirmLabel = 'Confirm', cancelLabel = 'Cancel', variant = 'default', }: ConfirmOptions = {}): Promise => { return new Promise((resolve) => { resolveRef.current = resolve; setState({ open: true, title, description, confirmLabel, cancelLabel, variant, loading: false, }); }); }, [] ); const handleConfirm = React.useCallback(async () => { setState((s) => ({ ...s, loading: true })); resolveRef.current?.(true); resolveRef.current = null; setState((s) => ({ ...s, open: false, loading: false })); }, []); const handleOpenChange = React.useCallback((open: boolean) => { if (!open) { resolveRef.current?.(false); resolveRef.current = null; setState((s) => ({ ...s, open: false })); } }, []); const ConfirmDialogComponent = React.useCallback( () => ( ), [state, handleConfirm, handleOpenChange] ); return { confirm, ConfirmDialogComponent }; }