diff --git a/src/routeTree.gen.ts b/src/routeTree.gen.ts index 9847ac5..83d2a1c 100644 --- a/src/routeTree.gen.ts +++ b/src/routeTree.gen.ts @@ -20,6 +20,7 @@ import { Route as AuthenticatedDashboardRouteImport } from './routes/_authentica import { Route as AuthenticatedCalendarRouteImport } from './routes/_authenticated/calendar' import { Route as AuthenticatedAttendanceRouteImport } from './routes/_authenticated/attendance' import { Route as AuthenticatedAdminRouteImport } from './routes/_authenticated/admin' +import { Route as AuthenticatedStudentsIndexRouteImport } from './routes/_authenticated/students.index' import { Route as AuthenticatedStudentsNewRouteImport } from './routes/_authenticated/students.new' import { Route as AuthenticatedStudentsIdRouteImport } from './routes/_authenticated/students.$id' @@ -77,6 +78,12 @@ const AuthenticatedAdminRoute = AuthenticatedAdminRouteImport.update({ path: '/admin', getParentRoute: () => AuthenticatedRouteRoute, } as any) +const AuthenticatedStudentsIndexRoute = + AuthenticatedStudentsIndexRouteImport.update({ + id: '/', + path: '/', + getParentRoute: () => AuthenticatedStudentsRoute, + } as any) const AuthenticatedStudentsNewRoute = AuthenticatedStudentsNewRouteImport.update({ id: '/new', @@ -102,6 +109,7 @@ export interface FileRoutesByFullPath { '/students': typeof AuthenticatedStudentsRouteWithChildren '/students/$id': typeof AuthenticatedStudentsIdRoute '/students/new': typeof AuthenticatedStudentsNewRoute + '/students/': typeof AuthenticatedStudentsIndexRoute } export interface FileRoutesByTo { '/': typeof IndexRoute @@ -113,9 +121,9 @@ export interface FileRoutesByTo { '/forms': typeof AuthenticatedFormsRoute '/ledger': typeof AuthenticatedLedgerRoute '/messages': typeof AuthenticatedMessagesRoute - '/students': typeof AuthenticatedStudentsRouteWithChildren '/students/$id': typeof AuthenticatedStudentsIdRoute '/students/new': typeof AuthenticatedStudentsNewRoute + '/students': typeof AuthenticatedStudentsIndexRoute } export interface FileRoutesById { __root__: typeof rootRouteImport @@ -132,6 +140,7 @@ export interface FileRoutesById { '/_authenticated/students': typeof AuthenticatedStudentsRouteWithChildren '/_authenticated/students/$id': typeof AuthenticatedStudentsIdRoute '/_authenticated/students/new': typeof AuthenticatedStudentsNewRoute + '/_authenticated/students/': typeof AuthenticatedStudentsIndexRoute } export interface FileRouteTypes { fileRoutesByFullPath: FileRoutesByFullPath @@ -148,6 +157,7 @@ export interface FileRouteTypes { | '/students' | '/students/$id' | '/students/new' + | '/students/' fileRoutesByTo: FileRoutesByTo to: | '/' @@ -159,9 +169,9 @@ export interface FileRouteTypes { | '/forms' | '/ledger' | '/messages' - | '/students' | '/students/$id' | '/students/new' + | '/students' id: | '__root__' | '/' @@ -177,6 +187,7 @@ export interface FileRouteTypes { | '/_authenticated/students' | '/_authenticated/students/$id' | '/_authenticated/students/new' + | '/_authenticated/students/' fileRoutesById: FileRoutesById } export interface RootRouteChildren { @@ -264,6 +275,13 @@ declare module '@tanstack/react-router' { preLoaderRoute: typeof AuthenticatedAdminRouteImport parentRoute: typeof AuthenticatedRouteRoute } + '/_authenticated/students/': { + id: '/_authenticated/students/' + path: '/' + fullPath: '/students/' + preLoaderRoute: typeof AuthenticatedStudentsIndexRouteImport + parentRoute: typeof AuthenticatedStudentsRoute + } '/_authenticated/students/new': { id: '/_authenticated/students/new' path: '/new' @@ -284,11 +302,13 @@ declare module '@tanstack/react-router' { interface AuthenticatedStudentsRouteChildren { AuthenticatedStudentsIdRoute: typeof AuthenticatedStudentsIdRoute AuthenticatedStudentsNewRoute: typeof AuthenticatedStudentsNewRoute + AuthenticatedStudentsIndexRoute: typeof AuthenticatedStudentsIndexRoute } const AuthenticatedStudentsRouteChildren: AuthenticatedStudentsRouteChildren = { AuthenticatedStudentsIdRoute: AuthenticatedStudentsIdRoute, AuthenticatedStudentsNewRoute: AuthenticatedStudentsNewRoute, + AuthenticatedStudentsIndexRoute: AuthenticatedStudentsIndexRoute, } const AuthenticatedStudentsRouteWithChildren = diff --git a/src/routes/_authenticated/students.index.tsx b/src/routes/_authenticated/students.index.tsx new file mode 100644 index 0000000..6a54276 --- /dev/null +++ b/src/routes/_authenticated/students.index.tsx @@ -0,0 +1,59 @@ +import { createFileRoute, Link } from "@tanstack/react-router"; +import { useQuery } from "@tanstack/react-query"; +import { supabase } from "@/integrations/supabase/client"; +import { useAuth } from "@/hooks/use-auth"; +import { Button } from "@/components/ui/button"; +import { Plus, ChevronRight } from "lucide-react"; + +export const Route = createFileRoute("/_authenticated/students/")({ + head: () => ({ meta: [{ title: "Students — School Portal" }] }), + component: StudentsIndexPage, +}); + +function StudentsIndexPage() { + const { roles } = useAuth(); + const isAdmin = roles.includes("admin"); + + const { data: students } = useQuery({ + queryKey: ["students"], + queryFn: async () => { + const { data, error } = await supabase + .from("students") + .select("id, first_name, last_name, dob, allergies, photo_release, class_id, classes(name)") + .order("last_name"); + if (error) throw error; + return data ?? []; + }, + }); + + return ( +
+
+
+

Students

+

{students?.length ?? 0} students visible to you

+
+ {isAdmin && ( + + + + )} +
+ +
+ {(students ?? []).map((s) => ( + +
+
{s.last_name}, {s.first_name}
+
+ {(s.classes as { name: string } | null)?.name ?? "No class"} · {s.allergies ? `Allergies: ${s.allergies}` : "No allergies"} +
+
+ + + ))} + {students?.length === 0 &&
No students yet.
} +
+
+ ); +} diff --git a/src/routes/_authenticated/students.new.tsx b/src/routes/_authenticated/students.new.tsx index 5884648..5638f5f 100644 --- a/src/routes/_authenticated/students.new.tsx +++ b/src/routes/_authenticated/students.new.tsx @@ -15,6 +15,12 @@ import { toast } from "sonner"; export const Route = createFileRoute("/_authenticated/students/new")({ head: () => ({ meta: [{ title: "New student — School Portal" }] }), component: NewStudentPage, + errorComponent: ({ error }) => ( +
+

This page hit an error

+
{error?.message}{"\n\n"}{error?.stack}
+
+ ), }); type Guardian = { diff --git a/src/routes/_authenticated/students.tsx b/src/routes/_authenticated/students.tsx index d851b9e..dfb175b 100644 --- a/src/routes/_authenticated/students.tsx +++ b/src/routes/_authenticated/students.tsx @@ -1,59 +1,7 @@ -import { createFileRoute, Link } from "@tanstack/react-router"; -import { useQuery } from "@tanstack/react-query"; -import { supabase } from "@/integrations/supabase/client"; -import { useAuth } from "@/hooks/use-auth"; -import { Button } from "@/components/ui/button"; -import { Plus, ChevronRight } from "lucide-react"; +import { createFileRoute, Outlet } from "@tanstack/react-router"; +// Layout route for /students. The list lives in students.index.tsx; the child +// routes (students.new, students.$id) render here through the Outlet. export const Route = createFileRoute("/_authenticated/students")({ - head: () => ({ meta: [{ title: "Students — School Portal" }] }), - component: StudentsPage, + component: () => , }); - -function StudentsPage() { - const { roles } = useAuth(); - const isAdmin = roles.includes("admin"); - - const { data: students } = useQuery({ - queryKey: ["students"], - queryFn: async () => { - const { data, error } = await supabase - .from("students") - .select("id, first_name, last_name, dob, allergies, photo_release, class_id, classes(name)") - .order("last_name"); - if (error) throw error; - return data ?? []; - }, - }); - - return ( -
-
-
-

Students

-

{students?.length ?? 0} students visible to you

-
- {isAdmin && ( - - - - )} -
- -
- {(students ?? []).map((s) => ( - -
-
{s.last_name}, {s.first_name}
-
- {(s.classes as { name: string } | null)?.name ?? "No class"} · {s.allergies ? `Allergies: ${s.allergies}` : "No allergies"} -
-
- - - ))} - {students?.length === 0 &&
No students yet.
} -
-
- ); -}