feat(submodules and login redirect): submodules added and login redirect

This commit is contained in:
2025-04-04 22:10:11 -05:00
parent f1abe7b33d
commit 85577b291f
15 changed files with 450 additions and 223 deletions

View File

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

View File

@@ -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<z.infer<typeof FormSchema>>({
resolver: zodResolver(FormSchema),
defaultValues: {
username: username || "",
password: "",
rememberMe: rememeberMe,
},
});
const onSubmitLogin = async (value: z.infer<typeof FormSchema>) => {
// 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<z.infer<typeof FormSchema>>({
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<typeof FormSchema>) => {
// 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 (
<div className="ml-[25%]">
<LstCard className="p-3 w-96">
<CardHeader>
<div>
<p className="text-2xl">Login to LST</p>
</div>
</CardHeader>
<hr className="rounded"></hr>
<form onSubmit={handleSubmit(onSubmitLogin)}>
<div>
<Label htmlFor="username" className="m-1">
Username
</Label>
<Input
placeholder="smith001"
{...register("username")}
className={errors.username ? "border-red-500" : ""}
aria-invalid={!!errors.username}
/>
{errors.username && (
<p className="text-red-500 text-sm mt-1">
{errors.username.message}
</p>
)}
</div>
<div>
<>
<Label htmlFor={"password"} className="m-1">
Password
</Label>
<Input
type="password"
{...register("password")}
className={errors.password ? "border-red-500" : ""}
aria-invalid={!!errors.password}
/>
{errors.password && (
<p className="text-red-500 text-sm mt-1">
{errors.password.message}
</p>
)}
</>
</div>
<div className="flex justify-between pt-2">
<div className="flex">
<Controller
render={({ field }) => (
<>
<Checkbox
id="remember"
checked={field.value}
onCheckedChange={field.onChange}
/>
<label
htmlFor="remember"
className="pl-2 text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
>
remember me
</label>
</>
)}
control={control}
name="rememberMe"
defaultValue={rememeberMe}
/>
</div>
setSession(prodUser, data.token);
toast.success(`You are logged in as ${data.user.username}`);
<div className="flex justify-end">
<Button type="submit">Submit</Button>
</div>
</div>
</form>
</LstCard>
</div>
);
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 (
<div className="ml-[25%]">
<LstCard className="p-3 w-96">
<CardHeader>
<div>
<p className="text-2xl">Login to LST</p>
</div>
</CardHeader>
<hr className="rounded"></hr>
<form onSubmit={handleSubmit(onSubmitLogin)}>
<div>
<Label htmlFor="username" className="m-1">
Username
</Label>
<Input
placeholder="smith001"
{...register("username")}
className={errors.username ? "border-red-500" : ""}
aria-invalid={!!errors.username}
/>
{errors.username && (
<p className="text-red-500 text-sm mt-1">
{errors.username.message}
</p>
)}
</div>
<div>
<>
<Label htmlFor={"password"} className="m-1">
Password
</Label>
<Input
type="password"
{...register("password")}
className={
errors.password ? "border-red-500" : ""
}
aria-invalid={!!errors.password}
/>
{errors.password && (
<p className="text-red-500 text-sm mt-1">
{errors.password.message}
</p>
)}
</>
</div>
<div className="flex justify-between pt-2">
<div className="flex">
<Controller
render={({ field }) => (
<>
<Checkbox
id="remember"
checked={field.value}
onCheckedChange={field.onChange}
/>
<label
htmlFor="remember"
className="pl-2 text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
>
remember me
</label>
</>
)}
control={control}
name="rememberMe"
defaultValue={rememeberMe}
/>
</div>
<div className="flex justify-end">
<Button type="submit">Submit</Button>
</div>
</div>
</form>
</LstCard>
</div>
);
};
export default LoginForm;

View File

@@ -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 (
<SidebarGroup>
<SidebarGroupLabel>Logistics</SidebarGroupLabel>
<SidebarGroupContent>
<SidebarMenu>
{items.map((item) => (
<SidebarMenuItem key={item.title}>
<>
{hasPageAccess(user, item.role, moduleID) &&
item.active && (
<SidebarMenuButton asChild>
<a href={item.url}>
<item.icon />
<span>{item.title}</span>
</a>
</SidebarMenuButton>
)}
</>
</SidebarMenuItem>
))}
{items.map((item) => {
return (
<SidebarMenuItem key={item.submodule_id}>
<>
{hasPageAccess(
user,
item.roles,
moduleID
) &&
item.active && (
<SidebarMenuButton asChild>
<a href={item.link}>
<span>{item.name}</span>
</a>
</SidebarMenuButton>
)}
</>
</SidebarMenuItem>
);
})}
</SidebarMenu>
</SidebarGroupContent>
</SidebarGroup>

View File

@@ -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 (
<QueryClientProvider client={queryClient}>

View File

@@ -0,0 +1,30 @@
import { SubModules } from "@/types/modules";
import axios from "axios";
import { create } from "zustand";
interface SettingState {
subModules: SubModules[];
fetchSubModules: () => Promise<void>;
setSubModules: (modules: SubModules[]) => void;
}
interface FetchModulesResponse {
data: SubModules[];
}
export const useSubModuleStore = create<SettingState>()((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: [] });
}
},
}));

View File

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

View File

@@ -0,0 +1,9 @@
import { createFileRoute } from '@tanstack/react-router'
export const Route = createFileRoute('/(logistics)/siloAdjustments/')({
component: RouteComponent,
})
function RouteComponent() {
return <div>Hello "/(logistics)/siloAdjustments/"!</div>
}

View File

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

View File

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

View File

@@ -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() {

View File

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

View File

@@ -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) => {

View File

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

View File

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

View File

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