"use client"; import { createContext, useCallback, useContext, useEffect, useMemo, useRef, useState, useTransition } from "react"; import { useRouter } from "next/navigation"; import { Undo2, X } from "lucide-react"; import { restoreImages } from "@/app/actions/trash"; interface ToastState { ids: number[]; visibleAt: number; failed?: { message: string }; } interface Ctx { show: (ids: number[]) => void; } const ToastCtx = createContext(null); const VISIBLE_MS = 8000; export function UndoDeleteToastProvider({ children }: { children: React.ReactNode }) { const [state, setState] = useState(null); const timerRef = useRef(null); const router = useRouter(); const [pending, start] = useTransition(); const dismiss = useCallback(() => { setState(null); if (timerRef.current != null) { clearTimeout(timerRef.current); timerRef.current = null; } }, []); const show = useCallback((ids: number[]) => { if (ids.length === 0) return; setState({ ids, visibleAt: Date.now() }); if (timerRef.current != null) clearTimeout(timerRef.current); timerRef.current = window.setTimeout(() => setState(null), VISIBLE_MS); }, []); useEffect(() => () => { if (timerRef.current != null) clearTimeout(timerRef.current); }, []); const undo = () => { if (!state) return; const ids = state.ids; // Hide the trash-confirmation copy while the restore is in flight, // but DON'T dismiss the toast — if restoreImages throws, the items // are still in trash and the user has no signal. Re-surface in the // catch with a retry affordance. if (timerRef.current != null) { clearTimeout(timerRef.current); timerRef.current = null; } start(async () => { try { await restoreImages(ids); router.refresh(); setState(null); } catch (e) { setState({ ids, visibleAt: Date.now(), failed: { message: (e as Error).message || "Restore failed" }, }); timerRef.current = window.setTimeout(() => setState(null), VISIBLE_MS); } }); }; const ctx = useMemo(() => ({ show }), [show]); return ( {children} {state && (
{state.failed ? ( <> Restore failed — {state.failed.message} ) : ( <> {state.ids.length} moved to trash )}
)} ); } export function useUndoDeleteToast() { const ctx = useContext(ToastCtx); if (!ctx) throw new Error("useUndoDeleteToast must be used within UndoDeleteToastProvider"); return ctx; }