From 604fdf1545e1fb894c733a1b72931f914d32f2ef Mon Sep 17 00:00:00 2001 From: Blake Matthes Date: Thu, 20 Feb 2025 10:25:35 -0600 Subject: [PATCH] feat(lst): added icons to the sidebar --- apiDocs/lstV2/Auth/Login.bru | 2 +- apiDocs/lstV2/Auth/session.bru | 13 +-- frontend/package.json | 2 + .../src/components/layout/lst-sidebar.tsx | 92 +++++++++++++-- .../layout/side-components/admin.tsx | 106 ++++++++++++++---- .../layout/side-components/forklift.tsx | 75 ++++++++++++- .../layout/side-components/logistics.tsx | 10 +- frontend/src/components/ui/collapsible.tsx | 31 +++++ server/src/services/auth/routes/session.ts | 12 +- 9 files changed, 291 insertions(+), 52 deletions(-) create mode 100644 frontend/src/components/ui/collapsible.tsx diff --git a/apiDocs/lstV2/Auth/Login.bru b/apiDocs/lstV2/Auth/Login.bru index 361529d..ad90de2 100644 --- a/apiDocs/lstV2/Auth/Login.bru +++ b/apiDocs/lstV2/Auth/Login.bru @@ -5,7 +5,7 @@ meta { } post { - url: http://localhost:4000/api/auth/login + url: http://localhost:3000/api/auth/login body: json auth: none } diff --git a/apiDocs/lstV2/Auth/session.bru b/apiDocs/lstV2/Auth/session.bru index 257b818..526d7f5 100644 --- a/apiDocs/lstV2/Auth/session.bru +++ b/apiDocs/lstV2/Auth/session.bru @@ -5,16 +5,11 @@ meta { } get { - url: http://localhost:4000/api/auth/session + url: http://localhost:3000/api/auth/session body: none - auth: basic + auth: bearer } -headers { - : -} - -auth:basic { - username: admin - password: pass123 +auth:bearer { + token: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyIjp7ImlkIjoxLCJ1c2VybmFtZSI6ImFkbWluIiwicGFzc3dvcmQiOiJwYXNzd29yZDEyMyIsInJvbGUiOiJhZG1pbiJ9LCJpYXQiOjE3NDAwMTc4MTcsImV4cCI6MTc0MDAxODExN30.84RPgbfNkLMWPE0dmhzF62yybeb9FpetYGwGsh8_m-g } diff --git a/frontend/package.json b/frontend/package.json index 810257b..c612064 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -11,6 +11,7 @@ }, "dependencies": { "@antfu/ni": "^23.3.1", + "@radix-ui/react-collapsible": "^1.1.3", "@radix-ui/react-dialog": "^1.1.6", "@radix-ui/react-dropdown-menu": "^2.1.6", "@radix-ui/react-separator": "^1.1.2", @@ -21,6 +22,7 @@ "@tanstack/react-router": "^1.106.0", "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", diff --git a/frontend/src/components/layout/lst-sidebar.tsx b/frontend/src/components/layout/lst-sidebar.tsx index 495d7f3..67bc346 100644 --- a/frontend/src/components/layout/lst-sidebar.tsx +++ b/frontend/src/components/layout/lst-sidebar.tsx @@ -3,21 +3,99 @@ import {ProductionSideBar} from "./side-components/production"; import {Header} from "./side-components/header"; import {LogisticsSideBar} from "./side-components/logistics"; import {QualitySideBar} from "./side-components/quality"; -import {AdminSideBar} from "./side-components/Admin"; import {ForkliftSideBar} from "./side-components/forklift"; import {EomSideBar} from "./side-components/eom"; +import {AdminSideBar} from "./side-components/admin"; + +type Feature = string; + +interface Module { + id: number; + name: string; + features: Feature[]; + active: boolean; +} + +interface RolePermissions { + [moduleName: string]: Feature[]; +} + +interface Roles { + [roleName: string]: RolePermissions; +} + +interface User { + id: number; + username: string; + role: keyof Roles; +} +const modules: Module[] = [ + {id: 1, name: "production", active: true, features: ["view", "edit", "approve"]}, + {id: 2, name: "logistics", active: true, features: ["view", "assign", "track"]}, + {id: 3, name: "quality", active: false, features: ["view", "audit", "approve"]}, + {id: 4, name: "forklift", active: true, features: ["view", "request", "operate"]}, + {id: 5, name: "admin", active: true, features: ["view", "manage_users", "view_logs", "settings"]}, +]; + +const rolePermissions: Roles = { + admin: { + production: ["view", "edit", "approve"], + logistics: ["view", "assign", "track"], + quality: ["view", "audit", "approve"], + forklift: ["view", "request", "operate"], + admin: ["view", "manage_users", "view_logs", "settings"], + }, + manager: { + production: ["view", "edit"], + logistics: ["view", "assign"], + quality: ["view", "audit"], + forklift: ["view", "request"], + admin: ["view_logs"], + }, + supervisor: { + production: ["view"], + logistics: ["view"], + quality: ["view"], + forklift: ["view", "request"], + admin: [], + }, + user: { + production: ["view"], + logistics: [], + quality: [], + forklift: [], + admin: [], + }, +}; + +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; +} + +function moduleActive(moduleName: string): boolean { + const module = modules.find((m) => m.name === moduleName); + return module ? module.active : false; +} export function AppSidebar() { + const user = {id: 4, username: "admin", role: "admin"}; return (
- - - - - - + {hasAccess(user, "production", "view") && moduleActive("production") && } + {hasAccess(user, "logistics", "view") && moduleActive("logistics") && } + {hasAccess(user, "forklift", "view") && moduleActive("forklift") && } + {hasAccess(user, "eom", "view") && moduleActive("admin") && } + {hasAccess(user, "quality", "view") && moduleActive("quality") && } + {hasAccess(user, "admin", "view") && moduleActive("admin") && } diff --git a/frontend/src/components/layout/side-components/admin.tsx b/frontend/src/components/layout/side-components/admin.tsx index ddce1e8..c372710 100644 --- a/frontend/src/components/layout/side-components/admin.tsx +++ b/frontend/src/components/layout/side-components/admin.tsx @@ -1,4 +1,4 @@ -import {Printer} from "lucide-react"; +import {Atom, Logs, Minus, Plus, Server, Settings, ShieldCheck, Users, Webhook} from "lucide-react"; import { SidebarGroup, SidebarGroupContent, @@ -6,41 +6,99 @@ import { SidebarMenu, SidebarMenuButton, SidebarMenuItem, + SidebarMenuSub, + SidebarMenuSubButton, + SidebarMenuSubItem, } from "../../ui/sidebar"; +import {Collapsible, CollapsibleContent, CollapsibleTrigger} from "../../ui/collapsible"; const items = [ { - title: "Settings", + title: "Servers", url: "#", - icon: Printer, - }, - { - title: "Swagger", - url: "#", - icon: Printer, - }, - { - title: "Logs", - url: "#", - icon: Printer, - }, - { - title: "Users", - url: "#", - icon: Printer, - }, - { - title: "UCD", - url: "#", - icon: Printer, + icon: Server, + isActive: false, }, ]; +const data = { + navMain: [ + { + title: "Admin", + url: "#", + icon: ShieldCheck, + items: [ + { + title: "Settings", + url: "#", + icon: Settings, + isActive: false, + }, + { + title: "Swagger", + url: "#", + icon: Webhook, + isActive: false, + }, + { + title: "Logs", + url: "#", + icon: Logs, + isActive: false, + }, + { + title: "Users", + url: "#", + icon: Users, + isActive: false, + }, + { + title: "UCD", + url: "#", + icon: Atom, + isActive: false, + }, + ], + }, + ], +}; export function AdminSideBar() { return ( - Admin + Admin section + + {data.navMain.map((item, index) => ( + + + + + + {item.title}{" "} + + + + + {item.items?.length ? ( + + + {item.items.map((item) => ( + + + + + {item.title} + + + + ))} + + + ) : null} + + + ))} + {items.map((item) => ( diff --git a/frontend/src/components/layout/side-components/forklift.tsx b/frontend/src/components/layout/side-components/forklift.tsx index 1b376d1..d1e26ea 100644 --- a/frontend/src/components/layout/side-components/forklift.tsx +++ b/frontend/src/components/layout/side-components/forklift.tsx @@ -1,4 +1,4 @@ -import {Printer} from "lucide-react"; +import {Forklift, Hourglass, Minus, Plus, Signature} from "lucide-react"; import { SidebarGroup, SidebarGroupContent, @@ -6,21 +6,88 @@ import { SidebarMenu, SidebarMenuButton, SidebarMenuItem, + SidebarMenuSub, + SidebarMenuSubButton, + SidebarMenuSubItem, } from "../../ui/sidebar"; +import {Collapsible, CollapsibleTrigger} from "../../ui/collapsible"; +import {CollapsibleContent} from "@radix-ui/react-collapsible"; const items = [ { - title: "Qaulity Request", + title: "Gemone", url: "#", - icon: Printer, + icon: Forklift, + isActive: false, }, ]; +const data = { + navMain: [ + { + title: "Forklift Management", + url: "#", + icon: Forklift, + items: [ + { + title: "All Forklifts", + url: "#", + icon: Forklift, + }, + { + title: "Leasing data", + url: "#", + isActive: false, + icon: Signature, + }, + { + title: "Forklift Hours", + url: "#", + isActive: false, + icon: Hourglass, + }, + ], + }, + ], +}; + export function ForkliftSideBar() { return ( - Forklift + Forklift Section + + {data.navMain.map((item, index) => ( + + + + + + {item.title}{" "} + + + + + {item.items?.length ? ( + + + {item.items.map((item) => ( + + + + + {item.title} + + + + ))} + + + ) : null} + + + ))} + {items.map((item) => ( diff --git a/frontend/src/components/layout/side-components/logistics.tsx b/frontend/src/components/layout/side-components/logistics.tsx index d6548b7..5b273e0 100644 --- a/frontend/src/components/layout/side-components/logistics.tsx +++ b/frontend/src/components/layout/side-components/logistics.tsx @@ -1,4 +1,4 @@ -import {Printer} from "lucide-react"; +import {Cylinder, Package, Printer, Truck} from "lucide-react"; import { SidebarGroup, SidebarGroupContent, @@ -12,22 +12,22 @@ const items = [ { title: "Silo Adjustments", url: "#", - icon: Printer, + icon: Cylinder, }, { title: "Bulk orders", url: "#", - icon: Printer, + icon: Truck, }, { title: "Forecast", url: "#", - icon: Printer, + icon: Truck, }, { title: "Ocme cycle counts", url: "#", - icon: Printer, + icon: Package, }, ]; diff --git a/frontend/src/components/ui/collapsible.tsx b/frontend/src/components/ui/collapsible.tsx new file mode 100644 index 0000000..77f86be --- /dev/null +++ b/frontend/src/components/ui/collapsible.tsx @@ -0,0 +1,31 @@ +import * as CollapsiblePrimitive from "@radix-ui/react-collapsible" + +function Collapsible({ + ...props +}: React.ComponentProps) { + return +} + +function CollapsibleTrigger({ + ...props +}: React.ComponentProps) { + return ( + + ) +} + +function CollapsibleContent({ + ...props +}: React.ComponentProps) { + return ( + + ) +} + +export { Collapsible, CollapsibleTrigger, CollapsibleContent } diff --git a/server/src/services/auth/routes/session.ts b/server/src/services/auth/routes/session.ts index 7c2dbfd..02486ee 100644 --- a/server/src/services/auth/routes/session.ts +++ b/server/src/services/auth/routes/session.ts @@ -3,7 +3,7 @@ import {verify} from "hono/jwt"; const session = new OpenAPIHono(); const tags = ["Auth"]; -const JWT_SECRET = "your-secret-key"; +const JWT_SECRET = process.env.JWT_SECRET; const route = createRoute({ tags: ["Auth"], @@ -21,6 +21,14 @@ const route = createRoute({ }, description: "Login successful", }, + 401: { + content: { + "application/json": { + schema: {message: ""}, + }, + }, + description: "Error of why you were not logged in.", + }, }, }); session.openapi(route, async (c) => { @@ -39,7 +47,7 @@ session.openapi(route, async (c) => { try { const payload = await verify(token, JWT_SECRET); - console.log(payload); + //console.log(payload); return c.json({data: {token, user: payload.user}}); } catch (err) { return c.json({error: "Invalid or expired token"}, 401);