Compare commits
13 Commits
26ceb95dae
...
7ed9db1bdb
| Author | SHA1 | Date | |
|---|---|---|---|
| 7ed9db1bdb | |||
| f4dd572a8f | |||
| 3b56a5e3e2 | |||
| 2eea2911bc | |||
| c155e89bc7 | |||
| 7d9ea42f8d | |||
| 974f6587fc | |||
| 2ac48138cb | |||
| d6d19f8e5b | |||
| 3cafbd92d0 | |||
| 77d9e5d095 | |||
| 4a02bbc368 | |||
| f75da6525d |
@@ -1,6 +1,14 @@
|
|||||||
import {text, pgTable, timestamp, uuid, uniqueIndex, jsonb, integer} from "drizzle-orm/pg-core";
|
import {
|
||||||
import {createInsertSchema, createSelectSchema} from "drizzle-zod";
|
text,
|
||||||
import {z} from "zod";
|
pgTable,
|
||||||
|
timestamp,
|
||||||
|
uuid,
|
||||||
|
uniqueIndex,
|
||||||
|
jsonb,
|
||||||
|
integer,
|
||||||
|
} from "drizzle-orm/pg-core";
|
||||||
|
import { createInsertSchema, createSelectSchema } from "drizzle-zod";
|
||||||
|
import { z } from "zod";
|
||||||
|
|
||||||
export const rfidTags = pgTable(
|
export const rfidTags = pgTable(
|
||||||
"rfidTags",
|
"rfidTags",
|
||||||
@@ -23,8 +31,8 @@ export const rfidTags = pgTable(
|
|||||||
);
|
);
|
||||||
|
|
||||||
// Schema for inserting a user - can be used to validate API requests
|
// Schema for inserting a user - can be used to validate API requests
|
||||||
export const insertRolesSchema = createInsertSchema(rfidTags, {
|
// export const insertRolesSchema = createInsertSchema(rfidTags, {
|
||||||
tagHex: z.string().min(3, {message: "Tag Should have more than 3 characters"}),
|
// tagHex: z.string().min(3, {message: "Tag Should have more than 3 characters"}),
|
||||||
});
|
// });
|
||||||
// Schema for selecting a Expenses - can be used to validate API responses
|
// Schema for selecting a Expenses - can be used to validate API responses
|
||||||
export const selectRolesSchema = createSelectSchema(rfidTags);
|
export const selectRolesSchema = createSelectSchema(rfidTags);
|
||||||
|
|||||||
@@ -1,5 +1,15 @@
|
|||||||
import {boolean, date, jsonb, numeric, pgTable, text, timestamp, uniqueIndex, uuid} from "drizzle-orm/pg-core";
|
import {
|
||||||
import {createSelectSchema} from "drizzle-zod";
|
boolean,
|
||||||
|
date,
|
||||||
|
jsonb,
|
||||||
|
numeric,
|
||||||
|
pgTable,
|
||||||
|
text,
|
||||||
|
timestamp,
|
||||||
|
uniqueIndex,
|
||||||
|
uuid,
|
||||||
|
} from "drizzle-orm/pg-core";
|
||||||
|
import { createSelectSchema } from "drizzle-zod";
|
||||||
|
|
||||||
export const serverData = pgTable(
|
export const serverData = pgTable(
|
||||||
"serverData",
|
"serverData",
|
||||||
@@ -21,9 +31,13 @@ export const serverData = pgTable(
|
|||||||
serverLoc: text("serverLoc"),
|
serverLoc: text("serverLoc"),
|
||||||
oldVersion: text("oldVersion"),
|
oldVersion: text("oldVersion"),
|
||||||
lastUpdated: timestamp("lastUpdated").defaultNow(),
|
lastUpdated: timestamp("lastUpdated").defaultNow(),
|
||||||
shippingHours: text("shippingHours").default('[{"early": "06:30", "late": "23:00"}]'),
|
shippingHours: text("shippingHours").default(
|
||||||
|
'[{"early": "06:30", "late": "23:00"}]'
|
||||||
|
),
|
||||||
tiPostTime: text("tiPostTime").default('[{"from": "24", "to": "24"}]'),
|
tiPostTime: text("tiPostTime").default('[{"from": "24", "to": "24"}]'),
|
||||||
otherSettings: jsonb("otherSettings").default([{specialInstructions: "something for ti", active: false}]),
|
otherSettings: jsonb("otherSettings").default([
|
||||||
|
{ specialInstructions: "something for ti", active: false },
|
||||||
|
]),
|
||||||
isUpgrading: boolean("isUpgrading").default(false),
|
isUpgrading: boolean("isUpgrading").default(false),
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,18 @@
|
|||||||
import {text, pgTable, numeric, index, timestamp, boolean, uuid, uniqueIndex} from "drizzle-orm/pg-core";
|
import {
|
||||||
import {createInsertSchema, createSelectSchema} from "drizzle-zod";
|
text,
|
||||||
import {z} from "zod";
|
pgTable,
|
||||||
import {users} from "./users.js";
|
numeric,
|
||||||
import {roles} from "./roles.js";
|
index,
|
||||||
import {modules} from "./modules.js";
|
timestamp,
|
||||||
|
boolean,
|
||||||
|
uuid,
|
||||||
|
uniqueIndex,
|
||||||
|
} from "drizzle-orm/pg-core";
|
||||||
|
import { createInsertSchema, createSelectSchema } from "drizzle-zod";
|
||||||
|
import { z } from "zod";
|
||||||
|
import { users } from "./users.js";
|
||||||
|
import { roles } from "./roles.js";
|
||||||
|
import { modules } from "./modules.js";
|
||||||
|
|
||||||
/*
|
/*
|
||||||
we will add the user
|
we will add the user
|
||||||
@@ -33,13 +42,18 @@ export const userRoles = pgTable(
|
|||||||
},
|
},
|
||||||
(table) => {
|
(table) => {
|
||||||
// ensures only one user gets permissions to one role
|
// ensures only one user gets permissions to one role
|
||||||
return [uniqueIndex("user_module_unique").on(table.user_id, table.module_id)];
|
return [
|
||||||
|
uniqueIndex("user_module_unique").on(
|
||||||
|
table.user_id,
|
||||||
|
table.module_id
|
||||||
|
),
|
||||||
|
];
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
// Schema for inserting a user - can be used to validate API requests
|
// Schema for inserting a user - can be used to validate API requests
|
||||||
export const insertUserRolesSchema = createInsertSchema(userRoles, {
|
// export const insertUserRolesSchema = createInsertSchema(userRoles, {
|
||||||
role: z.string().min(3, {message: "Role must be at least 3 characters"}),
|
// role: z.string().min(3, {message: "Role must be at least 3 characters"}),
|
||||||
});
|
// });
|
||||||
// Schema for selecting a Expenses - can be used to validate API responses
|
// Schema for selecting a Expenses - can be used to validate API responses
|
||||||
export const selectUserRolesSchema = createSelectSchema(userRoles);
|
export const selectUserRolesSchema = createSelectSchema(userRoles);
|
||||||
|
|||||||
@@ -1,6 +1,15 @@
|
|||||||
import {text, pgTable, numeric, index, timestamp, boolean, uuid, uniqueIndex} from "drizzle-orm/pg-core";
|
import {
|
||||||
import {createInsertSchema, createSelectSchema} from "drizzle-zod";
|
text,
|
||||||
import {z} from "zod";
|
pgTable,
|
||||||
|
numeric,
|
||||||
|
index,
|
||||||
|
timestamp,
|
||||||
|
boolean,
|
||||||
|
uuid,
|
||||||
|
uniqueIndex,
|
||||||
|
} from "drizzle-orm/pg-core";
|
||||||
|
import { createInsertSchema, createSelectSchema } from "drizzle-zod";
|
||||||
|
import { z } from "zod";
|
||||||
|
|
||||||
export const users = pgTable(
|
export const users = pgTable(
|
||||||
"users",
|
"users",
|
||||||
@@ -27,10 +36,10 @@ export const users = pgTable(
|
|||||||
);
|
);
|
||||||
|
|
||||||
// Schema for inserting a user - can be used to validate API requests
|
// Schema for inserting a user - can be used to validate API requests
|
||||||
export const insertUsersSchema = createInsertSchema(users, {
|
// export const insertUsersSchema = createInsertSchema(users, {
|
||||||
username: z.string().min(3, {message: "Username must be at least 3 characters"}),
|
// username: z.string().min(3, {message: "Username must be at least 3 characters"}),
|
||||||
email: z.string().email({message: "Invalid email"}),
|
// email: z.string().email({message: "Invalid email"}),
|
||||||
password: z.string().min(8, {message: "Password must be at least 8 characters"}),
|
// password: z.string().min(8, {message: "Password must be at least 8 characters"}),
|
||||||
});
|
// });
|
||||||
// Schema for selecting a Expenses - can be used to validate API responses
|
// Schema for selecting a Expenses - can be used to validate API responses
|
||||||
export const selectUsersSchema = createSelectSchema(users);
|
export const selectUsersSchema = createSelectSchema(users);
|
||||||
|
|||||||
3368
frontend/package-lock.json
generated
3368
frontend/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -12,69 +12,72 @@
|
|||||||
"checkupdates": "npm-check-updates"
|
"checkupdates": "npm-check-updates"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@hookform/resolvers": "^4.1.3",
|
"@hookform/resolvers": "^5.1.1",
|
||||||
"@radix-ui/react-accordion": "^1.2.3",
|
"@radix-ui/react-accordion": "^1.2.11",
|
||||||
"@radix-ui/react-avatar": "^1.1.3",
|
"@radix-ui/react-avatar": "^1.1.10",
|
||||||
"@radix-ui/react-checkbox": "^1.1.4",
|
"@radix-ui/react-checkbox": "^1.3.2",
|
||||||
"@radix-ui/react-collapsible": "^1.1.3",
|
"@radix-ui/react-collapsible": "^1.1.11",
|
||||||
"@radix-ui/react-dialog": "^1.1.6",
|
"@radix-ui/react-dialog": "^1.1.14",
|
||||||
"@radix-ui/react-dropdown-menu": "^2.1.6",
|
"@radix-ui/react-dropdown-menu": "^2.1.15",
|
||||||
"@radix-ui/react-label": "^2.1.2",
|
"@radix-ui/react-label": "^2.1.7",
|
||||||
"@radix-ui/react-popover": "^1.1.6",
|
"@radix-ui/react-popover": "^1.1.14",
|
||||||
"@radix-ui/react-scroll-area": "^1.2.3",
|
"@radix-ui/react-scroll-area": "^1.2.9",
|
||||||
"@radix-ui/react-select": "^2.1.6",
|
"@radix-ui/react-select": "^2.2.5",
|
||||||
"@radix-ui/react-separator": "^1.1.2",
|
"@radix-ui/react-separator": "^1.1.7",
|
||||||
"@radix-ui/react-slot": "^1.1.2",
|
"@radix-ui/react-slot": "^1.2.3",
|
||||||
"@radix-ui/react-tabs": "^1.1.3",
|
"@radix-ui/react-tabs": "^1.1.12",
|
||||||
"@radix-ui/react-tooltip": "^1.1.8",
|
"@radix-ui/react-tooltip": "^1.2.7",
|
||||||
"@react-pdf/renderer": "^4.3.0",
|
"@react-pdf/renderer": "^4.3.0",
|
||||||
"@tailwindcss/vite": "^4.0.15",
|
"@tailwindcss/vite": "^4.1.10",
|
||||||
"@tanstack/react-form": "^1.2.1",
|
"@tanstack/react-form": "^1.12.3",
|
||||||
"@tanstack/react-query": "^5.69.0",
|
"@tanstack/react-query": "^5.81.2",
|
||||||
"@tanstack/react-router": "^1.114.27",
|
"@tanstack/react-router": "^1.121.34",
|
||||||
"@tanstack/react-table": "^8.21.2",
|
"@tanstack/react-table": "^8.21.3",
|
||||||
"class-variance-authority": "^0.7.1",
|
"class-variance-authority": "^0.7.1",
|
||||||
"clsx": "^2.1.1",
|
"clsx": "^2.1.1",
|
||||||
"date-fns": "^4.1.0",
|
"date-fns": "^4.1.0",
|
||||||
"date-fns-tz": "^3.2.0",
|
"date-fns-tz": "^3.2.0",
|
||||||
"dotenv": "^16.4.7",
|
"dotenv": "^16.5.0",
|
||||||
"hono": "^4.7.5",
|
"hono": "^4.8.2",
|
||||||
"js-cookie": "^3.0.5",
|
"js-cookie": "^3.0.5",
|
||||||
"jsbarcode": "^3.11.6",
|
"jsbarcode": "^3.12.1",
|
||||||
"jsonwebtoken": "^9.0.2",
|
"jsonwebtoken": "^9.0.2",
|
||||||
"lucide-react": "^0.483.0",
|
"lucide-react": "^0.522.0",
|
||||||
"marked": "^15.0.8",
|
"marked": "^15.0.12",
|
||||||
"next-themes": "^0.4.6",
|
"next-themes": "^0.4.6",
|
||||||
"npm-check-updates": "^17.1.16",
|
"npm-check-updates": "^18.0.1",
|
||||||
"react": "^19.0.0",
|
"react": "^19.1.0",
|
||||||
"react-barcode": "^1.6.1",
|
"react-barcode": "^1.6.1",
|
||||||
"react-day-picker": "^8.10.1",
|
"react-day-picker": "^9.7.0",
|
||||||
"react-dom": "^19.0.0",
|
"react-dom": "^19.1.0",
|
||||||
"react-grid-layout": "^1.5.1",
|
"react-grid-layout": "^1.5.1",
|
||||||
"react-hook-form": "^7.54.2",
|
"react-hook-form": "^7.58.1",
|
||||||
"react-resizable-panels": "^2.1.7",
|
"react-resizable-panels": "^3.0.3",
|
||||||
"recharts": "^2.15.2",
|
"recharts": "^2.15.2",
|
||||||
"sonner": "^2.0.1",
|
"sonner": "^2.0.5",
|
||||||
"tailwind-merge": "^3.0.2",
|
"tailwind-merge": "^3.3.1",
|
||||||
"tailwindcss": "^4.0.15",
|
"tailwindcss": "^4.1.10",
|
||||||
"tailwindcss-animate": "^1.0.7",
|
"tailwindcss-animate": "^1.0.7",
|
||||||
"zod": "^3.24.2",
|
"zod": "^3.25.67",
|
||||||
"zustand": "^5.0.3"
|
"zustand": "^5.0.5"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@eslint/js": "^9.23.0",
|
"@eslint/js": "^9.29.0",
|
||||||
"@tanstack/router-devtools": "^1.114.27",
|
"@tanstack/router-devtools": "^1.121.34",
|
||||||
"@tanstack/router-plugin": "^1.114.27",
|
"@tanstack/router-plugin": "^1.121.34",
|
||||||
"@types/react": "^19.0.12",
|
"@types/react": "^19.1.8",
|
||||||
"@types/react-dom": "^19.0.4",
|
"@types/react-dom": "^19.1.6",
|
||||||
"@types/react-grid-layout": "^1.3.5",
|
"@types/react-grid-layout": "^1.3.5",
|
||||||
"@vitejs/plugin-react-swc": "^3.8.1",
|
"@vitejs/plugin-react-swc": "^3.10.2",
|
||||||
"eslint": "^9.23.0",
|
"eslint": "^9.29.0",
|
||||||
"eslint-plugin-react-hooks": "^5.2.0",
|
"eslint-plugin-react-hooks": "^5.2.0",
|
||||||
"eslint-plugin-react-refresh": "^0.4.19",
|
"eslint-plugin-react-refresh": "^0.4.20",
|
||||||
"globals": "^16.0.0",
|
"globals": "^16.2.0",
|
||||||
"typescript": "~5.8.2",
|
"typescript": "~5.8.3",
|
||||||
"typescript-eslint": "^8.27.0",
|
"typescript-eslint": "^8.35.0",
|
||||||
"vite": "^6.2.2"
|
"vite": "^6.3.5"
|
||||||
|
},
|
||||||
|
"overrides": {
|
||||||
|
"react-is": "^19.0.0-rc-69d4b800-20241021"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ import { Button } from "@/components/ui/button";
|
|||||||
import { getSettings } from "@/utils/querys/settings";
|
import { getSettings } from "@/utils/querys/settings";
|
||||||
import { toast } from "sonner";
|
import { toast } from "sonner";
|
||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
|
import { useEffect } from "react";
|
||||||
//import { useState } from "react";
|
//import { useState } from "react";
|
||||||
|
|
||||||
export type Servers = {
|
export type Servers = {
|
||||||
@@ -46,14 +47,35 @@ export default function ServerPage() {
|
|||||||
getServers(token ?? "")
|
getServers(token ?? "")
|
||||||
);
|
);
|
||||||
|
|
||||||
const adminModule = modules.filter((n) => n.name === "admin");
|
// const adminModule = modules.filter((n) => n.name === "admin");
|
||||||
|
// const userLevel =
|
||||||
|
// user?.roles?.filter((r) => r.module_id === adminModule[0].module_id) ||
|
||||||
|
// [];
|
||||||
|
|
||||||
|
// if (!adminModule[0]?.roles?.includes(userLevel[0]?.role)) {
|
||||||
|
// console.log("Something failed");
|
||||||
|
// //router.navigate({ to: "/" });
|
||||||
|
// }
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!user || modules.length === 0) return;
|
||||||
|
|
||||||
|
const adminModule = modules.find((n) => n.name === "admin");
|
||||||
|
if (!adminModule) {
|
||||||
|
console.log("no module loaded");
|
||||||
|
//router.navigate({ to: "/" });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const userLevel =
|
const userLevel =
|
||||||
user?.roles?.filter((r) => r.module_id === adminModule[0].module_id) ||
|
user?.roles?.filter((r) => r.module_id === adminModule.module_id) ||
|
||||||
[];
|
[];
|
||||||
|
|
||||||
if (!adminModule[0]?.roles?.includes(userLevel[0]?.role)) {
|
if (!adminModule.roles?.includes(userLevel[0]?.role)) {
|
||||||
router.navigate({ to: "/" });
|
console.log("Something failed");
|
||||||
|
//router.navigate({ to: "/" });
|
||||||
}
|
}
|
||||||
|
}, [modules, user, router]);
|
||||||
|
|
||||||
if (isError) {
|
if (isError) {
|
||||||
return <div>{JSON.stringify(error)}</div>;
|
return <div>{JSON.stringify(error)}</div>;
|
||||||
|
|||||||
@@ -1,12 +1,19 @@
|
|||||||
import {LstCard} from "@/components/extendedUI/LstCard";
|
import { LstCard } from "@/components/extendedUI/LstCard";
|
||||||
import {Table, TableBody, TableCell, TableHead, TableHeader, TableRow} from "@/components/ui/table";
|
import {
|
||||||
import {useSessionStore} from "@/lib/store/sessionStore";
|
Table,
|
||||||
import {useModuleStore} from "@/lib/store/useModuleStore";
|
TableBody,
|
||||||
import {useQuery} from "@tanstack/react-query";
|
TableCell,
|
||||||
import {useRouter} from "@tanstack/react-router";
|
TableHead,
|
||||||
import {ChangeSetting} from "./SettingForm";
|
TableHeader,
|
||||||
import {getSettings} from "@/utils/querys/settings";
|
TableRow,
|
||||||
import {Skeleton} from "@/components/ui/skeleton";
|
} from "@/components/ui/table";
|
||||||
|
import { useSessionStore } from "@/lib/store/sessionStore";
|
||||||
|
import { useModuleStore } from "@/lib/store/useModuleStore";
|
||||||
|
import { useQuery } from "@tanstack/react-query";
|
||||||
|
import { useRouter } from "@tanstack/react-router";
|
||||||
|
import { ChangeSetting } from "./SettingForm";
|
||||||
|
import { getSettings } from "@/utils/querys/settings";
|
||||||
|
import { Skeleton } from "@/components/ui/skeleton";
|
||||||
|
|
||||||
export type Settings = {
|
export type Settings = {
|
||||||
settings_id?: string;
|
settings_id?: string;
|
||||||
@@ -16,18 +23,22 @@ export type Settings = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export default function SettingsPage() {
|
export default function SettingsPage() {
|
||||||
const {user, token} = useSessionStore();
|
const { user, token } = useSessionStore();
|
||||||
const {modules} = useModuleStore();
|
const { modules } = useModuleStore();
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
||||||
const adminModule = modules.filter((n) => n.name === "admin");
|
const adminModule = modules.filter((n) => n.name === "admin");
|
||||||
const userLevel = user?.roles.filter((r) => r.module_id === adminModule[0].module_id) || [];
|
const userLevel =
|
||||||
|
user?.roles.filter((r) => r.module_id === adminModule[0].module_id) ||
|
||||||
|
[];
|
||||||
|
|
||||||
if (!adminModule[0].roles.includes(userLevel[0]?.role)) {
|
if (!adminModule[0].roles.includes(userLevel[0]?.role)) {
|
||||||
router.navigate({to: "/"});
|
router.navigate({ to: "/" });
|
||||||
}
|
}
|
||||||
|
|
||||||
const {data, isError, error, isLoading} = useQuery(getSettings(token ?? ""));
|
const { data, isError, error, isLoading } = useQuery(
|
||||||
|
getSettings(token ?? "")
|
||||||
|
);
|
||||||
|
|
||||||
// if (isLoading) {
|
// if (isLoading) {
|
||||||
// return <div>Loading.....</div>;
|
// return <div>Loading.....</div>;
|
||||||
@@ -74,9 +85,15 @@ export default function SettingsPage() {
|
|||||||
<TableBody>
|
<TableBody>
|
||||||
{data?.map((setting: Settings) => (
|
{data?.map((setting: Settings) => (
|
||||||
<TableRow key={setting.settings_id}>
|
<TableRow key={setting.settings_id}>
|
||||||
<TableCell className="font-medium">{setting.name}</TableCell>
|
<TableCell className="font-medium">
|
||||||
<TableCell className="font-medium">{setting.value}</TableCell>
|
{setting.name}
|
||||||
<TableCell className="font-medium">{setting.description}</TableCell>
|
</TableCell>
|
||||||
|
<TableCell className="font-medium">
|
||||||
|
{setting.value}
|
||||||
|
</TableCell>
|
||||||
|
<TableCell className="font-medium">
|
||||||
|
{setting.description}
|
||||||
|
</TableCell>
|
||||||
<TableCell className="font-medium">
|
<TableCell className="font-medium">
|
||||||
<ChangeSetting setting={setting} />
|
<ChangeSetting setting={setting} />
|
||||||
</TableCell>
|
</TableCell>
|
||||||
|
|||||||
@@ -1,25 +1,15 @@
|
|||||||
import { useCardStore } from "@/lib/store/useCardStore";
|
import { useCardStore } from "@/lib/store/useCardStore";
|
||||||
import { useForm } from "@tanstack/react-form";
|
|
||||||
import { Label } from "../ui/label";
|
import { Label } from "../ui/label";
|
||||||
import { Checkbox } from "../ui/checkbox";
|
import { Checkbox } from "../ui/checkbox";
|
||||||
import { Input } from "../ui/input";
|
|
||||||
// import {
|
|
||||||
// Select,
|
|
||||||
// SelectContent,
|
|
||||||
// SelectGroup,
|
|
||||||
// SelectItem,
|
|
||||||
// SelectLabel,
|
|
||||||
// SelectTrigger,
|
|
||||||
// SelectValue,
|
|
||||||
// } from "../ui/select";
|
|
||||||
import { Button } from "../ui/button";
|
import { Button } from "../ui/button";
|
||||||
|
import { useAppForm } from "@/utils/formStuff";
|
||||||
|
|
||||||
export default function Cards(card: any) {
|
export default function Cards(card: any) {
|
||||||
const { addCard, removeCard, cards } = useCardStore();
|
const { addCard, removeCard, cards } = useCardStore();
|
||||||
let existing: any = cards.filter((n: any) => n.name === card.name);
|
let existing: any = cards.filter((n: any) => n.name === card.name);
|
||||||
|
|
||||||
//console.log(existing);
|
//console.log(existing);
|
||||||
const form = useForm({
|
const form = useAppForm({
|
||||||
defaultValues: {
|
defaultValues: {
|
||||||
name: existing[0]?.name || card.name,
|
name: existing[0]?.name || card.name,
|
||||||
rowType: existing[0]?.type ?? card.rowType,
|
rowType: existing[0]?.type ?? card.rowType,
|
||||||
@@ -62,7 +52,7 @@ export default function Cards(card: any) {
|
|||||||
}}
|
}}
|
||||||
className="flex flex-row"
|
className="flex flex-row"
|
||||||
>
|
>
|
||||||
<form.Field
|
<form.AppField
|
||||||
name="active"
|
name="active"
|
||||||
// validators={{
|
// validators={{
|
||||||
// // We can choose between form-wide and field-specific validators
|
// // We can choose between form-wide and field-specific validators
|
||||||
@@ -95,83 +85,16 @@ export default function Cards(card: any) {
|
|||||||
/>
|
/>
|
||||||
{!card.inventory && (
|
{!card.inventory && (
|
||||||
<>
|
<>
|
||||||
<form.Field
|
<form.AppField
|
||||||
name="age"
|
name="age"
|
||||||
// validators={{
|
children={(field) => (
|
||||||
// // We can choose between form-wide and field-specific validators
|
<field.InputField
|
||||||
// onChange: ({ value }) =>
|
label="Age"
|
||||||
// value.length > 3
|
inputType="number"
|
||||||
// ? undefined
|
required={true}
|
||||||
// : "Username must be longer than 3 letters",
|
|
||||||
// }}
|
|
||||||
children={(field) => {
|
|
||||||
return (
|
|
||||||
<div className="m-2 min-w-48 p-2">
|
|
||||||
<Label htmlFor="active" className="">
|
|
||||||
Age
|
|
||||||
</Label>
|
|
||||||
<Input
|
|
||||||
name={field.name}
|
|
||||||
onBlur={field.handleBlur}
|
|
||||||
value={field.state.value}
|
|
||||||
type="number"
|
|
||||||
onChange={(e) =>
|
|
||||||
field.handleChange(
|
|
||||||
e.target.value
|
|
||||||
)
|
|
||||||
}
|
|
||||||
/>
|
/>
|
||||||
</div>
|
)}
|
||||||
);
|
|
||||||
}}
|
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{/* <form.Field
|
|
||||||
name="rowType"
|
|
||||||
//listeners={{onChange: ({value})=>{}}}
|
|
||||||
children={(field) => {
|
|
||||||
return (
|
|
||||||
<div className="m-2 min-w-48 max-w-96 p-2">
|
|
||||||
<Label htmlFor={field.name}>
|
|
||||||
Row Type
|
|
||||||
</Label>
|
|
||||||
<Select
|
|
||||||
value={field.state.value}
|
|
||||||
onValueChange={field.handleChange}
|
|
||||||
>
|
|
||||||
<SelectTrigger className="w-[180px]">
|
|
||||||
<SelectValue
|
|
||||||
id={field.name}
|
|
||||||
placeholder="Select Role"
|
|
||||||
/>
|
|
||||||
</SelectTrigger>
|
|
||||||
<SelectContent>
|
|
||||||
<SelectGroup>
|
|
||||||
<SelectLabel>
|
|
||||||
Row Type
|
|
||||||
</SelectLabel>
|
|
||||||
<SelectItem value="empty">
|
|
||||||
Empty
|
|
||||||
</SelectItem>
|
|
||||||
<SelectItem value="fg">
|
|
||||||
Finished Goods
|
|
||||||
</SelectItem>
|
|
||||||
<SelectItem value="materials">
|
|
||||||
Materials
|
|
||||||
</SelectItem>
|
|
||||||
<SelectItem value="waste">
|
|
||||||
Waste
|
|
||||||
</SelectItem>
|
|
||||||
<SelectItem value="packaging">
|
|
||||||
Packaging
|
|
||||||
</SelectItem>
|
|
||||||
</SelectGroup>
|
|
||||||
</SelectContent>
|
|
||||||
</Select>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}}
|
|
||||||
/> */}
|
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
<div className="mt-7">
|
<div className="mt-7">
|
||||||
|
|||||||
@@ -27,9 +27,10 @@ export default function DashBoard() {
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
|
//console.log(name.split("-")[0], a);
|
||||||
return (
|
return (
|
||||||
<div key={a.name} className="col-span-3">
|
<div key={a.name} className="col-span-3">
|
||||||
<Component age={a.age} type={a.rowType} />
|
<Component data={a} />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -106,6 +106,17 @@ export default function PreformReturn() {
|
|||||||
{...register1("lotNum")}
|
{...register1("lotNum")}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
<div className="m-2">
|
||||||
|
<Label htmlFor="lotNum">
|
||||||
|
Select type of material coming back.
|
||||||
|
</Label>
|
||||||
|
<Input
|
||||||
|
className="mt-2"
|
||||||
|
//defaultValue="634"
|
||||||
|
type="number"
|
||||||
|
{...register1("lotNum")}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
className="m-2"
|
className="m-2"
|
||||||
164
frontend/src/components/logistics/siloAdjustments/AttachSilo.tsx
Normal file
164
frontend/src/components/logistics/siloAdjustments/AttachSilo.tsx
Normal file
@@ -0,0 +1,164 @@
|
|||||||
|
import { Button } from "@/components/ui/button";
|
||||||
|
import {
|
||||||
|
Dialog,
|
||||||
|
DialogClose,
|
||||||
|
DialogContent,
|
||||||
|
DialogDescription,
|
||||||
|
DialogFooter,
|
||||||
|
DialogHeader,
|
||||||
|
DialogTitle,
|
||||||
|
DialogTrigger,
|
||||||
|
} from "@/components/ui/dialog";
|
||||||
|
|
||||||
|
import { useAppForm } from "@/utils/formStuff";
|
||||||
|
import { getMachineConnected } from "@/utils/querys/logistics/machineConnected";
|
||||||
|
import { getMachineNotConnected } from "@/utils/querys/logistics/notConnected";
|
||||||
|
import { useQuery } from "@tanstack/react-query";
|
||||||
|
import axios from "axios";
|
||||||
|
import { useState } from "react";
|
||||||
|
import { toast } from "sonner";
|
||||||
|
|
||||||
|
export function AttachSilo(props: any) {
|
||||||
|
const [open, setOpen] = useState(false);
|
||||||
|
const { data, isError, isLoading, refetch } = useQuery(
|
||||||
|
getMachineNotConnected({
|
||||||
|
siloID: props.silo.LocationID,
|
||||||
|
connectionType: "detached",
|
||||||
|
})
|
||||||
|
);
|
||||||
|
const { refetch: attached } = useQuery(
|
||||||
|
getMachineConnected({
|
||||||
|
siloID: props.silo.LocationID,
|
||||||
|
connectionType: "connected",
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
const form = useAppForm({
|
||||||
|
defaultValues: {
|
||||||
|
laneId: props.silo.LocationID,
|
||||||
|
productionLotId: "",
|
||||||
|
machineId: "",
|
||||||
|
},
|
||||||
|
onSubmit: async ({ value }) => {
|
||||||
|
console.log(value);
|
||||||
|
try {
|
||||||
|
const res = await axios.post(
|
||||||
|
"/api/logistics/attachsilo",
|
||||||
|
value
|
||||||
|
);
|
||||||
|
|
||||||
|
if (res.data.success) {
|
||||||
|
toast.success(res.data.message);
|
||||||
|
refetch();
|
||||||
|
attached();
|
||||||
|
form.reset();
|
||||||
|
setOpen(!open);
|
||||||
|
} else {
|
||||||
|
console.log(res.data);
|
||||||
|
toast.error(res.data.message);
|
||||||
|
refetch();
|
||||||
|
form.reset();
|
||||||
|
setOpen(!open);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error);
|
||||||
|
toast.error(
|
||||||
|
"There was an error attaching the silo please try again, if persist please enter a helpdesk ticket."
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
if (isError)
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<p>There was an error loading data</p>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
|
if (isLoading)
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<p>Loading....</p>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
|
// convert the array that comes over to label and value
|
||||||
|
const tranMachine = data.map((i: any) => ({
|
||||||
|
value: i.machineId.toString(),
|
||||||
|
label: i.name,
|
||||||
|
}));
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Dialog open={open}>
|
||||||
|
<DialogTrigger asChild>
|
||||||
|
<Button variant="outline" onClick={() => setOpen(!open)}>
|
||||||
|
Attach Silo
|
||||||
|
</Button>
|
||||||
|
</DialogTrigger>
|
||||||
|
|
||||||
|
<DialogContent className="sm:max-w-[425px]">
|
||||||
|
<form
|
||||||
|
onSubmit={(e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
form.handleSubmit();
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<DialogHeader>
|
||||||
|
<DialogTitle>
|
||||||
|
Attach silo for: {props.silo.Description}
|
||||||
|
</DialogTitle>
|
||||||
|
<DialogDescription>
|
||||||
|
Enter the new lotnumber, select the machine you
|
||||||
|
would like to attach.
|
||||||
|
</DialogDescription>
|
||||||
|
</DialogHeader>
|
||||||
|
<div>
|
||||||
|
<p className="text-sm">
|
||||||
|
NOTE: If the machine you are trying to attach is not
|
||||||
|
showing in the drop down this means it is already
|
||||||
|
attached to this silo.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div className="mt-3">
|
||||||
|
<form.AppField
|
||||||
|
name="productionLotId"
|
||||||
|
children={(field) => (
|
||||||
|
<field.InputField
|
||||||
|
label="Lot Number"
|
||||||
|
inputType="number"
|
||||||
|
required={true}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="mt-2">
|
||||||
|
<form.AppField
|
||||||
|
name="machineId"
|
||||||
|
children={(field) => (
|
||||||
|
<field.SelectField
|
||||||
|
label="Select Machine"
|
||||||
|
options={tranMachine}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<DialogFooter className="mt-2">
|
||||||
|
<DialogClose asChild>
|
||||||
|
<Button
|
||||||
|
variant="outline"
|
||||||
|
onClick={() => setOpen(!open)}
|
||||||
|
>
|
||||||
|
Cancel
|
||||||
|
</Button>
|
||||||
|
</DialogClose>
|
||||||
|
<form.AppForm>
|
||||||
|
<form.SubmitButton>Attach</form.SubmitButton>
|
||||||
|
</form.AppForm>
|
||||||
|
</DialogFooter>
|
||||||
|
</form>
|
||||||
|
</DialogContent>
|
||||||
|
</Dialog>
|
||||||
|
);
|
||||||
|
}
|
||||||
145
frontend/src/components/logistics/siloAdjustments/DetachSilo.tsx
Normal file
145
frontend/src/components/logistics/siloAdjustments/DetachSilo.tsx
Normal file
@@ -0,0 +1,145 @@
|
|||||||
|
import { Button } from "@/components/ui/button";
|
||||||
|
import {
|
||||||
|
Dialog,
|
||||||
|
DialogClose,
|
||||||
|
DialogContent,
|
||||||
|
DialogDescription,
|
||||||
|
DialogFooter,
|
||||||
|
DialogHeader,
|
||||||
|
DialogTitle,
|
||||||
|
DialogTrigger,
|
||||||
|
} from "@/components/ui/dialog";
|
||||||
|
|
||||||
|
import { useAppForm } from "@/utils/formStuff";
|
||||||
|
import { getMachineConnected } from "@/utils/querys/logistics/machineConnected";
|
||||||
|
import { getMachineNotConnected } from "@/utils/querys/logistics/notConnected";
|
||||||
|
|
||||||
|
import { useQuery } from "@tanstack/react-query";
|
||||||
|
import axios from "axios";
|
||||||
|
import { useState } from "react";
|
||||||
|
import { toast } from "sonner";
|
||||||
|
|
||||||
|
export function DetachSilo(props: any) {
|
||||||
|
const [open, setOpen] = useState(false);
|
||||||
|
const { data, isError, isLoading, refetch } = useQuery(
|
||||||
|
getMachineConnected({
|
||||||
|
siloID: props.silo.LocationID,
|
||||||
|
connectionType: "connected",
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
const { refetch: notConnected } = useQuery(
|
||||||
|
getMachineNotConnected({
|
||||||
|
siloID: props.silo.LocationID,
|
||||||
|
connectionType: "detached",
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
const form = useAppForm({
|
||||||
|
defaultValues: {
|
||||||
|
laneId: props.silo.LocationID,
|
||||||
|
machineId: 0,
|
||||||
|
},
|
||||||
|
onSubmit: async ({ value }) => {
|
||||||
|
try {
|
||||||
|
const res = await axios.post(
|
||||||
|
"/api/logistics/detachsilo",
|
||||||
|
value
|
||||||
|
);
|
||||||
|
|
||||||
|
if (res.status === 200) {
|
||||||
|
toast.success(res.data.message);
|
||||||
|
|
||||||
|
refetch();
|
||||||
|
notConnected();
|
||||||
|
form.reset();
|
||||||
|
setOpen(!open);
|
||||||
|
} else {
|
||||||
|
console.log(res.data);
|
||||||
|
toast.error(res.data.message);
|
||||||
|
refetch();
|
||||||
|
form.reset();
|
||||||
|
setOpen(!open);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error);
|
||||||
|
toast.error(
|
||||||
|
"There was an error detaching the silo please try again, if persist please enter a helpdesk ticket."
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
if (isError)
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<p>There was an error loading data</p>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
|
if (isLoading)
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<p>Loading....</p>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
|
// convert the array that comes over to label and value
|
||||||
|
const tranMachine = data.map((i: any) => ({
|
||||||
|
value: i.machineId.toString(),
|
||||||
|
label: i.name,
|
||||||
|
}));
|
||||||
|
return (
|
||||||
|
<Dialog open={open}>
|
||||||
|
<DialogTrigger asChild>
|
||||||
|
<Button
|
||||||
|
variant="outline"
|
||||||
|
onClick={() => setOpen(!open)}
|
||||||
|
disabled={data.length === 0}
|
||||||
|
>
|
||||||
|
Detach Silo
|
||||||
|
</Button>
|
||||||
|
</DialogTrigger>
|
||||||
|
<DialogContent className="sm:max-w-[425px]">
|
||||||
|
<form
|
||||||
|
onSubmit={(e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
form.handleSubmit();
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<DialogHeader>
|
||||||
|
<DialogTitle>
|
||||||
|
Attach silo for: {props.silo.Description}
|
||||||
|
</DialogTitle>
|
||||||
|
<DialogDescription>
|
||||||
|
Select the machine you would like to detach.
|
||||||
|
</DialogDescription>
|
||||||
|
</DialogHeader>
|
||||||
|
<div className="grid gap-4">
|
||||||
|
<div className="grid gap-3">
|
||||||
|
<div className="mt-2">
|
||||||
|
<form.AppField
|
||||||
|
name="machineId"
|
||||||
|
children={(field) => (
|
||||||
|
<field.SelectField
|
||||||
|
label="Select Machine"
|
||||||
|
options={tranMachine}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<DialogFooter>
|
||||||
|
<DialogClose asChild>
|
||||||
|
<Button variant="outline">Cancel</Button>
|
||||||
|
</DialogClose>
|
||||||
|
<form.AppForm>
|
||||||
|
<form.SubmitButton>Detach</form.SubmitButton>
|
||||||
|
</form.AppForm>
|
||||||
|
</DialogFooter>
|
||||||
|
</form>
|
||||||
|
</DialogContent>
|
||||||
|
</Dialog>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -19,6 +19,8 @@ import { CircleAlert } from "lucide-react";
|
|||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
import { toast } from "sonner";
|
import { toast } from "sonner";
|
||||||
import ChartData from "./ChartData";
|
import ChartData from "./ChartData";
|
||||||
|
import { AttachSilo } from "./AttachSilo";
|
||||||
|
import { DetachSilo } from "./DetachSilo";
|
||||||
|
|
||||||
export default function SiloCard(data: any) {
|
export default function SiloCard(data: any) {
|
||||||
const token = localStorage.getItem("auth_token");
|
const token = localStorage.getItem("auth_token");
|
||||||
@@ -151,6 +153,7 @@ export default function SiloCard(data: any) {
|
|||||||
/>
|
/>
|
||||||
<Button
|
<Button
|
||||||
className="ml-1"
|
className="ml-1"
|
||||||
|
variant="outline"
|
||||||
type="submit"
|
type="submit"
|
||||||
onClick={
|
onClick={
|
||||||
form.handleSubmit
|
form.handleSubmit
|
||||||
@@ -188,13 +191,17 @@ export default function SiloCard(data: any) {
|
|||||||
<div className="grow max-w-[600px]">
|
<div className="grow max-w-[600px]">
|
||||||
<ChartData laneId={silo.LocationID} />
|
<ChartData laneId={silo.LocationID} />
|
||||||
|
|
||||||
<div className="flex justify-end m-1">
|
<div className="flex justify-end m-1 gap-3">
|
||||||
|
<AttachSilo silo={silo} />
|
||||||
|
<DetachSilo silo={silo} />
|
||||||
|
<Button variant="outline">
|
||||||
<Link
|
<Link
|
||||||
to={"/siloAdjustments/$hist"}
|
to={"/siloAdjustments/$hist"}
|
||||||
params={{ hist: silo.LocationID }}
|
params={{ hist: silo.LocationID }}
|
||||||
>
|
>
|
||||||
Historical Data
|
Historical Data
|
||||||
</Link>
|
</Link>
|
||||||
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -9,8 +9,12 @@ import { useQuery } from "@tanstack/react-query";
|
|||||||
//import { toast } from "sonner";
|
//import { toast } from "sonner";
|
||||||
|
|
||||||
export default function INVCheckCard(props: any) {
|
export default function INVCheckCard(props: any) {
|
||||||
//{ style = {} }
|
const { age, rowType } = props.data;
|
||||||
const { data, isError, isLoading } = useQuery(getinventoryCheck(props));
|
|
||||||
|
//console.log(props.data);
|
||||||
|
const { data, isError, isLoading } = useQuery(
|
||||||
|
getinventoryCheck({ age: age })
|
||||||
|
);
|
||||||
|
|
||||||
if (isLoading) return <div>Loading inventory data...</div>;
|
if (isLoading) return <div>Loading inventory data...</div>;
|
||||||
if (isError) {
|
if (isError) {
|
||||||
@@ -23,11 +27,11 @@ export default function INVCheckCard(props: any) {
|
|||||||
let laneData: any = data;
|
let laneData: any = data;
|
||||||
if (props.type != "") {
|
if (props.type != "") {
|
||||||
laneData = laneData.filter(
|
laneData = laneData.filter(
|
||||||
(l: any) => l.rowType === props.type.toUpperCase()
|
(l: any) => l.rowType === rowType.toUpperCase()
|
||||||
);
|
);
|
||||||
|
|
||||||
// age
|
// age
|
||||||
laneData = laneData.filter((l: any) => l.DaysSinceLast >= props.age);
|
laneData = laneData.filter((l: any) => l.DaysSinceLast >= age);
|
||||||
}
|
}
|
||||||
|
|
||||||
// const handleCloseCard = () => {
|
// const handleCloseCard = () => {
|
||||||
@@ -36,5 +40,5 @@ export default function INVCheckCard(props: any) {
|
|||||||
// toast.success("card removed");
|
// toast.success("card removed");
|
||||||
// };
|
// };
|
||||||
|
|
||||||
return <InvTable columns={invColumns} data={laneData} info={props} />;
|
return <InvTable columns={invColumns} data={laneData} info={props.data} />;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ import {
|
|||||||
export default function OCPPage() {
|
export default function OCPPage() {
|
||||||
const { settings } = useSettingStore();
|
const { settings } = useSettingStore();
|
||||||
|
|
||||||
|
if (settings.length === 0) return;
|
||||||
let server = settings.filter((n) => n.name === "server");
|
let server = settings.filter((n) => n.name === "server");
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -73,7 +74,7 @@ export default function OCPPage() {
|
|||||||
<WrapperManualTrigger />
|
<WrapperManualTrigger />
|
||||||
</ResizablePanel>
|
</ResizablePanel>
|
||||||
)}
|
)}
|
||||||
{server[0].value === "localhost" && (
|
{server[0]?.value === "localhost" && (
|
||||||
<ResizablePanel className="max-h-[300px]">
|
<ResizablePanel className="max-h-[300px]">
|
||||||
<WrapperManualTrigger />
|
<WrapperManualTrigger />
|
||||||
</ResizablePanel>
|
</ResizablePanel>
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ export const SessionProvider = ({
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
fetchModules();
|
fetchModules();
|
||||||
fetchSettings();
|
fetchSettings();
|
||||||
|
console.log("settings grab ran");
|
||||||
fetchUserRoles();
|
fetchUserRoles();
|
||||||
fetchSubModules();
|
fetchSubModules();
|
||||||
}, []);
|
}, []);
|
||||||
|
|||||||
@@ -1,73 +1,208 @@
|
|||||||
import * as React from "react"
|
import * as React from "react"
|
||||||
import { ChevronLeft, ChevronRight } from "lucide-react"
|
import {
|
||||||
import { DayPicker } from "react-day-picker"
|
ChevronDownIcon,
|
||||||
|
ChevronLeftIcon,
|
||||||
|
ChevronRightIcon,
|
||||||
|
} from "lucide-react"
|
||||||
|
import { DayButton, DayPicker, getDefaultClassNames } from "react-day-picker"
|
||||||
|
|
||||||
import { cn } from "@/lib/utils"
|
import { cn } from "@/lib/utils"
|
||||||
import { buttonVariants } from "@/components/ui/button"
|
import { Button, buttonVariants } from "@/components/ui/button"
|
||||||
|
|
||||||
function Calendar({
|
function Calendar({
|
||||||
className,
|
className,
|
||||||
classNames,
|
classNames,
|
||||||
showOutsideDays = true,
|
showOutsideDays = true,
|
||||||
|
captionLayout = "label",
|
||||||
|
buttonVariant = "ghost",
|
||||||
|
formatters,
|
||||||
|
components,
|
||||||
...props
|
...props
|
||||||
}: React.ComponentProps<typeof DayPicker>) {
|
}: React.ComponentProps<typeof DayPicker> & {
|
||||||
|
buttonVariant?: React.ComponentProps<typeof Button>["variant"]
|
||||||
|
}) {
|
||||||
|
const defaultClassNames = getDefaultClassNames()
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<DayPicker
|
<DayPicker
|
||||||
showOutsideDays={showOutsideDays}
|
showOutsideDays={showOutsideDays}
|
||||||
className={cn("p-3", className)}
|
className={cn(
|
||||||
|
"bg-background group/calendar p-3 [--cell-size:--spacing(8)] [[data-slot=card-content]_&]:bg-transparent [[data-slot=popover-content]_&]:bg-transparent",
|
||||||
|
String.raw`rtl:**:[.rdp-button\_next>svg]:rotate-180`,
|
||||||
|
String.raw`rtl:**:[.rdp-button\_previous>svg]:rotate-180`,
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
captionLayout={captionLayout}
|
||||||
|
formatters={{
|
||||||
|
formatMonthDropdown: (date) =>
|
||||||
|
date.toLocaleString("default", { month: "short" }),
|
||||||
|
...formatters,
|
||||||
|
}}
|
||||||
classNames={{
|
classNames={{
|
||||||
months: "flex flex-col sm:flex-row gap-2",
|
root: cn("w-fit", defaultClassNames.root),
|
||||||
month: "flex flex-col gap-4",
|
months: cn(
|
||||||
caption: "flex justify-center pt-1 relative items-center w-full",
|
"flex gap-4 flex-col md:flex-row relative",
|
||||||
caption_label: "text-sm font-medium",
|
defaultClassNames.months
|
||||||
nav: "flex items-center gap-1",
|
|
||||||
nav_button: cn(
|
|
||||||
buttonVariants({ variant: "outline" }),
|
|
||||||
"size-7 bg-transparent p-0 opacity-50 hover:opacity-100"
|
|
||||||
),
|
),
|
||||||
nav_button_previous: "absolute left-1",
|
month: cn("flex flex-col w-full gap-4", defaultClassNames.month),
|
||||||
nav_button_next: "absolute right-1",
|
nav: cn(
|
||||||
table: "w-full border-collapse space-x-1",
|
"flex items-center gap-1 w-full absolute top-0 inset-x-0 justify-between",
|
||||||
head_row: "flex",
|
defaultClassNames.nav
|
||||||
head_cell:
|
),
|
||||||
"text-muted-foreground rounded-md w-8 font-normal text-[0.8rem]",
|
button_previous: cn(
|
||||||
row: "flex w-full mt-2",
|
buttonVariants({ variant: buttonVariant }),
|
||||||
cell: cn(
|
"size-(--cell-size) aria-disabled:opacity-50 p-0 select-none",
|
||||||
"relative p-0 text-center text-sm focus-within:relative focus-within:z-20 [&:has([aria-selected])]:bg-accent [&:has([aria-selected].day-range-end)]:rounded-r-md",
|
defaultClassNames.button_previous
|
||||||
props.mode === "range"
|
),
|
||||||
? "[&:has(>.day-range-end)]:rounded-r-md [&:has(>.day-range-start)]:rounded-l-md first:[&:has([aria-selected])]:rounded-l-md last:[&:has([aria-selected])]:rounded-r-md"
|
button_next: cn(
|
||||||
: "[&:has([aria-selected])]:rounded-md"
|
buttonVariants({ variant: buttonVariant }),
|
||||||
|
"size-(--cell-size) aria-disabled:opacity-50 p-0 select-none",
|
||||||
|
defaultClassNames.button_next
|
||||||
|
),
|
||||||
|
month_caption: cn(
|
||||||
|
"flex items-center justify-center h-(--cell-size) w-full px-(--cell-size)",
|
||||||
|
defaultClassNames.month_caption
|
||||||
|
),
|
||||||
|
dropdowns: cn(
|
||||||
|
"w-full flex items-center text-sm font-medium justify-center h-(--cell-size) gap-1.5",
|
||||||
|
defaultClassNames.dropdowns
|
||||||
|
),
|
||||||
|
dropdown_root: cn(
|
||||||
|
"relative has-focus:border-ring border border-input shadow-xs has-focus:ring-ring/50 has-focus:ring-[3px] rounded-md",
|
||||||
|
defaultClassNames.dropdown_root
|
||||||
|
),
|
||||||
|
dropdown: cn("absolute inset-0 opacity-0", defaultClassNames.dropdown),
|
||||||
|
caption_label: cn(
|
||||||
|
"select-none font-medium",
|
||||||
|
captionLayout === "label"
|
||||||
|
? "text-sm"
|
||||||
|
: "rounded-md pl-2 pr-1 flex items-center gap-1 text-sm h-8 [&>svg]:text-muted-foreground [&>svg]:size-3.5",
|
||||||
|
defaultClassNames.caption_label
|
||||||
|
),
|
||||||
|
table: "w-full border-collapse",
|
||||||
|
weekdays: cn("flex", defaultClassNames.weekdays),
|
||||||
|
weekday: cn(
|
||||||
|
"text-muted-foreground rounded-md flex-1 font-normal text-[0.8rem] select-none",
|
||||||
|
defaultClassNames.weekday
|
||||||
|
),
|
||||||
|
week: cn("flex w-full mt-2", defaultClassNames.week),
|
||||||
|
week_number_header: cn(
|
||||||
|
"select-none w-(--cell-size)",
|
||||||
|
defaultClassNames.week_number_header
|
||||||
|
),
|
||||||
|
week_number: cn(
|
||||||
|
"text-[0.8rem] select-none text-muted-foreground",
|
||||||
|
defaultClassNames.week_number
|
||||||
),
|
),
|
||||||
day: cn(
|
day: cn(
|
||||||
buttonVariants({ variant: "ghost" }),
|
"relative w-full h-full p-0 text-center [&:first-child[data-selected=true]_button]:rounded-l-md [&:last-child[data-selected=true]_button]:rounded-r-md group/day aspect-square select-none",
|
||||||
"size-8 p-0 font-normal aria-selected:opacity-100"
|
defaultClassNames.day
|
||||||
),
|
),
|
||||||
day_range_start:
|
range_start: cn(
|
||||||
"day-range-start aria-selected:bg-primary aria-selected:text-primary-foreground",
|
"rounded-l-md bg-accent",
|
||||||
day_range_end:
|
defaultClassNames.range_start
|
||||||
"day-range-end aria-selected:bg-primary aria-selected:text-primary-foreground",
|
),
|
||||||
day_selected:
|
range_middle: cn("rounded-none", defaultClassNames.range_middle),
|
||||||
"bg-primary text-primary-foreground hover:bg-primary hover:text-primary-foreground focus:bg-primary focus:text-primary-foreground",
|
range_end: cn("rounded-r-md bg-accent", defaultClassNames.range_end),
|
||||||
day_today: "bg-accent text-accent-foreground",
|
today: cn(
|
||||||
day_outside:
|
"bg-accent text-accent-foreground rounded-md data-[selected=true]:rounded-none",
|
||||||
"day-outside text-muted-foreground aria-selected:text-muted-foreground",
|
defaultClassNames.today
|
||||||
day_disabled: "text-muted-foreground opacity-50",
|
),
|
||||||
day_range_middle:
|
outside: cn(
|
||||||
"aria-selected:bg-accent aria-selected:text-accent-foreground",
|
"text-muted-foreground aria-selected:text-muted-foreground",
|
||||||
day_hidden: "invisible",
|
defaultClassNames.outside
|
||||||
|
),
|
||||||
|
disabled: cn(
|
||||||
|
"text-muted-foreground opacity-50",
|
||||||
|
defaultClassNames.disabled
|
||||||
|
),
|
||||||
|
hidden: cn("invisible", defaultClassNames.hidden),
|
||||||
...classNames,
|
...classNames,
|
||||||
}}
|
}}
|
||||||
components={{
|
components={{
|
||||||
IconLeft: ({ className, ...props }) => (
|
Root: ({ className, rootRef, ...props }) => {
|
||||||
<ChevronLeft className={cn("size-4", className)} {...props} />
|
return (
|
||||||
),
|
<div
|
||||||
IconRight: ({ className, ...props }) => (
|
data-slot="calendar"
|
||||||
<ChevronRight className={cn("size-4", className)} {...props} />
|
ref={rootRef}
|
||||||
),
|
className={cn(className)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
},
|
||||||
|
Chevron: ({ className, orientation, ...props }) => {
|
||||||
|
if (orientation === "left") {
|
||||||
|
return (
|
||||||
|
<ChevronLeftIcon className={cn("size-4", className)} {...props} />
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (orientation === "right") {
|
||||||
|
return (
|
||||||
|
<ChevronRightIcon
|
||||||
|
className={cn("size-4", className)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ChevronDownIcon className={cn("size-4", className)} {...props} />
|
||||||
|
)
|
||||||
|
},
|
||||||
|
DayButton: CalendarDayButton,
|
||||||
|
WeekNumber: ({ children, ...props }) => {
|
||||||
|
return (
|
||||||
|
<td {...props}>
|
||||||
|
<div className="flex size-(--cell-size) items-center justify-center text-center">
|
||||||
|
{children}
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
)
|
||||||
|
},
|
||||||
|
...components,
|
||||||
}}
|
}}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
export { Calendar }
|
function CalendarDayButton({
|
||||||
|
className,
|
||||||
|
day,
|
||||||
|
modifiers,
|
||||||
|
...props
|
||||||
|
}: React.ComponentProps<typeof DayButton>) {
|
||||||
|
const defaultClassNames = getDefaultClassNames()
|
||||||
|
|
||||||
|
const ref = React.useRef<HTMLButtonElement>(null)
|
||||||
|
React.useEffect(() => {
|
||||||
|
if (modifiers.focused) ref.current?.focus()
|
||||||
|
}, [modifiers.focused])
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Button
|
||||||
|
ref={ref}
|
||||||
|
variant="ghost"
|
||||||
|
size="icon"
|
||||||
|
data-day={day.date.toLocaleDateString()}
|
||||||
|
data-selected-single={
|
||||||
|
modifiers.selected &&
|
||||||
|
!modifiers.range_start &&
|
||||||
|
!modifiers.range_end &&
|
||||||
|
!modifiers.range_middle
|
||||||
|
}
|
||||||
|
data-range-start={modifiers.range_start}
|
||||||
|
data-range-end={modifiers.range_end}
|
||||||
|
data-range-middle={modifiers.range_middle}
|
||||||
|
className={cn(
|
||||||
|
"data-[selected-single=true]:bg-primary data-[selected-single=true]:text-primary-foreground data-[range-middle=true]:bg-accent data-[range-middle=true]:text-accent-foreground data-[range-start=true]:bg-primary data-[range-start=true]:text-primary-foreground data-[range-end=true]:bg-primary data-[range-end=true]:text-primary-foreground group-data-[focused=true]/day:border-ring group-data-[focused=true]/day:ring-ring/50 dark:hover:text-accent-foreground flex aspect-square size-auto w-full min-w-(--cell-size) flex-col gap-1 leading-none font-normal group-data-[focused=true]/day:relative group-data-[focused=true]/day:z-10 group-data-[focused=true]/day:ring-[3px] data-[range-end=true]:rounded-md data-[range-end=true]:rounded-r-md data-[range-middle=true]:rounded-none data-[range-start=true]:rounded-md data-[range-start=true]:rounded-l-md [&>span]:text-xs [&>span]:opacity-70",
|
||||||
|
defaultClassNames.day,
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export { Calendar, CalendarDayButton }
|
||||||
|
|||||||
@@ -19,7 +19,10 @@ function CardHeader({ className, ...props }: React.ComponentProps<"div">) {
|
|||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
data-slot="card-header"
|
data-slot="card-header"
|
||||||
className={cn("flex flex-col gap-1.5 px-6", className)}
|
className={cn(
|
||||||
|
"@container/card-header grid auto-rows-min grid-rows-[auto_auto] items-start gap-1.5 px-6 has-data-[slot=card-action]:grid-cols-[1fr_auto] [.border-b]:pb-6",
|
||||||
|
className
|
||||||
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
@@ -45,6 +48,19 @@ function CardDescription({ className, ...props }: React.ComponentProps<"div">) {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function CardAction({ className, ...props }: React.ComponentProps<"div">) {
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
data-slot="card-action"
|
||||||
|
className={cn(
|
||||||
|
"col-start-2 row-span-2 row-start-1 self-start justify-self-end",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
function CardContent({ className, ...props }: React.ComponentProps<"div">) {
|
function CardContent({ className, ...props }: React.ComponentProps<"div">) {
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
@@ -59,10 +75,18 @@ function CardFooter({ className, ...props }: React.ComponentProps<"div">) {
|
|||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
data-slot="card-footer"
|
data-slot="card-footer"
|
||||||
className={cn("flex items-center px-6", className)}
|
className={cn("flex items-center px-6 [.border-t]:pt-6", className)}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
export { Card, CardHeader, CardFooter, CardTitle, CardDescription, CardContent }
|
export {
|
||||||
|
Card,
|
||||||
|
CardHeader,
|
||||||
|
CardFooter,
|
||||||
|
CardTitle,
|
||||||
|
CardAction,
|
||||||
|
CardDescription,
|
||||||
|
CardContent,
|
||||||
|
}
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ function PopoverContent({
|
|||||||
align={align}
|
align={align}
|
||||||
sideOffset={sideOffset}
|
sideOffset={sideOffset}
|
||||||
className={cn(
|
className={cn(
|
||||||
"bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 w-72 rounded-md border p-4 shadow-md outline-hidden",
|
"bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 w-72 origin-(--radix-popover-content-transform-origin) rounded-md border p-4 shadow-md outline-hidden",
|
||||||
className
|
className
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
|
|||||||
@@ -1,9 +1,8 @@
|
|||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
import {create} from "zustand";
|
import { create } from "zustand";
|
||||||
|
|
||||||
interface SettingState {
|
interface SettingState {
|
||||||
settings: any[];
|
settings: any[];
|
||||||
|
|
||||||
fetchSettings: () => Promise<void>;
|
fetchSettings: () => Promise<void>;
|
||||||
setSettings: (settings: any[]) => void;
|
setSettings: (settings: any[]) => void;
|
||||||
}
|
}
|
||||||
@@ -13,17 +12,17 @@ interface FetchModulesResponse {
|
|||||||
|
|
||||||
export const useSettingStore = create<SettingState>()((set) => ({
|
export const useSettingStore = create<SettingState>()((set) => ({
|
||||||
settings: [],
|
settings: [],
|
||||||
setSettings: (settings) => set({settings}),
|
setSettings: (settings) => set({ settings }),
|
||||||
fetchSettings: async () => {
|
fetchSettings: 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 response = await axios.get(`/api/server/settings`, {});
|
const response = await axios.get(`/api/server/settings`, {});
|
||||||
const data: FetchModulesResponse = response.data; //await response.json();
|
const data: FetchModulesResponse = response.data; //await response.json();
|
||||||
//console.log(data);
|
//console.log(data);
|
||||||
set({settings: data.data});
|
set({ settings: data.data });
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Failed to fetch settings:", error);
|
console.error("Failed to fetch settings:", error);
|
||||||
set({settings: []});
|
set({ settings: [] });
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
}));
|
}));
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -1,5 +1,5 @@
|
|||||||
import ConsumeMaterial from "@/components/logistics/materialHelper/consumption/ConsumeMaterial";
|
import ConsumeMaterial from "@/components/logistics/materialHelper/consumption/ConsumeMaterial";
|
||||||
import PreformReturn from "@/components/logistics/materialHelper/consumption/PreformReturn";
|
import PreformReturn from "@/components/logistics/materialHelper/consumption/MaterialReturn";
|
||||||
import { createFileRoute } from "@tanstack/react-router";
|
import { createFileRoute } from "@tanstack/react-router";
|
||||||
|
|
||||||
export const Route = createFileRoute(
|
export const Route = createFileRoute(
|
||||||
|
|||||||
15
frontend/src/utils/formStuff/index.tsx
Normal file
15
frontend/src/utils/formStuff/index.tsx
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
import { createFormHook, createFormHookContexts } from "@tanstack/react-form";
|
||||||
|
import { InputField } from "./options/InputField";
|
||||||
|
import { SubmitButton } from "./options/submitButton";
|
||||||
|
import { SelectField } from "./options/selectorField";
|
||||||
|
import { CheckboxField } from "./options/checkbox";
|
||||||
|
|
||||||
|
export const { fieldContext, useFieldContext, formContext, useFormContext } =
|
||||||
|
createFormHookContexts();
|
||||||
|
|
||||||
|
export const { useAppForm } = createFormHook({
|
||||||
|
fieldComponents: { InputField, SelectField, CheckboxField },
|
||||||
|
formComponents: { SubmitButton },
|
||||||
|
fieldContext,
|
||||||
|
formContext,
|
||||||
|
});
|
||||||
16
frontend/src/utils/formStuff/options/FieldErrors.tsx
Normal file
16
frontend/src/utils/formStuff/options/FieldErrors.tsx
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
import { AnyFieldMeta } from "@tanstack/react-form";
|
||||||
|
import { ZodError } from "zod";
|
||||||
|
|
||||||
|
type FieldErrorsProps = {
|
||||||
|
meta: AnyFieldMeta;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const FieldErrors = ({ meta }: FieldErrorsProps) => {
|
||||||
|
if (!meta.isTouched) return null;
|
||||||
|
|
||||||
|
return meta.errors.map(({ message }: ZodError, index) => (
|
||||||
|
<p key={index} className="text-sm font-medium text-destructive">
|
||||||
|
{message}
|
||||||
|
</p>
|
||||||
|
));
|
||||||
|
};
|
||||||
@@ -1,32 +1,28 @@
|
|||||||
//import { Input } from "@/components/ui/input";
|
import { Label } from "@/components/ui/label";
|
||||||
//import { Label } from "@radix-ui/react-dropdown-menu";
|
import { useFieldContext } from "..";
|
||||||
|
import { Input } from "@/components/ui/input";
|
||||||
|
import { FieldErrors } from "./FieldErrors";
|
||||||
|
|
||||||
// export const FormInput = (form: any, label: string) => {
|
type InputFieldProps = {
|
||||||
// // <form.Field
|
label: string;
|
||||||
// // name="username"
|
inputType: string;
|
||||||
// // validators={{
|
required: boolean;
|
||||||
// // // We can choose between form-wide and field-specific validators
|
};
|
||||||
// // onChange: ({ value }) =>
|
export const InputField = ({ label, inputType, required }: InputFieldProps) => {
|
||||||
// // value.length > 3
|
const field = useFieldContext<any>();
|
||||||
// // ? undefined
|
|
||||||
// // : "Username must be longer than 3 letters",
|
return (
|
||||||
// // }}
|
<div className="grid gap-3">
|
||||||
// // children={(field) => {
|
<Label htmlFor={field.name}>{label}</Label>
|
||||||
// // return (
|
<Input
|
||||||
// // <div className="m-2 min-w-48 max-w-96 p-2">
|
id={field.name}
|
||||||
// // <Label htmlFor="username">{label}</Label>
|
value={field.state.value}
|
||||||
// // <Input
|
onChange={(e) => field.handleChange(e.target.value)}
|
||||||
// // name={field.name}
|
onBlur={field.handleBlur}
|
||||||
// // value={field.state.value}
|
type={inputType}
|
||||||
// // onBlur={field.handleBlur}
|
required={required}
|
||||||
// // //type="number"
|
/>
|
||||||
// // onChange={(e) => field.handleChange(e.target.value)}
|
<FieldErrors meta={field.state.meta} />
|
||||||
// // />
|
</div>
|
||||||
// // {field.state.meta.errors.length ? (
|
);
|
||||||
// // <em>{field.state.meta.errors.join(",")}</em>
|
};
|
||||||
// // ) : null}
|
|
||||||
// // </div>
|
|
||||||
// // );
|
|
||||||
// // }}
|
|
||||||
// // />;
|
|
||||||
// };
|
|
||||||
|
|||||||
34
frontend/src/utils/formStuff/options/checkbox.tsx
Normal file
34
frontend/src/utils/formStuff/options/checkbox.tsx
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
import { Checkbox } from "@radix-ui/react-checkbox";
|
||||||
|
import { useFieldContext } from "..";
|
||||||
|
import { Label } from "@/components/ui/label";
|
||||||
|
import { FieldErrors } from "./FieldErrors";
|
||||||
|
|
||||||
|
type CheckboxFieldProps = {
|
||||||
|
label: string;
|
||||||
|
description?: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const CheckboxField = ({ label }: CheckboxFieldProps) => {
|
||||||
|
const field = useFieldContext<boolean>();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<div className="m-2 p-2 flex flex-row">
|
||||||
|
<div>
|
||||||
|
<Label htmlFor="active">
|
||||||
|
<span>{label}</span>
|
||||||
|
</Label>
|
||||||
|
</div>
|
||||||
|
<Checkbox
|
||||||
|
id={field.name}
|
||||||
|
checked={field.state.value}
|
||||||
|
onCheckedChange={(checked) => {
|
||||||
|
field.handleChange(checked === true);
|
||||||
|
}}
|
||||||
|
onBlur={field.handleBlur}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<FieldErrors meta={field.state.meta} />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
57
frontend/src/utils/formStuff/options/selectorField.tsx
Normal file
57
frontend/src/utils/formStuff/options/selectorField.tsx
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
import { Label } from "@/components/ui/label";
|
||||||
|
import { useFieldContext } from "..";
|
||||||
|
import {
|
||||||
|
Select,
|
||||||
|
SelectContent,
|
||||||
|
SelectItem,
|
||||||
|
SelectTrigger,
|
||||||
|
SelectValue,
|
||||||
|
} from "@/components/ui/select";
|
||||||
|
import { FieldErrors } from "./FieldErrors";
|
||||||
|
|
||||||
|
type SelectOption = {
|
||||||
|
value: string;
|
||||||
|
label: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
type SelectFieldProps = {
|
||||||
|
label: string;
|
||||||
|
options: SelectOption[];
|
||||||
|
placeholder?: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const SelectField = ({
|
||||||
|
label,
|
||||||
|
options,
|
||||||
|
placeholder,
|
||||||
|
}: SelectFieldProps) => {
|
||||||
|
const field = useFieldContext<string>();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="grid gap-3">
|
||||||
|
<div className="grid gap-3">
|
||||||
|
<Label htmlFor={field.name}>{label}</Label>
|
||||||
|
<Select
|
||||||
|
value={field.state.value}
|
||||||
|
onValueChange={(value) => field.handleChange(value)}
|
||||||
|
>
|
||||||
|
<SelectTrigger
|
||||||
|
id={field.name}
|
||||||
|
onBlur={field.handleBlur}
|
||||||
|
className="w-[380px]"
|
||||||
|
>
|
||||||
|
<SelectValue placeholder={placeholder} />
|
||||||
|
</SelectTrigger>
|
||||||
|
<SelectContent>
|
||||||
|
{options.map((option) => (
|
||||||
|
<SelectItem key={option.value} value={option.value}>
|
||||||
|
{option.label}
|
||||||
|
</SelectItem>
|
||||||
|
))}
|
||||||
|
</SelectContent>
|
||||||
|
</Select>
|
||||||
|
</div>
|
||||||
|
<FieldErrors meta={field.state.meta} />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
24
frontend/src/utils/formStuff/options/submitButton.tsx
Normal file
24
frontend/src/utils/formStuff/options/submitButton.tsx
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
import { useStore } from "@tanstack/react-form";
|
||||||
|
import { useFormContext } from "..";
|
||||||
|
import { Button } from "@/components/ui/button";
|
||||||
|
|
||||||
|
type SubmitButtonProps = {
|
||||||
|
children: React.ReactNode;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const SubmitButton = ({ children }: SubmitButtonProps) => {
|
||||||
|
const form = useFormContext();
|
||||||
|
|
||||||
|
const [isSubmitting] = useStore(form.store, (state) => [
|
||||||
|
state.isSubmitting,
|
||||||
|
state.canSubmit,
|
||||||
|
]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="">
|
||||||
|
<Button type="submit" disabled={isSubmitting}>
|
||||||
|
{children}
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -13,7 +13,7 @@ export function getinventoryCheck(data: any) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const fetchStockSilo = async (info: any) => {
|
const fetchStockSilo = async (info: any) => {
|
||||||
console.log(info);
|
//console.log("What tpye of info:", info);
|
||||||
const { data } = await axios.post(`/api/logistics/cyclecountcheck`, {
|
const { data } = await axios.post(`/api/logistics/cyclecountcheck`, {
|
||||||
age: info.age ? parseInt(info.age) : null,
|
age: info.age ? parseInt(info.age) : null,
|
||||||
type: "",
|
type: "",
|
||||||
|
|||||||
23
frontend/src/utils/querys/logistics/machineConnected.tsx
Normal file
23
frontend/src/utils/querys/logistics/machineConnected.tsx
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
import { queryOptions } from "@tanstack/react-query";
|
||||||
|
import axios from "axios";
|
||||||
|
|
||||||
|
export function getMachineConnected(siloCon: any) {
|
||||||
|
return queryOptions({
|
||||||
|
queryKey: [`siloConnectionAttached-${siloCon.siloID}`],
|
||||||
|
queryFn: () => fetchStockSilo(siloCon),
|
||||||
|
//enabled:
|
||||||
|
//staleTime: 1000,
|
||||||
|
//refetchInterval: 60 * 1000,
|
||||||
|
refetchOnWindowFocus: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const fetchStockSilo = async (siloCon: any) => {
|
||||||
|
const { data } = await axios.post(`/api/logistics/siloconnection`, {
|
||||||
|
siloID: siloCon.siloID,
|
||||||
|
connectionType: siloCon.connectionType,
|
||||||
|
});
|
||||||
|
// if we are not localhost ignore the devDir setting.
|
||||||
|
//const url: string = window.location.host.split(":")[0];
|
||||||
|
return data.data ?? [];
|
||||||
|
};
|
||||||
23
frontend/src/utils/querys/logistics/notConnected.tsx
Normal file
23
frontend/src/utils/querys/logistics/notConnected.tsx
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
import { queryOptions } from "@tanstack/react-query";
|
||||||
|
import axios from "axios";
|
||||||
|
|
||||||
|
export function getMachineNotConnected(siloCon: any) {
|
||||||
|
return queryOptions({
|
||||||
|
queryKey: [`siloConnectionNotConnected-${siloCon.siloID}`],
|
||||||
|
queryFn: () => fetchStockSilo(siloCon),
|
||||||
|
//enabled:
|
||||||
|
//staleTime: 1000,
|
||||||
|
//refetchInterval: 60 * 1000,
|
||||||
|
refetchOnWindowFocus: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const fetchStockSilo = async (siloCon: any) => {
|
||||||
|
const { data } = await axios.post(`/api/logistics/siloconnection`, {
|
||||||
|
siloID: siloCon.siloID,
|
||||||
|
connectionType: siloCon.connectionType,
|
||||||
|
});
|
||||||
|
// if we are not localhost ignore the devDir setting.
|
||||||
|
//const url: string = window.location.host.split(":")[0];
|
||||||
|
return data.data ?? [];
|
||||||
|
};
|
||||||
1641
package-lock.json
generated
1641
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
54
package.json
54
package.json
@@ -36,7 +36,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"admConfig": {
|
"admConfig": {
|
||||||
"build": 426,
|
"build": 429,
|
||||||
"oldBuild": "backend-0.1.3.zip"
|
"oldBuild": "backend-0.1.3.zip"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
@@ -45,52 +45,52 @@
|
|||||||
"@types/fs-extra": "^11.0.4",
|
"@types/fs-extra": "^11.0.4",
|
||||||
"@types/js-cookie": "^3.0.6",
|
"@types/js-cookie": "^3.0.6",
|
||||||
"@types/mssql": "^9.1.7",
|
"@types/mssql": "^9.1.7",
|
||||||
"@types/node": "^22.13.11",
|
"@types/node": "^24.0.3",
|
||||||
"@types/node-cron": "^3.0.11",
|
"@types/node-cron": "^3.0.11",
|
||||||
"@types/nodemailer": "^6.4.17",
|
"@types/nodemailer": "^6.4.17",
|
||||||
"@types/pg": "^8.11.11",
|
"@types/pg": "^8.15.4",
|
||||||
"@types/ws": "^8.18.0",
|
"@types/ws": "^8.18.1",
|
||||||
"concurrently": "^9.1.2",
|
"concurrently": "^9.1.2",
|
||||||
"cz-conventional-changelog": "^3.3.0",
|
"cz-conventional-changelog": "^3.3.0",
|
||||||
"standard-version": "^9.5.0",
|
"standard-version": "^9.5.0",
|
||||||
"tsx": "^4.19.3",
|
"tsx": "^4.20.3",
|
||||||
"typescript": "^5.8.2"
|
"typescript": "^5.8.3"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@dotenvx/dotenvx": "^1.39.0",
|
"@dotenvx/dotenvx": "^1.45.1",
|
||||||
"@hono/node-server": "^1.14.0",
|
"@hono/node-server": "^1.14.4",
|
||||||
"@hono/zod-openapi": "^0.19.2",
|
"@hono/zod-openapi": "^0.19.8",
|
||||||
"@scalar/hono-api-reference": "^0.7.2",
|
"@scalar/hono-api-reference": "^0.9.5",
|
||||||
"@tanstack/react-form": "^1.2.1",
|
"@tanstack/react-form": "^1.12.3",
|
||||||
"@tanstack/react-table": "^8.21.2",
|
"@tanstack/react-table": "^8.21.3",
|
||||||
"@types/jsonwebtoken": "^9.0.9",
|
"@types/jsonwebtoken": "^9.0.10",
|
||||||
"@types/nodemailer-express-handlebars": "^4.0.5",
|
"@types/nodemailer-express-handlebars": "^4.0.5",
|
||||||
"adm-zip": "^0.5.16",
|
"adm-zip": "^0.5.16",
|
||||||
"axios": "^1.8.4",
|
"axios": "^1.10.0",
|
||||||
"bcryptjs": "^3.0.2",
|
"bcryptjs": "^3.0.2",
|
||||||
"croner": "^9.0.0",
|
"croner": "^9.1.0",
|
||||||
"date-fns": "^4.1.0",
|
"date-fns": "^4.1.0",
|
||||||
"date-fns-tz": "^3.2.0",
|
"date-fns-tz": "^3.2.0",
|
||||||
"drizzle-kit": "^0.30.5",
|
"drizzle-kit": "^0.31.1",
|
||||||
"drizzle-orm": "^0.41.0",
|
"drizzle-orm": "^0.44.2",
|
||||||
"drizzle-zod": "^0.7.0",
|
"drizzle-zod": "^0.8.2",
|
||||||
"excel-date-to-js": "^1.1.5",
|
"excel-date-to-js": "^1.1.5",
|
||||||
"fast-xml-parser": "^5.0.9",
|
"fast-xml-parser": "^5.2.5",
|
||||||
"fs-extra": "^11.3.0",
|
"fs-extra": "^11.3.0",
|
||||||
"jsonwebtoken": "^9.0.2",
|
"jsonwebtoken": "^9.0.2",
|
||||||
"mssql": "^11.0.1",
|
"mssql": "^11.0.1",
|
||||||
"nodemailer": "^6.10.0",
|
"nodemailer": "^7.0.3",
|
||||||
"nodemailer-express-handlebars": "^7.0.0",
|
"nodemailer-express-handlebars": "^7.0.0",
|
||||||
"pg": "^8.14.1",
|
"pg": "^8.16.2",
|
||||||
"pino": "^9.6.0",
|
"pino": "^9.7.0",
|
||||||
"pino-abstract-transport": "^2.0.0",
|
"pino-abstract-transport": "^2.0.0",
|
||||||
"pino-pretty": "^13.0.0",
|
"pino-pretty": "^13.0.0",
|
||||||
"postgres": "^3.4.5",
|
"postgres": "^3.4.7",
|
||||||
"react-resizable-panels": "^2.1.7",
|
"react-resizable-panels": "^3.0.3",
|
||||||
"rimraf": "^6.0.1",
|
"rimraf": "^6.0.1",
|
||||||
"st-ethernet-ip": "^2.7.3",
|
"st-ethernet-ip": "^2.7.5",
|
||||||
"ws": "^8.18.1",
|
"ws": "^8.18.2",
|
||||||
"xlsx": "^0.18.5",
|
"xlsx": "^0.18.5",
|
||||||
"zod": "^3.24.2"
|
"zod": "^3.25.67"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
92
server/globalUtils/runProdApi.ts
Normal file
92
server/globalUtils/runProdApi.ts
Normal file
@@ -0,0 +1,92 @@
|
|||||||
|
import axios from "axios";
|
||||||
|
import { prodEndpointCreation } from "./createUrl.js";
|
||||||
|
import { tryCatch } from "./tryCatch.js";
|
||||||
|
import { createLog } from "../services/logger/logger.js";
|
||||||
|
|
||||||
|
type bodyData = any;
|
||||||
|
|
||||||
|
type Data = {
|
||||||
|
endpoint: string;
|
||||||
|
data: bodyData[];
|
||||||
|
};
|
||||||
|
export const runProdApi = async (data: Data) => {
|
||||||
|
/**
|
||||||
|
* Detachs a silo
|
||||||
|
*/
|
||||||
|
|
||||||
|
let url = await prodEndpointCreation(data.endpoint);
|
||||||
|
|
||||||
|
const { data: d, error } = await tryCatch(
|
||||||
|
axios.post(url, data.data[0], {
|
||||||
|
headers: {
|
||||||
|
"X-API-Key": process.env.TEC_API_KEY || "",
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
},
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
let e = error as any;
|
||||||
|
if (e) {
|
||||||
|
//console.log(e.response);
|
||||||
|
if (e.status === 401) {
|
||||||
|
createLog(
|
||||||
|
"error",
|
||||||
|
"lst",
|
||||||
|
"logistics",
|
||||||
|
`Not autorized: ${JSON.stringify(e.response?.data)}`
|
||||||
|
);
|
||||||
|
const data = {
|
||||||
|
success: false,
|
||||||
|
message: `Not autorized: ${JSON.stringify(e.response?.data)}`,
|
||||||
|
data: {
|
||||||
|
status: e.response?.status,
|
||||||
|
statusText: e.response?.statusText,
|
||||||
|
data: e.response?.data,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
return data;
|
||||||
|
} else {
|
||||||
|
createLog(
|
||||||
|
"error",
|
||||||
|
"lst",
|
||||||
|
"logistics",
|
||||||
|
`There was an error processing the endpoint: ${JSON.stringify(
|
||||||
|
e.response?.data
|
||||||
|
)}`
|
||||||
|
);
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
message: `There was an error processing the endpoint: ${JSON.stringify(
|
||||||
|
e.response?.data
|
||||||
|
)}`,
|
||||||
|
data: {
|
||||||
|
status: e.response?.status,
|
||||||
|
statusText: e.response?.statusText,
|
||||||
|
data: e.response?.data,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (d?.status !== 200) {
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
message: "Error processing endpoint",
|
||||||
|
data: {
|
||||||
|
status: d?.status,
|
||||||
|
statusText: d?.statusText,
|
||||||
|
data: d?.data,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
return {
|
||||||
|
success: true,
|
||||||
|
message: "Endpoint was processed",
|
||||||
|
data: {
|
||||||
|
status: d.status,
|
||||||
|
statusText: d.statusText,
|
||||||
|
data: d.data,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -41,15 +41,21 @@ export const postAdjustment = async (data: any, prod: any) => {
|
|||||||
|
|
||||||
const { data: silo, error } = await tryCatch(
|
const { data: silo, error } = await tryCatch(
|
||||||
axios.post(url, siloAdjustment, {
|
axios.post(url, siloAdjustment, {
|
||||||
headers: { Authorization: `Basic ${prod}` },
|
headers: {
|
||||||
|
"X-API-Key": process.env.TEC_API_KEY || "",
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
},
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
let e = error as any;
|
let e = error as any;
|
||||||
if (e) {
|
if (e) {
|
||||||
|
console.log(e.response);
|
||||||
if (e.status === 401) {
|
if (e.status === 401) {
|
||||||
const data = {
|
const data = {
|
||||||
success: false,
|
success: false,
|
||||||
message: "Incorrect alpla prod password.",
|
message: `There was error posting the data: ${JSON.stringify(
|
||||||
|
e.response?.data
|
||||||
|
)}`,
|
||||||
data: {
|
data: {
|
||||||
status: e.response?.status,
|
status: e.response?.status,
|
||||||
statusText: e.response?.statusText,
|
statusText: e.response?.statusText,
|
||||||
|
|||||||
@@ -0,0 +1,43 @@
|
|||||||
|
import { runProdApi } from "../../../../globalUtils/runProdApi.js";
|
||||||
|
import { tryCatch } from "../../../../globalUtils/tryCatch.js";
|
||||||
|
|
||||||
|
export const attachSilo = async (data: any) => {
|
||||||
|
/**
|
||||||
|
* Detachs a silo
|
||||||
|
*/
|
||||||
|
|
||||||
|
const detachData = {
|
||||||
|
endpoint: "/public/v1.0/IssueMaterial/AssignSiloToMachine",
|
||||||
|
data: [
|
||||||
|
{
|
||||||
|
laneId: data.laneId,
|
||||||
|
machineId: data.machineId,
|
||||||
|
productionLotId: data.productionLotId,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
const { data: d, error } = await tryCatch(runProdApi(detachData));
|
||||||
|
|
||||||
|
if (error) {
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
message: "Error processing attachingSilo data",
|
||||||
|
data: error,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!d.success) {
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
message: "Error processing silo attach data",
|
||||||
|
data: d.message,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
success: true,
|
||||||
|
message: "silo attach was completed",
|
||||||
|
data: d.data,
|
||||||
|
};
|
||||||
|
};
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
import { runProdApi } from "../../../../globalUtils/runProdApi.js";
|
||||||
|
import { tryCatch } from "../../../../globalUtils/tryCatch.js";
|
||||||
|
|
||||||
|
export const detachSilo = async (data: any) => {
|
||||||
|
/**
|
||||||
|
* Detachs a silo
|
||||||
|
*/
|
||||||
|
|
||||||
|
const detachData = {
|
||||||
|
endpoint: "/public/v1.0/IssueMaterial/DetachSiloFromMachine",
|
||||||
|
data: [
|
||||||
|
{
|
||||||
|
laneId: data.laneId,
|
||||||
|
machineId: data.machineId,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
const { data: d, error } = await tryCatch(runProdApi(detachData));
|
||||||
|
|
||||||
|
if (error) {
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
message: "Error processing detach data",
|
||||||
|
data: error,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!d.success) {
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
message: "Error processing detach data",
|
||||||
|
data: d.message,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
success: true,
|
||||||
|
message: "Detach was completed",
|
||||||
|
data: d.data,
|
||||||
|
};
|
||||||
|
};
|
||||||
@@ -0,0 +1,63 @@
|
|||||||
|
import { tryCatch } from "../../../../globalUtils/tryCatch.js";
|
||||||
|
import { createLog } from "../../../logger/logger.js";
|
||||||
|
import { query } from "../../../sqlServer/prodSqlServer.js";
|
||||||
|
import {
|
||||||
|
connectedToMachine,
|
||||||
|
notconnectedToMachine,
|
||||||
|
} from "../../../sqlServer/querys/silo/connectionCheck.js";
|
||||||
|
|
||||||
|
type Data = {
|
||||||
|
siloID: string;
|
||||||
|
connectionType: string;
|
||||||
|
};
|
||||||
|
export const siloConnectionType = async (data: Data) => {
|
||||||
|
/**
|
||||||
|
* Will return the machines that are attached or detached based on the silo and connection type
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (!data) {
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
message: "Missing mandatory data",
|
||||||
|
data: [{ error: "Missing siloId or ConnectionType" }],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// change the silo id to the correct one
|
||||||
|
let newQuery = "";
|
||||||
|
|
||||||
|
if (data.connectionType === "connected") {
|
||||||
|
newQuery = connectedToMachine.replace("[siloID]", data.siloID);
|
||||||
|
} else {
|
||||||
|
newQuery = notconnectedToMachine.replace("[siloID]", data.siloID);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get the silo data
|
||||||
|
*/
|
||||||
|
const { data: s, error } = (await tryCatch(
|
||||||
|
query(newQuery, "Silo connection check")
|
||||||
|
)) as any;
|
||||||
|
|
||||||
|
if (error) {
|
||||||
|
createLog(
|
||||||
|
"error",
|
||||||
|
"lst",
|
||||||
|
"logistics",
|
||||||
|
`There was an error getting the silo connection data: ${JSON.stringify(
|
||||||
|
error
|
||||||
|
)}`
|
||||||
|
);
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
message: "There was an error getting the silo connection data.",
|
||||||
|
data: error,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
success: true,
|
||||||
|
message: `silo ${data.connectionType} data`,
|
||||||
|
data: s.data,
|
||||||
|
};
|
||||||
|
};
|
||||||
@@ -21,6 +21,9 @@ import intervalChecks from "./route/getActiveLogistics.js";
|
|||||||
import getActiveLanes from "./route/getActiveLanes.js";
|
import getActiveLanes from "./route/getActiveLanes.js";
|
||||||
import removeAsNonReable from "./route/removeAsNonReusable.js";
|
import removeAsNonReable from "./route/removeAsNonReusable.js";
|
||||||
import getSSCC from "./route/getSSCCNumber.js";
|
import getSSCC from "./route/getSSCCNumber.js";
|
||||||
|
import getConnectionType from "./route/getSiloConnectionData.js";
|
||||||
|
import detachSilo from "./route/detachSilo.js";
|
||||||
|
import attachSilo from "./route/attachSilo.js";
|
||||||
|
|
||||||
const app = new OpenAPIHono();
|
const app = new OpenAPIHono();
|
||||||
|
|
||||||
@@ -33,6 +36,9 @@ const routes = [
|
|||||||
postComment,
|
postComment,
|
||||||
getStockSilo,
|
getStockSilo,
|
||||||
getSiloAdjustments,
|
getSiloAdjustments,
|
||||||
|
getConnectionType,
|
||||||
|
detachSilo,
|
||||||
|
attachSilo,
|
||||||
//lanes
|
//lanes
|
||||||
getCycleCountCheck,
|
getCycleCountCheck,
|
||||||
//warehouse
|
//warehouse
|
||||||
|
|||||||
65
server/services/logistics/route/attachSilo.ts
Normal file
65
server/services/logistics/route/attachSilo.ts
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
import { createRoute, OpenAPIHono, z } from "@hono/zod-openapi";
|
||||||
|
import { responses } from "../../../globalUtils/routeDefs/responses.js";
|
||||||
|
import { tryCatch } from "../../../globalUtils/tryCatch.js";
|
||||||
|
import { apiHit } from "../../../globalUtils/apiHits.js";
|
||||||
|
import { attachSilo } from "../controller/siloAttachments/attachSilo.js";
|
||||||
|
|
||||||
|
const app = new OpenAPIHono();
|
||||||
|
|
||||||
|
// const Body = z
|
||||||
|
// .object({
|
||||||
|
// age: z.number().optional().openapi({ example: 90 }),
|
||||||
|
// //email: z.string().optional().openapi({example: "s.smith@example.com"}),
|
||||||
|
// type: z.string().optional().openapi({ example: "fg" }),
|
||||||
|
// })
|
||||||
|
// .openapi("User");
|
||||||
|
app.openapi(
|
||||||
|
createRoute({
|
||||||
|
tags: ["logistics"],
|
||||||
|
summary: "Returns all the silo connection based on connection type",
|
||||||
|
method: "post",
|
||||||
|
path: "/attachsilo",
|
||||||
|
// request: {
|
||||||
|
// body: {
|
||||||
|
// content: {
|
||||||
|
// "application/json": { schema: Body },
|
||||||
|
// },
|
||||||
|
// },
|
||||||
|
// },
|
||||||
|
// description:
|
||||||
|
// "Provided a running number and lot number you can consume material.",
|
||||||
|
responses: responses(),
|
||||||
|
}),
|
||||||
|
async (c: any) => {
|
||||||
|
apiHit(c, { endpoint: "/attachSilo" });
|
||||||
|
|
||||||
|
const { data: body, error: bodyError } = await tryCatch(c.req.json());
|
||||||
|
|
||||||
|
if (bodyError) {
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
message: "Missing mandatory data",
|
||||||
|
data: [{ error: "Missing Data" }],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
let b = body as any;
|
||||||
|
|
||||||
|
const { data: silo, error } = await tryCatch(attachSilo(b));
|
||||||
|
|
||||||
|
if (error) {
|
||||||
|
return c.json({
|
||||||
|
success: false,
|
||||||
|
message: "Error detaching silo.",
|
||||||
|
data: error,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.json({
|
||||||
|
success: silo.success,
|
||||||
|
message: silo.message,
|
||||||
|
data: silo.data,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
);
|
||||||
|
export default app;
|
||||||
67
server/services/logistics/route/detachSilo.ts
Normal file
67
server/services/logistics/route/detachSilo.ts
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
import { createRoute, OpenAPIHono, z } from "@hono/zod-openapi";
|
||||||
|
import { responses } from "../../../globalUtils/routeDefs/responses.js";
|
||||||
|
import { tryCatch } from "../../../globalUtils/tryCatch.js";
|
||||||
|
import { apiHit } from "../../../globalUtils/apiHits.js";
|
||||||
|
|
||||||
|
import { siloConnectionType } from "../controller/siloAttachments/siloConnectionData.js";
|
||||||
|
import { detachSilo } from "../controller/siloAttachments/detachSilo.js";
|
||||||
|
|
||||||
|
const app = new OpenAPIHono();
|
||||||
|
|
||||||
|
// const Body = z
|
||||||
|
// .object({
|
||||||
|
// age: z.number().optional().openapi({ example: 90 }),
|
||||||
|
// //email: z.string().optional().openapi({example: "s.smith@example.com"}),
|
||||||
|
// type: z.string().optional().openapi({ example: "fg" }),
|
||||||
|
// })
|
||||||
|
// .openapi("User");
|
||||||
|
app.openapi(
|
||||||
|
createRoute({
|
||||||
|
tags: ["logistics"],
|
||||||
|
summary: "Returns all the silo connection based on connection type",
|
||||||
|
method: "post",
|
||||||
|
path: "/detachsilo",
|
||||||
|
// request: {
|
||||||
|
// body: {
|
||||||
|
// content: {
|
||||||
|
// "application/json": { schema: Body },
|
||||||
|
// },
|
||||||
|
// },
|
||||||
|
// },
|
||||||
|
// description:
|
||||||
|
// "Provided a running number and lot number you can consume material.",
|
||||||
|
responses: responses(),
|
||||||
|
}),
|
||||||
|
async (c: any) => {
|
||||||
|
apiHit(c, { endpoint: "/attachSilo" });
|
||||||
|
|
||||||
|
const { data: body, error: bodyError } = await tryCatch(c.req.json());
|
||||||
|
|
||||||
|
if (bodyError) {
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
message: "Missing mandatory data",
|
||||||
|
data: [{ error: "Missing Data" }],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
let b = body as any;
|
||||||
|
|
||||||
|
const { data: silo, error } = await tryCatch(detachSilo(b));
|
||||||
|
|
||||||
|
if (error) {
|
||||||
|
return c.json({
|
||||||
|
success: false,
|
||||||
|
message: "Error detaching silo.",
|
||||||
|
data: error,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.json({
|
||||||
|
success: silo.success,
|
||||||
|
message: silo.message,
|
||||||
|
data: silo.data,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
);
|
||||||
|
export default app;
|
||||||
66
server/services/logistics/route/getSiloConnectionData.ts
Normal file
66
server/services/logistics/route/getSiloConnectionData.ts
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
import { createRoute, OpenAPIHono, z } from "@hono/zod-openapi";
|
||||||
|
import { responses } from "../../../globalUtils/routeDefs/responses.js";
|
||||||
|
import { tryCatch } from "../../../globalUtils/tryCatch.js";
|
||||||
|
import { apiHit } from "../../../globalUtils/apiHits.js";
|
||||||
|
|
||||||
|
import { siloConnectionType } from "../controller/siloAttachments/siloConnectionData.js";
|
||||||
|
|
||||||
|
const app = new OpenAPIHono();
|
||||||
|
|
||||||
|
// const Body = z
|
||||||
|
// .object({
|
||||||
|
// age: z.number().optional().openapi({ example: 90 }),
|
||||||
|
// //email: z.string().optional().openapi({example: "s.smith@example.com"}),
|
||||||
|
// type: z.string().optional().openapi({ example: "fg" }),
|
||||||
|
// })
|
||||||
|
// .openapi("User");
|
||||||
|
app.openapi(
|
||||||
|
createRoute({
|
||||||
|
tags: ["logistics"],
|
||||||
|
summary: "Returns all the silo connection based on connection type",
|
||||||
|
method: "post",
|
||||||
|
path: "/siloconnection",
|
||||||
|
// request: {
|
||||||
|
// body: {
|
||||||
|
// content: {
|
||||||
|
// "application/json": { schema: Body },
|
||||||
|
// },
|
||||||
|
// },
|
||||||
|
// },
|
||||||
|
// description:
|
||||||
|
// "Provided a running number and lot number you can consume material.",
|
||||||
|
responses: responses(),
|
||||||
|
}),
|
||||||
|
async (c: any) => {
|
||||||
|
apiHit(c, { endpoint: "/siloconnection" });
|
||||||
|
|
||||||
|
const { data: body, error: bodyError } = await tryCatch(c.req.json());
|
||||||
|
|
||||||
|
if (bodyError) {
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
message: "Missing mandatory data",
|
||||||
|
data: [{ error: "Missing Data" }],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
let b = body as any;
|
||||||
|
|
||||||
|
const { data: silo, error } = await tryCatch(siloConnectionType(b));
|
||||||
|
|
||||||
|
if (error) {
|
||||||
|
return c.json({
|
||||||
|
success: false,
|
||||||
|
message: "Error getting silo connection data.",
|
||||||
|
data: error,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.json({
|
||||||
|
success: silo.success,
|
||||||
|
message: silo.message,
|
||||||
|
data: silo.data,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
);
|
||||||
|
export default app;
|
||||||
@@ -224,7 +224,7 @@
|
|||||||
"active": true,
|
"active": true,
|
||||||
"serverLoc": "E:\\LST\\lstv2",
|
"serverLoc": "E:\\LST\\lstv2",
|
||||||
"oldVersion": "E:\\LST\\lst_backend",
|
"oldVersion": "E:\\LST\\lst_backend",
|
||||||
"shippingHours": "[{\"early\": \"07:00\", \"late\": \"11:00\"}]",
|
"shippingHours": "[{\"early\": \"13:00\", \"late\": \"15:00\"}]",
|
||||||
"tiPostTime": "[{\"from\": \"24\", \"to\": \"24\"}]",
|
"tiPostTime": "[{\"from\": \"24\", \"to\": \"24\"}]",
|
||||||
"otherSettings": [{ "specialInstructions": "" }]
|
"otherSettings": [{ "specialInstructions": "" }]
|
||||||
},
|
},
|
||||||
|
|||||||
42
server/services/sqlServer/querys/silo/connectionCheck.ts
Normal file
42
server/services/sqlServer/querys/silo/connectionCheck.ts
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
export const notconnectedToMachine = `
|
||||||
|
select distinct HumanReadableId as machineId
|
||||||
|
,Location as location
|
||||||
|
,name
|
||||||
|
--,[SiloHumanReadableId]
|
||||||
|
from [test1_AlplaPROD2.0_Read].[masterData].[Machine] (nolock) m
|
||||||
|
|
||||||
|
left join
|
||||||
|
[test1_AlplaPROD2.0_Read].[issueMaterial].[SiloAssignment] (nolock) s
|
||||||
|
on s.MachineId = m.id
|
||||||
|
|
||||||
|
|
||||||
|
where m.id not in (
|
||||||
|
SELECT
|
||||||
|
[MachineId]
|
||||||
|
|
||||||
|
FROM [test1_AlplaPROD2.0_Read].[issueMaterial].[SiloAssignment]
|
||||||
|
|
||||||
|
where [SiloHumanReadableId] = [siloID]
|
||||||
|
)
|
||||||
|
|
||||||
|
and name not like '%REWORK%'
|
||||||
|
`;
|
||||||
|
|
||||||
|
export const connectedToMachine = `
|
||||||
|
SELECT
|
||||||
|
[SiloHumanReadableId]
|
||||||
|
,[SiloDescription]
|
||||||
|
,[MaterialHumanReadableId]
|
||||||
|
,[MaterialDescription]
|
||||||
|
,[ConnectionDate]
|
||||||
|
,m.HumanReadableId as machineId
|
||||||
|
,m.Location as location
|
||||||
|
,m.Name as name
|
||||||
|
FROM [test1_AlplaPROD2.0_Read].[issueMaterial].[SiloAssignment] s
|
||||||
|
|
||||||
|
left join
|
||||||
|
[test1_AlplaPROD2.0_Read].[masterData].[Machine] m
|
||||||
|
on m.id = s.MachineId
|
||||||
|
|
||||||
|
where [SiloHumanReadableId] = [siloID]
|
||||||
|
`;
|
||||||
Reference in New Issue
Block a user