import { useEffect, useRef, useState, type ReactNode } from 'react'; import { DialogRoot, DialogContent, DialogFooter } from './ui/dialog'; import { Input } from './ui/input'; import { buttonVariants } from './ui/button'; import { cn } from '../lib/utils'; export interface ConfirmOptions { title: string; body?: ReactNode; confirmLabel?: string; cancelLabel?: string; danger?: boolean; /** When set, the confirm button stays disabled until this exact text is typed. */ requireText?: string; requireTextLabel?: string; } interface ConfirmRequest { options: ConfirmOptions; resolve: (ok: boolean) => void; } export function ConfirmDialog({request, onClose}: {request: ConfirmRequest | undefined; onClose: (ok: boolean) => void}) { const [typed, setTyped] = useState(''); useEffect(() => { setTyped(''); }, [request]); const options = request?.options; const needsText = !!options?.requireText; const confirmed = !needsText || typed === options?.requireText; return { if (!open) onClose(false); }}> {options && { if (!needsText) return; e.preventDefault(); }}> {options.body &&
{options.body}
} {needsText && }
}
; } /** * Promise-based replacement for window.confirm / window.prompt(confirm-id). * Render {confirm.element} once near the page root; ask() resolves true/false. * Plain functions (no useCallback) keep it usable in bare vnode-tree tests. */ export function useConfirm() { const [request, setRequest] = useState(); // A ref tracks the live request so back-to-back ask() calls (e.g. a fast // double submit before re-render) cancel the previous promise instead of // leaking it. Direct value sets keep bare vnode-tree tests working. const current = useRef(undefined); useEffect(() => () => { current.current?.resolve(false); current.current = undefined; }, []); const ask = (options: ConfirmOptions) => new Promise(resolve => { current.current?.resolve(false); const next: ConfirmRequest = {options, resolve}; current.current = next; setRequest(next); }); const close = (ok: boolean) => { current.current?.resolve(ok); current.current = undefined; setRequest(undefined); }; return {ask, element: }; }