From 85577b291f60744749abfd815efd6feceb393478 Mon Sep 17 00:00:00 2001 From: Blake Matthes Date: Fri, 4 Apr 2025 22:10:11 -0500 Subject: [PATCH] feat(submodules and login redirect): submodules added and login redirect --- database/schema/subModules.ts | 11 +- frontend/src/components/auth/LoginForm.tsx | 281 +++++++++--------- .../layout/side-components/logistics.tsx | 162 +++++----- .../src/components/providers/Providers.tsx | 3 + frontend/src/lib/store/useSubModuleStore.ts | 30 ++ frontend/src/routeTree.gen.ts | 55 ++++ .../(logistics)/siloAdjustments/index.tsx | 9 + frontend/src/routes/_admin.tsx | 8 +- frontend/src/routes/_auth.tsx | 8 +- frontend/src/routes/login.tsx | 6 +- frontend/src/types/modules.ts | 10 + server/services/logistics/logisticsService.ts | 11 +- .../server/route/modules/getSubModules.ts | 73 +++++ server/services/server/systemServer.ts | 2 + .../services/server/utils/subModuleCheck.ts | 4 +- 15 files changed, 450 insertions(+), 223 deletions(-) create mode 100644 frontend/src/lib/store/useSubModuleStore.ts create mode 100644 frontend/src/routes/(logistics)/siloAdjustments/index.tsx create mode 100644 server/services/server/route/modules/getSubModules.ts diff --git a/database/schema/subModules.ts b/database/schema/subModules.ts index b5aa619..22557e6 100644 --- a/database/schema/subModules.ts +++ b/database/schema/subModules.ts @@ -23,16 +23,17 @@ export const subModules = pgTable( link: text("link").notNull(), active: boolean("active").default(false), roles: jsonb("roles").notNull().default(["systemAdmin"]), // ["view", "technician", "supervisor","manager", "admin","systemAdmin"] + icon: text("icon"), subSubModule: jsonb("subSubModule").default([]), add_User: text("add_User").default("LST_System").notNull(), add_Date: timestamp("add_Date").defaultNow(), upd_user: text("upd_User").default("LST_System").notNull(), upd_date: timestamp("upd_date").defaultNow(), - } - // (table) => [ - // // uniqueIndex('emailUniqueIndex').on(sql`lower(${table.email})`), - // uniqueIndex("subModule_name").on(table.name), - // ] + }, + (table) => [ + // uniqueIndex('emailUniqueIndex').on(sql`lower(${table.email})`), + uniqueIndex("subModule_name").on(table.name), + ] ); // Schema for inserting a user - can be used to validate API requests diff --git a/frontend/src/components/auth/LoginForm.tsx b/frontend/src/components/auth/LoginForm.tsx index f9ea4fc..dd25dba 100644 --- a/frontend/src/components/auth/LoginForm.tsx +++ b/frontend/src/components/auth/LoginForm.tsx @@ -3,7 +3,7 @@ import { LstCard } from "../extendedUI/LstCard"; import { CardHeader } from "../ui/card"; import { toast } from "sonner"; import { z } from "zod"; -import { useRouter } from "@tanstack/react-router"; +import { useRouter, useSearch } from "@tanstack/react-router"; import { Controller, useForm } from "react-hook-form"; import { zodResolver } from "@hookform/resolvers/zod"; import { Label } from "../ui/label"; @@ -12,153 +12,160 @@ import { Checkbox } from "../ui/checkbox"; import { Button } from "../ui/button"; const FormSchema = z.object({ - username: z.string().min(1, "You must enter a valid username"), - password: z.string().min(4, "You must enter a valid password"), - rememberMe: z.boolean(), + username: z.string().min(1, "You must enter a valid username"), + password: z.string().min(4, "You must enter a valid password"), + rememberMe: z.boolean(), }); const LoginForm = () => { - const { setSession } = useSessionStore(); - const rememeberMe = localStorage.getItem("rememberMe") === "true"; - const username = localStorage.getItem("username") || ""; - const router = useRouter(); - const { - register, - handleSubmit, - control, - formState: { errors }, - } = useForm>({ - resolver: zodResolver(FormSchema), - defaultValues: { - username: username || "", - password: "", - rememberMe: rememeberMe, - }, - }); - - const onSubmitLogin = async (value: z.infer) => { - // Do something with form data - - // first update the rememberMe incase it was selected - if (value.rememberMe) { - localStorage.setItem("rememberMe", value.rememberMe.toString()); - localStorage.setItem("username", value.username); - } else { - localStorage.removeItem("rememberMe"); - localStorage.removeItem("username"); - } - - try { - const response = await fetch("/api/auth/login", { - method: "POST", - headers: { - "Content-Type": "application/json", + const { setSession } = useSessionStore(); + const rememeberMe = localStorage.getItem("rememberMe") === "true"; + const username = localStorage.getItem("username") || ""; + const router = useRouter(); + const search = useSearch({ from: "/login" }); + const { + register, + handleSubmit, + control, + formState: { errors }, + } = useForm>({ + resolver: zodResolver(FormSchema), + defaultValues: { + username: username || "", + password: "", + rememberMe: rememeberMe, }, - body: JSON.stringify({ - username: value.username, - password: value.password, - }), - }); + }); - const data = await response.json(); + const onSubmitLogin = async (value: z.infer) => { + // Do something with form data - // Store token in localStorage - // localStorage.setItem("auth_token", data.data.token); - if (data.success) { - const prod = btoa(`${value.username.toLowerCase()}:${value.password}`); - const prodUser = { ...data.user, prod: prod }; + // first update the rememberMe incase it was selected + if (value.rememberMe) { + localStorage.setItem("rememberMe", value.rememberMe.toString()); + localStorage.setItem("username", value.username); + } else { + localStorage.removeItem("rememberMe"); + localStorage.removeItem("username"); + } - setSession(prodUser, data.token); - toast.success(`You are logged in as ${data.user.username}`); - router.navigate({ to: "/" }); - } + try { + const response = await fetch("/api/auth/login", { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ + username: value.username, + password: value.password, + }), + }); - if (!data.success) { - toast.error(`${data.message}`); - } + const data = await response.json(); - //console.log(data); - } catch (err) { - toast.error("Invalid credentials"); - } - }; + // Store token in localStorage + // localStorage.setItem("auth_token", data.data.token); + if (data.success) { + const prod = btoa( + `${value.username.toLowerCase()}:${value.password}` + ); + const prodUser = { ...data.user, prod: prod }; - return ( -
- - -
-

Login to LST

-
-
-
-
-
- - - {errors.username && ( -

- {errors.username.message} -

- )} -
-
- <> - - - {errors.password && ( -

- {errors.password.message} -

- )} - -
-
-
- ( - <> - - - - )} - control={control} - name="rememberMe" - defaultValue={rememeberMe} - /> -
+ setSession(prodUser, data.token); + toast.success(`You are logged in as ${data.user.username}`); -
- -
-
-
-
-
- ); + console.log(search.redirect ? search.redirect : "oops"); + router.history.push(search.redirect ? search.redirect : "/"); + } + + if (!data.success) { + toast.error(`${data.message}`); + } + + //console.log(data); + } catch (err) { + toast.error("Invalid credentials"); + } + }; + + return ( +
+ + +
+

Login to LST

+
+
+
+
+
+ + + {errors.username && ( +

+ {errors.username.message} +

+ )} +
+
+ <> + + + {errors.password && ( +

+ {errors.password.message} +

+ )} + +
+
+
+ ( + <> + + + + )} + control={control} + name="rememberMe" + defaultValue={rememeberMe} + /> +
+ +
+ +
+
+
+
+
+ ); }; export default LoginForm; diff --git a/frontend/src/components/layout/side-components/logistics.tsx b/frontend/src/components/layout/side-components/logistics.tsx index 0317662..924429a 100644 --- a/frontend/src/components/layout/side-components/logistics.tsx +++ b/frontend/src/components/layout/side-components/logistics.tsx @@ -1,4 +1,4 @@ -import { Cylinder, Package, Truck } from "lucide-react"; +//import { Cylinder, Package, Truck } from "lucide-react"; import { SidebarGroup, SidebarGroupContent, @@ -9,67 +9,68 @@ import { } from "../../ui/sidebar"; import { hasPageAccess } from "@/utils/userAccess"; import { User } from "@/types/users"; +import { useSubModuleStore } from "@/lib/store/useSubModuleStore"; // this will need to be moved to a links section the db to make it more easy to remove and add -const items = [ - { - title: "Silo Adjustments", - url: "#", - icon: Cylinder, - role: ["admin", "systemAdmin"], - module: "logistics", - active: true, - }, - { - name: "Bulk orders", - moduleName: "logistics", - description: "", - link: "#", - icon: Truck, - role: ["systemAdmin"], - active: true, - subSubModule: [], - }, - { - name: "Forecast", - moduleName: "logistics", - description: "", - link: "#", - icon: Truck, - role: ["systemAdmin"], - active: true, - subSubModule: [], - }, - { - name: "Ocme cycle counts", - moduleName: "logistics", - description: "", - link: "#", - icon: Package, - role: ["technician", "supervisor", "manager", "admin", "systemAdmin"], - active: false, - subSubModule: [], - }, - { - name: "Material Helper", - moduleName: "logistics", - description: "", - link: "/materialHelper/consumption", - icon: Package, - role: ["technician", "supervisor", "manager", "admin", "systemAdmin"], - active: true, - subSubModule: [], - }, - { - name: "Ocme Cyclecount", - moduleName: "logistics", - description: "", - link: "/cyclecount", - icon: Package, - role: ["technician", "supervisor", "manager", "admin", "systemAdmin"], - active: true, - subSubModule: [], - }, -]; +// const items = [ +// { +// title: "Silo Adjustments", +// url: "#", +// icon: Cylinder, +// role: ["admin", "systemAdmin"], +// module: "logistics", +// active: true, +// }, +// { +// name: "Bulk orders", +// moduleName: "logistics", +// description: "", +// link: "#", +// icon: Truck, +// role: ["systemAdmin"], +// active: true, +// subSubModule: [], +// }, +// { +// name: "Forecast", +// moduleName: "logistics", +// description: "", +// link: "#", +// icon: Truck, +// role: ["systemAdmin"], +// active: true, +// subSubModule: [], +// }, +// { +// name: "Ocme cycle counts", +// moduleName: "logistics", +// description: "", +// link: "#", +// icon: Package, +// role: ["technician", "supervisor", "manager", "admin", "systemAdmin"], +// active: false, +// subSubModule: [], +// }, +// { +// name: "Material Helper", +// moduleName: "logistics", +// description: "", +// link: "/materialHelper/consumption", +// icon: Package, +// role: ["technician", "supervisor", "manager", "admin", "systemAdmin"], +// active: true, +// subSubModule: [], +// }, +// { +// name: "Ocme Cyclecount", +// moduleName: "logistics", +// description: "", +// link: "/cyclecount", +// icon: Package, +// role: ["technician", "supervisor", "manager", "admin", "systemAdmin"], +// active: true, +// subSubModule: [], +// }, +// ]; export function LogisticsSideBar({ user, @@ -78,26 +79,35 @@ export function LogisticsSideBar({ user: User | null; moduleID: string; }) { + const { subModules } = useSubModuleStore(); + + const items = subModules.filter((m) => m.moduleName === "logistics"); + console.log(items); return ( Logistics - {items.map((item) => ( - - <> - {hasPageAccess(user, item.role, moduleID) && - item.active && ( - - - - {item.title} - - - )} - - - ))} + {items.map((item) => { + return ( + + <> + {hasPageAccess( + user, + item.roles, + moduleID + ) && + item.active && ( + + + {item.name} + + + )} + + + ); + })} diff --git a/frontend/src/components/providers/Providers.tsx b/frontend/src/components/providers/Providers.tsx index 675f076..4b2a666 100644 --- a/frontend/src/components/providers/Providers.tsx +++ b/frontend/src/components/providers/Providers.tsx @@ -3,6 +3,7 @@ import { useModuleStore } from "../../lib/store/useModuleStore"; import { useEffect } from "react"; import { useSettingStore } from "@/lib/store/useSettings"; import { useGetUserRoles } from "@/lib/store/useGetRoles"; +import { useSubModuleStore } from "@/lib/store/useSubModuleStore"; const queryClient = new QueryClient(); @@ -14,11 +15,13 @@ export const SessionProvider = ({ const { fetchModules } = useModuleStore(); const { fetchSettings } = useSettingStore(); const { fetchUserRoles } = useGetUserRoles(); + const { fetchSubModules } = useSubModuleStore(); useEffect(() => { fetchModules(); fetchSettings(); fetchUserRoles(); + fetchSubModules(); }, []); return ( diff --git a/frontend/src/lib/store/useSubModuleStore.ts b/frontend/src/lib/store/useSubModuleStore.ts new file mode 100644 index 0000000..85c9615 --- /dev/null +++ b/frontend/src/lib/store/useSubModuleStore.ts @@ -0,0 +1,30 @@ +import { SubModules } from "@/types/modules"; +import axios from "axios"; +import { create } from "zustand"; + +interface SettingState { + subModules: SubModules[]; + + fetchSubModules: () => Promise; + setSubModules: (modules: SubModules[]) => void; +} +interface FetchModulesResponse { + data: SubModules[]; +} + +export const useSubModuleStore = create()((set) => ({ + subModules: [], + setSubModules: (subModules) => set({ subModules }), + fetchSubModules: async () => { + try { + //const response = await axios.get<{data: Setting[]}>(`${process.env.NEXT_PUBLIC_URL}/api/settings/client`); + const response = await axios.get(`/api/server/submodules`, {}); + const data: FetchModulesResponse = response.data; //await response.json(); + //console.log(data); + set({ subModules: data.data }); + } catch (error) { + console.error("Failed to fetch settings:", error); + set({ subModules: [] }); + } + }, +})); diff --git a/frontend/src/routeTree.gen.ts b/frontend/src/routeTree.gen.ts index d2a4d72..ce4f3fa 100644 --- a/frontend/src/routeTree.gen.ts +++ b/frontend/src/routeTree.gen.ts @@ -25,10 +25,12 @@ import { Route as AdminSettingsImport } from './routes/_admin/settings' import { Route as AdminServersImport } from './routes/_admin/servers' import { Route as AdminModulesImport } from './routes/_admin/modules' import { Route as ocmeCyclecountIndexImport } from './routes/(ocme)/cyclecount/index' +import { Route as logisticsSiloAdjustmentsIndexImport } from './routes/(logistics)/siloAdjustments/index' import { Route as logisticsMaterialHelperIndexImport } from './routes/(logistics)/materialHelper/index' import { Route as EomArticleAvImport } from './routes/_eom/article/$av' import { Route as logisticsMaterialHelperSiloLinkIndexImport } from './routes/(logistics)/materialHelper/siloLink/index' import { Route as logisticsMaterialHelperConsumptionIndexImport } from './routes/(logistics)/materialHelper/consumption/index' +import { Route as logisticsSiloAdjustmentsCommentCommentImport } from './routes/(logistics)/siloAdjustments/comment/$comment' // Create/Update Routes @@ -113,6 +115,13 @@ const ocmeCyclecountIndexRoute = ocmeCyclecountIndexImport.update({ getParentRoute: () => rootRoute, } as any) +const logisticsSiloAdjustmentsIndexRoute = + logisticsSiloAdjustmentsIndexImport.update({ + id: '/(logistics)/siloAdjustments/', + path: '/siloAdjustments/', + getParentRoute: () => rootRoute, + } as any) + const logisticsMaterialHelperIndexRoute = logisticsMaterialHelperIndexImport.update({ id: '/(logistics)/materialHelper/', @@ -140,6 +149,13 @@ const logisticsMaterialHelperConsumptionIndexRoute = getParentRoute: () => rootRoute, } as any) +const logisticsSiloAdjustmentsCommentCommentRoute = + logisticsSiloAdjustmentsCommentCommentImport.update({ + id: '/(logistics)/siloAdjustments/comment/$comment', + path: '/siloAdjustments/comment/$comment', + getParentRoute: () => rootRoute, + } as any) + // Populate the FileRoutesByPath interface declare module '@tanstack/react-router' { @@ -249,6 +265,13 @@ declare module '@tanstack/react-router' { preLoaderRoute: typeof logisticsMaterialHelperIndexImport parentRoute: typeof rootRoute } + '/(logistics)/siloAdjustments/': { + id: '/(logistics)/siloAdjustments/' + path: '/siloAdjustments' + fullPath: '/siloAdjustments' + preLoaderRoute: typeof logisticsSiloAdjustmentsIndexImport + parentRoute: typeof rootRoute + } '/(ocme)/cyclecount/': { id: '/(ocme)/cyclecount/' path: '/cyclecount' @@ -256,6 +279,13 @@ declare module '@tanstack/react-router' { preLoaderRoute: typeof ocmeCyclecountIndexImport parentRoute: typeof rootRoute } + '/(logistics)/siloAdjustments/comment/$comment': { + id: '/(logistics)/siloAdjustments/comment/$comment' + path: '/siloAdjustments/comment/$comment' + fullPath: '/siloAdjustments/comment/$comment' + preLoaderRoute: typeof logisticsSiloAdjustmentsCommentCommentImport + parentRoute: typeof rootRoute + } '/(logistics)/materialHelper/consumption/': { id: '/(logistics)/materialHelper/consumption/' path: '/materialHelper/consumption' @@ -327,7 +357,9 @@ export interface FileRoutesByFullPath { '/ocp': typeof OcpIndexRoute '/article/$av': typeof EomArticleAvRoute '/materialHelper': typeof logisticsMaterialHelperIndexRoute + '/siloAdjustments': typeof logisticsSiloAdjustmentsIndexRoute '/cyclecount': typeof ocmeCyclecountIndexRoute + '/siloAdjustments/comment/$comment': typeof logisticsSiloAdjustmentsCommentCommentRoute '/materialHelper/consumption': typeof logisticsMaterialHelperConsumptionIndexRoute '/materialHelper/siloLink': typeof logisticsMaterialHelperSiloLinkIndexRoute } @@ -346,7 +378,9 @@ export interface FileRoutesByTo { '/ocp': typeof OcpIndexRoute '/article/$av': typeof EomArticleAvRoute '/materialHelper': typeof logisticsMaterialHelperIndexRoute + '/siloAdjustments': typeof logisticsSiloAdjustmentsIndexRoute '/cyclecount': typeof ocmeCyclecountIndexRoute + '/siloAdjustments/comment/$comment': typeof logisticsSiloAdjustmentsCommentCommentRoute '/materialHelper/consumption': typeof logisticsMaterialHelperConsumptionIndexRoute '/materialHelper/siloLink': typeof logisticsMaterialHelperSiloLinkIndexRoute } @@ -368,7 +402,9 @@ export interface FileRoutesById { '/ocp/': typeof OcpIndexRoute '/_eom/article/$av': typeof EomArticleAvRoute '/(logistics)/materialHelper/': typeof logisticsMaterialHelperIndexRoute + '/(logistics)/siloAdjustments/': typeof logisticsSiloAdjustmentsIndexRoute '/(ocme)/cyclecount/': typeof ocmeCyclecountIndexRoute + '/(logistics)/siloAdjustments/comment/$comment': typeof logisticsSiloAdjustmentsCommentCommentRoute '/(logistics)/materialHelper/consumption/': typeof logisticsMaterialHelperConsumptionIndexRoute '/(logistics)/materialHelper/siloLink/': typeof logisticsMaterialHelperSiloLinkIndexRoute } @@ -389,7 +425,9 @@ export interface FileRouteTypes { | '/ocp' | '/article/$av' | '/materialHelper' + | '/siloAdjustments' | '/cyclecount' + | '/siloAdjustments/comment/$comment' | '/materialHelper/consumption' | '/materialHelper/siloLink' fileRoutesByTo: FileRoutesByTo @@ -407,7 +445,9 @@ export interface FileRouteTypes { | '/ocp' | '/article/$av' | '/materialHelper' + | '/siloAdjustments' | '/cyclecount' + | '/siloAdjustments/comment/$comment' | '/materialHelper/consumption' | '/materialHelper/siloLink' id: @@ -427,7 +467,9 @@ export interface FileRouteTypes { | '/ocp/' | '/_eom/article/$av' | '/(logistics)/materialHelper/' + | '/(logistics)/siloAdjustments/' | '/(ocme)/cyclecount/' + | '/(logistics)/siloAdjustments/comment/$comment' | '/(logistics)/materialHelper/consumption/' | '/(logistics)/materialHelper/siloLink/' fileRoutesById: FileRoutesById @@ -442,7 +484,9 @@ export interface RootRouteChildren { LoginRoute: typeof LoginRoute OcpIndexRoute: typeof OcpIndexRoute logisticsMaterialHelperIndexRoute: typeof logisticsMaterialHelperIndexRoute + logisticsSiloAdjustmentsIndexRoute: typeof logisticsSiloAdjustmentsIndexRoute ocmeCyclecountIndexRoute: typeof ocmeCyclecountIndexRoute + logisticsSiloAdjustmentsCommentCommentRoute: typeof logisticsSiloAdjustmentsCommentCommentRoute logisticsMaterialHelperConsumptionIndexRoute: typeof logisticsMaterialHelperConsumptionIndexRoute logisticsMaterialHelperSiloLinkIndexRoute: typeof logisticsMaterialHelperSiloLinkIndexRoute } @@ -456,7 +500,10 @@ const rootRouteChildren: RootRouteChildren = { LoginRoute: LoginRoute, OcpIndexRoute: OcpIndexRoute, logisticsMaterialHelperIndexRoute: logisticsMaterialHelperIndexRoute, + logisticsSiloAdjustmentsIndexRoute: logisticsSiloAdjustmentsIndexRoute, ocmeCyclecountIndexRoute: ocmeCyclecountIndexRoute, + logisticsSiloAdjustmentsCommentCommentRoute: + logisticsSiloAdjustmentsCommentCommentRoute, logisticsMaterialHelperConsumptionIndexRoute: logisticsMaterialHelperConsumptionIndexRoute, logisticsMaterialHelperSiloLinkIndexRoute: @@ -481,7 +528,9 @@ export const routeTree = rootRoute "/login", "/ocp/", "/(logistics)/materialHelper/", + "/(logistics)/siloAdjustments/", "/(ocme)/cyclecount/", + "/(logistics)/siloAdjustments/comment/$comment", "/(logistics)/materialHelper/consumption/", "/(logistics)/materialHelper/siloLink/" ] @@ -551,9 +600,15 @@ export const routeTree = rootRoute "/(logistics)/materialHelper/": { "filePath": "(logistics)/materialHelper/index.tsx" }, + "/(logistics)/siloAdjustments/": { + "filePath": "(logistics)/siloAdjustments/index.tsx" + }, "/(ocme)/cyclecount/": { "filePath": "(ocme)/cyclecount/index.tsx" }, + "/(logistics)/siloAdjustments/comment/$comment": { + "filePath": "(logistics)/siloAdjustments/comment/$comment.tsx" + }, "/(logistics)/materialHelper/consumption/": { "filePath": "(logistics)/materialHelper/consumption/index.tsx" }, diff --git a/frontend/src/routes/(logistics)/siloAdjustments/index.tsx b/frontend/src/routes/(logistics)/siloAdjustments/index.tsx new file mode 100644 index 0000000..bed2f05 --- /dev/null +++ b/frontend/src/routes/(logistics)/siloAdjustments/index.tsx @@ -0,0 +1,9 @@ +import { createFileRoute } from '@tanstack/react-router' + +export const Route = createFileRoute('/(logistics)/siloAdjustments/')({ + component: RouteComponent, +}) + +function RouteComponent() { + return
Hello "/(logistics)/siloAdjustments/"!
+} diff --git a/frontend/src/routes/_admin.tsx b/frontend/src/routes/_admin.tsx index 9bb2468..61b6f18 100644 --- a/frontend/src/routes/_admin.tsx +++ b/frontend/src/routes/_admin.tsx @@ -1,4 +1,4 @@ -import {createFileRoute, redirect} from "@tanstack/react-router"; +import { createFileRoute, redirect } from "@tanstack/react-router"; // src/routes/_authenticated.tsx export const Route = createFileRoute("/_admin")({ @@ -7,6 +7,12 @@ export const Route = createFileRoute("/_admin")({ if (!auth) { throw redirect({ to: "/login", + search: { + // Use the current location to power a redirect after login + // (Do not use `router.state.resolvedLocation` as it can + // potentially lag behind the actual current location) + redirect: location.pathname + location.search, + }, }); } }, diff --git a/frontend/src/routes/_auth.tsx b/frontend/src/routes/_auth.tsx index e1edc58..730dfb8 100644 --- a/frontend/src/routes/_auth.tsx +++ b/frontend/src/routes/_auth.tsx @@ -1,4 +1,4 @@ -import {createFileRoute, redirect} from "@tanstack/react-router"; +import { createFileRoute, redirect } from "@tanstack/react-router"; // src/routes/_authenticated.tsx export const Route = createFileRoute("/_auth")({ @@ -7,6 +7,12 @@ export const Route = createFileRoute("/_auth")({ if (!auth) { throw redirect({ to: "/login", + search: { + // Use the current location to power a redirect after login + // (Do not use `router.state.resolvedLocation` as it can + // potentially lag behind the actual current location) + redirect: location.href, + }, }); } }, diff --git a/frontend/src/routes/login.tsx b/frontend/src/routes/login.tsx index 05133fe..11c50d5 100644 --- a/frontend/src/routes/login.tsx +++ b/frontend/src/routes/login.tsx @@ -1,6 +1,7 @@ -import {createFileRoute, redirect} from "@tanstack/react-router"; +import { createFileRoute, redirect } from "@tanstack/react-router"; import LoginForm from "@/components/auth/LoginForm"; +import { z } from "zod"; export const Route = createFileRoute("/login")({ component: RouteComponent, @@ -12,6 +13,9 @@ export const Route = createFileRoute("/login")({ }); } }, + validateSearch: z.object({ + redirect: z.string().optional(), + }), }); function RouteComponent() { diff --git a/frontend/src/types/modules.ts b/frontend/src/types/modules.ts index 95a2f11..c07b89e 100644 --- a/frontend/src/types/modules.ts +++ b/frontend/src/types/modules.ts @@ -8,3 +8,13 @@ export interface Modules { upd_user: string; upd_date: Date; } + +export interface SubModules { + submodule_id: string; + name: string; + link: string; + icon: string; + moduleName: string; + active: boolean; + roles: string[]; +} diff --git a/server/services/logistics/logisticsService.ts b/server/services/logistics/logisticsService.ts index 27a9f5a..b0695d3 100644 --- a/server/services/logistics/logisticsService.ts +++ b/server/services/logistics/logisticsService.ts @@ -2,9 +2,18 @@ import { OpenAPIHono } from "@hono/zod-openapi"; import comsumeMaterial from "./route/consumeMaterial.js"; import returnMat from "./route/returnMaterial.js"; +import createSiloAdjustment from "./route/siloAdjustments/createSiloAdjustment.js"; +import postComment from "./route/siloAdjustments/postComment.js"; const app = new OpenAPIHono(); -const routes = [comsumeMaterial, returnMat] as const; +const routes = [ + comsumeMaterial, + returnMat, + + // silo + createSiloAdjustment, + postComment, +] as const; // app.route("/server", modules); const appRoutes = routes.forEach((route) => { diff --git a/server/services/server/route/modules/getSubModules.ts b/server/services/server/route/modules/getSubModules.ts new file mode 100644 index 0000000..831e796 --- /dev/null +++ b/server/services/server/route/modules/getSubModules.ts @@ -0,0 +1,73 @@ +import { z, createRoute, OpenAPIHono } from "@hono/zod-openapi"; +import { modules } from "../../../../../database/schema/modules.js"; +import { db } from "../../../../../database/dbclient.js"; +import { subModules } from "../../../../../database/schema/subModules.js"; + +// Define the request body schema +const requestSchema = z.object({ + ip: z.string().optional(), + endpoint: z.string().optional(), + action: z.string().optional(), + stats: z.string().optional(), +}); + +// Define the response schema +const responseSchema = z.object({ + message: z.string().optional(), + module_id: z + .string() + .openapi({ example: "6c922c6c-7de3-4ec4-acb0-f068abdc" }) + .optional(), + name: z.string().openapi({ example: "Production" }).optional(), + active: z.boolean().openapi({ example: true }).optional(), + roles: z + .string() + .openapi({ example: `["viewer","technician"]` }) + .optional(), +}); + +const app = new OpenAPIHono(); + +app.openapi( + createRoute({ + tags: ["server"], + summary: "Returns all submodules in the server", + method: "get", + path: "/submodules", + responses: { + 200: { + content: { + "application/json": { schema: responseSchema }, + }, + description: "Response message", + }, + }, + }), + async (c) => { + //console.log("system modules"); + let module: any = []; + try { + module = await db.select().from(subModules); // .where(eq(modules.active, true)); + } catch (error) { + console.log(error); + module = []; + } + + // parse the roles + const updateModules = module.map((m: any) => { + if (m.roles) { + return { ...m, roles: m?.roles }; + } + return m; + }); //JSON.parse(module[0]?.roles); + + // Return response with the received data + + return c.json({ + message: `All active submodules`, + data: module, + }); + } +); + +export default app; diff --git a/server/services/server/systemServer.ts b/server/services/server/systemServer.ts index 1d3cd4f..644bc4e 100644 --- a/server/services/server/systemServer.ts +++ b/server/services/server/systemServer.ts @@ -15,6 +15,7 @@ import updateServer from "./route/updates/updateServer.js"; import { setPerms } from "./utils/testServerPerms.js"; import serviceControl from "./route/servers/serverContorl.js"; import { areSubModulesIn } from "./utils/subModuleCheck.js"; +import getSubmodules from "./route/modules/getSubModules.js"; // making sure all modules are in properly setTimeout(async () => { @@ -31,6 +32,7 @@ const routes = [ getModules, updateModule, addModule, + getSubmodules, // settings addSetting, getSettings, diff --git a/server/services/server/utils/subModuleCheck.ts b/server/services/server/utils/subModuleCheck.ts index 4c85466..0f3781b 100644 --- a/server/services/server/utils/subModuleCheck.ts +++ b/server/services/server/utils/subModuleCheck.ts @@ -12,7 +12,7 @@ const newSubModules = [ name: "Silo Adjustmnet", moduleName: "logistics", description: "Do a silo adjustmnet", - link: "/sa", + link: "/siloAdjustments", icon: "Cylinder", active: false, roles: ["tester", "systemAdmin"], @@ -156,6 +156,7 @@ export const areSubModulesIn = async () => { roles: newSubModules[i].roles, link: newSubModules[i].link, subSubModule: newSubModules[i].subSubModule, + icon: newSubModules[i].icon, }, }) // this will only update the ones that are new :D .returning({ name: subModules.name }); @@ -167,6 +168,7 @@ export const areSubModulesIn = async () => { "SubModules were just added due to missing them on server startup" ); } catch (error) { + console.log(error); createLog( "error", "lst",