Implement tasks 25, 26 + completion visibility setting

Task 25: Multiple dashboards — dashboards table + migration, /d/[slug]
route, root redirect, dashboard tabs in nav with create/rename/delete/
set-default. Task 26: Editable dashboard — react-grid-layout drag/resize
editor, widget picker modal with per-widget configurator auto-generated
from default config, save/reset server actions with Zod validation.

Completion visibility: server-side per-user setting (hours) replaces
localStorage timer; queries filter completed items by updatedAt cutoff;
Settings page dropdown persists preference via server action.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
ginnoir
2026-05-06 15:52:59 -05:00
co-authored by Claude Sonnet 4.6
parent 2ad9521ef9
commit d5a8bf9d95
27 changed files with 1646 additions and 237 deletions
+26 -10
View File
@@ -1,25 +1,41 @@
"use client";
import { DELAY_OPTIONS, useCompletionDelay } from "@/hooks/use-completion-delay";
import { useTransition } from "react";
import { setCompletionVisibilityHours } from "@/app/settings/actions";
export function CompletionDelaySetting() {
const { delay, setDelay } = useCompletionDelay();
const OPTIONS = [
{ label: "1 hour", value: 1 },
{ label: "4 hours", value: 4 },
{ label: "8 hours", value: 8 },
{ label: "24 hours (default)", value: 24 },
{ label: "48 hours", value: 48 },
{ label: "7 days", value: 168 },
{ label: "Never hide", value: 8760 },
];
export function CompletionDelaySetting({ initialHours }: { initialHours: number }) {
const [isPending, startTransition] = useTransition();
function handleChange(e: React.ChangeEvent<HTMLSelectElement>) {
const hours = Number(e.target.value);
startTransition(() => setCompletionVisibilityHours(hours));
}
return (
<div className="flex items-center justify-between gap-4">
<div>
<p className="text-sm font-medium">Completion delay</p>
<p className="text-sm font-medium">Show completed items for</p>
<p className="text-xs text-muted-foreground">
How long a checked-off item stays visible before disappearing from list cards and the
dashboard.
How long checked-off items remain visible on list cards and the dashboard.
</p>
</div>
<select
value={delay}
onChange={(e) => setDelay(Number(e.target.value))}
className="rounded-md border border-input bg-background px-3 py-1.5 text-sm shadow-sm focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring"
defaultValue={initialHours}
onChange={handleChange}
disabled={isPending}
className="rounded-md border border-input bg-background px-3 py-1.5 text-sm shadow-sm focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:opacity-50"
>
{DELAY_OPTIONS.map((opt) => (
{OPTIONS.map((opt) => (
<option key={opt.value} value={opt.value}>
{opt.label}
</option>