feat: implement Story 1.1 — create and view diagrams

Add diagram/project DB schema, CRUD API, dashboard pages with grid/card/
empty state, create dialog with type selector, editor placeholder, and
26 schema validation tests. Includes code review fixes: soft-delete
filter on GET /:id, error handling, keyboard accessibility, type-safe
API response types, and error states on pages.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Alejandro Gutiérrez
2026-02-22 23:54:50 +00:00
parent da3368fbdb
commit 392da385f4
20 changed files with 3785 additions and 0 deletions

View File

@@ -0,0 +1,49 @@
"use client";
import { useParams } from "next/navigation";
import { useQuery } from "@tanstack/react-query";
import { Icons } from "@turbostarter/ui-web/icons";
import { api } from "~/lib/api/client";
export default function DiagramEditorPage() {
const params = useParams<{ id: string }>();
const { data, isLoading, isError } = useQuery({
queryKey: ["diagram", params.id],
queryFn: async () => {
const res = await api.diagrams[":id"].$get({ param: { id: params.id } });
return await res.json();
},
});
if (isLoading) {
return (
<div className="flex h-full items-center justify-center">
<Icons.Loader2 className="h-6 w-6 animate-spin text-muted-foreground" />
</div>
);
}
if (isError) {
return (
<div className="flex h-full flex-col items-center justify-center gap-2 p-6">
<Icons.AlertTriangle className="h-8 w-8 text-destructive" />
<p className="text-sm text-muted-foreground">
Failed to load diagram. It may have been deleted or you don't have access.
</p>
</div>
);
}
return (
<div className="flex h-full flex-col items-center justify-center gap-4 p-6">
<Icons.LayoutDashboard className="h-16 w-16 text-muted-foreground/30" />
<div className="text-center">
<h1 className="text-xl font-semibold">{data?.data?.title ?? "Diagram"}</h1>
<p className="mt-2 text-sm text-muted-foreground">
The diagram editor canvas will be implemented in Epic 2.
</p>
</div>
</div>
);
}

View File

@@ -0,0 +1,33 @@
"use client";
import { useQuery } from "@tanstack/react-query";
import { Icons } from "@turbostarter/ui-web/icons";
import { api } from "~/lib/api/client";
import { DiagramGrid } from "~/modules/diagram/components/DiagramGrid";
export default function DiagramsPage() {
const { data, isLoading, isError } = useQuery({
queryKey: ["diagrams"],
queryFn: async () => {
const res = await api.diagrams.$get();
return await res.json();
},
});
if (isError) {
return (
<div className="flex h-full flex-col items-center justify-center gap-2 p-6">
<Icons.AlertTriangle className="h-8 w-8 text-destructive" />
<p className="text-sm text-muted-foreground">
Failed to load diagrams. Please try again later.
</p>
</div>
);
}
return (
<div className="@container h-full p-6">
<DiagramGrid diagrams={data?.data ?? []} isLoading={isLoading} />
</div>
);
}