import React, { useEffect, useCallback, type ReactNode } from 'react' import { createPortal } from 'react-dom' import { AlertTriangle, HelpCircle } from 'lucide-react' import { useTranslation } from '../../i18n' import { useIsPhone } from '../../mobile/useIsPhone' import { DialogTile, NEUTRAL_TINT, fs } from './DialogShell' interface ConfirmDialogProps { isOpen: boolean onClose: () => void onConfirm: () => void title?: string message?: string confirmLabel?: string cancelLabel?: string danger?: boolean /** Extra content under the message, such as a list of what the action takes with it. */ children?: ReactNode } // Callers commonly pass an async handler that reports its own failure and then // rethrows. The dialog has already closed at that point, so the rejection would // escape as an unhandled promise — absorb it here. function runConfirm(onConfirm: () => void): void { const result = onConfirm() as unknown if (result && typeof (result as PromiseLike).then === 'function') { void Promise.resolve(result).catch(() => {}) } } export default function ConfirmDialog({ isOpen, onClose, onConfirm, title, message, confirmLabel, cancelLabel, danger = true, children, }: ConfirmDialogProps) { const { t } = useTranslation() const isPhone = useIsPhone() // Captured and stopped here: the question often opens over another dialog // (a Modal) that closes on Escape too, and one key press should only take // back the question, not the dialog it was asked from. const handleEsc = useCallback((e: KeyboardEvent) => { if (e.key !== 'Escape') return e.stopPropagation() onClose() }, [onClose]) useEffect(() => { if (!isOpen) return document.addEventListener('keydown', handleEsc, true) return () => document.removeEventListener('keydown', handleEsc, true) }, [isOpen, handleEsc]) if (!isOpen) return null return createPortal(
{isPhone ? ( <> {/* Capped at the viewport: a long list of what goes along scrolls on its own, and the two buttons below it always stay in reach. */}
e.stopPropagation()} >
{danger && (
)}

{title || t('common.confirm')}

{message}

{children}
) : ( // The desktop draws the question like the planner's dialogs: a head band // with its tile, the message below, the answers in a bar at the foot.
e.stopPropagation()} >
{danger ? : }

{title || t('common.confirm')}

{message}

{children}
)}
, document.body ) }