fix+upstream: hooks-order crash, ConfirmDialog/PageHeader/skeletons, styled error boundary

Hoists hooks above early return (render-time Navigate); ports finance's
ConfirmDialog/PageHeader/loading/states + APC error-copy mapper; removes
window.confirm, dead appbar search, and seeded fake notifications; wires toasts.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
jules
2026-07-04 13:46:12 +10:00
parent 3dbf2ac175
commit 675f6f8b35
13 changed files with 809 additions and 319 deletions

View File

@@ -0,0 +1,99 @@
import { useState, type ReactElement, type ReactNode } from "react"
import { Loader2 } from "lucide-react"
import {
AlertDialog,
AlertDialogAction,
AlertDialogCancel,
AlertDialogContent,
AlertDialogDescription,
AlertDialogFooter,
AlertDialogHeader,
AlertDialogTitle,
AlertDialogTrigger,
} from "~/components/ui/alert-dialog"
type Props = {
/** The element that opens the dialog — a Button or bare button. */
trigger: ReactElement
title: string
description?: ReactNode
confirmLabel?: string
destructive?: boolean
onConfirm: () => Promise<void> | void
}
/** Branded confirm dialog. Replaces `window.confirm` — branded buttons,
* keyboard-trapped, dismisses on Esc, awaits async confirm handlers
* so we can show a spinner while the operation runs. */
export function ConfirmDialog({
trigger,
title,
description,
confirmLabel = "Confirm",
destructive,
onConfirm,
}: Props) {
const [open, setOpen] = useState(false)
const [busy, setBusy] = useState(false)
const [error, setError] = useState<string | null>(null)
async function handleConfirm() {
setBusy(true)
setError(null)
try {
await onConfirm()
setOpen(false)
} catch (e) {
setError(e instanceof Error ? e.message : String(e))
} finally {
setBusy(false)
}
}
return (
<AlertDialog
open={open}
onOpenChange={(v) => {
if (!busy) setOpen(v)
}}
>
<AlertDialogTrigger render={trigger} />
<AlertDialogContent>
<AlertDialogHeader>
<AlertDialogTitle>{title}</AlertDialogTitle>
{description ? (
<AlertDialogDescription>{description}</AlertDialogDescription>
) : null}
</AlertDialogHeader>
{error ? <p className="text-sm text-destructive">{error}</p> : null}
<AlertDialogFooter>
<AlertDialogCancel data-action="confirm-cancel" disabled={busy}>
Cancel
</AlertDialogCancel>
<AlertDialogAction
data-action="confirm-accept"
onClick={(e) => {
e.preventDefault()
void handleConfirm()
}}
disabled={busy}
className={
destructive
? "bg-destructive text-destructive-foreground hover:bg-destructive/90"
: undefined
}
>
{busy ? (
<>
<Loader2 className="animate-spin" /> Working
</>
) : (
confirmLabel
)}
</AlertDialogAction>
</AlertDialogFooter>
</AlertDialogContent>
</AlertDialog>
)
}