// frontend/components/Dialog.tsx // 앱 전역 통합 다이얼로그 — window.confirm/alert 대체. // useDialog().confirm({...}) → Promise, .alert({...}) → Promise. "use client"; import { createContext, useCallback, useContext, useEffect, useRef, useState, } from "react"; type DialogTone = "danger" | "primary"; export type DialogOptions = { title?: string; message?: string; confirmText?: string; cancelText?: string; // confirm 전용 tone?: DialogTone; }; type DialogState = DialogOptions & { kind: "confirm" | "alert" }; type DialogApi = { confirm: (opts: DialogOptions) => Promise; alert: (opts: DialogOptions) => Promise; }; const Ctx = createContext(null); export function useDialog(): DialogApi { const c = useContext(Ctx); if (!c) throw new Error("useDialog must be used within "); return c; } function DialogModal({ state, onClose, }: { state: DialogState; onClose: (ok: boolean) => void; }) { const isConfirm = state.kind === "confirm"; const tone: DialogTone = state.tone ?? (isConfirm ? "danger" : "primary"); const okRef = useRef(null); useEffect(() => { okRef.current?.focus(); const h = (e: KeyboardEvent) => { if (e.key === "Escape") { e.preventDefault(); onClose(false); } else if (e.key === "Enter") { e.preventDefault(); onClose(true); } }; window.addEventListener("keydown", h); return () => window.removeEventListener("keydown", h); }, [onClose]); return (
onClose(false)} role="presentation">
e.stopPropagation()} > {state.title &&

{state.title}

} {state.message &&

{state.message}

}
{isConfirm && ( )}
); } export function DialogProvider({ children }: { children: React.ReactNode }) { const [state, setState] = useState(null); const resolver = useRef<((ok: boolean) => void) | null>(null); const close = useCallback((ok: boolean) => { resolver.current?.(ok); resolver.current = null; setState(null); }, []); const confirm = useCallback( (opts: DialogOptions) => new Promise((resolve) => { resolver.current = resolve; setState({ kind: "confirm", ...opts }); }), [], ); const alert = useCallback( (opts: DialogOptions) => new Promise((resolve) => { resolver.current = () => resolve(); setState({ kind: "alert", ...opts }); }), [], ); return ( {children} {state && } ); }