File
Blob: src/client/router.ts
| 1 | import { createRootRoute, createRoute, createRouter, redirect } from "@tanstack/react-router"; |
| 2 | |
| 3 | import { AppShell } from "@/client/components/app-shell"; |
| 4 | import { meQueryOptions } from "@/client/auth/use-me"; |
| 5 | import { paths } from "@/client/lib/paths"; |
| 6 | import { queryClient } from "@/client/query"; |
| 7 | import { AddressbooksPage } from "@/client/pages/addressbooks"; |
| 8 | import { CalendarsPage } from "@/client/pages/calendars"; |
| 9 | import { FilesPage } from "@/client/pages/files"; |
| 10 | import { LoginPage } from "@/client/pages/login"; |
| 11 | import { MePage } from "@/client/pages/me"; |
| 12 | import { NotFoundPage } from "@/client/pages/not-found"; |
| 13 | import { PatsPage } from "@/client/pages/pats"; |
| 14 | |
| 15 | const rootRoute = createRootRoute({ component: AppShell, notFoundComponent: NotFoundPage }); |
| 16 | |
| 17 | async function requireSession({ location }: { location: { pathname: string } }): Promise<void> { |
| 18 | const me = await queryClient.ensureQueryData(meQueryOptions); |
| 19 | if (!me) { |
| 20 | throw redirect({ |
| 21 | to: paths.login, |
| 22 | search: { return_to: location.pathname }, |
| 23 | }); |
| 24 | } |
| 25 | } |
| 26 | |
| 27 | const loginRoute = createRoute({ |
| 28 | getParentRoute: () => rootRoute, |
| 29 | path: paths.login, |
| 30 | validateSearch: (search: Record<string, unknown>) => ({ |
| 31 | return_to: typeof search.return_to === "string" ? search.return_to : paths.home, |
| 32 | }), |
| 33 | component: LoginPage, |
| 34 | }); |
| 35 | |
| 36 | const homeRoute = createRoute({ |
| 37 | getParentRoute: () => rootRoute, |
| 38 | path: paths.home, |
| 39 | beforeLoad: async ({ location }) => { |
| 40 | await requireSession({ location }); |
| 41 | throw redirect({ to: paths.me, replace: true }); |
| 42 | }, |
| 43 | }); |
| 44 | |
| 45 | const meRoute = createRoute({ |
| 46 | getParentRoute: () => rootRoute, |
| 47 | path: paths.me, |
| 48 | beforeLoad: ({ location }) => requireSession({ location }), |
| 49 | component: MePage, |
| 50 | }); |
| 51 | |
| 52 | const patsRoute = createRoute({ |
| 53 | getParentRoute: () => rootRoute, |
| 54 | path: paths.pats, |
| 55 | beforeLoad: ({ location }) => requireSession({ location }), |
| 56 | component: PatsPage, |
| 57 | }); |
| 58 | |
| 59 | const calendarsRoute = createRoute({ |
| 60 | getParentRoute: () => rootRoute, |
| 61 | path: paths.calendars, |
| 62 | beforeLoad: ({ location }) => requireSession({ location }), |
| 63 | component: CalendarsPage, |
| 64 | }); |
| 65 | |
| 66 | const addressbooksRoute = createRoute({ |
| 67 | getParentRoute: () => rootRoute, |
| 68 | path: paths.addressbooks, |
| 69 | beforeLoad: ({ location }) => requireSession({ location }), |
| 70 | component: AddressbooksPage, |
| 71 | }); |
| 72 | |
| 73 | const filesRoute = createRoute({ |
| 74 | getParentRoute: () => rootRoute, |
| 75 | path: paths.files, |
| 76 | beforeLoad: ({ location }) => requireSession({ location }), |
| 77 | validateSearch: (search: Record<string, unknown>) => ({ |
| 78 | path: typeof search.path === "string" ? search.path : "/files/", |
| 79 | }), |
| 80 | component: FilesPage, |
| 81 | }); |
| 82 | |
| 83 | const routeTree = rootRoute.addChildren([ |
| 84 | homeRoute, |
| 85 | loginRoute, |
| 86 | meRoute, |
| 87 | patsRoute, |
| 88 | calendarsRoute, |
| 89 | addressbooksRoute, |
| 90 | filesRoute, |
| 91 | ]); |
| 92 | |
| 93 | export const router = createRouter({ |
| 94 | routeTree, |
| 95 | context: { queryClient }, |
| 96 | defaultPreload: "intent", |
| 97 | }); |
| 98 | |
| 99 | declare module "@tanstack/react-router" { |
| 100 | interface Register { |
| 101 | router: typeof router; |
| 102 | } |
| 103 | } |