176 lines
5.2 KiB
TypeScript
176 lines
5.2 KiB
TypeScript
import {
|
|
HeadContent,
|
|
Navigate,
|
|
Outlet,
|
|
Scripts,
|
|
createRootRouteWithContext,
|
|
} from "@tanstack/react-router";
|
|
import * as React from "react";
|
|
import { DefaultCatchBoundary } from "@/components/DefaultCatchBoundary";
|
|
import { type QueryClient } from "@tanstack/react-query";
|
|
import { ensureSuperTokensFrontend } from "@/lib/supertokens/client";
|
|
import { AuthContextType } from "@/contexts/auth-context";
|
|
import Providers from "@/features/core/components/providers";
|
|
import { SessionMonitor } from "@/components/session-monitor";
|
|
import { IOSInstallPrompt } from "@/components/ios-install-prompt";
|
|
import { ColorSchemeScript, mantineHtmlProps } from "@mantine/core";
|
|
import { HeaderConfig } from "@/features/core/types/header-config";
|
|
import { playerQueries } from "@/features/players/queries";
|
|
import { ensureServerQueryData } from "@/lib/tanstack-query/utils/ensure";
|
|
import FullScreenLoader from "@/components/full-screen-loader";
|
|
import mantineCssUrl from '@mantine/core/styles.css?url'
|
|
import mantineDatesCssUrl from '@mantine/dates/styles.css?url'
|
|
import mantineCarouselCssUrl from '@mantine/carousel/styles.css?url'
|
|
import mantineTiptapCssUrl from '@mantine/tiptap/styles.css?url'
|
|
|
|
export const Route = createRootRouteWithContext<{
|
|
queryClient: QueryClient;
|
|
auth: AuthContextType;
|
|
header: HeaderConfig;
|
|
refresh: string[];
|
|
withPadding: boolean;
|
|
fullWidth: boolean;
|
|
}>()({
|
|
head: () => ({
|
|
title: "FLXN IX",
|
|
meta: [
|
|
{
|
|
charSet: "utf-8",
|
|
},
|
|
{
|
|
name: "viewport",
|
|
content:
|
|
"width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, interactive-widget=resizes-content",
|
|
},
|
|
{ property: 'og:title', content: 'FLXN IX' },
|
|
{ property: 'og:description', content: 'Register for FLXN IX and view FLXN stats' },
|
|
{ property: 'og:url', content: 'https://flexxon.app' },
|
|
{ property: 'og:type', content: 'website' },
|
|
{ property: 'og:site_name', content: 'FLXN IX' },
|
|
{ property: 'og:image', content: 'https://flexxon.app/favicon.png' },
|
|
{ property: 'og:image:width', content: '512' },
|
|
{ property: 'og:image:height', content: '512' },
|
|
{ name: 'mobile-web-app-capable', content: 'yes' },
|
|
{ name: 'apple-mobile-web-app-capable', content: 'yes' },
|
|
{ name: 'apple-mobile-web-app-status-bar-style', content: 'black-translucent' },
|
|
{ name: 'apple-mobile-web-app-title', content: 'FLXN' },
|
|
],
|
|
links: [
|
|
{
|
|
rel: "apple-touch-icon",
|
|
sizes: "180x180",
|
|
href: "/favicon.png",
|
|
},
|
|
{
|
|
rel: "icon",
|
|
type: "image/png",
|
|
sizes: "32x32",
|
|
href: "/favicon.png",
|
|
},
|
|
{
|
|
rel: "icon",
|
|
type: "image/png",
|
|
sizes: "16x16",
|
|
href: "/favicon.png",
|
|
},
|
|
{ rel: "manifest", href: "/site.webmanifest" },
|
|
{ rel: "icon", href: "/favicon.ico" },
|
|
{ rel: 'stylesheet', href: mantineCssUrl },
|
|
{ rel: 'stylesheet', href: mantineCarouselCssUrl },
|
|
{ rel: 'stylesheet', href: mantineDatesCssUrl },
|
|
{ rel: 'stylesheet', href: mantineTiptapCssUrl },
|
|
{ rel: "preconnect", href: "https://fonts.googleapis.com" },
|
|
{
|
|
rel: "preconnect",
|
|
href: "https://fonts.gstatic.com",
|
|
crossOrigin: "anonymous",
|
|
},
|
|
{
|
|
rel: "stylesheet",
|
|
href: "https://fonts.googleapis.com/css2?family=Inter:ital,opsz,wght@0,14..32,100..900;1,14..32,100..900&family=League+Spartan:wght@100..900&display=swap",
|
|
}
|
|
],
|
|
}),
|
|
errorComponent: (props) => {
|
|
return (
|
|
<RootDocument>
|
|
<Providers>
|
|
<DefaultCatchBoundary {...props} />
|
|
</Providers>
|
|
</RootDocument>
|
|
);
|
|
},
|
|
component: RootComponent,
|
|
notFoundComponent: () => <Navigate to="/" />,
|
|
beforeLoad: async ({ context, location }) => {
|
|
// Skip auth check for refresh-session route to avoid infinite loops
|
|
if (location.pathname === '/refresh-session') {
|
|
return {};
|
|
}
|
|
|
|
if (location.pathname === '/login' || location.pathname === '/logout') {
|
|
return {};
|
|
}
|
|
|
|
try {
|
|
// https://github.com/TanStack/router/discussions/3531
|
|
const auth = await ensureServerQueryData(
|
|
context.queryClient,
|
|
playerQueries.auth()
|
|
);
|
|
return { auth };
|
|
} catch (error) {
|
|
return {};
|
|
}
|
|
},
|
|
pendingComponent: () => <Providers><FullScreenLoader /></Providers>,
|
|
});
|
|
|
|
function RootComponent() {
|
|
React.useEffect(() => {
|
|
ensureSuperTokensFrontend();
|
|
}, []);
|
|
|
|
return (
|
|
<RootDocument>
|
|
<Providers>
|
|
<SessionMonitor />
|
|
<IOSInstallPrompt />
|
|
<Outlet />
|
|
</Providers>
|
|
</RootDocument>
|
|
);
|
|
}
|
|
|
|
// todo: analytics -> process.env data-website-id
|
|
function RootDocument({ children }: { children: React.ReactNode }) {
|
|
return (
|
|
<html
|
|
{...mantineHtmlProps}
|
|
style={{
|
|
overflowX: "hidden",
|
|
height: "100%",
|
|
width: "100%",
|
|
}}
|
|
>
|
|
<head>
|
|
<HeadContent />
|
|
<ColorSchemeScript />
|
|
<link rel="stylesheet" href="/styles.css" />
|
|
</head>
|
|
<body
|
|
style={{
|
|
overflowX: "hidden",
|
|
height: "100%",
|
|
width: "100%",
|
|
margin: 0,
|
|
padding: 0,
|
|
}}
|
|
>
|
|
<div className="app">{children}</div>
|
|
<Scripts />
|
|
</body>
|
|
</html>
|
|
);
|
|
}
|