import { TanStackDevtools } from "@tanstack/react-devtools"; import type { QueryClient } from "@tanstack/react-query"; import { createRootRouteWithContext, HeadContent, redirect, Scripts, } from "@tanstack/react-router"; import { TanStackRouterDevtoolsPanel } from "@tanstack/react-router-devtools"; import type * as React from "react"; import { useEffect } from "react"; import { toast } from "sonner"; import type { AuthSession } from "#/lib/auth.serverfn"; import { fetchSession, sessionQueryKey } from "#/lib/auth-client"; import { client } from "#/lib/eden"; import { clearJoinIdFromLocation, clearPendingPartyJoin, getJoinIdFromLocation, readPendingPartyJoin, writePendingPartyJoin, } from "#/lib/party-join"; import { Toaster } from "@/components/ui/sonner"; import TanStackQueryDevtools from "../integrations/tanstack-query/devtools"; import appCss from "../styles.css?url"; interface MyRouterContext { queryClient: QueryClient; } export const Route = createRootRouteWithContext()({ head: () => ({ meta: [ { charSet: "utf-8", }, { name: "viewport", content: "width=device-width, initial-scale=1", }, { title: "Music Quiz", }, ], links: [ { rel: "stylesheet", href: appCss, }, ], }), shellComponent: RootDocument, beforeLoad: async ({ context, location }) => { const authPublicPaths = new Set(["/login"]); const isAuthPublicPath = authPublicPaths.has(location.pathname); let session: AuthSession | null; if (typeof window === "undefined") { const { getSession } = await import("../lib/auth.serverfn"); session = await getSession(); } else { session = await context.queryClient.fetchQuery({ queryKey: sessionQueryKey, queryFn: fetchSession, staleTime: 30_000, }); } const user = session?.user; if (!user && !isAuthPublicPath) { throw redirect({ to: "/login", search: { redirect: location.href }, }); } return { user, session }; }, }); function RootDocument({ children }: { children: React.ReactNode }) { const { user } = Route.useRouteContext(); useEffect(() => { if (typeof window === "undefined") return; const joinId = getJoinIdFromLocation(); if (!joinId) return; const storedId = readPendingPartyJoin(); if (storedId !== joinId) { writePendingPartyJoin(joinId); } clearJoinIdFromLocation(); }, []); useEffect(() => { if (!user) return; const joinId = readPendingPartyJoin(); if (!joinId) return; let cancelled = false; const attemptJoin = async () => { try { const result = await client.api.party.join.post({ targetUserId: joinId, }); if (result?.error) { toast.error(result.error); clearPendingPartyJoin(); } else { toast.success("Joined party."); clearPendingPartyJoin(); } } catch (_error) { if (!cancelled) { toast.error("Failed to join party."); } } }; attemptJoin(); return () => { cancelled = true; }; }, [user]); return ( {children} , }, TanStackQueryDevtools, ]} /> ); }