refactor(lst): more dashboard work

This commit is contained in:
2025-02-20 13:18:47 -06:00
parent 604fdf1545
commit d939332499
13 changed files with 152 additions and 190 deletions

View File

@@ -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",

View File

@@ -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;

View File

@@ -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>

View File

@@ -1,4 +1,4 @@
import {Cylinder, Package, Printer, Truck} from "lucide-react";
import {Cylinder, Package, Truck} from "lucide-react";
import {
SidebarGroup,
SidebarGroupContent,

View File

@@ -11,7 +11,7 @@ import {
const items = [
{
title: "One Click Print",
url: "#",
url: "/ocp",
icon: Printer,
},
];

View 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 }

View File

@@ -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>
);

View File

@@ -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"
},

View File

@@ -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}>

View File

@@ -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>
);
}

View File

@@ -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>
</>
);
}

View File

@@ -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>;
}

View File

@@ -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>
);
})}