diff --git a/frontend/src/app/senators/[id]/loading.tsx b/frontend/src/app/senators/[id]/loading.tsx new file mode 100644 index 0000000..1a217c7 --- /dev/null +++ b/frontend/src/app/senators/[id]/loading.tsx @@ -0,0 +1,5 @@ +import LoadingSpinner from "@/components/ui/LoadingSpinner"; + +export default function SenatorDetailLoading() { + return ; +} diff --git a/frontend/src/app/senators/[id]/not-found.tsx b/frontend/src/app/senators/[id]/not-found.tsx new file mode 100644 index 0000000..d1480a3 --- /dev/null +++ b/frontend/src/app/senators/[id]/not-found.tsx @@ -0,0 +1,17 @@ +import Link from "next/link"; +import { Button } from "@/components/ui/button"; + +export default function SenatorNotFound() { + return ( +
+

Senator Not Found

+

+ We couldn't find the senator you're looking for. They may no + longer be active or the ID is incorrect. +

+ +
+ ); +} diff --git a/frontend/src/app/senators/[id]/page.tsx b/frontend/src/app/senators/[id]/page.tsx new file mode 100644 index 0000000..a37e0ae --- /dev/null +++ b/frontend/src/app/senators/[id]/page.tsx @@ -0,0 +1,131 @@ +import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; +import { + Table, + TableBody, + TableCell, + TableHead, + TableHeader, + TableRow, +} from "@/components/ui/table"; +import { ApiError, getSenatorById } from "@/lib/api"; +import Link from "next/link"; +import { notFound } from "next/navigation"; + +export const dynamic = "force-dynamic"; + +function initials(name: string) { + return name + .split(" ") + .map((s) => s[0]?.toUpperCase() ?? "") + .slice(0, 2) + .join(""); +} + +export default async function SenatorDetailPage({ + params, +}: { + params: Promise<{ id: string }>; +}) { + const resolvedParams = await params; + let senator; + + try { + senator = await getSenatorById(resolvedParams.id); + } catch (error) { + if (error instanceof ApiError && error.status === 404) { + notFound(); + } + throw error; + } + + const fullName = `${senator.first_name} ${senator.last_name}`; + + return ( +
+
+ {senator.headshot_url ? ( + // eslint-disable-next-line @next/next/no-img-element + {fullName} + ) : ( +
+ {initials(fullName)} +
+ )} +
+

{fullName}

+ {senator.email && ( + + {senator.email} + + )} +
+
+ + + + Details + + +

+ District:{" "} + {senator.district_id} +

+

+ Session:{" "} + {senator.session_number} +

+

+ Status:{" "} + {senator.is_active ? "Active" : "Inactive"} +

+
+
+ +
+

Committee Assignments

+
+ + + + Committee + Role + + + + {senator.committees.map((c) => ( + + + + {c.committee_name} + + + {c.role} + + ))} + {senator.committees.length === 0 && ( + + + No committee assignments. + + + )} + +
+
+
+
+ ); +}