diff --git a/src/app/admin/clients/page.tsx b/src/app/admin/clients/page.tsx new file mode 100644 index 0000000..b2db361 --- /dev/null +++ b/src/app/admin/clients/page.tsx @@ -0,0 +1,53 @@ +import { AppShell } from "@/components/shell/app-shell"; +import { TopBar } from "@/components/shell/top-bar"; +import { AdminTable, AdminCell } from "@/components/admin/admin-table"; +import { NewClientForm, ToggleClientActive } from "@/components/admin/client-form"; +import { Pill } from "@/components/ui/pill"; +import { loadClients } from "@/lib/data/admin"; + +export default async function AdminClientsPage() { + const rows = await loadClients(); + + return ( + + + + + +
+ + {rows.map(({ client, projectCount, managerCount }) => ( + + +
+ + + {client.name} + + {client.slug} +
+
+ {projectCount} + {managerCount} + + + {client.active ? "Active" : "Inactive"} + + + + + + + ))} +
+
+
+ ); +} \ No newline at end of file diff --git a/src/components/admin/client-form.tsx b/src/components/admin/client-form.tsx new file mode 100644 index 0000000..edac38f --- /dev/null +++ b/src/components/admin/client-form.tsx @@ -0,0 +1,111 @@ +"use client"; + +import { useState, useTransition } from "react"; +import { Plus } from "lucide-react"; + +import { createClient, updateClient } from "@/app/actions/clients"; +import type { ClientRecord } from "@/lib/pb/types"; + +export function NewClientForm() { + const [open, setOpen] = useState(false); + const [name, setName] = useState(""); + const [brandColor, setBrandColor] = useState("#2f6dad"); + const [pending, startTransition] = useTransition(); + const [error, setError] = useState(null); + + function submit(event: React.FormEvent) { + event.preventDefault(); + if (!name.trim()) return; + setError(null); + + startTransition(async () => { + try { + await createClient({ name, brandColor }); + setName(""); + setOpen(false); + } catch (e) { + setError(e instanceof Error ? e.message : "Could not create that client"); + } + }); + } + + if (!open) { + return ( + + ); + } + + return ( +
+ + + + + + + + {error && ( +

+ {error} +

+ )} +
+ ); +} + +export function ToggleClientActive({ client }: { client: ClientRecord }) { + const [pending, startTransition] = useTransition(); + + return ( + + ); +} \ No newline at end of file