feat(17-04): wire initiative dashboard with filter, list, and create dialog
Replace placeholder DashboardPage with fully functional initiative dashboard: - Page header with title, status filter dropdown, and New Initiative button - InitiativeList with statusFilter prop for backend-driven filtering - CreateInitiativeDialog controlled by local state - Navigation to /initiatives/$id via TanStack Router useNavigate - All card callbacks wired (view, spawn architect, delete placeholder)
This commit is contained in:
@@ -1,19 +1,76 @@
|
|||||||
import { createFileRoute } from '@tanstack/react-router'
|
import { useState } from "react";
|
||||||
import { trpc } from '../../lib/trpc'
|
import { createFileRoute, useNavigate } from "@tanstack/react-router";
|
||||||
|
import { Plus } from "lucide-react";
|
||||||
|
import { Button } from "@/components/ui/button";
|
||||||
|
import { InitiativeList } from "@/components/InitiativeList";
|
||||||
|
import { CreateInitiativeDialog } from "@/components/CreateInitiativeDialog";
|
||||||
|
|
||||||
export const Route = createFileRoute('/initiatives/')({
|
export const Route = createFileRoute("/initiatives/")({
|
||||||
component: DashboardPage,
|
component: DashboardPage,
|
||||||
})
|
});
|
||||||
|
|
||||||
|
type StatusFilter = "all" | "active" | "completed" | "archived";
|
||||||
|
|
||||||
|
const filterOptions: { value: StatusFilter; label: string }[] = [
|
||||||
|
{ value: "all", label: "All" },
|
||||||
|
{ value: "active", label: "Active" },
|
||||||
|
{ value: "completed", label: "Completed" },
|
||||||
|
{ value: "archived", label: "Archived" },
|
||||||
|
];
|
||||||
|
|
||||||
function DashboardPage() {
|
function DashboardPage() {
|
||||||
const health = trpc.health.useQuery()
|
const navigate = useNavigate();
|
||||||
|
const [statusFilter, setStatusFilter] = useState<StatusFilter>("all");
|
||||||
|
const [createDialogOpen, setCreateDialogOpen] = useState(false);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div className="space-y-6">
|
||||||
<h1 className="text-2xl font-bold">Initiative Dashboard</h1>
|
{/* Page header */}
|
||||||
<p className="text-muted-foreground mt-2">
|
<div className="flex items-center justify-between">
|
||||||
Server: {health.data?.status ?? 'connecting...'}
|
<h1 className="text-2xl font-bold">Initiatives</h1>
|
||||||
</p>
|
<div className="flex items-center gap-3">
|
||||||
<p className="text-muted-foreground mt-1">Content coming in Phase 17</p>
|
<select
|
||||||
</div>
|
value={statusFilter}
|
||||||
)
|
onChange={(e) =>
|
||||||
|
setStatusFilter(e.target.value as StatusFilter)
|
||||||
|
}
|
||||||
|
className="rounded-md border border-input bg-background px-3 py-1.5 text-sm ring-offset-background focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2"
|
||||||
|
>
|
||||||
|
{filterOptions.map((opt) => (
|
||||||
|
<option key={opt.value} value={opt.value}>
|
||||||
|
{opt.label}
|
||||||
|
</option>
|
||||||
|
))}
|
||||||
|
</select>
|
||||||
|
<Button size="sm" onClick={() => setCreateDialogOpen(true)}>
|
||||||
|
<Plus className="mr-1 h-4 w-4" />
|
||||||
|
New Initiative
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Initiative list */}
|
||||||
|
<InitiativeList
|
||||||
|
statusFilter={statusFilter}
|
||||||
|
onCreateNew={() => setCreateDialogOpen(true)}
|
||||||
|
onViewInitiative={(id) =>
|
||||||
|
navigate({ to: "/initiatives/$id", params: { id } })
|
||||||
|
}
|
||||||
|
onSpawnArchitect={(_initiativeId, _mode) => {
|
||||||
|
// Architect spawning is self-contained within SpawnArchitectDropdown
|
||||||
|
// This callback is available for future toast notifications
|
||||||
|
}}
|
||||||
|
onDeleteInitiative={(_id) => {
|
||||||
|
// Delete is a placeholder (no deleteInitiative tRPC procedure yet)
|
||||||
|
// ActionMenu handles this internally when implemented
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
|
||||||
|
{/* Create initiative dialog */}
|
||||||
|
<CreateInitiativeDialog
|
||||||
|
open={createDialogOpen}
|
||||||
|
onOpenChange={setCreateDialogOpen}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user