test(frontend): work on the frontend to have better admin
This commit is contained in:
@@ -0,0 +1,8 @@
|
|||||||
|
export default function DataMartStats() {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
The stats for all the data mart querys out there and whos and when
|
||||||
|
they are last used to understand if we want to keep them or not
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
export default function NotificationMGT() {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
Manage all notifications from here instad of going to the db,
|
||||||
|
locking some items that are auto updated on server restarts
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -19,6 +19,11 @@ import { adminUrlCheck } from "@/utils/adminUrlCheck";
|
|||||||
import RestartServer from "./RestartServer";
|
import RestartServer from "./RestartServer";
|
||||||
import StopServer from "./StopServer";
|
import StopServer from "./StopServer";
|
||||||
import StartServer from "./StartServer";
|
import StartServer from "./StartServer";
|
||||||
|
import { Button } from "@/components/ui/button";
|
||||||
|
import { getSettings } from "@/utils/querys/settings";
|
||||||
|
import { toast } from "sonner";
|
||||||
|
import axios from "axios";
|
||||||
|
//import { useState } from "react";
|
||||||
|
|
||||||
export type Servers = {
|
export type Servers = {
|
||||||
server_id?: string;
|
server_id?: string;
|
||||||
@@ -33,6 +38,7 @@ export type Servers = {
|
|||||||
export default function ServerPage() {
|
export default function ServerPage() {
|
||||||
const { user, token } = useSessionStore();
|
const { user, token } = useSessionStore();
|
||||||
const { modules } = useModuleStore();
|
const { modules } = useModuleStore();
|
||||||
|
//const [upgrading, setUpgrading] = useState(false);
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
||||||
const { data, isError, error, isLoading } = useQuery(
|
const { data, isError, error, isLoading } = useQuery(
|
||||||
@@ -51,10 +57,45 @@ export default function ServerPage() {
|
|||||||
if (isError) {
|
if (isError) {
|
||||||
return <div>{JSON.stringify(error)}</div>;
|
return <div>{JSON.stringify(error)}</div>;
|
||||||
}
|
}
|
||||||
|
const { data: set } = useQuery(getSettings(token ?? ""));
|
||||||
|
const upgrade = async () => {
|
||||||
|
let devDir = set.filter((n: any) => n.name === "devDir");
|
||||||
|
toast.success("All Servers was just triggered.");
|
||||||
|
|
||||||
|
try {
|
||||||
|
const result = await axios.post(
|
||||||
|
`/api/server/update/localhost`,
|
||||||
|
{ devDir: devDir[0].value, all: true },
|
||||||
|
{
|
||||||
|
headers: { Authorization: `Bearer ${token}` },
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
if (result.data.success) {
|
||||||
|
toast.success(result.data.message);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!result.data.success) {
|
||||||
|
toast.success(result.data.message);
|
||||||
|
}
|
||||||
|
} catch (error: any) {
|
||||||
|
toast.error(
|
||||||
|
`There was an error updating the server: ${error.data.message}`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
//console.log(data);
|
//console.log(data);
|
||||||
return (
|
return (
|
||||||
<LstCard className="m-2 flex place-content-center w-dvh">
|
<LstCard className="m-2 flex place-content-center w-dvh">
|
||||||
|
<div className="flex justify-end m-2">
|
||||||
|
<Button
|
||||||
|
onClick={upgrade}
|
||||||
|
disabled={data?.some((d: any) => d.isUpgrading)}
|
||||||
|
>
|
||||||
|
Update All Servers
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
<Table>
|
<Table>
|
||||||
<TableHeader>
|
<TableHeader>
|
||||||
<TableRow>
|
<TableRow>
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import { LstCard } from "@/components/extendedUI/LstCard";
|
||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
import { Input } from "@/components/ui/input";
|
import { Input } from "@/components/ui/input";
|
||||||
import { Label } from "@/components/ui/label";
|
import { Label } from "@/components/ui/label";
|
||||||
@@ -10,6 +11,7 @@ import {
|
|||||||
SelectTrigger,
|
SelectTrigger,
|
||||||
SelectValue,
|
SelectValue,
|
||||||
} from "@/components/ui/select";
|
} from "@/components/ui/select";
|
||||||
|
|
||||||
import { DebugButton } from "@/utils/formStuff/debugButton";
|
import { DebugButton } from "@/utils/formStuff/debugButton";
|
||||||
import { userFormOptions } from "@/utils/formStuff/options/userformOptions";
|
import { userFormOptions } from "@/utils/formStuff/options/userformOptions";
|
||||||
import { generatePassword } from "@/utils/passwordGen";
|
import { generatePassword } from "@/utils/passwordGen";
|
||||||
@@ -18,10 +20,16 @@ import { useForm } from "@tanstack/react-form";
|
|||||||
import { useQuery } from "@tanstack/react-query";
|
import { useQuery } from "@tanstack/react-query";
|
||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
import { toast } from "sonner";
|
import { toast } from "sonner";
|
||||||
|
import UserRoles from "./UserRoles";
|
||||||
|
import { CardHeader } from "@/components/ui/card";
|
||||||
|
|
||||||
export default function UserCard(data: any) {
|
export default function UserCard(data: any) {
|
||||||
const token = localStorage.getItem("auth_token");
|
const token = localStorage.getItem("auth_token");
|
||||||
const { refetch } = useQuery(getUsers());
|
const { refetch } = useQuery(getUsers());
|
||||||
|
|
||||||
|
//console.log(modules);
|
||||||
|
//console.log(data.user);
|
||||||
|
//console.log(userRoles);
|
||||||
const form = useForm({
|
const form = useForm({
|
||||||
...userFormOptions(data.user),
|
...userFormOptions(data.user),
|
||||||
onSubmit: async ({ value }) => {
|
onSubmit: async ({ value }) => {
|
||||||
@@ -53,185 +61,224 @@ export default function UserCard(data: any) {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
return (
|
return (
|
||||||
<div>
|
<div className="flex flex-row">
|
||||||
<form
|
<div className="m-2">
|
||||||
onSubmit={(e) => {
|
<LstCard>
|
||||||
e.preventDefault();
|
<CardHeader>User Profile</CardHeader>
|
||||||
e.stopPropagation();
|
<form
|
||||||
}}
|
onSubmit={(e) => {
|
||||||
>
|
e.preventDefault();
|
||||||
<form.Field
|
e.stopPropagation();
|
||||||
name="username"
|
}}
|
||||||
validators={{
|
>
|
||||||
// We can choose between form-wide and field-specific validators
|
<form.Field
|
||||||
onChange: ({ value }) =>
|
name="username"
|
||||||
value.length > 3
|
validators={{
|
||||||
? undefined
|
// We can choose between form-wide and field-specific validators
|
||||||
: "Username must be longer than 3 letters",
|
onChange: ({ value }) =>
|
||||||
}}
|
value.length > 3
|
||||||
children={(field) => {
|
? undefined
|
||||||
return (
|
: "Username must be longer than 3 letters",
|
||||||
<div className="m-2 min-w-48 max-w-96 p-2">
|
}}
|
||||||
<Label htmlFor="username">Username</Label>
|
children={(field) => {
|
||||||
<Input
|
return (
|
||||||
name={field.name}
|
<div className="m-2 min-w-48 max-w-96 p-2">
|
||||||
value={field.state.value}
|
<Label htmlFor="username">
|
||||||
onBlur={field.handleBlur}
|
Username
|
||||||
//type="number"
|
</Label>
|
||||||
onChange={(e) =>
|
<Input
|
||||||
field.handleChange(e.target.value)
|
name={field.name}
|
||||||
}
|
value={field.state.value}
|
||||||
/>
|
onBlur={field.handleBlur}
|
||||||
{field.state.meta.errors.length ? (
|
//type="number"
|
||||||
<em>{field.state.meta.errors.join(",")}</em>
|
onChange={(e) =>
|
||||||
) : null}
|
field.handleChange(
|
||||||
</div>
|
e.target.value
|
||||||
);
|
)
|
||||||
}}
|
}
|
||||||
/>
|
|
||||||
<form.Field
|
|
||||||
name="email"
|
|
||||||
validators={{
|
|
||||||
// We can choose between form-wide and field-specific validators
|
|
||||||
onChange: ({ value }) =>
|
|
||||||
value.length > 3
|
|
||||||
? undefined
|
|
||||||
: "You must enter a correct ",
|
|
||||||
}}
|
|
||||||
children={(field) => {
|
|
||||||
return (
|
|
||||||
<div className="m-2 min-w-48 max-w-96 p-2">
|
|
||||||
<Label htmlFor="email">Email</Label>
|
|
||||||
<Input
|
|
||||||
name={field.name}
|
|
||||||
value={field.state.value}
|
|
||||||
onBlur={field.handleBlur}
|
|
||||||
//type="number"
|
|
||||||
onChange={(e) =>
|
|
||||||
field.handleChange(e.target.value)
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
{field.state.meta.errors.length ? (
|
|
||||||
<em>{field.state.meta.errors.join(",")}</em>
|
|
||||||
) : null}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
<form.Field
|
|
||||||
name="role"
|
|
||||||
//listeners={{onChange: ({value})=>{}}}
|
|
||||||
children={(field) => {
|
|
||||||
return (
|
|
||||||
<div className="m-2 min-w-48 max-w-96 p-2">
|
|
||||||
<Label htmlFor={field.name}>Select role</Label>
|
|
||||||
<Select
|
|
||||||
value={field.state.value}
|
|
||||||
onValueChange={field.handleChange}
|
|
||||||
>
|
|
||||||
<SelectTrigger className="w-[180px]">
|
|
||||||
<SelectValue
|
|
||||||
id={field.name}
|
|
||||||
placeholder="Select Role"
|
|
||||||
/>
|
/>
|
||||||
</SelectTrigger>
|
{field.state.meta.errors.length ? (
|
||||||
<SelectContent>
|
<em>
|
||||||
<SelectGroup>
|
{field.state.meta.errors.join(
|
||||||
<SelectLabel>Roles</SelectLabel>
|
","
|
||||||
<SelectItem value="viewer">
|
)}
|
||||||
Viewer
|
</em>
|
||||||
</SelectItem>
|
) : null}
|
||||||
<SelectItem value="operator">
|
</div>
|
||||||
Operator
|
);
|
||||||
</SelectItem>
|
}}
|
||||||
<SelectItem value="manager">
|
/>
|
||||||
Manager
|
<form.Field
|
||||||
</SelectItem>
|
name="email"
|
||||||
<SelectItem value="admin">
|
validators={{
|
||||||
Admin
|
// We can choose between form-wide and field-specific validators
|
||||||
</SelectItem>
|
onChange: ({ value }) =>
|
||||||
</SelectGroup>
|
value.length > 3
|
||||||
</SelectContent>
|
? undefined
|
||||||
</Select>
|
: "You must enter a correct ",
|
||||||
</div>
|
}}
|
||||||
);
|
children={(field) => {
|
||||||
}}
|
return (
|
||||||
/>
|
<div className="m-2 min-w-48 max-w-96 p-2">
|
||||||
<form.Field
|
<Label htmlFor="email">Email</Label>
|
||||||
name="password"
|
<Input
|
||||||
validators={{
|
name={field.name}
|
||||||
onChangeAsyncDebounceMs: 500,
|
value={field.state.value}
|
||||||
onChangeAsync: ({ value }) => {
|
onBlur={field.handleBlur}
|
||||||
if (
|
//type="number"
|
||||||
window.location.pathname.includes("/users") &&
|
onChange={(e) =>
|
||||||
value.length === 0
|
field.handleChange(
|
||||||
) {
|
e.target.value
|
||||||
return;
|
)
|
||||||
}
|
}
|
||||||
if (value.length < 4) {
|
/>
|
||||||
return "Password must be at least 4 characters long.";
|
{field.state.meta.errors.length ? (
|
||||||
}
|
<em>
|
||||||
|
{field.state.meta.errors.join(
|
||||||
|
","
|
||||||
|
)}
|
||||||
|
</em>
|
||||||
|
) : null}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<form.Field
|
||||||
|
name="role"
|
||||||
|
//listeners={{onChange: ({value})=>{}}}
|
||||||
|
children={(field) => {
|
||||||
|
return (
|
||||||
|
<div className="m-2 min-w-48 max-w-96 p-2">
|
||||||
|
<Label htmlFor={field.name}>
|
||||||
|
Select role
|
||||||
|
</Label>
|
||||||
|
<Select
|
||||||
|
value={field.state.value}
|
||||||
|
onValueChange={field.handleChange}
|
||||||
|
>
|
||||||
|
<SelectTrigger className="w-[180px]">
|
||||||
|
<SelectValue
|
||||||
|
id={field.name}
|
||||||
|
placeholder="Select Role"
|
||||||
|
/>
|
||||||
|
</SelectTrigger>
|
||||||
|
<SelectContent>
|
||||||
|
<SelectGroup>
|
||||||
|
<SelectLabel>
|
||||||
|
Roles
|
||||||
|
</SelectLabel>
|
||||||
|
<SelectItem value="viewer">
|
||||||
|
Viewer
|
||||||
|
</SelectItem>
|
||||||
|
<SelectItem value="operator">
|
||||||
|
Operator
|
||||||
|
</SelectItem>
|
||||||
|
<SelectItem value="manager">
|
||||||
|
Manager
|
||||||
|
</SelectItem>
|
||||||
|
<SelectItem value="admin">
|
||||||
|
Admin
|
||||||
|
</SelectItem>
|
||||||
|
</SelectGroup>
|
||||||
|
</SelectContent>
|
||||||
|
</Select>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<form.Field
|
||||||
|
name="password"
|
||||||
|
validators={{
|
||||||
|
onChangeAsyncDebounceMs: 500,
|
||||||
|
onChangeAsync: ({ value }) => {
|
||||||
|
if (
|
||||||
|
window.location.pathname.includes(
|
||||||
|
"/users"
|
||||||
|
) &&
|
||||||
|
value.length === 0
|
||||||
|
) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (value.length < 4) {
|
||||||
|
return "Password must be at least 4 characters long.";
|
||||||
|
}
|
||||||
|
|
||||||
if (!/[A-Z]/.test(value)) {
|
if (!/[A-Z]/.test(value)) {
|
||||||
return "Password must contain at least one uppercase letter.";
|
return "Password must contain at least one uppercase letter.";
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!/[a-z]/.test(value)) {
|
if (!/[a-z]/.test(value)) {
|
||||||
return "Password must contain at least one lower case letter.";
|
return "Password must contain at least one lower case letter.";
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!/[0-9]/.test(value)) {
|
if (!/[0-9]/.test(value)) {
|
||||||
return "Password must contain at least one number.";
|
return "Password must contain at least one number.";
|
||||||
}
|
}
|
||||||
|
|
||||||
if (
|
if (
|
||||||
!/[!@#$%^&*()_+\-=\[\]{};':"\\|,.<>\/?]/.test(
|
!/[!@#$%^&*()_+\-=\[\]{};':"\\|,.<>\/?]/.test(
|
||||||
value
|
value
|
||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
return "Password must contain at least one special character.";
|
return "Password must contain at least one special character.";
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
}}
|
}}
|
||||||
children={(field) => {
|
children={(field) => {
|
||||||
return (
|
return (
|
||||||
<div className="m-2 p-2">
|
<div className="m-2 p-2">
|
||||||
<Label htmlFor="password">
|
<Label htmlFor="password">
|
||||||
Change Password
|
Change Password
|
||||||
</Label>
|
</Label>
|
||||||
<div className="mt-2 flex flex-row">
|
<div className="mt-2 flex flex-row">
|
||||||
<Input
|
<Input
|
||||||
className="min-w-48 max-w-96"
|
className="min-w-48 max-w-96"
|
||||||
name={field.name}
|
name={field.name}
|
||||||
value={field.state.value}
|
value={field.state.value}
|
||||||
onBlur={field.handleBlur}
|
onBlur={field.handleBlur}
|
||||||
//type="number"
|
//type="number"
|
||||||
onChange={(e) =>
|
onChange={(e) =>
|
||||||
field.handleChange(e.target.value)
|
field.handleChange(
|
||||||
}
|
e.target.value
|
||||||
/>
|
)
|
||||||
<Button
|
}
|
||||||
className="ml-2"
|
/>
|
||||||
onClick={() =>
|
<Button
|
||||||
field.handleChange(
|
className="ml-2"
|
||||||
generatePassword(8)
|
onClick={() =>
|
||||||
)
|
field.handleChange(
|
||||||
}
|
generatePassword(8)
|
||||||
>
|
)
|
||||||
Random password
|
}
|
||||||
</Button>
|
>
|
||||||
<DebugButton data={form.state.values} />
|
Random password
|
||||||
</div>
|
</Button>
|
||||||
{field.state.meta.errors.length ? (
|
<DebugButton
|
||||||
<em>{field.state.meta.errors.join(",")}</em>
|
data={form.state.values}
|
||||||
) : null}
|
/>
|
||||||
</div>
|
</div>
|
||||||
);
|
{field.state.meta.errors.length ? (
|
||||||
}}
|
<em>
|
||||||
/>
|
{field.state.meta.errors.join(
|
||||||
</form>
|
","
|
||||||
<div>
|
)}
|
||||||
<Button onClick={form.handleSubmit}>Save</Button>
|
</em>
|
||||||
|
) : null}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</form>
|
||||||
|
</LstCard>
|
||||||
|
<div>
|
||||||
|
<Button onClick={form.handleSubmit}>Save</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="m-2">
|
||||||
|
<LstCard>
|
||||||
|
<CardHeader>User Module / Role Access</CardHeader>
|
||||||
|
<UserRoles user={data.user} />
|
||||||
|
</LstCard>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
16
frontend/src/components/admin/user/components/UserRoles.tsx
Normal file
16
frontend/src/components/admin/user/components/UserRoles.tsx
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
import { Label } from "@/components/ui/label";
|
||||||
|
import { useModuleStore } from "@/lib/store/useModuleStore";
|
||||||
|
//import { Checkbox } from "@radix-ui/react-checkbox";
|
||||||
|
|
||||||
|
export default function UserRoles(user: any) {
|
||||||
|
const { modules } = useModuleStore();
|
||||||
|
console.log(user);
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
{modules?.map((m: any) => {
|
||||||
|
console.log(m);
|
||||||
|
return <Label>{m.name}</Label>;
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
import {Cylinder, Package, Truck} from "lucide-react";
|
import { Cylinder, Package, Truck } from "lucide-react";
|
||||||
import {
|
import {
|
||||||
SidebarGroup,
|
SidebarGroup,
|
||||||
SidebarGroupContent,
|
SidebarGroupContent,
|
||||||
@@ -7,8 +7,8 @@ import {
|
|||||||
SidebarMenuButton,
|
SidebarMenuButton,
|
||||||
SidebarMenuItem,
|
SidebarMenuItem,
|
||||||
} from "../../ui/sidebar";
|
} from "../../ui/sidebar";
|
||||||
import {hasPageAccess} from "@/utils/userAccess";
|
import { hasPageAccess } from "@/utils/userAccess";
|
||||||
import {User} from "@/types/users";
|
import { User } from "@/types/users";
|
||||||
// this will need to be moved to a links section the db to make it more easy to remove and add
|
// this will need to be moved to a links section the db to make it more easy to remove and add
|
||||||
const items = [
|
const items = [
|
||||||
{
|
{
|
||||||
@@ -20,48 +20,64 @@ const items = [
|
|||||||
active: true,
|
active: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "Bulk orders",
|
name: "Bulk orders",
|
||||||
url: "#",
|
moduleName: "logistics",
|
||||||
|
description: "",
|
||||||
|
link: "#",
|
||||||
icon: Truck,
|
icon: Truck,
|
||||||
role: ["systemAdmin"],
|
role: ["systemAdmin"],
|
||||||
module: "logistics",
|
|
||||||
active: true,
|
active: true,
|
||||||
|
subSubModule: [],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "Forecast",
|
name: "Forecast",
|
||||||
url: "#",
|
moduleName: "logistics",
|
||||||
|
description: "",
|
||||||
|
link: "#",
|
||||||
icon: Truck,
|
icon: Truck,
|
||||||
role: ["systemAdmin"],
|
role: ["systemAdmin"],
|
||||||
module: "logistics",
|
|
||||||
active: true,
|
active: true,
|
||||||
|
subSubModule: [],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "Ocme cycle counts",
|
name: "Ocme cycle counts",
|
||||||
url: "#",
|
moduleName: "logistics",
|
||||||
|
description: "",
|
||||||
|
link: "#",
|
||||||
icon: Package,
|
icon: Package,
|
||||||
role: ["technician", "supervisor", "manager", "admin", "systemAdmin"],
|
role: ["technician", "supervisor", "manager", "admin", "systemAdmin"],
|
||||||
module: "logistics",
|
|
||||||
active: false,
|
active: false,
|
||||||
|
subSubModule: [],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "Material Helper",
|
name: "Material Helper",
|
||||||
url: "/materialHelper/consumption",
|
moduleName: "logistics",
|
||||||
|
description: "",
|
||||||
|
link: "/materialHelper/consumption",
|
||||||
icon: Package,
|
icon: Package,
|
||||||
role: ["technician", "supervisor", "manager", "admin", "systemAdmin"],
|
role: ["technician", "supervisor", "manager", "admin", "systemAdmin"],
|
||||||
module: "logistics",
|
|
||||||
active: true,
|
active: true,
|
||||||
|
subSubModule: [],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "Ocme Cyclecount",
|
name: "Ocme Cyclecount",
|
||||||
url: "/cyclecount",
|
moduleName: "logistics",
|
||||||
|
description: "",
|
||||||
|
link: "/cyclecount",
|
||||||
icon: Package,
|
icon: Package,
|
||||||
role: ["technician", "supervisor", "manager", "admin", "systemAdmin"],
|
role: ["technician", "supervisor", "manager", "admin", "systemAdmin"],
|
||||||
module: "logistics",
|
|
||||||
active: true,
|
active: true,
|
||||||
|
subSubModule: [],
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
export function LogisticsSideBar({user, moduleID}: {user: User | null; moduleID: string}) {
|
export function LogisticsSideBar({
|
||||||
|
user,
|
||||||
|
moduleID,
|
||||||
|
}: {
|
||||||
|
user: User | null;
|
||||||
|
moduleID: string;
|
||||||
|
}) {
|
||||||
return (
|
return (
|
||||||
<SidebarGroup>
|
<SidebarGroup>
|
||||||
<SidebarGroupLabel>Logistics</SidebarGroupLabel>
|
<SidebarGroupLabel>Logistics</SidebarGroupLabel>
|
||||||
@@ -70,14 +86,15 @@ export function LogisticsSideBar({user, moduleID}: {user: User | null; moduleID:
|
|||||||
{items.map((item) => (
|
{items.map((item) => (
|
||||||
<SidebarMenuItem key={item.title}>
|
<SidebarMenuItem key={item.title}>
|
||||||
<>
|
<>
|
||||||
{hasPageAccess(user, item.role, moduleID) && item.active && (
|
{hasPageAccess(user, item.role, moduleID) &&
|
||||||
<SidebarMenuButton asChild>
|
item.active && (
|
||||||
<a href={item.url}>
|
<SidebarMenuButton asChild>
|
||||||
<item.icon />
|
<a href={item.url}>
|
||||||
<span>{item.title}</span>
|
<item.icon />
|
||||||
</a>
|
<span>{item.title}</span>
|
||||||
</SidebarMenuButton>
|
</a>
|
||||||
)}
|
</SidebarMenuButton>
|
||||||
|
)}
|
||||||
</>
|
</>
|
||||||
</SidebarMenuItem>
|
</SidebarMenuItem>
|
||||||
))}
|
))}
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ let lotColumns = [
|
|||||||
label: "AvDescription",
|
label: "AvDescription",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: "LOT",
|
key: "lot",
|
||||||
label: "LotNumber",
|
label: "LotNumber",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -208,10 +208,14 @@ export default function Lots() {
|
|||||||
<TableCell className="font-medium">
|
<TableCell className="font-medium">
|
||||||
{lot.Alias}
|
{lot.Alias}
|
||||||
</TableCell>
|
</TableCell>
|
||||||
<TableCell className="font-medium">
|
<TableCell
|
||||||
{lot.LOT}
|
className={`font-medium ${lot.ProlinkLot != lot.lot ? "text-red-500" : ""}`}
|
||||||
|
>
|
||||||
|
{lot.lot}
|
||||||
</TableCell>
|
</TableCell>
|
||||||
<TableCell className="font-medium">
|
<TableCell
|
||||||
|
className={`font-medium ${lot.ProlinkLot != lot.lot ? "text-red-500" : ""}`}
|
||||||
|
>
|
||||||
{lot.ProlinkLot}
|
{lot.ProlinkLot}
|
||||||
</TableCell>
|
</TableCell>
|
||||||
<TableCell className="font-medium">
|
<TableCell className="font-medium">
|
||||||
|
|||||||
@@ -1,20 +1,28 @@
|
|||||||
import {QueryClient, QueryClientProvider} from "@tanstack/react-query";
|
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
|
||||||
import {useModuleStore} from "../../lib/store/useModuleStore";
|
import { useModuleStore } from "../../lib/store/useModuleStore";
|
||||||
import {useEffect} from "react";
|
import { useEffect } from "react";
|
||||||
import {useSettingStore} from "@/lib/store/useSettings";
|
import { useSettingStore } from "@/lib/store/useSettings";
|
||||||
//import {useGetUserRoles} from "@/lib/store/useGetRoles";
|
import { useGetUserRoles } from "@/lib/store/useGetRoles";
|
||||||
|
|
||||||
const queryClient = new QueryClient();
|
const queryClient = new QueryClient();
|
||||||
|
|
||||||
export const SessionProvider = ({children}: {children: React.ReactNode}) => {
|
export const SessionProvider = ({
|
||||||
const {fetchModules} = useModuleStore();
|
children,
|
||||||
const {fetchSettings} = useSettingStore();
|
}: {
|
||||||
//const {fetchUserRoles} = useGetUserRoles();
|
children: React.ReactNode;
|
||||||
|
}) => {
|
||||||
|
const { fetchModules } = useModuleStore();
|
||||||
|
const { fetchSettings } = useSettingStore();
|
||||||
|
const { fetchUserRoles } = useGetUserRoles();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
fetchModules();
|
fetchModules();
|
||||||
fetchSettings();
|
fetchSettings();
|
||||||
//fetchUserRoles();
|
fetchUserRoles();
|
||||||
}, []);
|
}, []);
|
||||||
return <QueryClientProvider client={queryClient}>{children}</QueryClientProvider>;
|
return (
|
||||||
|
<QueryClientProvider client={queryClient}>
|
||||||
|
{children}
|
||||||
|
</QueryClientProvider>
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ function Checkbox({
|
|||||||
<CheckboxPrimitive.Root
|
<CheckboxPrimitive.Root
|
||||||
data-slot="checkbox"
|
data-slot="checkbox"
|
||||||
className={cn(
|
className={cn(
|
||||||
"peer border-input data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground data-[state=checked]:border-primary focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive size-4 shrink-0 rounded-[4px] border shadow-xs transition-shadow outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50",
|
"peer border-input dark:bg-input/30 data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground dark:data-[state=checked]:bg-primary data-[state=checked]:border-primary focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive size-4 shrink-0 rounded-[4px] border shadow-xs transition-shadow outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50",
|
||||||
className
|
className
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
import {create} from "zustand";
|
import { create } from "zustand";
|
||||||
import {useSessionStore} from "./sessionStore";
|
import { Modules } from "@/types/modules";
|
||||||
import {Modules} from "@/types/modules";
|
|
||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
|
|
||||||
interface SettingState {
|
interface SettingState {
|
||||||
@@ -15,15 +14,17 @@ interface FetchModulesResponse {
|
|||||||
|
|
||||||
export const useGetUserRoles = create<SettingState>()((set) => ({
|
export const useGetUserRoles = create<SettingState>()((set) => ({
|
||||||
userRoles: [],
|
userRoles: [],
|
||||||
setUserRoles: (userRoles) => set({userRoles}),
|
setUserRoles: (userRoles) => set({ userRoles }),
|
||||||
fetchUserRoles: async () => {
|
fetchUserRoles: async () => {
|
||||||
try {
|
try {
|
||||||
//const response = await axios.get<{data: Setting[]}>(`${process.env.NEXT_PUBLIC_URL}/api/settings/client`);
|
//const response = await axios.get<{data: Setting[]}>(`${process.env.NEXT_PUBLIC_URL}/api/settings/client`);
|
||||||
const {token} = useSessionStore();
|
const token = localStorage.getItem("auth_token");
|
||||||
const response = await axios.get("/api/auth/getuseraccess", {headers: {Authorization: `Bearer ${token}`}});
|
const response = await axios.get("/api/auth/getuseraccess", {
|
||||||
|
headers: { Authorization: `Bearer ${token}` },
|
||||||
|
});
|
||||||
const data: FetchModulesResponse = response.data; //await response.json();
|
const data: FetchModulesResponse = response.data; //await response.json();
|
||||||
//console.log(data);
|
//console.log(data);
|
||||||
set({userRoles: data.data});
|
set({ userRoles: data.data });
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Failed to fetch settings:", error);
|
console.error("Failed to fetch settings:", error);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
export type LotType = {
|
export type LotType = {
|
||||||
AV: number;
|
AV: number;
|
||||||
Alias: string;
|
Alias: string;
|
||||||
LOT: number;
|
lot: number;
|
||||||
LabelOnlineID: number;
|
LabelOnlineID: number;
|
||||||
MachineDescription: string;
|
MachineDescription: string;
|
||||||
MachineID: number;
|
MachineID: number;
|
||||||
|
|||||||
Reference in New Issue
Block a user