feat(lst): tan stack routes added with protected routes
This commit is contained in:
@@ -1,31 +0,0 @@
|
||||
import LoginForm from "./components/LoginForm";
|
||||
import {Button} from "./components/ui/button";
|
||||
import {useSession} from "./lib/hooks/useSession";
|
||||
import {useLogout} from "./lib/hooks/useLogout";
|
||||
import "./styles.css";
|
||||
|
||||
function App() {
|
||||
const {session, status} = useSession();
|
||||
const logout = useLogout();
|
||||
|
||||
if (!session || status === "error") {
|
||||
return (
|
||||
<p>
|
||||
no session please login <LoginForm />
|
||||
</p>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
{/* <p>Logged in user: {session.user.username}</p> */}
|
||||
<>Session: {JSON.stringify(session)}</>
|
||||
<p>Status: {JSON.stringify(status)}</p>
|
||||
<p>
|
||||
<Button onClick={() => logout()}>Logout</Button>
|
||||
</p>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export default App;
|
||||
@@ -1,5 +1,5 @@
|
||||
import {useState} from "react";
|
||||
import {useSessionStore} from "../lib/store/sessionStore";
|
||||
import {useSessionStore} from "../../lib/store/sessionStore";
|
||||
import {useQueryClient} from "@tanstack/react-query";
|
||||
|
||||
const LoginForm = () => {
|
||||
@@ -36,7 +36,7 @@ const LoginForm = () => {
|
||||
setSession(data.data.token);
|
||||
|
||||
// Refetch the session data to reflect the logged-in state
|
||||
queryClient.invalidateQueries(["session"]);
|
||||
queryClient.invalidateQueries();
|
||||
|
||||
setUsername("");
|
||||
setPassword("");
|
||||
@@ -15,7 +15,7 @@ const fetchSession = async () => {
|
||||
Authorization: `Bearer ${token}`,
|
||||
},
|
||||
});
|
||||
console.log(res);
|
||||
// console.log(res);
|
||||
if (!res.ok) {
|
||||
throw new Error("Session not found");
|
||||
}
|
||||
@@ -31,7 +31,7 @@ export const useSession = () => {
|
||||
queryKey: ["session"],
|
||||
queryFn: fetchSession,
|
||||
enabled: !!token, // Prevents query if token is null
|
||||
staleTime: 5 * 60 * 1000, // 5 mins
|
||||
staleTime: 60 * 1000,
|
||||
gcTime: 10 * 60 * 1000, // 10 mins
|
||||
refetchOnWindowFocus: true,
|
||||
});
|
||||
@@ -47,3 +47,5 @@ export const useSession = () => {
|
||||
|
||||
return {session: data && token ? {user: data.user, token: data.token} : null, status, error};
|
||||
};
|
||||
|
||||
export type SessionType = ReturnType<typeof useSession>;
|
||||
|
||||
@@ -1,13 +1,38 @@
|
||||
import {StrictMode} from "react";
|
||||
import {createRoot} from "react-dom/client";
|
||||
import ReactDOM from "react-dom/client";
|
||||
import "./styles.css";
|
||||
import App from "./App.tsx";
|
||||
import {SessionProvider} from "./components/providers/Providers.tsx";
|
||||
|
||||
createRoot(document.getElementById("root")!).render(
|
||||
<StrictMode>
|
||||
<SessionProvider>
|
||||
<App />
|
||||
</SessionProvider>
|
||||
</StrictMode>
|
||||
);
|
||||
import {SessionProvider} from "./components/providers/Providers.tsx";
|
||||
import {RouterProvider, createRouter} from "@tanstack/react-router";
|
||||
|
||||
// Import the generated route tree
|
||||
import {routeTree} from "./routeTree.gen";
|
||||
import {useSession} from "./lib/hooks/useSession.ts";
|
||||
|
||||
// Create a new router instance
|
||||
const router = createRouter({routeTree, context: {sessionType: undefined!}});
|
||||
|
||||
// Register the router instance for type safety
|
||||
declare module "@tanstack/react-router" {
|
||||
interface Register {
|
||||
router: typeof router;
|
||||
}
|
||||
}
|
||||
|
||||
function App() {
|
||||
const sessionType = useSession();
|
||||
return <RouterProvider router={router} context={{sessionType}} />;
|
||||
}
|
||||
|
||||
// Render the app
|
||||
const rootElement = document.getElementById("root")!;
|
||||
if (!rootElement.innerHTML) {
|
||||
const root = ReactDOM.createRoot(rootElement);
|
||||
root.render(
|
||||
<StrictMode>
|
||||
<SessionProvider>
|
||||
<App />
|
||||
</SessionProvider>
|
||||
</StrictMode>
|
||||
);
|
||||
}
|
||||
|
||||
311
frontend/src/routeTree.gen.ts
Normal file
311
frontend/src/routeTree.gen.ts
Normal file
@@ -0,0 +1,311 @@
|
||||
/* eslint-disable */
|
||||
|
||||
// @ts-nocheck
|
||||
|
||||
// noinspection JSUnusedGlobalSymbols
|
||||
|
||||
// This file was automatically generated by TanStack Router.
|
||||
// You should NOT make any changes in this file as it will be overwritten.
|
||||
// Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified.
|
||||
|
||||
// Import Routes
|
||||
|
||||
import { Route as rootRoute } from './routes/__root'
|
||||
import { Route as LoginImport } from './routes/login'
|
||||
import { Route as AboutImport } from './routes/about'
|
||||
import { Route as AuthImport } from './routes/_auth'
|
||||
import { Route as IndexImport } from './routes/index'
|
||||
import { Route as OcpIndexImport } from './routes/ocp/index'
|
||||
import { Route as OcpLotsImport } from './routes/ocp/lots'
|
||||
import { Route as OcpLineIDImport } from './routes/ocp/$lineID'
|
||||
import { Route as AuthProfileImport } from './routes/_auth/profile'
|
||||
import { Route as AuthDashboardImport } from './routes/_auth/dashboard'
|
||||
|
||||
// Create/Update Routes
|
||||
|
||||
const LoginRoute = LoginImport.update({
|
||||
id: '/login',
|
||||
path: '/login',
|
||||
getParentRoute: () => rootRoute,
|
||||
} as any)
|
||||
|
||||
const AboutRoute = AboutImport.update({
|
||||
id: '/about',
|
||||
path: '/about',
|
||||
getParentRoute: () => rootRoute,
|
||||
} as any)
|
||||
|
||||
const AuthRoute = AuthImport.update({
|
||||
id: '/_auth',
|
||||
getParentRoute: () => rootRoute,
|
||||
} as any)
|
||||
|
||||
const IndexRoute = IndexImport.update({
|
||||
id: '/',
|
||||
path: '/',
|
||||
getParentRoute: () => rootRoute,
|
||||
} as any)
|
||||
|
||||
const OcpIndexRoute = OcpIndexImport.update({
|
||||
id: '/ocp/',
|
||||
path: '/ocp/',
|
||||
getParentRoute: () => rootRoute,
|
||||
} as any)
|
||||
|
||||
const OcpLotsRoute = OcpLotsImport.update({
|
||||
id: '/ocp/lots',
|
||||
path: '/ocp/lots',
|
||||
getParentRoute: () => rootRoute,
|
||||
} as any)
|
||||
|
||||
const OcpLineIDRoute = OcpLineIDImport.update({
|
||||
id: '/ocp/$lineID',
|
||||
path: '/ocp/$lineID',
|
||||
getParentRoute: () => rootRoute,
|
||||
} as any)
|
||||
|
||||
const AuthProfileRoute = AuthProfileImport.update({
|
||||
id: '/profile',
|
||||
path: '/profile',
|
||||
getParentRoute: () => AuthRoute,
|
||||
} as any)
|
||||
|
||||
const AuthDashboardRoute = AuthDashboardImport.update({
|
||||
id: '/dashboard',
|
||||
path: '/dashboard',
|
||||
getParentRoute: () => AuthRoute,
|
||||
} as any)
|
||||
|
||||
// Populate the FileRoutesByPath interface
|
||||
|
||||
declare module '@tanstack/react-router' {
|
||||
interface FileRoutesByPath {
|
||||
'/': {
|
||||
id: '/'
|
||||
path: '/'
|
||||
fullPath: '/'
|
||||
preLoaderRoute: typeof IndexImport
|
||||
parentRoute: typeof rootRoute
|
||||
}
|
||||
'/_auth': {
|
||||
id: '/_auth'
|
||||
path: ''
|
||||
fullPath: ''
|
||||
preLoaderRoute: typeof AuthImport
|
||||
parentRoute: typeof rootRoute
|
||||
}
|
||||
'/about': {
|
||||
id: '/about'
|
||||
path: '/about'
|
||||
fullPath: '/about'
|
||||
preLoaderRoute: typeof AboutImport
|
||||
parentRoute: typeof rootRoute
|
||||
}
|
||||
'/login': {
|
||||
id: '/login'
|
||||
path: '/login'
|
||||
fullPath: '/login'
|
||||
preLoaderRoute: typeof LoginImport
|
||||
parentRoute: typeof rootRoute
|
||||
}
|
||||
'/_auth/dashboard': {
|
||||
id: '/_auth/dashboard'
|
||||
path: '/dashboard'
|
||||
fullPath: '/dashboard'
|
||||
preLoaderRoute: typeof AuthDashboardImport
|
||||
parentRoute: typeof AuthImport
|
||||
}
|
||||
'/_auth/profile': {
|
||||
id: '/_auth/profile'
|
||||
path: '/profile'
|
||||
fullPath: '/profile'
|
||||
preLoaderRoute: typeof AuthProfileImport
|
||||
parentRoute: typeof AuthImport
|
||||
}
|
||||
'/ocp/$lineID': {
|
||||
id: '/ocp/$lineID'
|
||||
path: '/ocp/$lineID'
|
||||
fullPath: '/ocp/$lineID'
|
||||
preLoaderRoute: typeof OcpLineIDImport
|
||||
parentRoute: typeof rootRoute
|
||||
}
|
||||
'/ocp/lots': {
|
||||
id: '/ocp/lots'
|
||||
path: '/ocp/lots'
|
||||
fullPath: '/ocp/lots'
|
||||
preLoaderRoute: typeof OcpLotsImport
|
||||
parentRoute: typeof rootRoute
|
||||
}
|
||||
'/ocp/': {
|
||||
id: '/ocp/'
|
||||
path: '/ocp'
|
||||
fullPath: '/ocp'
|
||||
preLoaderRoute: typeof OcpIndexImport
|
||||
parentRoute: typeof rootRoute
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Create and export the route tree
|
||||
|
||||
interface AuthRouteChildren {
|
||||
AuthDashboardRoute: typeof AuthDashboardRoute
|
||||
AuthProfileRoute: typeof AuthProfileRoute
|
||||
}
|
||||
|
||||
const AuthRouteChildren: AuthRouteChildren = {
|
||||
AuthDashboardRoute: AuthDashboardRoute,
|
||||
AuthProfileRoute: AuthProfileRoute,
|
||||
}
|
||||
|
||||
const AuthRouteWithChildren = AuthRoute._addFileChildren(AuthRouteChildren)
|
||||
|
||||
export interface FileRoutesByFullPath {
|
||||
'/': typeof IndexRoute
|
||||
'': typeof AuthRouteWithChildren
|
||||
'/about': typeof AboutRoute
|
||||
'/login': typeof LoginRoute
|
||||
'/dashboard': typeof AuthDashboardRoute
|
||||
'/profile': typeof AuthProfileRoute
|
||||
'/ocp/$lineID': typeof OcpLineIDRoute
|
||||
'/ocp/lots': typeof OcpLotsRoute
|
||||
'/ocp': typeof OcpIndexRoute
|
||||
}
|
||||
|
||||
export interface FileRoutesByTo {
|
||||
'/': typeof IndexRoute
|
||||
'': typeof AuthRouteWithChildren
|
||||
'/about': typeof AboutRoute
|
||||
'/login': typeof LoginRoute
|
||||
'/dashboard': typeof AuthDashboardRoute
|
||||
'/profile': typeof AuthProfileRoute
|
||||
'/ocp/$lineID': typeof OcpLineIDRoute
|
||||
'/ocp/lots': typeof OcpLotsRoute
|
||||
'/ocp': typeof OcpIndexRoute
|
||||
}
|
||||
|
||||
export interface FileRoutesById {
|
||||
__root__: typeof rootRoute
|
||||
'/': typeof IndexRoute
|
||||
'/_auth': typeof AuthRouteWithChildren
|
||||
'/about': typeof AboutRoute
|
||||
'/login': typeof LoginRoute
|
||||
'/_auth/dashboard': typeof AuthDashboardRoute
|
||||
'/_auth/profile': typeof AuthProfileRoute
|
||||
'/ocp/$lineID': typeof OcpLineIDRoute
|
||||
'/ocp/lots': typeof OcpLotsRoute
|
||||
'/ocp/': typeof OcpIndexRoute
|
||||
}
|
||||
|
||||
export interface FileRouteTypes {
|
||||
fileRoutesByFullPath: FileRoutesByFullPath
|
||||
fullPaths:
|
||||
| '/'
|
||||
| ''
|
||||
| '/about'
|
||||
| '/login'
|
||||
| '/dashboard'
|
||||
| '/profile'
|
||||
| '/ocp/$lineID'
|
||||
| '/ocp/lots'
|
||||
| '/ocp'
|
||||
fileRoutesByTo: FileRoutesByTo
|
||||
to:
|
||||
| '/'
|
||||
| ''
|
||||
| '/about'
|
||||
| '/login'
|
||||
| '/dashboard'
|
||||
| '/profile'
|
||||
| '/ocp/$lineID'
|
||||
| '/ocp/lots'
|
||||
| '/ocp'
|
||||
id:
|
||||
| '__root__'
|
||||
| '/'
|
||||
| '/_auth'
|
||||
| '/about'
|
||||
| '/login'
|
||||
| '/_auth/dashboard'
|
||||
| '/_auth/profile'
|
||||
| '/ocp/$lineID'
|
||||
| '/ocp/lots'
|
||||
| '/ocp/'
|
||||
fileRoutesById: FileRoutesById
|
||||
}
|
||||
|
||||
export interface RootRouteChildren {
|
||||
IndexRoute: typeof IndexRoute
|
||||
AuthRoute: typeof AuthRouteWithChildren
|
||||
AboutRoute: typeof AboutRoute
|
||||
LoginRoute: typeof LoginRoute
|
||||
OcpLineIDRoute: typeof OcpLineIDRoute
|
||||
OcpLotsRoute: typeof OcpLotsRoute
|
||||
OcpIndexRoute: typeof OcpIndexRoute
|
||||
}
|
||||
|
||||
const rootRouteChildren: RootRouteChildren = {
|
||||
IndexRoute: IndexRoute,
|
||||
AuthRoute: AuthRouteWithChildren,
|
||||
AboutRoute: AboutRoute,
|
||||
LoginRoute: LoginRoute,
|
||||
OcpLineIDRoute: OcpLineIDRoute,
|
||||
OcpLotsRoute: OcpLotsRoute,
|
||||
OcpIndexRoute: OcpIndexRoute,
|
||||
}
|
||||
|
||||
export const routeTree = rootRoute
|
||||
._addFileChildren(rootRouteChildren)
|
||||
._addFileTypes<FileRouteTypes>()
|
||||
|
||||
/* ROUTE_MANIFEST_START
|
||||
{
|
||||
"routes": {
|
||||
"__root__": {
|
||||
"filePath": "__root.tsx",
|
||||
"children": [
|
||||
"/",
|
||||
"/_auth",
|
||||
"/about",
|
||||
"/login",
|
||||
"/ocp/$lineID",
|
||||
"/ocp/lots",
|
||||
"/ocp/"
|
||||
]
|
||||
},
|
||||
"/": {
|
||||
"filePath": "index.tsx"
|
||||
},
|
||||
"/_auth": {
|
||||
"filePath": "_auth.tsx",
|
||||
"children": [
|
||||
"/_auth/dashboard",
|
||||
"/_auth/profile"
|
||||
]
|
||||
},
|
||||
"/about": {
|
||||
"filePath": "about.tsx"
|
||||
},
|
||||
"/login": {
|
||||
"filePath": "login.tsx"
|
||||
},
|
||||
"/_auth/dashboard": {
|
||||
"filePath": "_auth/dashboard.tsx",
|
||||
"parent": "/_auth"
|
||||
},
|
||||
"/_auth/profile": {
|
||||
"filePath": "_auth/profile.tsx",
|
||||
"parent": "/_auth"
|
||||
},
|
||||
"/ocp/$lineID": {
|
||||
"filePath": "ocp/$lineID.tsx"
|
||||
},
|
||||
"/ocp/lots": {
|
||||
"filePath": "ocp/lots.tsx"
|
||||
},
|
||||
"/ocp/": {
|
||||
"filePath": "ocp/index.tsx"
|
||||
}
|
||||
}
|
||||
}
|
||||
ROUTE_MANIFEST_END */
|
||||
42
frontend/src/routes/__root.tsx
Normal file
42
frontend/src/routes/__root.tsx
Normal file
@@ -0,0 +1,42 @@
|
||||
import {createRootRouteWithContext, Link, Outlet} from "@tanstack/react-router";
|
||||
import {TanStackRouterDevtools} from "@tanstack/router-devtools";
|
||||
import {SessionType} from "../lib/hooks/useSession";
|
||||
|
||||
type RouterContext = {
|
||||
sessionType: SessionType;
|
||||
};
|
||||
// same as the layout
|
||||
export const Route = createRootRouteWithContext<RouterContext>()({
|
||||
component: () => {
|
||||
return (
|
||||
<>
|
||||
<div className="p-2 flex gap-2">
|
||||
<Link to="/" className="[&.active]:font-bold">
|
||||
Home
|
||||
</Link>{" "}
|
||||
<Link to="/about" className="[&.active]:font-bold">
|
||||
About
|
||||
</Link>
|
||||
<Link to="/dashboard" className="[&.active]:font-bold">
|
||||
dashboard
|
||||
</Link>
|
||||
<Link to="/profile" className="[&.active]:font-bold">
|
||||
{({isActive}) => <>Profile {isActive && "~"}</>}
|
||||
</Link>
|
||||
<Link
|
||||
to="/ocp"
|
||||
search={{q: "1"}}
|
||||
activeProps={{style: {fontWeight: "bold"}}}
|
||||
className="[&.active]:font-bold"
|
||||
>
|
||||
{({isActive}) => <>OCP {isActive && "~"}</>}
|
||||
</Link>
|
||||
</div>
|
||||
<hr />
|
||||
<Outlet />
|
||||
|
||||
<TanStackRouterDevtools />
|
||||
</>
|
||||
);
|
||||
},
|
||||
});
|
||||
12
frontend/src/routes/_auth.tsx
Normal file
12
frontend/src/routes/_auth.tsx
Normal file
@@ -0,0 +1,12 @@
|
||||
import {createFileRoute, redirect} from "@tanstack/react-router";
|
||||
|
||||
// src/routes/_authenticated.tsx
|
||||
export const Route = createFileRoute("/_auth")({
|
||||
beforeLoad: async ({context}) => {
|
||||
if (!context.sessionType.session) {
|
||||
throw redirect({
|
||||
to: "/",
|
||||
});
|
||||
}
|
||||
},
|
||||
});
|
||||
9
frontend/src/routes/_auth/dashboard.tsx
Normal file
9
frontend/src/routes/_auth/dashboard.tsx
Normal file
@@ -0,0 +1,9 @@
|
||||
import { createFileRoute } from '@tanstack/react-router'
|
||||
|
||||
export const Route = createFileRoute('/_auth/dashboard')({
|
||||
component: RouteComponent,
|
||||
})
|
||||
|
||||
function RouteComponent() {
|
||||
return <div>Hello "/_auth/dashboard"!</div>
|
||||
}
|
||||
9
frontend/src/routes/_auth/profile.tsx
Normal file
9
frontend/src/routes/_auth/profile.tsx
Normal file
@@ -0,0 +1,9 @@
|
||||
import {createFileRoute} from "@tanstack/react-router";
|
||||
|
||||
export const Route = createFileRoute("/_auth/profile")({
|
||||
component: RouteComponent,
|
||||
});
|
||||
|
||||
function RouteComponent() {
|
||||
return <div>Hello "/profile"!</div>;
|
||||
}
|
||||
13
frontend/src/routes/about.tsx
Normal file
13
frontend/src/routes/about.tsx
Normal file
@@ -0,0 +1,13 @@
|
||||
import {createFileRoute} from "@tanstack/react-router";
|
||||
|
||||
export const Route = createFileRoute("/about")({
|
||||
component: About,
|
||||
});
|
||||
|
||||
function About() {
|
||||
return (
|
||||
<div className="m-auto">
|
||||
<h2>About page to come.</h2>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
29
frontend/src/routes/index.tsx
Normal file
29
frontend/src/routes/index.tsx
Normal file
@@ -0,0 +1,29 @@
|
||||
import {createFileRoute} from "@tanstack/react-router";
|
||||
import LoginForm from "../components/auth/LoginForm";
|
||||
import {Button} from "../components/ui/button";
|
||||
import {useLogout} from "../lib/hooks/useLogout";
|
||||
import {useSession} from "../lib/hooks/useSession";
|
||||
|
||||
export const Route = createFileRoute("/")({
|
||||
component: Index,
|
||||
});
|
||||
|
||||
function Index() {
|
||||
const {session} = useSession();
|
||||
const logout = useLogout();
|
||||
return (
|
||||
<div className="p-2">
|
||||
<h3>Welcome Home!</h3>
|
||||
<br></br>
|
||||
<p>
|
||||
{session ? (
|
||||
<>
|
||||
<Button onClick={() => logout()}>Logout</Button>{" "}
|
||||
</>
|
||||
) : (
|
||||
<LoginForm />
|
||||
)}
|
||||
</p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
38
frontend/src/routes/login.tsx
Normal file
38
frontend/src/routes/login.tsx
Normal file
@@ -0,0 +1,38 @@
|
||||
import {createFileRoute, useRouter} from "@tanstack/react-router";
|
||||
import {isAuthenticated, signIn, signOut} from "../utils/auth";
|
||||
import {Button} from "../components/ui/button";
|
||||
|
||||
export const Route = createFileRoute("/login")({
|
||||
component: RouteComponent,
|
||||
});
|
||||
|
||||
function RouteComponent() {
|
||||
const router = useRouter();
|
||||
return (
|
||||
<div>
|
||||
<h2>Ligin</h2>
|
||||
{isAuthenticated() ? (
|
||||
<>
|
||||
<p>Hello User!</p>
|
||||
<Button
|
||||
onClick={async () => {
|
||||
signOut();
|
||||
router.invalidate();
|
||||
}}
|
||||
>
|
||||
signOut
|
||||
</Button>
|
||||
</>
|
||||
) : (
|
||||
<Button
|
||||
onClick={async () => {
|
||||
signIn();
|
||||
router.invalidate();
|
||||
}}
|
||||
>
|
||||
Sign in
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
17
frontend/src/routes/ocp/$lineID.tsx
Normal file
17
frontend/src/routes/ocp/$lineID.tsx
Normal file
@@ -0,0 +1,17 @@
|
||||
import {createFileRoute} from "@tanstack/react-router";
|
||||
|
||||
export const Route = createFileRoute("/ocp/$lineID")({
|
||||
component: RouteComponent,
|
||||
loader: async ({params}) => {
|
||||
await new Promise((r) => setTimeout(r, 1500));
|
||||
//throw new Error();
|
||||
return {lineID: params.lineID};
|
||||
},
|
||||
pendingComponent: () => <div className="m-auto">Loading....</div>,
|
||||
errorComponent: () => <div className="m-auto">Error....</div>,
|
||||
});
|
||||
|
||||
function RouteComponent() {
|
||||
const {lineID} = Route.useLoaderData();
|
||||
return <div>Hello "/ocp/{lineID}"!</div>;
|
||||
}
|
||||
34
frontend/src/routes/ocp/index.tsx
Normal file
34
frontend/src/routes/ocp/index.tsx
Normal file
@@ -0,0 +1,34 @@
|
||||
import {createFileRoute, Link} from "@tanstack/react-router";
|
||||
|
||||
export const Route = createFileRoute("/ocp/")({
|
||||
component: RouteComponent,
|
||||
validateSearch: (search) => {
|
||||
return {
|
||||
q: (search.q as string) || "",
|
||||
};
|
||||
},
|
||||
loaderDeps: ({search: {q}}) => ({q}),
|
||||
loader: async ({deps: {q}}) => {
|
||||
return {line: q};
|
||||
},
|
||||
});
|
||||
|
||||
function RouteComponent() {
|
||||
const {line} = Route.useLoaderData();
|
||||
|
||||
const lines = ["l", "2", "3"];
|
||||
return (
|
||||
<div>
|
||||
<h2>Hello "/ocp/{line}/something"!</h2>
|
||||
{lines.map((line) => {
|
||||
return (
|
||||
<div key={line}>
|
||||
<Link to="/ocp/$lineID" params={{lineID: line}}>
|
||||
Post
|
||||
</Link>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
9
frontend/src/routes/ocp/lots.tsx
Normal file
9
frontend/src/routes/ocp/lots.tsx
Normal file
@@ -0,0 +1,9 @@
|
||||
import { createFileRoute } from '@tanstack/react-router'
|
||||
|
||||
export const Route = createFileRoute('/ocp/lots')({
|
||||
component: RouteComponent,
|
||||
})
|
||||
|
||||
function RouteComponent() {
|
||||
return <div>Hello "/ocp/lots"!</div>
|
||||
}
|
||||
11
frontend/src/utils/auth.ts
Normal file
11
frontend/src/utils/auth.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
export function isAuthenticated() {
|
||||
return localStorage.getItem("isAuthenticated") === "true";
|
||||
}
|
||||
|
||||
export function signIn() {
|
||||
return localStorage.setItem("isAuthenticated", "true");
|
||||
}
|
||||
|
||||
export function signOut() {
|
||||
return localStorage.removeItem("isAuthenticated");
|
||||
}
|
||||
Reference in New Issue
Block a user