refactor(lst): more dashboard work
This commit is contained in:
@@ -11,6 +11,7 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@antfu/ni": "^23.3.1",
|
||||
"@radix-ui/react-avatar": "^1.1.3",
|
||||
"@radix-ui/react-collapsible": "^1.1.3",
|
||||
"@radix-ui/react-dialog": "^1.1.6",
|
||||
"@radix-ui/react-dropdown-menu": "^2.1.6",
|
||||
@@ -20,13 +21,14 @@
|
||||
"@tailwindcss/vite": "^4.0.6",
|
||||
"@tanstack/react-query": "^5.66.5",
|
||||
"@tanstack/react-router": "^1.106.0",
|
||||
"@types/react-grid-layout": "^1.3.5",
|
||||
"class-variance-authority": "^0.7.1",
|
||||
"clsx": "^2.1.1",
|
||||
"gridstack": "^11.3.0",
|
||||
"js-cookie": "^3.0.5",
|
||||
"lucide-react": "^0.475.0",
|
||||
"react": "^19.0.0",
|
||||
"react-dom": "^19.0.0",
|
||||
"react-grid-layout": "^1.5.0",
|
||||
"shadcn": "^2.4.0-canary.6",
|
||||
"tailwind-merge": "^3.0.1",
|
||||
"tailwindcss": "^4.0.6",
|
||||
|
||||
@@ -68,12 +68,12 @@ const rolePermissions: Roles = {
|
||||
},
|
||||
};
|
||||
|
||||
const users: User[] = [
|
||||
{id: 1, username: "admin", role: "admin"},
|
||||
{id: 2, username: "manager", role: "manager"},
|
||||
{id: 3, username: "supervisor", role: "supervisor"},
|
||||
{id: 4, username: "user", role: "user"},
|
||||
];
|
||||
// const users: User[] = [
|
||||
// {id: 1, username: "admin", role: "admin"},
|
||||
// {id: 2, username: "manager", role: "manager"},
|
||||
// {id: 3, username: "supervisor", role: "supervisor"},
|
||||
// {id: 4, username: "user", role: "user"},
|
||||
// ];
|
||||
|
||||
function hasAccess(user: User, moduleName: string, feature: Feature): boolean {
|
||||
return rolePermissions[user.role]?.[moduleName]?.includes(feature) || false;
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import {Link} from "@tanstack/react-router";
|
||||
import {SidebarHeader, SidebarMenu, SidebarMenuButton, SidebarMenuItem} from "../../ui/sidebar";
|
||||
|
||||
export function Header() {
|
||||
@@ -5,15 +6,18 @@ export function Header() {
|
||||
<SidebarHeader>
|
||||
<SidebarMenu>
|
||||
<SidebarMenuItem>
|
||||
<SidebarMenuButton size="lg" asChild>
|
||||
<div>
|
||||
<img src="/imgs/dkLst.png" alt="Description" className="size-8" />
|
||||
<div className="flex flex-col gap-0.5 leading-none">
|
||||
<span className="font-semibold">Logistics Support Tool</span>
|
||||
<span className="">v1.0.0</span>
|
||||
<Link to="/">
|
||||
<SidebarMenuButton size="lg" asChild>
|
||||
<div className="flex flex-row">
|
||||
<img src="/imgs/dkLst.png" alt="Description" className="size-8" />
|
||||
|
||||
<div className="flex flex-col gap-0.5 leading-none">
|
||||
<span className="font-semibold">Logistics Support Tool</span>
|
||||
<span className="">v1.0.0</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</SidebarMenuButton>
|
||||
</SidebarMenuButton>
|
||||
</Link>
|
||||
</SidebarMenuItem>
|
||||
</SidebarMenu>
|
||||
</SidebarHeader>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import {Cylinder, Package, Printer, Truck} from "lucide-react";
|
||||
import {Cylinder, Package, Truck} from "lucide-react";
|
||||
import {
|
||||
SidebarGroup,
|
||||
SidebarGroupContent,
|
||||
|
||||
@@ -11,7 +11,7 @@ import {
|
||||
const items = [
|
||||
{
|
||||
title: "One Click Print",
|
||||
url: "#",
|
||||
url: "/ocp",
|
||||
icon: Printer,
|
||||
},
|
||||
];
|
||||
|
||||
51
frontend/src/components/ui/avatar.tsx
Normal file
51
frontend/src/components/ui/avatar.tsx
Normal file
@@ -0,0 +1,51 @@
|
||||
import * as React from "react"
|
||||
import * as AvatarPrimitive from "@radix-ui/react-avatar"
|
||||
|
||||
import { cn } from "@/lib/utils"
|
||||
|
||||
function Avatar({
|
||||
className,
|
||||
...props
|
||||
}: React.ComponentProps<typeof AvatarPrimitive.Root>) {
|
||||
return (
|
||||
<AvatarPrimitive.Root
|
||||
data-slot="avatar"
|
||||
className={cn(
|
||||
"relative flex size-8 shrink-0 overflow-hidden rounded-full",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
function AvatarImage({
|
||||
className,
|
||||
...props
|
||||
}: React.ComponentProps<typeof AvatarPrimitive.Image>) {
|
||||
return (
|
||||
<AvatarPrimitive.Image
|
||||
data-slot="avatar-image"
|
||||
className={cn("aspect-square size-full", className)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
function AvatarFallback({
|
||||
className,
|
||||
...props
|
||||
}: React.ComponentProps<typeof AvatarPrimitive.Fallback>) {
|
||||
return (
|
||||
<AvatarPrimitive.Fallback
|
||||
data-slot="avatar-fallback"
|
||||
className={cn(
|
||||
"bg-muted flex size-full items-center justify-center rounded-full",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
export { Avatar, AvatarImage, AvatarFallback }
|
||||
@@ -1,18 +1,12 @@
|
||||
import {StrictMode, useEffect, useState} from "react";
|
||||
import {StrictMode} from "react";
|
||||
import ReactDOM from "react-dom/client";
|
||||
import "./styles.css";
|
||||
import Cookies from "js-cookie";
|
||||
|
||||
import {SessionProvider} from "./components/providers/Providers.tsx";
|
||||
import {RouterProvider, createRouter} from "@tanstack/react-router";
|
||||
import {SidebarProvider, SidebarTrigger} from "./components/ui/sidebar";
|
||||
import {AppSidebar} from "./components/layout/lst-sidebar.tsx";
|
||||
import {ThemeProvider} from "./components/layout/theme-provider.tsx";
|
||||
|
||||
// Import the generated route tree
|
||||
import {routeTree} from "./routeTree.gen";
|
||||
import {ModeToggle} from "./components/layout/mode-toggle.tsx";
|
||||
import {TanStackRouterDevtools} from "@tanstack/router-devtools";
|
||||
|
||||
// Create a new router instance
|
||||
const router = createRouter({routeTree});
|
||||
@@ -24,32 +18,6 @@ declare module "@tanstack/react-router" {
|
||||
}
|
||||
}
|
||||
|
||||
function App() {
|
||||
const [defaultOpen, setDefaultOpen] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
const sidebarState = Cookies.get("sidebar_state") === "true";
|
||||
setDefaultOpen(sidebarState);
|
||||
}, []);
|
||||
|
||||
// come back later and deal with the defaultOpen={sidebarState} as its not wokring with the cookies
|
||||
console.log(defaultOpen);
|
||||
return (
|
||||
// <ThemeProvider>
|
||||
// <nav className="flex justify-end">
|
||||
// <div className="m-2">
|
||||
// <ModeToggle />
|
||||
// </div>
|
||||
// </nav>
|
||||
// <SidebarProvider>
|
||||
// <AppSidebar />
|
||||
// <RouterProvider router={router} />
|
||||
// </SidebarProvider>
|
||||
// </ThemeProvider>
|
||||
<RouterProvider router={router} />
|
||||
);
|
||||
}
|
||||
|
||||
// Render the app
|
||||
const rootElement = document.getElementById("root")!;
|
||||
if (!rootElement.innerHTML) {
|
||||
@@ -57,7 +25,7 @@ if (!rootElement.innerHTML) {
|
||||
root.render(
|
||||
<StrictMode>
|
||||
<SessionProvider>
|
||||
<App />
|
||||
<RouterProvider router={router} />
|
||||
</SessionProvider>
|
||||
</StrictMode>
|
||||
);
|
||||
|
||||
@@ -17,9 +17,7 @@ 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
|
||||
|
||||
@@ -58,24 +56,12 @@ const OcpLotsRoute = OcpLotsImport.update({
|
||||
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' {
|
||||
@@ -108,13 +94,6 @@ declare module '@tanstack/react-router' {
|
||||
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'
|
||||
@@ -122,13 +101,6 @@ declare module '@tanstack/react-router' {
|
||||
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'
|
||||
@@ -149,12 +121,10 @@ declare module '@tanstack/react-router' {
|
||||
// Create and export the route tree
|
||||
|
||||
interface AuthRouteChildren {
|
||||
AuthDashboardRoute: typeof AuthDashboardRoute
|
||||
AuthProfileRoute: typeof AuthProfileRoute
|
||||
}
|
||||
|
||||
const AuthRouteChildren: AuthRouteChildren = {
|
||||
AuthDashboardRoute: AuthDashboardRoute,
|
||||
AuthProfileRoute: AuthProfileRoute,
|
||||
}
|
||||
|
||||
@@ -165,9 +135,7 @@ export interface FileRoutesByFullPath {
|
||||
'': 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
|
||||
}
|
||||
@@ -177,9 +145,7 @@ export interface FileRoutesByTo {
|
||||
'': 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
|
||||
}
|
||||
@@ -190,45 +156,23 @@ export interface FileRoutesById {
|
||||
'/_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'
|
||||
fullPaths: '/' | '' | '/about' | '/login' | '/profile' | '/ocp/lots' | '/ocp'
|
||||
fileRoutesByTo: FileRoutesByTo
|
||||
to:
|
||||
| '/'
|
||||
| ''
|
||||
| '/about'
|
||||
| '/login'
|
||||
| '/dashboard'
|
||||
| '/profile'
|
||||
| '/ocp/$lineID'
|
||||
| '/ocp/lots'
|
||||
| '/ocp'
|
||||
to: '/' | '' | '/about' | '/login' | '/profile' | '/ocp/lots' | '/ocp'
|
||||
id:
|
||||
| '__root__'
|
||||
| '/'
|
||||
| '/_auth'
|
||||
| '/about'
|
||||
| '/login'
|
||||
| '/_auth/dashboard'
|
||||
| '/_auth/profile'
|
||||
| '/ocp/$lineID'
|
||||
| '/ocp/lots'
|
||||
| '/ocp/'
|
||||
fileRoutesById: FileRoutesById
|
||||
@@ -239,7 +183,6 @@ export interface RootRouteChildren {
|
||||
AuthRoute: typeof AuthRouteWithChildren
|
||||
AboutRoute: typeof AboutRoute
|
||||
LoginRoute: typeof LoginRoute
|
||||
OcpLineIDRoute: typeof OcpLineIDRoute
|
||||
OcpLotsRoute: typeof OcpLotsRoute
|
||||
OcpIndexRoute: typeof OcpIndexRoute
|
||||
}
|
||||
@@ -249,7 +192,6 @@ const rootRouteChildren: RootRouteChildren = {
|
||||
AuthRoute: AuthRouteWithChildren,
|
||||
AboutRoute: AboutRoute,
|
||||
LoginRoute: LoginRoute,
|
||||
OcpLineIDRoute: OcpLineIDRoute,
|
||||
OcpLotsRoute: OcpLotsRoute,
|
||||
OcpIndexRoute: OcpIndexRoute,
|
||||
}
|
||||
@@ -268,7 +210,6 @@ export const routeTree = rootRoute
|
||||
"/_auth",
|
||||
"/about",
|
||||
"/login",
|
||||
"/ocp/$lineID",
|
||||
"/ocp/lots",
|
||||
"/ocp/"
|
||||
]
|
||||
@@ -279,7 +220,6 @@ export const routeTree = rootRoute
|
||||
"/_auth": {
|
||||
"filePath": "_auth.tsx",
|
||||
"children": [
|
||||
"/_auth/dashboard",
|
||||
"/_auth/profile"
|
||||
]
|
||||
},
|
||||
@@ -289,17 +229,10 @@ export const routeTree = rootRoute
|
||||
"/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"
|
||||
},
|
||||
|
||||
@@ -5,6 +5,15 @@ import {SidebarProvider} from "../components/ui/sidebar";
|
||||
import {ThemeProvider} from "../components/layout/theme-provider";
|
||||
import {ModeToggle} from "../components/layout/mode-toggle";
|
||||
import {AppSidebar} from "../components/layout/lst-sidebar";
|
||||
import {Avatar, AvatarFallback, AvatarImage} from "../components/ui/avatar";
|
||||
import {
|
||||
DropdownMenu,
|
||||
DropdownMenuContent,
|
||||
DropdownMenuItem,
|
||||
DropdownMenuLabel,
|
||||
DropdownMenuSeparator,
|
||||
DropdownMenuTrigger,
|
||||
} from "../components/ui/dropdown-menu";
|
||||
|
||||
// same as the layout
|
||||
export const Route = createRootRoute({
|
||||
@@ -15,8 +24,31 @@ export const Route = createRootRoute({
|
||||
<>
|
||||
<ThemeProvider>
|
||||
<nav className="flex justify-end">
|
||||
<div className="m-2">
|
||||
<ModeToggle />
|
||||
<div className="m-2 flex flex-row">
|
||||
<div className="m-auto pr-2">
|
||||
<p>Add Card</p>
|
||||
</div>
|
||||
<div className="m-1">
|
||||
<ModeToggle />
|
||||
</div>
|
||||
<div className="m-1">
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger>
|
||||
<Avatar>
|
||||
<AvatarImage src="https://github.com/shadcn.png" alt="@shadcn" />
|
||||
<AvatarFallback>CN</AvatarFallback>
|
||||
</Avatar>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent>
|
||||
<DropdownMenuLabel>My Account</DropdownMenuLabel>
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuItem>Profile</DropdownMenuItem>
|
||||
<DropdownMenuItem>Billing</DropdownMenuItem>
|
||||
<DropdownMenuItem>Team</DropdownMenuItem>
|
||||
<DropdownMenuItem>Subscription</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
<SidebarProvider defaultOpen={sidebarState}>
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
import {createFileRoute} from "@tanstack/react-router";
|
||||
import {Button} from "../../components/ui/button";
|
||||
import {useLogout} from "../../lib/hooks/useLogout";
|
||||
|
||||
export const Route = createFileRoute("/_auth/dashboard")({
|
||||
component: RouteComponent,
|
||||
});
|
||||
|
||||
function RouteComponent() {
|
||||
const logout = useLogout();
|
||||
return (
|
||||
<div>
|
||||
Hello "/_auth/dashboard"!<Button onClick={() => logout()}>Logout</Button>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -1,30 +1,48 @@
|
||||
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";
|
||||
import {useSessionStore} from "../lib/store/sessionStore";
|
||||
import GridLayout from "react-grid-layout";
|
||||
import "../../node_modules/react-grid-layout/css/styles.css";
|
||||
import "../../node_modules/react-resizable/css/styles.css";
|
||||
|
||||
export const Route = createFileRoute("/")({
|
||||
component: Index,
|
||||
});
|
||||
|
||||
function Index() {
|
||||
const {session} = useSession();
|
||||
const {user} = useSessionStore();
|
||||
const logout = useLogout();
|
||||
// const [layout, setLayout] = useState([
|
||||
// {
|
||||
// i: "PPOO",
|
||||
// x: 0,
|
||||
// y: 0,
|
||||
// w: 5,
|
||||
// h: 3,
|
||||
// minW: 2,
|
||||
// maxW: 6,
|
||||
// minH: 2,
|
||||
// maxH: 4,
|
||||
// isResizable: true,
|
||||
// isDraggable: true,
|
||||
// },
|
||||
// {i: "OCPLogs", x: 2, y: 0, w: 5, h: 3, isResizable: true, isDraggable: true},
|
||||
// ]);
|
||||
|
||||
// const [cardData, setCardData] = useState([
|
||||
// {i: "card1", name: "PPOO"},
|
||||
// {i: "card2", name: "OCPLogs"},
|
||||
// ]);
|
||||
return (
|
||||
<div className="p-2">
|
||||
{session ? (
|
||||
<>
|
||||
<h3>Welcome Home {user?.username}</h3>
|
||||
<p>Your current role is: {user?.role}</p>
|
||||
<br></br>
|
||||
<Button onClick={() => logout()}>Logout</Button>{" "}
|
||||
</>
|
||||
) : (
|
||||
<LoginForm />
|
||||
)}
|
||||
</div>
|
||||
<>
|
||||
{/* <AddCards addCard={addCard} cards={cards} /> */}
|
||||
<GridLayout className="layout" cols={12} rowHeight={30} width={window.innerWidth}>
|
||||
<div className="bg-blue-400" key="a" data-grid={{x: 0, y: 0, w: 1, h: 2, static: true}}>
|
||||
a
|
||||
</div>
|
||||
<div className="bg-blue-400" key="b" data-grid={{x: 1, y: 0, w: 3, h: 2, minW: 2, maxW: 4}}>
|
||||
b
|
||||
</div>
|
||||
<div className="bg-blue-400" key="c" data-grid={{x: 4, y: 0, w: 1, h: 2}}>
|
||||
c
|
||||
</div>
|
||||
</GridLayout>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
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>;
|
||||
}
|
||||
@@ -2,30 +2,17 @@ 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>
|
||||
<h2>Hello "/ocp/something"!</h2>
|
||||
{lines.map((line) => {
|
||||
return (
|
||||
<div key={line}>
|
||||
<Link to="/ocp/$lineID" params={{lineID: line}}>
|
||||
Post
|
||||
</Link>
|
||||
<Link to="/ocp">Specific Line</Link>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
|
||||
Reference in New Issue
Block a user