"use client";
import * as React from "react";
import { Archive, Send, Trash2 } from "lucide-react";
import { UndoCountdownButton } from "@/components/ui/undo-countdown-button";
import type { UndoState } from "@/components/ui/undo-countdown-button";
type DemoProps = { autoplay?: boolean; bare?: boolean; controlled?: boolean; window?: number };
type LogEntry = { id: number; text: string };
const ACTIONS = [
{ id: "invoice", label: "Send invoice", icon: Send, variant: "default" as const, commit: "Invoice #1042 sent", undo: "Invoice kept as draft" },
{ id: "delete", label: "Delete project", icon: Trash2, variant: "destructive" as const, commit: "Project deleted", undo: "Project restored" },
{ id: "archive", label: "Archive 3 tasks", icon: Archive, variant: "outline" as const, commit: "3 tasks archived", undo: "Tasks left in place" },
];
export default function UndoCountdownDemo({ autoplay = true, bare = false, controlled = false, window: undoWindow = 5000 }: DemoProps) {
const [log, setLog] = React.useState([] as LogEntry[]);
const [states, setStates] = React.useState({ invoice: "idle", delete: "idle", archive: "idle" } as { [id: string]: UndoState });
const [motion, setMotion] = React.useState({ ready: false, reduced: true });
const [run, setRun] = React.useState(0);
const [paused, setPaused] = React.useState(false);
const refs = React.useRef({} as { [id: string]: HTMLButtonElement | null });
const counter = React.useRef(0);
const note = (text: string) => setLog((previous) => [{ id: ++counter.current, text }, ...previous].slice(0, 4));
React.useEffect(() => {
const media = window.matchMedia("(prefers-reduced-motion: reduce)");
const update = () => setMotion({ ready: true, reduced: media.matches });
update();
media.addEventListener("change", update);
return () => media.removeEventListener("change", update);
}, []);
React.useEffect(() => {
if (!motion.ready || !autoplay || motion.reduced || paused) return;
const timers: number[] = [];
const click = (id: string) => refs.current[id]?.click();
timers.push(window.setTimeout(() => click("invoice"), 600));
timers.push(window.setTimeout(() => click("delete"), 1600));
timers.push(window.setTimeout(() => click("delete"), 3300));
timers.push(window.setTimeout(() => click("archive"), 4200));
timers.push(window.setTimeout(() => setRun((previous) => previous + 1), 11000));
return () => timers.forEach((timer) => window.clearTimeout(timer));
}, [motion.ready, motion.reduced, autoplay, paused, run]);
return (
<main className="flex min-h-svh w-full flex-col items-center justify-center gap-5 bg-background px-5 py-6 text-foreground" onPointerDownCapture={() => autoplay && setPaused(true)}>
{!bare && (
<header className="w-full max-w-[420px]">
<p className="mb-1 text-[10px] font-medium uppercase tracking-[0.2em] text-muted-foreground">Five seconds to change your mind</p>
<h1 className="text-[24px] font-semibold leading-tight tracking-tight">No confirm dialog. Just undo.</h1>
</header>
)}
<div className="w-full max-w-[420px] space-y-3 rounded-3xl border border-border bg-card p-5 shadow-xl shadow-primary/5">
{ACTIONS.map((action) => {
const Icon = action.icon;
return (
<div key={action.id} className="flex items-center justify-between gap-4">
<span className="flex min-w-0 items-center gap-2 text-sm text-muted-foreground"><Icon className="size-4 shrink-0" aria-hidden="true" /><span className="truncate">{action.label}</span></span>
<UndoCountdownButton
ref={(node) => { refs.current[action.id] = node; }}
label={action.label}
variant={action.variant}
undoWindow={undoWindow}
{...(controlled ? { state: states[action.id], onStateChange: (state) => setStates((previous) => ({ ...previous, [action.id]: state })) } : {})}
onStart={() => note(`${action.label} · undo in ${Math.round(undoWindow / 1000)}s`)}
onCommit={() => note(action.commit)}
onUndo={() => note(action.undo)}
className="min-w-[164px]"
/>
</div>
);
})}
<ul data-log aria-label="Activity" className="mt-2 min-h-[72px] space-y-1 border-t border-border pt-3 text-xs text-muted-foreground">
{log.length === 0 ? <li className="text-muted-foreground/70">Sample actions · nothing is really sent</li> : log.map((entry) => <li key={entry.id} data-log-entry className="truncate">{entry.text}</li>)}
</ul>
</div>
{!bare && (
<footer className="flex w-full max-w-[420px] items-center justify-between text-[10px] text-muted-foreground">
<span>Click once to start, click again to undo</span>
<button type="button" data-replay onClick={() => { setPaused(false); setLog([]); setRun((previous) => previous + 1); }} className="rounded px-1 underline decoration-border underline-offset-4 hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring">Replay</button>
</footer>
)}
</main>
);
}