From d3acdfb481ee2f78f543979c2bf892ef885d7a66 Mon Sep 17 00:00:00 2001 From: Blake Matthes Date: Sat, 1 Mar 2025 15:22:34 -0600 Subject: [PATCH] test(auth): more auth work --- frontend/package-lock.json | 144 +++++++++++++++++- frontend/package.json | 5 +- .../src/components/layout/lst-sidebar.tsx | 14 +- .../layout/side-components/logistics.tsx | 4 + frontend/src/lib/store/sessionStore.ts | 8 +- frontend/src/lib/store/useGetRoles.ts | 48 ++++++ frontend/src/lib/store/useModuleStore.ts | 21 +-- frontend/src/main.tsx | 34 +++-- frontend/src/types/modules.ts | 10 ++ frontend/src/utils/moduleActive.ts | 2 +- frontend/src/utils/userAccess.ts | 61 +++----- frontend/vite.config.ts | 2 +- 12 files changed, 275 insertions(+), 78 deletions(-) create mode 100644 frontend/src/lib/store/useGetRoles.ts create mode 100644 frontend/src/types/modules.ts diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 6b6d752..712312e 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -23,7 +23,9 @@ "@tanstack/react-router": "^1.111.11", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", + "hono": "^4.7.2", "js-cookie": "^3.0.5", + "jsonwebtoken": "^9.0.2", "lucide-react": "^0.476.0", "next-themes": "^0.4.4", "react": "^19.0.0", @@ -43,6 +45,7 @@ "@tanstack/router-plugin": "^1.106.0", "@types/react": "^19.0.10", "@types/react-dom": "^19.0.4", + "@types/react-grid-layout": "^1.3.5", "@vitejs/plugin-react-swc": "^3.8.0", "eslint": "^9.21.0", "eslint-plugin-react-hooks": "^5.0.0", @@ -2909,6 +2912,16 @@ "@types/react": "^19.0.0" } }, + "node_modules/@types/react-grid-layout": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/@types/react-grid-layout/-/react-grid-layout-1.3.5.tgz", + "integrity": "sha512-WH/po1gcEcoR6y857yAnPGug+ZhkF4PaTUxgAbwfeSH/QOgVSakKHBXoPGad/sEznmkiaK3pqHk+etdWisoeBQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/react": "*" + } + }, "node_modules/@typescript-eslint/eslint-plugin": { "version": "8.25.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.25.0.tgz", @@ -3317,6 +3330,12 @@ "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" } }, + "node_modules/buffer-equal-constant-time": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", + "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==", + "license": "BSD-3-Clause" + }, "node_modules/callsites": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", @@ -3533,6 +3552,15 @@ "node": ">=0.3.1" } }, + "node_modules/ecdsa-sig-formatter": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", + "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", + "license": "Apache-2.0", + "dependencies": { + "safe-buffer": "^5.0.1" + } + }, "node_modules/electron-to-chromium": { "version": "1.5.107", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.107.tgz", @@ -4029,6 +4057,15 @@ "node": ">=8" } }, + "node_modules/hono": { + "version": "4.7.2", + "resolved": "https://registry.npmjs.org/hono/-/hono-4.7.2.tgz", + "integrity": "sha512-8V5XxoOF6SI12jkHkzX/6aLBMU5GEF5g387EjVSQipS0DlxWgWGSMeEayY3CRBjtTUQYwLHx9JYouWqKzy2Vng==", + "license": "MIT", + "engines": { + "node": ">=16.9.0" + } + }, "node_modules/ignore": { "version": "5.3.2", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", @@ -4202,6 +4239,49 @@ "node": ">=6" } }, + "node_modules/jsonwebtoken": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.2.tgz", + "integrity": "sha512-PRp66vJ865SSqOlgqS8hujT5U4AOgMfhrwYIuIhfKaoSCZcirrmASQr8CX7cUg+RMih+hgznrjp99o+W4pJLHQ==", + "license": "MIT", + "dependencies": { + "jws": "^3.2.2", + "lodash.includes": "^4.3.0", + "lodash.isboolean": "^3.0.3", + "lodash.isinteger": "^4.0.4", + "lodash.isnumber": "^3.0.3", + "lodash.isplainobject": "^4.0.6", + "lodash.isstring": "^4.0.1", + "lodash.once": "^4.0.0", + "ms": "^2.1.1", + "semver": "^7.5.4" + }, + "engines": { + "node": ">=12", + "npm": ">=6" + } + }, + "node_modules/jwa": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz", + "integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==", + "license": "MIT", + "dependencies": { + "buffer-equal-constant-time": "1.0.1", + "ecdsa-sig-formatter": "1.0.11", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/jws": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz", + "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==", + "license": "MIT", + "dependencies": { + "jwa": "^1.4.1", + "safe-buffer": "^5.0.1" + } + }, "node_modules/keyv": { "version": "4.5.4", "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", @@ -4470,6 +4550,42 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/lodash.includes": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", + "integrity": "sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==", + "license": "MIT" + }, + "node_modules/lodash.isboolean": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", + "integrity": "sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==", + "license": "MIT" + }, + "node_modules/lodash.isinteger": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz", + "integrity": "sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==", + "license": "MIT" + }, + "node_modules/lodash.isnumber": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz", + "integrity": "sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw==", + "license": "MIT" + }, + "node_modules/lodash.isplainobject": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", + "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==", + "license": "MIT" + }, + "node_modules/lodash.isstring": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", + "integrity": "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==", + "license": "MIT" + }, "node_modules/lodash.merge": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", @@ -4477,6 +4593,12 @@ "dev": true, "license": "MIT" }, + "node_modules/lodash.once": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", + "integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==", + "license": "MIT" + }, "node_modules/loose-envify": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", @@ -4549,7 +4671,6 @@ "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true, "license": "MIT" }, "node_modules/nanoid": { @@ -5089,6 +5210,26 @@ "queue-microtask": "^1.2.2" } }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, "node_modules/scheduler": { "version": "0.25.0", "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.25.0.tgz", @@ -5099,7 +5240,6 @@ "version": "7.7.1", "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==", - "dev": true, "license": "ISC", "bin": { "semver": "bin/semver.js" diff --git a/frontend/package.json b/frontend/package.json index 96daa24..454e862 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -5,7 +5,7 @@ "type": "module", "scripts": { "dev": "vite", - "build": "tsc -b && vite build", + "build": "rimraf dist && tsc -b && vite build", "lint": "eslint .", "preview": "vite preview", "shad": "npx shadcn@canary add " @@ -26,7 +26,9 @@ "@tanstack/react-router": "^1.111.11", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", + "hono": "^4.7.2", "js-cookie": "^3.0.5", + "jsonwebtoken": "^9.0.2", "lucide-react": "^0.476.0", "next-themes": "^0.4.4", "react": "^19.0.0", @@ -46,6 +48,7 @@ "@tanstack/router-plugin": "^1.106.0", "@types/react": "^19.0.10", "@types/react-dom": "^19.0.4", + "@types/react-grid-layout": "^1.3.5", "@vitejs/plugin-react-swc": "^3.8.0", "eslint": "^9.21.0", "eslint-plugin-react-hooks": "^5.0.0", diff --git a/frontend/src/components/layout/lst-sidebar.tsx b/frontend/src/components/layout/lst-sidebar.tsx index ac2bbdf..d1ec89d 100644 --- a/frontend/src/components/layout/lst-sidebar.tsx +++ b/frontend/src/components/layout/lst-sidebar.tsx @@ -9,19 +9,23 @@ import {AdminSideBar} from "./side-components/admin"; import {useSessionStore} from "../../lib/store/sessionStore"; import {hasAccess} from "../../utils/userAccess"; import {moduleActive} from "../../utils/moduleActive"; +import {useModuleStore} from "../../lib/store/useModuleStore"; export function AppSidebar() { const {user} = useSessionStore(); + const {modules} = useModuleStore(); + + console.log(user); return (
{moduleActive("production") && } - {moduleActive("logistics") && hasAccess(user, "logistics", "view") && } - {moduleActive("forklift") && hasAccess(user, "forklift", "view") && } - {moduleActive("admin") && hasAccess(user, "eom", "view") && } - {moduleActive("quality") && hasAccess(user, "quality", "view") && } - {moduleActive("admin") && hasAccess(user, "admin", "view") && } + {moduleActive("logistics") && hasAccess(user, "logistics", modules) && } + {moduleActive("forklift") && hasAccess(user, "forklift", modules) && } + {moduleActive("admin") && hasAccess(user, "eom", modules) && } + {moduleActive("quality") && hasAccess(user, "quality", modules) && } + {moduleActive("admin") && hasAccess(user, "admin", modules) && } diff --git a/frontend/src/components/layout/side-components/logistics.tsx b/frontend/src/components/layout/side-components/logistics.tsx index 92f4971..6a1bb5c 100644 --- a/frontend/src/components/layout/side-components/logistics.tsx +++ b/frontend/src/components/layout/side-components/logistics.tsx @@ -13,21 +13,25 @@ const items = [ title: "Silo Adjustments", url: "#", icon: Cylinder, + role: ["technician", "supervisor", "manager", "admin", "systemAdmin"], }, { title: "Bulk orders", url: "#", icon: Truck, + role: ["technician", "supervisor", "manager", "admin", "systemAdmin"], }, { title: "Forecast", url: "#", icon: Truck, + role: ["technician", "supervisor", "manager", "admin", "systemAdmin"], }, { title: "Ocme cycle counts", url: "#", icon: Package, + role: ["technician", "supervisor", "manager", "admin", "systemAdmin"], }, ]; diff --git a/frontend/src/lib/store/sessionStore.ts b/frontend/src/lib/store/sessionStore.ts index a2400e7..492f2a0 100644 --- a/frontend/src/lib/store/sessionStore.ts +++ b/frontend/src/lib/store/sessionStore.ts @@ -1,11 +1,17 @@ import {create} from "zustand"; type User = { - id: number; + user_id: string; + email: string; username: string; + roles: keyof Roles[]; role: string; }; +interface Roles { + role: string; +} + export type SessionState = { user: User | null; token: string | null; diff --git a/frontend/src/lib/store/useGetRoles.ts b/frontend/src/lib/store/useGetRoles.ts new file mode 100644 index 0000000..5fa705b --- /dev/null +++ b/frontend/src/lib/store/useGetRoles.ts @@ -0,0 +1,48 @@ +import {create} from "zustand"; +import {useSessionStore} from "./sessionStore"; +//import useSWR from "swr"; + +interface Modules { + module_id: string; + name: string; + active: boolean; + roles: string; + add_user: string; + add_date: Date; + upd_user: string; + upd_date: Date; +} + +interface SettingState { + userRoles: Modules[]; + + fetchUserRoles: () => Promise; + setUserRoles: (userRoles: Modules[]) => void; +} +interface FetchModulesResponse { + data: Modules[]; +} + +export const useModuleStore = create()((set) => ({ + userRoles: [], + setUserRoles: (userRoles) => set({userRoles}), + fetchUserRoles: async () => { + try { + //const response = await axios.get<{data: Setting[]}>(`${process.env.NEXT_PUBLIC_URL}/api/settings/client`); + const {token} = useSessionStore(); + const response = await fetch(`/api/auth/getuseraccess`, { + method: "GET", + headers: { + "Content-Type": "application/json", + Authentication: `Beaer ${token}`, + // You can add other headers here if necessary + }, + }); + const data: FetchModulesResponse = await response.json(); + //console.log(data); + set({userRoles: data.data}); + } catch (error) { + console.error("Failed to fetch settings:", error); + } + }, +})); diff --git a/frontend/src/lib/store/useModuleStore.ts b/frontend/src/lib/store/useModuleStore.ts index 5f0bc64..b4005ae 100644 --- a/frontend/src/lib/store/useModuleStore.ts +++ b/frontend/src/lib/store/useModuleStore.ts @@ -1,16 +1,17 @@ +import {Modules} from "@/types/modules"; import {create} from "zustand"; //import useSWR from "swr"; -interface Modules { - module_id: string; - name: string; - active: boolean; - roles: string; - add_user: string; - add_date: Date; - upd_user: string; - upd_date: Date; -} +// interface Modules { +// module_id: string; +// name: string; +// active: boolean; +// roles: string; +// add_user: string; +// add_date: Date; +// upd_user: string; +// upd_date: Date; +// } interface SettingState { modules: Modules[]; diff --git a/frontend/src/main.tsx b/frontend/src/main.tsx index 4b59ec6..d5d1475 100644 --- a/frontend/src/main.tsx +++ b/frontend/src/main.tsx @@ -1,4 +1,4 @@ -import {StrictMode} from "react"; +import React from "react"; import ReactDOM from "react-dom/client"; import "./styles.css"; import {RouterProvider, createRouter} from "@tanstack/react-router"; @@ -19,15 +19,23 @@ declare module "@tanstack/react-router" { } } -// Render the app -const rootElement = document.getElementById("root")!; -if (!rootElement.innerHTML) { - const root = ReactDOM.createRoot(rootElement); - root.render( - - - - - - ); -} +ReactDOM.createRoot(document.getElementById("root")!).render( + + + + + +); + +// // Render the app +// const rootElement = document.getElementById("root")!; +// if (!rootElement.innerHTML) { +// const root = ReactDOM.createRoot(rootElement); +// root.render( +// +// +// +// +// +// ); +// } diff --git a/frontend/src/types/modules.ts b/frontend/src/types/modules.ts new file mode 100644 index 0000000..8241ffb --- /dev/null +++ b/frontend/src/types/modules.ts @@ -0,0 +1,10 @@ +export interface Modules { + module_id: string; + name: string; + active: boolean; + roles: string; + add_User: string; + add_Date: Date; + upd_user: string; + upd_date: Date; +} diff --git a/frontend/src/utils/moduleActive.ts b/frontend/src/utils/moduleActive.ts index 1673970..d104278 100644 --- a/frontend/src/utils/moduleActive.ts +++ b/frontend/src/utils/moduleActive.ts @@ -19,5 +19,5 @@ import {useModuleStore} from "../lib/store/useModuleStore"; export function moduleActive(moduleName: string): boolean { const {modules} = useModuleStore(); const module = modules.find((m: any) => m.name === moduleName); - return module ? module.active : false; + return module ? true : false; } diff --git a/frontend/src/utils/userAccess.ts b/frontend/src/utils/userAccess.ts index 47b5c20..908c791 100644 --- a/frontend/src/utils/userAccess.ts +++ b/frontend/src/utils/userAccess.ts @@ -1,52 +1,25 @@ -interface User { - id: number; +import {Modules} from "@/types/modules"; + +type User = { + user_id: string; + email: string; username: string; - role: keyof Roles; -} + roles: keyof Roles[]; + role: string; +}; interface Roles { - [roleName: string]: RolePermissions; + role: string; } -interface RolePermissions { - [moduleName: string]: Feature[]; -} - -type Feature = string; - -const rolePermissions: Roles = { - admin: { - production: ["view", "manage", "update", "admin"], - logistics: ["view", "manage", "update", "admin"], - quality: ["view", "request", "manage", "update", "admin"], - forklift: ["view", "manage", "update", "admin"], - admin: ["view", "view_logs", "manage", "update", "admin"], - }, - manager: { - production: ["view", "manage"], - logistics: ["view", "manage"], - quality: ["view", "manage"], - forklift: ["view", "manage"], - admin: ["view_logs"], - }, - supervisor: { - production: ["view", "update"], - logistics: ["view", "update"], - quality: ["view", "update"], - forklift: ["view"], - admin: [], - }, - user: { - production: ["view"], - logistics: ["view"], - quality: ["view"], - forklift: [], - admin: [], - }, -}; - // user will need access to the module. // users role will determine there visual access -export function hasAccess(user: User | null, moduleName: string, feature: Feature): boolean { - return user?.role ? rolePermissions[user.role]?.[moduleName]?.includes(feature) || false : false; +export function hasAccess(user: User | null, moduleName: string | null, modules: Modules[]): boolean { + // get the modules for the id + const filteredModule = modules?.filter((f) => f.name === moduleName); + console.log(filteredModule); + // userroles and filter out by the module id, + + console.log(user); + return false; } diff --git a/frontend/vite.config.ts b/frontend/vite.config.ts index 93f0319..8c2dcce 100644 --- a/frontend/vite.config.ts +++ b/frontend/vite.config.ts @@ -6,7 +6,7 @@ import path from "path"; // https://vite.dev/config/ export default defineConfig({ - plugins: [react(), tailwindcss(), TanStackRouterVite({autoCodeSplitting: true})], + plugins: [react(), tailwindcss(), TanStackRouterVite({target: "react", autoCodeSplitting: true})], resolve: { alias: { "@": path.resolve(__dirname, "./src"),