Compare commits
16 Commits
9baeb1ceff
...
2a6af066bc
| Author | SHA1 | Date | |
|---|---|---|---|
| 2a6af066bc | |||
| acd89d926c | |||
| bb20046890 | |||
| ae7ea2bb90 | |||
| 17773e9a23 | |||
| 25785703db | |||
| 087d14c585 | |||
| 328b61f6cc | |||
| c02d289b80 | |||
| e0e7e03d37 | |||
| 5fb7b5c59e | |||
| aabcf12bee | |||
| f0a5d6e949 | |||
| bdeea6bd1a | |||
| 89ace4343c | |||
| 242b90c75a |
23
database/migrations/0049_certain_tarot.sql
Normal file
23
database/migrations/0049_certain_tarot.sql
Normal file
@@ -0,0 +1,23 @@
|
||||
CREATE TABLE "qualityRequest" (
|
||||
"request_id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
|
||||
"article" numeric,
|
||||
"description" text,
|
||||
"runningNr" text,
|
||||
"lotNr" numeric,
|
||||
"warehouseAtRequest" text,
|
||||
"locationAtRequest" text,
|
||||
"warehouseMovedTo" text,
|
||||
"locationMovedTo" text,
|
||||
"durationToMove" numeric,
|
||||
"locationDropOff" text,
|
||||
"palletStatus" numeric,
|
||||
"palletStatusText" text,
|
||||
"palletRequest" numeric,
|
||||
"add_date" timestamp DEFAULT now(),
|
||||
"add_user" text DEFAULT 'LST',
|
||||
"upd_date" timestamp DEFAULT now(),
|
||||
"upd_user" text DEFAULT 'LST'
|
||||
);
|
||||
--> statement-breakpoint
|
||||
ALTER TABLE "rfidReaders" ADD COLUMN "lastTagScanned" text;--> statement-breakpoint
|
||||
ALTER TABLE "logs" DROP COLUMN "checkedAt";
|
||||
1699
database/migrations/meta/0049_snapshot.json
Normal file
1699
database/migrations/meta/0049_snapshot.json
Normal file
File diff suppressed because it is too large
Load Diff
@@ -344,6 +344,13 @@
|
||||
"when": 1743946411873,
|
||||
"tag": "0048_tearful_bushwacker",
|
||||
"breakpoints": true
|
||||
},
|
||||
{
|
||||
"idx": 49,
|
||||
"version": "7",
|
||||
"when": 1744649552936,
|
||||
"tag": "0049_certain_tarot",
|
||||
"breakpoints": true
|
||||
}
|
||||
]
|
||||
}
|
||||
47
database/schema/qualityRequest.ts
Normal file
47
database/schema/qualityRequest.ts
Normal file
@@ -0,0 +1,47 @@
|
||||
import {
|
||||
text,
|
||||
pgTable,
|
||||
numeric,
|
||||
index,
|
||||
timestamp,
|
||||
boolean,
|
||||
uuid,
|
||||
uniqueIndex,
|
||||
} from "drizzle-orm/pg-core";
|
||||
import { createInsertSchema, createSelectSchema } from "drizzle-zod";
|
||||
import { z } from "zod";
|
||||
|
||||
export const qualityRequest = pgTable(
|
||||
"qualityRequest",
|
||||
{
|
||||
request_id: uuid("request_id").defaultRandom().primaryKey(),
|
||||
article: numeric("article"),
|
||||
description: text("description"),
|
||||
runningNr: text("runningNr"),
|
||||
lotNr: numeric("lotNr"),
|
||||
warehouseAtRequest: text("warehouseAtRequest"),
|
||||
locationAtRequest: text("locationAtRequest"),
|
||||
warehouseMovedTo: text("warehouseMovedTo"),
|
||||
locationMovedTo: text("locationMovedTo"),
|
||||
durationToMove: numeric("durationToMove"),
|
||||
locationDropOff: text("locationDropOff"),
|
||||
palletStatus: numeric("palletStatus"),
|
||||
palletStatusText: text("palletStatusText"),
|
||||
palletRequest: numeric("palletRequest"),
|
||||
add_date: timestamp("add_date").defaultNow(),
|
||||
add_user: text("add_user").default("LST"),
|
||||
upd_date: timestamp("upd_date").defaultNow(),
|
||||
upd_user: text("upd_user").default("LST"),
|
||||
},
|
||||
(table) => [
|
||||
// uniqueIndex('emailUniqueIndex').on(sql`lower(${table.email})`),
|
||||
// uniqueIndex("role_name").on(table.name),
|
||||
]
|
||||
);
|
||||
|
||||
// Schema for inserting a user - can be used to validate API requests
|
||||
// export const insertRolesSchema = createInsertSchema(roles, {
|
||||
// name: z.string().min(3, {message: "Role name must be more than 3 letters"}),
|
||||
// });
|
||||
// Schema for selecting a Expenses - can be used to validate API responses
|
||||
export const selectRolesSchema = createSelectSchema(qualityRequest);
|
||||
67
frontend/package-lock.json
generated
67
frontend/package-lock.json
generated
@@ -23,6 +23,7 @@
|
||||
"@radix-ui/react-slot": "^1.1.2",
|
||||
"@radix-ui/react-tabs": "^1.1.3",
|
||||
"@radix-ui/react-tooltip": "^1.1.8",
|
||||
"@tailwindcss/typography": "^0.5.16",
|
||||
"@tailwindcss/vite": "^4.0.15",
|
||||
"@tanstack/react-form": "^1.2.1",
|
||||
"@tanstack/react-query": "^5.69.0",
|
||||
@@ -37,6 +38,7 @@
|
||||
"js-cookie": "^3.0.5",
|
||||
"jsonwebtoken": "^9.0.2",
|
||||
"lucide-react": "^0.483.0",
|
||||
"marked": "^15.0.8",
|
||||
"next-themes": "^0.4.6",
|
||||
"npm-check-updates": "^17.1.16",
|
||||
"react": "^19.0.0",
|
||||
@@ -2937,6 +2939,21 @@
|
||||
"node": ">= 10"
|
||||
}
|
||||
},
|
||||
"node_modules/@tailwindcss/typography": {
|
||||
"version": "0.5.16",
|
||||
"resolved": "https://registry.npmjs.org/@tailwindcss/typography/-/typography-0.5.16.tgz",
|
||||
"integrity": "sha512-0wDLwCVF5V3x3b1SGXPCDcdsbDHMBe+lkFzBRaHeLvNi+nrrnZ1lA18u+OTWO8iSWU2GxUOCvlXtDuqftc1oiA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"lodash.castarray": "^4.4.0",
|
||||
"lodash.isplainobject": "^4.0.6",
|
||||
"lodash.merge": "^4.6.2",
|
||||
"postcss-selector-parser": "6.0.10"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"tailwindcss": ">=3.0.0 || insiders || >=4.0.0-alpha.20 || >=4.0.0-beta.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@tailwindcss/vite": {
|
||||
"version": "4.0.15",
|
||||
"resolved": "https://registry.npmjs.org/@tailwindcss/vite/-/vite-4.0.15.tgz",
|
||||
@@ -4177,6 +4194,18 @@
|
||||
"node": ">= 8"
|
||||
}
|
||||
},
|
||||
"node_modules/cssesc": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz",
|
||||
"integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==",
|
||||
"license": "MIT",
|
||||
"bin": {
|
||||
"cssesc": "bin/cssesc"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/csstype": {
|
||||
"version": "3.1.3",
|
||||
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz",
|
||||
@@ -5717,6 +5746,12 @@
|
||||
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/lodash.castarray": {
|
||||
"version": "4.4.0",
|
||||
"resolved": "https://registry.npmjs.org/lodash.castarray/-/lodash.castarray-4.4.0.tgz",
|
||||
"integrity": "sha512-aVx8ztPv7/2ULbArGJ2Y42bG1mEQ5mGjpdvrbJcJFU3TbYybe+QlLS4pst9zV52ymy2in1KpFPiZnAOATxD4+Q==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/lodash.includes": {
|
||||
"version": "4.3.0",
|
||||
"resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz",
|
||||
@@ -5757,7 +5792,6 @@
|
||||
"version": "4.6.2",
|
||||
"resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz",
|
||||
"integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/lodash.once": {
|
||||
@@ -5797,6 +5831,18 @@
|
||||
"react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/marked": {
|
||||
"version": "15.0.8",
|
||||
"resolved": "https://registry.npmjs.org/marked/-/marked-15.0.8.tgz",
|
||||
"integrity": "sha512-rli4l2LyZqpQuRve5C0rkn6pj3hT8EWPC+zkAxFTAJLxRbENfTAhEQq9itrmf1Y81QtAX5D/MYlGlIomNgj9lA==",
|
||||
"license": "MIT",
|
||||
"bin": {
|
||||
"marked": "bin/marked.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 18"
|
||||
}
|
||||
},
|
||||
"node_modules/math-intrinsics": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz",
|
||||
@@ -6075,6 +6121,19 @@
|
||||
"node": "^10 || ^12 || >=14"
|
||||
}
|
||||
},
|
||||
"node_modules/postcss-selector-parser": {
|
||||
"version": "6.0.10",
|
||||
"resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.10.tgz",
|
||||
"integrity": "sha512-IQ7TZdoaqbT+LCpShg46jnZVlhWD2w6iQYAcYXfHARZ7X1t/UGhhceQDs5X0cGqKvYlHNOuv7Oa1xmb0oQuA3w==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"cssesc": "^3.0.0",
|
||||
"util-deprecate": "^1.0.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/prelude-ls": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz",
|
||||
@@ -7029,6 +7088,12 @@
|
||||
"which-typed-array": "^1.1.2"
|
||||
}
|
||||
},
|
||||
"node_modules/util-deprecate": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
|
||||
"integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/victory-vendor": {
|
||||
"version": "36.9.2",
|
||||
"resolved": "https://registry.npmjs.org/victory-vendor/-/victory-vendor-36.9.2.tgz",
|
||||
|
||||
@@ -41,6 +41,7 @@
|
||||
"js-cookie": "^3.0.5",
|
||||
"jsonwebtoken": "^9.0.2",
|
||||
"lucide-react": "^0.483.0",
|
||||
"marked": "^15.0.8",
|
||||
"next-themes": "^0.4.6",
|
||||
"npm-check-updates": "^17.1.16",
|
||||
"react": "^19.0.0",
|
||||
|
||||
@@ -36,7 +36,7 @@ export function ChangeModule({ module }: { module: any }) {
|
||||
active: module.active,
|
||||
},
|
||||
onSubmit: async ({ value }) => {
|
||||
console.log(value);
|
||||
//console.log(value);
|
||||
try {
|
||||
const result = await axios.patch(
|
||||
`/api/server/modules/${module.module_id}`,
|
||||
|
||||
@@ -1,8 +1,22 @@
|
||||
import { getnotifications } from "@/utils/querys/admin/notifications";
|
||||
import { notifyColumns } from "@/utils/tableData/notifications/notifyColumns";
|
||||
import { NotifyTable } from "@/utils/tableData/notifications/notifyData";
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
|
||||
export default function NotificationMGT() {
|
||||
const { data, isError, isLoading } = useQuery(getnotifications());
|
||||
|
||||
if (isLoading) return <div>Loading adjustmnet data...</div>;
|
||||
if (isError) {
|
||||
return (
|
||||
<div>
|
||||
Manage all notifications from here instad of going to the db,
|
||||
locking some items that are auto updated on server restarts
|
||||
<p>There was an error getting the adjustments.</p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<div>
|
||||
<NotifyTable columns={notifyColumns} data={data} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
33
frontend/src/components/changelog/ChangeLog.tsx
Normal file
33
frontend/src/components/changelog/ChangeLog.tsx
Normal file
@@ -0,0 +1,33 @@
|
||||
// src/components/Changelog.jsx
|
||||
import { marked } from "marked";
|
||||
import changelog from "../../../../CHANGELOG.md?raw"; // assuming changelog.md is in root
|
||||
|
||||
const Changelog = () => {
|
||||
const html: any = marked.parse(changelog);
|
||||
const recentChanges = html.split("<h2>")[1];
|
||||
// const [htmlContent, setHtmlContent] = useState("");
|
||||
|
||||
// useEffect(() => {
|
||||
// fetch("/changelog.md")
|
||||
// .then((res) => res.text())
|
||||
// .then((md) => {
|
||||
// const versionBlocks = md.split(/^##\s+/gm); // Split on headings
|
||||
// if (versionBlocks.length > 1) {
|
||||
// const latestBlock = `## ${versionBlocks[1]}`;
|
||||
// const html: any = marked.parse(latestBlock, {
|
||||
// breaks: true,
|
||||
// gfm: true,
|
||||
// });
|
||||
// setHtmlContent(html);
|
||||
// }
|
||||
// });
|
||||
// }, []);
|
||||
return (
|
||||
<div
|
||||
className="prose m-3"
|
||||
dangerouslySetInnerHTML={{ __html: `<h2>${recentChanges}` }}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default Changelog;
|
||||
@@ -3,55 +3,37 @@ import {
|
||||
Dialog,
|
||||
DialogContent,
|
||||
DialogDescription,
|
||||
DialogFooter,
|
||||
DialogHeader,
|
||||
DialogTitle,
|
||||
DialogTrigger,
|
||||
} from "@/components/ui/dialog";
|
||||
|
||||
import { useCardStore } from "@/lib/store/useCardStore";
|
||||
import { toast } from "sonner";
|
||||
import Cards from "./Cards";
|
||||
//import { toast } from "sonner";
|
||||
|
||||
export function AddCards() {
|
||||
const { cards, addCard } = useCardStore();
|
||||
|
||||
const handleAddPPOO = () => {
|
||||
const existingCard = cards.filter((c) => c.i === "PPOO");
|
||||
//console.log(existingCard.length);
|
||||
//console.log(data);
|
||||
if (existingCard.length != 0) {
|
||||
toast.error(`PPOO already exists no card will be added`);
|
||||
return;
|
||||
}
|
||||
addCard({
|
||||
i: "PPOO",
|
||||
x: 0,
|
||||
y: 0,
|
||||
w: 5,
|
||||
h: 3,
|
||||
isResizable: true,
|
||||
isDraggable: true,
|
||||
});
|
||||
};
|
||||
return (
|
||||
<Dialog>
|
||||
<DialogTrigger asChild>
|
||||
<Button variant="outline">Add Cards</Button>
|
||||
</DialogTrigger>
|
||||
<DialogContent className="sm:max-w-[425px]">
|
||||
<DialogContent className="min-w-fit ">
|
||||
<DialogHeader>
|
||||
<DialogTitle>Cards</DialogTitle>
|
||||
<DialogDescription>
|
||||
Please add a card below.
|
||||
Manage Cards and there settings.
|
||||
</DialogDescription>
|
||||
</DialogHeader>
|
||||
<Button onClick={handleAddPPOO} className="w-48">
|
||||
PPOO
|
||||
</Button>
|
||||
|
||||
<DialogFooter>
|
||||
<Cards name={"ppoo"} inventory />
|
||||
<Cards name={"inv-empty"} rowType={"empty"} />
|
||||
<Cards name={"inv-fg"} rowType={"fg"} />
|
||||
<Cards name={"inv-materials"} rowType={"materials"} />
|
||||
<Cards name={"inv-packaging"} rowType={"packaging"} />
|
||||
<Cards name={"inv-waste"} rowType={"waste"} />
|
||||
|
||||
{/* <DialogFooter>
|
||||
<Button type="submit">Save changes</Button>
|
||||
</DialogFooter>
|
||||
</DialogFooter> */}
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
);
|
||||
|
||||
183
frontend/src/components/dashboard/Cards.tsx
Normal file
183
frontend/src/components/dashboard/Cards.tsx
Normal file
@@ -0,0 +1,183 @@
|
||||
import { useCardStore } from "@/lib/store/useCardStore";
|
||||
import { useForm } from "@tanstack/react-form";
|
||||
import { Label } from "../ui/label";
|
||||
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 { toast } from "sonner";
|
||||
|
||||
export default function Cards(card: any) {
|
||||
const { addCard, removeCard, cards } = useCardStore();
|
||||
let existing: any = cards.filter((n: any) => n.name === card.name);
|
||||
|
||||
console.log(existing);
|
||||
const form = useForm({
|
||||
defaultValues: {
|
||||
name: existing?.name || card.name,
|
||||
rowType: existing?.type ?? card.rowType,
|
||||
age: existing?.age ?? 90,
|
||||
active: existing.active ? existing.active : false,
|
||||
},
|
||||
onSubmit: async ({ value }) => {
|
||||
console.log(value);
|
||||
const testCard: any = cards.filter(
|
||||
(i: any) => i.name === value.name
|
||||
);
|
||||
|
||||
if (value.active) {
|
||||
if (testCard.length > 0) {
|
||||
toast.error("Card already exists");
|
||||
return;
|
||||
}
|
||||
// change the name for a type card
|
||||
const newCard = {
|
||||
name: `${value.name}`,
|
||||
rowType: value.rowType,
|
||||
age: value.age ?? 90,
|
||||
active: value.active,
|
||||
};
|
||||
addCard(newCard);
|
||||
} else {
|
||||
removeCard(value.name);
|
||||
}
|
||||
},
|
||||
});
|
||||
return (
|
||||
<div className="border-solid border-2">
|
||||
<p>{card.name}</p>
|
||||
<form
|
||||
onSubmit={(e) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
}}
|
||||
className="flex flex-row"
|
||||
>
|
||||
<form.Field
|
||||
name="active"
|
||||
// validators={{
|
||||
// // We can choose between form-wide and field-specific validators
|
||||
// onChange: ({ value }) =>
|
||||
// value.length > 3
|
||||
// ? undefined
|
||||
// : "Username must be longer than 3 letters",
|
||||
// }}
|
||||
children={(field) => {
|
||||
return (
|
||||
<div className="m-2 p-2 flex flex-row">
|
||||
<div>
|
||||
<Label htmlFor="active">
|
||||
<span>Active</span>
|
||||
</Label>
|
||||
</div>
|
||||
|
||||
<Checkbox
|
||||
className="ml-2"
|
||||
name={field.name}
|
||||
onBlur={field.handleBlur}
|
||||
checked={field.state.value}
|
||||
onCheckedChange={(e) =>
|
||||
field.handleChange(e)
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}}
|
||||
/>
|
||||
{!card.inventory && (
|
||||
<>
|
||||
<form.Field
|
||||
name="age"
|
||||
// validators={{
|
||||
// // We can choose between form-wide and field-specific validators
|
||||
// onChange: ({ value }) =>
|
||||
// value.length > 3
|
||||
// ? undefined
|
||||
// : "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}
|
||||
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">
|
||||
<Button type="submit" onClick={() => form.handleSubmit()}>
|
||||
Save Card
|
||||
</Button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -1,68 +1,74 @@
|
||||
export default function DashBoard() {
|
||||
// const handleResizeStop = (newLayout: any, newItem: any) => {
|
||||
// updateCard(
|
||||
// newItem.i,
|
||||
// newLayout.filter((n: any) => n.i === newItem.i)[0]
|
||||
// ); // Store the new layout in state
|
||||
// };
|
||||
import { useCardStore } from "@/lib/store/useCardStore";
|
||||
import INVCheckCard from "../logistics/warehouse/InventoryCard";
|
||||
import PPOO from "../logistics/warehouse/PPOOCard";
|
||||
|
||||
// const handleDragStop = (newLayout: any, newItem: any) => {
|
||||
// updateCard(
|
||||
// newItem.i,
|
||||
// newLayout.filter((n: any) => n.i === newItem.i)[0]
|
||||
// ); // Persist the updated layout with custom name
|
||||
// };
|
||||
const componentsMap: any = {
|
||||
ppoo: PPOO,
|
||||
inv: INVCheckCard,
|
||||
//QualityRequest,
|
||||
};
|
||||
|
||||
export default function DashBoard() {
|
||||
const { cards } = useCardStore();
|
||||
|
||||
//console.log(cards);
|
||||
return (
|
||||
<div className="ml-5 w-11/12 h-9/10 grid grid-cols-12 gap-1">
|
||||
{cards.map((a: any) => {
|
||||
const name = a.name; //.filter((c) => c.i === card.i)[0].i || "name";
|
||||
|
||||
const Component = componentsMap[name.split("-")[0]];
|
||||
|
||||
return (
|
||||
<div className="ml-5 w-11/12 h-9/10">
|
||||
<p>Comming soon...</p>
|
||||
{/* <ResizablePanelGroup
|
||||
direction="horizontal"
|
||||
//className="rounded-lg border"
|
||||
autoSaveId="persistence"
|
||||
>
|
||||
<ResizablePanel>
|
||||
<ResizablePanelGroup direction="vertical">
|
||||
<ResizablePanel>
|
||||
<div className="overflow: auto">
|
||||
<Lots />
|
||||
</div>
|
||||
</ResizablePanel>
|
||||
<ResizableHandle />
|
||||
<ResizablePanel>
|
||||
<ResizablePanelGroup direction="horizontal">
|
||||
<ResizablePanel>
|
||||
<LabelLog />
|
||||
</ResizablePanel>
|
||||
<ResizableHandle />
|
||||
<ResizablePanel>
|
||||
<OcpLogs />
|
||||
</ResizablePanel>
|
||||
</ResizablePanelGroup>
|
||||
</ResizablePanel>
|
||||
</ResizablePanelGroup>
|
||||
</ResizablePanel>
|
||||
<ResizableHandle />
|
||||
<ResizablePanel defaultSize={25}>
|
||||
<ResizablePanelGroup direction="vertical">
|
||||
{server[0].value === "usday1vms006" && (
|
||||
<ResizablePanel className="max-h-[300px]">
|
||||
<WrapperManualTrigger />
|
||||
</ResizablePanel>
|
||||
)}
|
||||
{server[0].value === "usday1vms006" && (
|
||||
<ResizablePanel className="max-h-[300px]">
|
||||
<WrapperManualTrigger />
|
||||
</ResizablePanel>
|
||||
)}
|
||||
|
||||
<ResizableHandle />
|
||||
<ResizablePanel>
|
||||
<PrinterStatus />
|
||||
</ResizablePanel>
|
||||
</ResizablePanelGroup>
|
||||
</ResizablePanel>
|
||||
</ResizablePanelGroup> */}
|
||||
<div key={a.name} className="col-span-3">
|
||||
<Component age={a.age} type={a.rowType} />{" "}
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
);
|
||||
|
||||
// return (
|
||||
// <div className="ml-5 w-11/12 h-9/10 grid grid-cols-12 gap-1">
|
||||
// <div className="col-span-3">
|
||||
// <PPOO />
|
||||
// </div>
|
||||
// <div className="col-span-3">
|
||||
// <INVCheckCard age={90} type={"empty"} />
|
||||
// </div>
|
||||
// <div className="col-span-3">
|
||||
// <INVCheckCard age={75} type={"fg"} />
|
||||
// </div>
|
||||
// <div className="col-span-3">
|
||||
// <INVCheckCard age={30} type={"materials"} />
|
||||
// </div>
|
||||
// <div className="col-span-3">
|
||||
// <INVCheckCard age={7} type={"waste"} />
|
||||
// </div>
|
||||
// <div className="col-span-3">
|
||||
// <INVCheckCard age={7} type={"packaging"} />
|
||||
// </div>
|
||||
// </div>
|
||||
// );
|
||||
}
|
||||
|
||||
/*
|
||||
<div className="col-span-3">
|
||||
<PPOO />
|
||||
</div>
|
||||
<div className="col-span-3">
|
||||
<INVCheckCard age={30} type={"empty"} />
|
||||
</div>
|
||||
<div className="col-span-3">
|
||||
<INVCheckCard age={30} type={"fg"} />
|
||||
</div>
|
||||
<div className="col-span-3">
|
||||
<INVCheckCard age={30} type={"materials"} />
|
||||
</div>
|
||||
<div className="col-span-3">
|
||||
<INVCheckCard age={30} type={"waste"} />
|
||||
</div>
|
||||
<div className="col-span-3">
|
||||
<INVCheckCard age={30} type={"packaging"} />
|
||||
</div>
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,153 @@
|
||||
import { Button } from "@/components/ui/button";
|
||||
import {
|
||||
Dialog,
|
||||
DialogContent,
|
||||
DialogDescription,
|
||||
DialogFooter,
|
||||
DialogHeader,
|
||||
DialogTitle,
|
||||
DialogTrigger,
|
||||
} from "@/components/ui/dialog";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { Label } from "@/components/ui/label";
|
||||
|
||||
import { useForm } from "@tanstack/react-form";
|
||||
import axios from "axios";
|
||||
import { format } from "date-fns";
|
||||
import { useState } from "react";
|
||||
import { toast } from "sonner";
|
||||
|
||||
export default function ExportInventoryData() {
|
||||
const [open, setOpen] = useState(false);
|
||||
const [saving, setSaving] = useState(false);
|
||||
|
||||
const form = useForm({
|
||||
defaultValues: {
|
||||
age: "",
|
||||
},
|
||||
onSubmit: async ({ value }) => {
|
||||
setSaving(true);
|
||||
try {
|
||||
const res = await axios.get(
|
||||
`/api/logistics/getcyclecount?age=${value.age}`,
|
||||
{
|
||||
responseType: "blob",
|
||||
}
|
||||
);
|
||||
|
||||
const blob = new Blob([res.data], {
|
||||
type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
|
||||
});
|
||||
|
||||
const link = document.createElement("a");
|
||||
link.href = window.URL.createObjectURL(blob);
|
||||
link.download = `CycleCount-${format(new Date(Date.now()), "M-d-yyyy")}.xlsx`; // You can make this dynamic
|
||||
document.body.appendChild(link);
|
||||
link.click();
|
||||
|
||||
// Clean up
|
||||
document.body.removeChild(link);
|
||||
window.URL.revokeObjectURL(link.href);
|
||||
toast.success(`File Downloaded`);
|
||||
setSaving(false);
|
||||
setOpen(false);
|
||||
form.reset();
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
console.log(`There was an error getting cycle counts.`);
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Dialog
|
||||
open={open}
|
||||
onOpenChange={(isOpen) => {
|
||||
if (!open) {
|
||||
form.reset();
|
||||
}
|
||||
setOpen(isOpen);
|
||||
// toast.message("Model was something", {
|
||||
// description: isOpen ? "Modal is open" : "Modal is closed",
|
||||
// });
|
||||
}}
|
||||
>
|
||||
<DialogTrigger asChild>
|
||||
<Button variant="outline">Export Inventory Check</Button>
|
||||
</DialogTrigger>
|
||||
<DialogContent className="sm:max-w-[425px]">
|
||||
<DialogHeader>
|
||||
<DialogTitle>Export Inventory lane check</DialogTitle>
|
||||
<DialogDescription>
|
||||
Exports all lanes based on the age you enter, except
|
||||
empty lanes.
|
||||
</DialogDescription>
|
||||
</DialogHeader>
|
||||
<form
|
||||
onSubmit={(e) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
}}
|
||||
>
|
||||
<div>
|
||||
<>
|
||||
<form.Field
|
||||
name="age"
|
||||
// validators={{
|
||||
// // We can choose between form-wide and field-specific validators
|
||||
// onChange: ({ value }) =>
|
||||
// value.length > 3
|
||||
// ? undefined
|
||||
// : "Username must be longer than 3 letters",
|
||||
// }}
|
||||
children={(field) => {
|
||||
return (
|
||||
<div className="m-2 min-w-48 max-w-96 p-2 flex flex-row">
|
||||
<Label htmlFor="active">
|
||||
Age
|
||||
</Label>
|
||||
<Input
|
||||
className="ml-2"
|
||||
name={field.name}
|
||||
onBlur={field.handleBlur}
|
||||
type="number"
|
||||
onChange={(e) =>
|
||||
field.handleChange(
|
||||
e.target.value
|
||||
)
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}}
|
||||
/>
|
||||
</>
|
||||
</div>
|
||||
|
||||
<DialogFooter>
|
||||
<div className="flex justify-end mt-2">
|
||||
<Button onClick={() => setOpen(false)}>
|
||||
Close
|
||||
</Button>
|
||||
<Button
|
||||
type="submit"
|
||||
disabled={saving}
|
||||
onClick={form.handleSubmit}
|
||||
>
|
||||
{saving ? (
|
||||
<>
|
||||
<span>Saving....</span>
|
||||
</>
|
||||
) : (
|
||||
<span>Save setting</span>
|
||||
)}
|
||||
</Button>
|
||||
</div>
|
||||
</DialogFooter>
|
||||
</form>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
//import { LstCard } from "@/components/extendedUI/LstCard";
|
||||
import { getinventoryCheck } from "@/utils/querys/logistics/getInventoryCheck";
|
||||
import { invColumns } from "@/utils/tableData/InventoryCards/inventoryColumns";
|
||||
import { InvTable } from "@/utils/tableData/InventoryCards/inventoryData";
|
||||
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
//import { CircleX } from "lucide-react";
|
||||
//import { Suspense } from "react";
|
||||
//import { toast } from "sonner";
|
||||
|
||||
export default function INVCheckCard(props: any) {
|
||||
//{ style = {} }
|
||||
const { data, isError, isLoading } = useQuery(getinventoryCheck(props));
|
||||
|
||||
if (isLoading) return <div>Loading inventory data...</div>;
|
||||
if (isError) {
|
||||
return (
|
||||
<div>
|
||||
<p>There was an error getting the inv.</p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
let laneData: any = data;
|
||||
if (props.type != "") {
|
||||
laneData = laneData.filter(
|
||||
(l: any) => l.rowType === props.type.toUpperCase()
|
||||
);
|
||||
}
|
||||
|
||||
// const handleCloseCard = () => {
|
||||
// //removeCard("PPOO");
|
||||
|
||||
// toast.success("card removed");
|
||||
// };
|
||||
|
||||
return <InvTable columns={invColumns} data={laneData} info={props} />;
|
||||
}
|
||||
@@ -1,15 +1,14 @@
|
||||
import { LstCard } from "@/components/extendedUI/LstCard";
|
||||
import { useCardStore } from "@/lib/store/useCardStore";
|
||||
//import { LstCard } from "@/components/extendedUI/LstCard";
|
||||
import { getPPOO } from "@/utils/querys/logistics/getPPOO";
|
||||
import { columns } from "@/utils/tableData/ppoo/ppooColumns";
|
||||
import { PPOOTable } from "@/utils/tableData/ppoo/ppooData";
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import { CircleX } from "lucide-react";
|
||||
import { Suspense } from "react";
|
||||
import { toast } from "sonner";
|
||||
//import { CircleX } from "lucide-react";
|
||||
//import { Suspense } from "react";
|
||||
//import { toast } from "sonner";
|
||||
|
||||
export default function PPOO({ style = {} }) {
|
||||
const { removeCard } = useCardStore();
|
||||
export default function PPOO() {
|
||||
//{ style = {} }
|
||||
const { data, isError, isLoading } = useQuery(getPPOO());
|
||||
|
||||
if (isLoading) return <div>Loading adjustmnet data...</div>;
|
||||
@@ -21,30 +20,42 @@ export default function PPOO({ style = {} }) {
|
||||
);
|
||||
}
|
||||
|
||||
const handleCloseCard = () => {
|
||||
removeCard("PPOO");
|
||||
// const handleCloseCard = () => {
|
||||
// //removeCard("PPOO");
|
||||
|
||||
// toast.success("card removed");
|
||||
// };
|
||||
|
||||
toast.success("card removed");
|
||||
};
|
||||
return (
|
||||
<div style={style}>
|
||||
<LstCard style={style}>
|
||||
<Suspense fallback={<p>Loading PPOO...</p>}>
|
||||
<div className={`flex justify-center`}>
|
||||
<p
|
||||
className={`drag-handle w-fit`}
|
||||
style={{ cursor: "move", padding: "5px" }}
|
||||
>
|
||||
PPOO
|
||||
</p>
|
||||
|
||||
<button onClick={handleCloseCard}>
|
||||
<CircleX />
|
||||
</button>
|
||||
</div>
|
||||
<PPOOTable columns={columns} data={data} style={style} />
|
||||
</Suspense>
|
||||
</LstCard>
|
||||
</div>
|
||||
<PPOOTable
|
||||
columns={columns}
|
||||
data={data}
|
||||
//style={style}
|
||||
/>
|
||||
);
|
||||
// return (
|
||||
// <div style={style}>
|
||||
// <LstCard style={style}>
|
||||
// <Suspense fallback={<p>Loading PPOO...</p>}>
|
||||
// <div className={`flex justify-center`}>
|
||||
// <p
|
||||
// className={`drag-handle w-fit`}
|
||||
// style={{ cursor: "move", padding: "5px" }}
|
||||
// >
|
||||
// PPOO
|
||||
// </p>
|
||||
|
||||
// <button onClick={handleCloseCard}>
|
||||
// <CircleX />
|
||||
// </button>
|
||||
// </div>
|
||||
// <PPOOTable
|
||||
// columns={columns}
|
||||
// data={data}
|
||||
// //style={style}
|
||||
// />
|
||||
// </Suspense>
|
||||
// </LstCard>
|
||||
// </div>
|
||||
// );
|
||||
}
|
||||
|
||||
@@ -1,31 +1,23 @@
|
||||
import { create } from "zustand";
|
||||
import { devtools, persist } from "zustand/middleware";
|
||||
|
||||
interface CardSettings {
|
||||
daysSinceLast?: number;
|
||||
rowType?: string;
|
||||
}
|
||||
// interface CardSettings {
|
||||
// daysSinceLast?: number;
|
||||
// rowType?: string;
|
||||
// }
|
||||
|
||||
export interface Card {
|
||||
i: string;
|
||||
x: number;
|
||||
y: number;
|
||||
w: number;
|
||||
h: number;
|
||||
minW?: number;
|
||||
maxW?: number;
|
||||
minH?: number;
|
||||
maxH?: number;
|
||||
isResizable: boolean;
|
||||
isDraggable: boolean;
|
||||
cardSettings?: CardSettings;
|
||||
name: string;
|
||||
rowType: string;
|
||||
age: string;
|
||||
active: boolean;
|
||||
}
|
||||
|
||||
interface CardStore {
|
||||
cards: Card[]; // Array of card objects
|
||||
addCard: (card: Card) => void;
|
||||
updateCard: (id: string, updatedCard: Partial<Card>) => void;
|
||||
removeCard: (id: string) => void;
|
||||
updateCard: (name: string, updatedCard: Partial<Card>) => void;
|
||||
removeCard: (name: string) => void;
|
||||
}
|
||||
|
||||
export const useCardStore = create<CardStore>()(
|
||||
@@ -37,16 +29,18 @@ export const useCardStore = create<CardStore>()(
|
||||
addCard: (card) =>
|
||||
set((state) => ({ cards: [...state.cards, card] })),
|
||||
|
||||
updateCard: (id, updatedCard) =>
|
||||
updateCard: (name, updatedCard) =>
|
||||
set((state) => ({
|
||||
cards: state.cards.map((card) =>
|
||||
card.i === id ? { ...card, ...updatedCard } : card
|
||||
card.name === name
|
||||
? { ...card, ...updatedCard }
|
||||
: card
|
||||
),
|
||||
})),
|
||||
|
||||
removeCard: (id) =>
|
||||
removeCard: (name) =>
|
||||
set((state) => ({
|
||||
cards: state.cards.filter((card) => card.i !== id),
|
||||
cards: state.cards.filter((card) => card.name !== name),
|
||||
})),
|
||||
}),
|
||||
{ name: "card-storage" }
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
|
||||
import { Route as rootRoute } from './routes/__root'
|
||||
import { Route as LoginImport } from './routes/login'
|
||||
import { Route as ChangelogImport } from './routes/changelog'
|
||||
import { Route as AboutImport } from './routes/about'
|
||||
import { Route as EomImport } from './routes/_eom'
|
||||
import { Route as AuthImport } from './routes/_auth'
|
||||
@@ -43,6 +44,12 @@ const LoginRoute = LoginImport.update({
|
||||
getParentRoute: () => rootRoute,
|
||||
} as any)
|
||||
|
||||
const ChangelogRoute = ChangelogImport.update({
|
||||
id: '/changelog',
|
||||
path: '/changelog',
|
||||
getParentRoute: () => rootRoute,
|
||||
} as any)
|
||||
|
||||
const AboutRoute = AboutImport.update({
|
||||
id: '/about',
|
||||
path: '/about',
|
||||
@@ -217,6 +224,13 @@ declare module '@tanstack/react-router' {
|
||||
preLoaderRoute: typeof AboutImport
|
||||
parentRoute: typeof rootRoute
|
||||
}
|
||||
'/changelog': {
|
||||
id: '/changelog'
|
||||
path: '/changelog'
|
||||
fullPath: '/changelog'
|
||||
preLoaderRoute: typeof ChangelogImport
|
||||
parentRoute: typeof rootRoute
|
||||
}
|
||||
'/login': {
|
||||
id: '/login'
|
||||
path: '/login'
|
||||
@@ -394,6 +408,7 @@ export interface FileRoutesByFullPath {
|
||||
'/': typeof IndexRoute
|
||||
'': typeof EomRouteWithChildren
|
||||
'/about': typeof AboutRoute
|
||||
'/changelog': typeof ChangelogRoute
|
||||
'/login': typeof LoginRoute
|
||||
'/modules': typeof AdminModulesRoute
|
||||
'/notificationMGT': typeof AdminNotificationMGTRoute
|
||||
@@ -418,6 +433,7 @@ export interface FileRoutesByTo {
|
||||
'/': typeof IndexRoute
|
||||
'': typeof EomRouteWithChildren
|
||||
'/about': typeof AboutRoute
|
||||
'/changelog': typeof ChangelogRoute
|
||||
'/login': typeof LoginRoute
|
||||
'/modules': typeof AdminModulesRoute
|
||||
'/notificationMGT': typeof AdminNotificationMGTRoute
|
||||
@@ -445,6 +461,7 @@ export interface FileRoutesById {
|
||||
'/_auth': typeof AuthRouteWithChildren
|
||||
'/_eom': typeof EomRouteWithChildren
|
||||
'/about': typeof AboutRoute
|
||||
'/changelog': typeof ChangelogRoute
|
||||
'/login': typeof LoginRoute
|
||||
'/_admin/modules': typeof AdminModulesRoute
|
||||
'/_admin/notificationMGT': typeof AdminNotificationMGTRoute
|
||||
@@ -471,6 +488,7 @@ export interface FileRouteTypes {
|
||||
| '/'
|
||||
| ''
|
||||
| '/about'
|
||||
| '/changelog'
|
||||
| '/login'
|
||||
| '/modules'
|
||||
| '/notificationMGT'
|
||||
@@ -494,6 +512,7 @@ export interface FileRouteTypes {
|
||||
| '/'
|
||||
| ''
|
||||
| '/about'
|
||||
| '/changelog'
|
||||
| '/login'
|
||||
| '/modules'
|
||||
| '/notificationMGT'
|
||||
@@ -519,6 +538,7 @@ export interface FileRouteTypes {
|
||||
| '/_auth'
|
||||
| '/_eom'
|
||||
| '/about'
|
||||
| '/changelog'
|
||||
| '/login'
|
||||
| '/_admin/modules'
|
||||
| '/_admin/notificationMGT'
|
||||
@@ -546,6 +566,7 @@ export interface RootRouteChildren {
|
||||
AuthRoute: typeof AuthRouteWithChildren
|
||||
EomRoute: typeof EomRouteWithChildren
|
||||
AboutRoute: typeof AboutRoute
|
||||
ChangelogRoute: typeof ChangelogRoute
|
||||
LoginRoute: typeof LoginRoute
|
||||
OcpIndexRoute: typeof OcpIndexRoute
|
||||
logisticsSiloAdjustmentsHistRoute: typeof logisticsSiloAdjustmentsHistRoute
|
||||
@@ -563,6 +584,7 @@ const rootRouteChildren: RootRouteChildren = {
|
||||
AuthRoute: AuthRouteWithChildren,
|
||||
EomRoute: EomRouteWithChildren,
|
||||
AboutRoute: AboutRoute,
|
||||
ChangelogRoute: ChangelogRoute,
|
||||
LoginRoute: LoginRoute,
|
||||
OcpIndexRoute: OcpIndexRoute,
|
||||
logisticsSiloAdjustmentsHistRoute: logisticsSiloAdjustmentsHistRoute,
|
||||
@@ -592,6 +614,7 @@ export const routeTree = rootRoute
|
||||
"/_auth",
|
||||
"/_eom",
|
||||
"/about",
|
||||
"/changelog",
|
||||
"/login",
|
||||
"/ocp/",
|
||||
"/(logistics)/siloAdjustments/$hist",
|
||||
@@ -633,6 +656,9 @@ export const routeTree = rootRoute
|
||||
"/about": {
|
||||
"filePath": "about.tsx"
|
||||
},
|
||||
"/changelog": {
|
||||
"filePath": "changelog.tsx"
|
||||
},
|
||||
"/login": {
|
||||
"filePath": "login.tsx"
|
||||
},
|
||||
|
||||
@@ -1,4 +1,9 @@
|
||||
import { createRootRoute, Link, Outlet } from "@tanstack/react-router";
|
||||
import {
|
||||
createRootRoute,
|
||||
Link,
|
||||
Outlet,
|
||||
useLocation,
|
||||
} from "@tanstack/react-router";
|
||||
//import {TanStackRouterDevtools} from "@tanstack/router-devtools";
|
||||
import Cookies from "js-cookie";
|
||||
import { SidebarProvider } from "../components/ui/sidebar";
|
||||
@@ -17,11 +22,12 @@ import {
|
||||
import { SessionProvider } from "../components/providers/Providers";
|
||||
import { Toaster } from "sonner";
|
||||
//import { Button } from "../components/ui/button";
|
||||
|
||||
import { useSessionStore } from "../lib/store/sessionStore";
|
||||
import { useSession } from "@/hooks/useSession";
|
||||
import { useLogout } from "@/hooks/useLogout";
|
||||
import ExportInventoryData from "@/components/logistics/warehouse/ExportInventoryData";
|
||||
import { AddCards } from "@/components/dashboard/AddCards";
|
||||
//import { AddCards } from "@/components/dashboard/AddCards";
|
||||
|
||||
// same as the layout
|
||||
export const Route = createRootRoute({
|
||||
@@ -30,16 +36,20 @@ export const Route = createRootRoute({
|
||||
const { session } = useSession();
|
||||
const { user } = useSessionStore();
|
||||
const logout = useLogout();
|
||||
const location = useLocation();
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="overflow-hidden">
|
||||
<SessionProvider>
|
||||
<ThemeProvider>
|
||||
<nav className="flex justify-end">
|
||||
<nav className="flex justify-end w-full shadow ">
|
||||
<div className="m-2 flex flex-row">
|
||||
<div className="m-auto pr-2">
|
||||
{location.pathname === "/" && (
|
||||
<div className="m-auto pr-2 flex flex-row gap-2">
|
||||
<ExportInventoryData />
|
||||
<AddCards />
|
||||
</div>
|
||||
)}
|
||||
<div className="m-1">
|
||||
<ModeToggle />
|
||||
</div>
|
||||
@@ -88,16 +98,18 @@ export const Route = createRootRoute({
|
||||
)}
|
||||
</div>
|
||||
</nav>
|
||||
<main>
|
||||
<SidebarProvider defaultOpen={sidebarState}>
|
||||
<AppSidebar />
|
||||
<Toaster expand={true} richColors closeButton />
|
||||
<Outlet />
|
||||
</SidebarProvider>
|
||||
</main>
|
||||
</ThemeProvider>
|
||||
</SessionProvider>
|
||||
|
||||
{/* <TanStackRouterDevtools position="bottom-right" /> */}
|
||||
</>
|
||||
</div>
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
14
frontend/src/routes/changelog.tsx
Normal file
14
frontend/src/routes/changelog.tsx
Normal file
@@ -0,0 +1,14 @@
|
||||
import Changelog from "@/components/changelog/ChangeLog";
|
||||
import { createFileRoute } from "@tanstack/react-router";
|
||||
|
||||
export const Route = createFileRoute("/changelog")({
|
||||
component: RouteComponent,
|
||||
});
|
||||
|
||||
function RouteComponent() {
|
||||
return (
|
||||
<div>
|
||||
<Changelog />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
26
frontend/src/utils/querys/admin/notifications.tsx
Normal file
26
frontend/src/utils/querys/admin/notifications.tsx
Normal file
@@ -0,0 +1,26 @@
|
||||
import { queryOptions } from "@tanstack/react-query";
|
||||
import axios from "axios";
|
||||
|
||||
export function getnotifications() {
|
||||
const token = localStorage.getItem("auth_token");
|
||||
return queryOptions({
|
||||
queryKey: ["getNotifications"],
|
||||
queryFn: () => fetchUsers(token),
|
||||
enabled: !!token, // Prevents query if token is null
|
||||
staleTime: 1000,
|
||||
refetchInterval: 2 * 2000,
|
||||
refetchOnWindowFocus: true,
|
||||
});
|
||||
}
|
||||
|
||||
const fetchUsers = async (token: string | null) => {
|
||||
const { data } = await axios.get(`/api/notify/notifications`, {
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
Authorization: `Bearer ${token}`,
|
||||
},
|
||||
});
|
||||
// if we are not localhost ignore the devDir setting.
|
||||
//const url: string = window.location.host.split(":")[0];
|
||||
return data.data ?? [];
|
||||
};
|
||||
25
frontend/src/utils/querys/logistics/getInventoryCheck.tsx
Normal file
25
frontend/src/utils/querys/logistics/getInventoryCheck.tsx
Normal file
@@ -0,0 +1,25 @@
|
||||
import { queryOptions } from "@tanstack/react-query";
|
||||
import axios from "axios";
|
||||
|
||||
export function getinventoryCheck(data: any) {
|
||||
return queryOptions({
|
||||
queryKey: ["getInvCheck"],
|
||||
queryFn: () => fetchStockSilo(data),
|
||||
//enabled:
|
||||
staleTime: 1000,
|
||||
refetchInterval: 60 * 1000,
|
||||
refetchOnWindowFocus: true,
|
||||
});
|
||||
}
|
||||
|
||||
const fetchStockSilo = async (info: any) => {
|
||||
console.log(info);
|
||||
const { data } = await axios.post(`/api/logistics/cyclecountcheck`, {
|
||||
age: info.age ? parseInt(info.age) : null,
|
||||
type: "",
|
||||
});
|
||||
|
||||
// if we are not localhost ignore the devDir setting.
|
||||
//const url: string = window.location.host.split(":")[0];
|
||||
return data.data ?? [];
|
||||
};
|
||||
@@ -7,7 +7,7 @@ export function getPPOO() {
|
||||
queryFn: () => fetchStockSilo(),
|
||||
//enabled:
|
||||
staleTime: 1000,
|
||||
refetchInterval: 2 * 2000,
|
||||
refetchInterval: 60 * 1000,
|
||||
refetchOnWindowFocus: true,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
import { ColumnDef } from "@tanstack/react-table";
|
||||
|
||||
// This type is used to define the shape of our data.
|
||||
// You can use a Zod schema here if you want.
|
||||
export type Adjustmnets = {
|
||||
siloAdjust_id: string;
|
||||
currentStockLevel: string;
|
||||
newLevel: number;
|
||||
dateAdjusted: string;
|
||||
lastDateAdjusted: string;
|
||||
comment: string;
|
||||
commentAddedBy: string;
|
||||
commentDate: string;
|
||||
add_user: string;
|
||||
};
|
||||
|
||||
export const invColumns: ColumnDef<Adjustmnets>[] = [
|
||||
{
|
||||
accessorKey: "Description",
|
||||
header: () => <div className="text-left">Lane</div>,
|
||||
},
|
||||
{
|
||||
accessorKey: "DaysSinceLast",
|
||||
header: "Age",
|
||||
//enableSorting: true,
|
||||
},
|
||||
];
|
||||
166
frontend/src/utils/tableData/InventoryCards/inventoryData.tsx
Normal file
166
frontend/src/utils/tableData/InventoryCards/inventoryData.tsx
Normal file
@@ -0,0 +1,166 @@
|
||||
import {
|
||||
ColumnDef,
|
||||
flexRender,
|
||||
getCoreRowModel,
|
||||
useReactTable,
|
||||
getPaginationRowModel,
|
||||
getSortedRowModel,
|
||||
} from "@tanstack/react-table";
|
||||
import {
|
||||
Table,
|
||||
TableBody,
|
||||
TableCell,
|
||||
TableHead,
|
||||
TableHeader,
|
||||
TableRow,
|
||||
} from "@/components/ui/table";
|
||||
//import { Button } from "@/components/ui/button";
|
||||
import { useState } from "react";
|
||||
import { ScrollArea } from "@/components/ui/scroll-area";
|
||||
import { LstCard } from "@/components/extendedUI/LstCard";
|
||||
|
||||
interface DataTableProps<TData, TValue> {
|
||||
columns: ColumnDef<TData, TValue>[];
|
||||
data: TData[];
|
||||
info: any;
|
||||
}
|
||||
|
||||
type ColumnSort = {
|
||||
id: string;
|
||||
desc: boolean;
|
||||
};
|
||||
type SortingState = ColumnSort[];
|
||||
|
||||
export function InvTable<TData, TValue>({
|
||||
columns,
|
||||
data,
|
||||
info,
|
||||
}: DataTableProps<TData, TValue>) {
|
||||
const [sorting, setSorting] = useState<SortingState>([]);
|
||||
const [pagination, setPagination] = useState({
|
||||
pageIndex: 0, //initial page index
|
||||
pageSize: 5, //default page size
|
||||
});
|
||||
const table = useReactTable({
|
||||
data,
|
||||
columns,
|
||||
getCoreRowModel: getCoreRowModel(),
|
||||
getPaginationRowModel: getPaginationRowModel(),
|
||||
onPaginationChange: setPagination,
|
||||
getSortedRowModel: getSortedRowModel(),
|
||||
state: {
|
||||
//...
|
||||
pagination,
|
||||
sorting,
|
||||
},
|
||||
manualSorting: true,
|
||||
onSortingChange: setSorting,
|
||||
initialState: {
|
||||
sorting: [
|
||||
{
|
||||
id: "DaysSinceLast",
|
||||
desc: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
});
|
||||
//console.log(table.getState().sorting);
|
||||
//console.log(parseInt(style.height.replace("px", "")) - 50);
|
||||
return (
|
||||
<LstCard
|
||||
className="p-3"
|
||||
// style={{
|
||||
// width: `${parseInt(style.width.replace("px", "")) - 50}px`,
|
||||
// height: `${parseInt(style.height.replace("px", "")) - 150}px`,
|
||||
// cursor: "move",
|
||||
// }}
|
||||
//style={{ overflow: "auto" }}
|
||||
>
|
||||
<div>
|
||||
<div className="flex flex-row justify-between">
|
||||
<p className="text-center text-pretty">
|
||||
{info.type} {data.length > 0 ? "lanes" : "lane"} older
|
||||
than: {info.age}, needing to be completed
|
||||
</p>
|
||||
</div>
|
||||
<ScrollArea className="h-72 rounded-md border m-2">
|
||||
<Table
|
||||
// style={{
|
||||
// width: `${parseInt(style.width.replace("px", "")) - 50}px`,
|
||||
// height: `${parseInt(style.height.replace("px", "")) - 200}px`,
|
||||
// cursor: "move",
|
||||
// }}
|
||||
>
|
||||
<TableHeader>
|
||||
{table.getHeaderGroups().map((headerGroup) => (
|
||||
<TableRow key={headerGroup.id}>
|
||||
{headerGroup.headers.map((header) => {
|
||||
return (
|
||||
<TableHead key={header.id}>
|
||||
{header.isPlaceholder
|
||||
? null
|
||||
: flexRender(
|
||||
header.column
|
||||
.columnDef.header,
|
||||
header.getContext()
|
||||
)}
|
||||
</TableHead>
|
||||
);
|
||||
})}
|
||||
</TableRow>
|
||||
))}
|
||||
</TableHeader>
|
||||
<TableBody>
|
||||
{table.getRowModel().rows?.length ? (
|
||||
table.getRowModel().rows.map((row) => (
|
||||
<TableRow
|
||||
key={row.id}
|
||||
data-state={
|
||||
row.getIsSelected() && "selected"
|
||||
}
|
||||
>
|
||||
{row.getVisibleCells().map((cell) => (
|
||||
<TableCell key={cell.id}>
|
||||
{flexRender(
|
||||
cell.column.columnDef.cell,
|
||||
cell.getContext()
|
||||
)}
|
||||
</TableCell>
|
||||
))}
|
||||
</TableRow>
|
||||
))
|
||||
) : (
|
||||
<TableRow>
|
||||
<TableCell
|
||||
colSpan={columns.length}
|
||||
className="h-24 text-center"
|
||||
>
|
||||
No results.
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
)}
|
||||
</TableBody>
|
||||
</Table>
|
||||
</ScrollArea>
|
||||
</div>
|
||||
{/* <div className="flex items-center justify-end space-x-2">
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
onClick={() => table.previousPage()}
|
||||
disabled={!table.getCanPreviousPage()}
|
||||
>
|
||||
Previous
|
||||
</Button>
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
onClick={() => table.nextPage()}
|
||||
disabled={!table.getCanNextPage()}
|
||||
>
|
||||
Next
|
||||
</Button>
|
||||
</div> */}
|
||||
</LstCard>
|
||||
);
|
||||
}
|
||||
68
frontend/src/utils/tableData/notifications/notifyColumns.tsx
Normal file
68
frontend/src/utils/tableData/notifications/notifyColumns.tsx
Normal file
@@ -0,0 +1,68 @@
|
||||
import { ColumnDef } from "@tanstack/react-table";
|
||||
import { format } from "date-fns";
|
||||
|
||||
// This type is used to define the shape of our data.
|
||||
// You can use a Zod schema here if you want.
|
||||
export type Adjustmnets = {
|
||||
siloAdjust_id: string;
|
||||
currentStockLevel: string;
|
||||
newLevel: number;
|
||||
dateAdjusted: string;
|
||||
lastDateAdjusted: string;
|
||||
comment: string;
|
||||
commentAddedBy: string;
|
||||
commentDate: string;
|
||||
add_user: string;
|
||||
};
|
||||
|
||||
export const notifyColumns: ColumnDef<Adjustmnets>[] = [
|
||||
{
|
||||
accessorKey: "name",
|
||||
header: () => <div className="text-left">Name</div>,
|
||||
},
|
||||
{
|
||||
accessorKey: "description",
|
||||
header: "Description",
|
||||
cell: ({ row }) => {
|
||||
return (
|
||||
<div className="text-left font-medium">
|
||||
<p className="max-w-48 text-pretty">
|
||||
{row.getValue("description")}
|
||||
</p>
|
||||
</div>
|
||||
);
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
accessorKey: "checkInterval",
|
||||
header: "Check Interval",
|
||||
},
|
||||
{
|
||||
accessorKey: "timeType",
|
||||
header: "Time tpye",
|
||||
},
|
||||
{
|
||||
accessorKey: "emails",
|
||||
header: "Emails",
|
||||
},
|
||||
{
|
||||
accessorKey: "active",
|
||||
header: "Active",
|
||||
},
|
||||
{
|
||||
accessorKey: "lastRan",
|
||||
header: "Last Ran",
|
||||
cell: ({ row }) => {
|
||||
if (row.getValue("lastRan")) {
|
||||
const correctDate = format(
|
||||
row.getValue("lastRan"),
|
||||
"M/d/yyyy hh:mm"
|
||||
);
|
||||
return (
|
||||
<div className="text-left font-medium">{correctDate}</div>
|
||||
);
|
||||
}
|
||||
},
|
||||
},
|
||||
];
|
||||
134
frontend/src/utils/tableData/notifications/notifyData.tsx
Normal file
134
frontend/src/utils/tableData/notifications/notifyData.tsx
Normal file
@@ -0,0 +1,134 @@
|
||||
import {
|
||||
ColumnDef,
|
||||
flexRender,
|
||||
getCoreRowModel,
|
||||
useReactTable,
|
||||
getPaginationRowModel,
|
||||
} from "@tanstack/react-table";
|
||||
import {
|
||||
Table,
|
||||
TableBody,
|
||||
TableCell,
|
||||
TableHead,
|
||||
TableHeader,
|
||||
TableRow,
|
||||
} from "@/components/ui/table";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { useState } from "react";
|
||||
|
||||
interface DataTableProps<TData, TValue> {
|
||||
columns: ColumnDef<TData, TValue>[];
|
||||
data: TData[];
|
||||
//style: any;
|
||||
}
|
||||
|
||||
export function NotifyTable<TData, TValue>({
|
||||
columns,
|
||||
data,
|
||||
//style,
|
||||
}: DataTableProps<TData, TValue>) {
|
||||
const [pagination, setPagination] = useState({
|
||||
pageIndex: 0, //initial page index
|
||||
pageSize: 5, //default page size
|
||||
});
|
||||
const table = useReactTable({
|
||||
data,
|
||||
columns,
|
||||
getCoreRowModel: getCoreRowModel(),
|
||||
getPaginationRowModel: getPaginationRowModel(),
|
||||
onPaginationChange: setPagination,
|
||||
state: {
|
||||
//...
|
||||
pagination,
|
||||
},
|
||||
});
|
||||
|
||||
// console.log(parseInt(style.height.replace("px", "")) - 50);
|
||||
return (
|
||||
<div
|
||||
// style={{
|
||||
// width: `${parseInt(style.width.replace("px", "")) - 50}px`,
|
||||
// height: `${parseInt(style.height.replace("px", "")) - 150}px`,
|
||||
// cursor: "move",
|
||||
// }}
|
||||
>
|
||||
<div>
|
||||
<Table
|
||||
// style={{
|
||||
// width: `${parseInt(style.width.replace("px", "")) - 50}px`,
|
||||
// height: `${parseInt(style.height.replace("px", "")) - 200}px`,
|
||||
// cursor: "move",
|
||||
// }}
|
||||
>
|
||||
<TableHeader>
|
||||
{table.getHeaderGroups().map((headerGroup) => (
|
||||
<TableRow key={headerGroup.id}>
|
||||
{headerGroup.headers.map((header) => {
|
||||
return (
|
||||
<TableHead key={header.id}>
|
||||
{header.isPlaceholder
|
||||
? null
|
||||
: flexRender(
|
||||
header.column.columnDef
|
||||
.header,
|
||||
header.getContext()
|
||||
)}
|
||||
</TableHead>
|
||||
);
|
||||
})}
|
||||
</TableRow>
|
||||
))}
|
||||
</TableHeader>
|
||||
<TableBody>
|
||||
{table.getRowModel().rows?.length ? (
|
||||
table.getRowModel().rows.map((row) => (
|
||||
<TableRow
|
||||
key={row.id}
|
||||
data-state={
|
||||
row.getIsSelected() && "selected"
|
||||
}
|
||||
>
|
||||
{row.getVisibleCells().map((cell) => (
|
||||
<TableCell key={cell.id}>
|
||||
{flexRender(
|
||||
cell.column.columnDef.cell,
|
||||
cell.getContext()
|
||||
)}
|
||||
</TableCell>
|
||||
))}
|
||||
</TableRow>
|
||||
))
|
||||
) : (
|
||||
<TableRow>
|
||||
<TableCell
|
||||
colSpan={columns.length}
|
||||
className="h-24 text-center"
|
||||
>
|
||||
No results.
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
)}
|
||||
</TableBody>
|
||||
</Table>
|
||||
</div>
|
||||
<div className="flex items-center justify-end space-x-2 py-4">
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
onClick={() => table.previousPage()}
|
||||
disabled={!table.getCanPreviousPage()}
|
||||
>
|
||||
Previous
|
||||
</Button>
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
onClick={() => table.nextPage()}
|
||||
disabled={!table.getCanNextPage()}
|
||||
>
|
||||
Next
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -14,41 +14,93 @@ import {
|
||||
TableRow,
|
||||
} from "@/components/ui/table";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { useState } from "react";
|
||||
import {
|
||||
Select,
|
||||
SelectContent,
|
||||
SelectGroup,
|
||||
SelectItem,
|
||||
SelectLabel,
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
} from "@/components/ui/select";
|
||||
import { ScrollArea } from "@/components/ui/scroll-area";
|
||||
import { LstCard } from "@/components/extendedUI/LstCard";
|
||||
|
||||
interface DataTableProps<TData, TValue> {
|
||||
columns: ColumnDef<TData, TValue>[];
|
||||
data: TData[];
|
||||
style: any;
|
||||
//style: any;
|
||||
}
|
||||
|
||||
export function PPOOTable<TData, TValue>({
|
||||
columns,
|
||||
data,
|
||||
style,
|
||||
//style,
|
||||
}: DataTableProps<TData, TValue>) {
|
||||
const [pagination, setPagination] = useState({
|
||||
pageIndex: 0, //initial page index
|
||||
pageSize: 5, //default page size
|
||||
});
|
||||
const table = useReactTable({
|
||||
data,
|
||||
columns,
|
||||
getCoreRowModel: getCoreRowModel(),
|
||||
getPaginationRowModel: getPaginationRowModel(),
|
||||
onPaginationChange: setPagination,
|
||||
state: {
|
||||
//...
|
||||
pagination,
|
||||
},
|
||||
});
|
||||
|
||||
console.log(parseInt(style.height.replace("px", "")) - 50);
|
||||
//console.log(parseInt(style.height.replace("px", "")) - 50);
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
width: `${parseInt(style.width.replace("px", "")) - 50}px`,
|
||||
height: `${parseInt(style.height.replace("px", "")) - 150}px`,
|
||||
cursor: "move",
|
||||
}}
|
||||
<LstCard
|
||||
className="p-3"
|
||||
// style={{
|
||||
// width: `${parseInt(style.width.replace("px", "")) - 50}px`,
|
||||
// height: `${parseInt(style.height.replace("px", "")) - 150}px`,
|
||||
// cursor: "move",
|
||||
// }}
|
||||
//style={{ overflow: "auto" }}
|
||||
>
|
||||
<div>
|
||||
<div className="flex flex-row justify-between">
|
||||
<p className="text-center">PPOO Data </p>
|
||||
<Select
|
||||
value={pagination.pageSize.toString()}
|
||||
onValueChange={(e) =>
|
||||
setPagination({
|
||||
...pagination,
|
||||
pageSize: parseInt(e),
|
||||
})
|
||||
}
|
||||
>
|
||||
<SelectTrigger className="w-[180px]">
|
||||
<SelectValue
|
||||
//id={field.name}
|
||||
placeholder="Select Page"
|
||||
/>
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectGroup>
|
||||
<SelectLabel>Page Size</SelectLabel>
|
||||
<SelectItem value="5">5</SelectItem>
|
||||
<SelectItem value="10">10</SelectItem>
|
||||
<SelectItem value="50">50</SelectItem>
|
||||
<SelectItem value="100">100</SelectItem>
|
||||
</SelectGroup>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
<ScrollArea className="h-72 rounded-md border m-2">
|
||||
<Table
|
||||
style={{
|
||||
width: `${parseInt(style.width.replace("px", "")) - 50}px`,
|
||||
height: `${parseInt(style.height.replace("px", "")) - 200}px`,
|
||||
cursor: "move",
|
||||
}}
|
||||
// style={{
|
||||
// width: `${parseInt(style.width.replace("px", "")) - 50}px`,
|
||||
// height: `${parseInt(style.height.replace("px", "")) - 200}px`,
|
||||
// cursor: "move",
|
||||
// }}
|
||||
>
|
||||
<TableHeader>
|
||||
{table.getHeaderGroups().map((headerGroup) => (
|
||||
@@ -59,8 +111,8 @@ export function PPOOTable<TData, TValue>({
|
||||
{header.isPlaceholder
|
||||
? null
|
||||
: flexRender(
|
||||
header.column.columnDef
|
||||
.header,
|
||||
header.column
|
||||
.columnDef.header,
|
||||
header.getContext()
|
||||
)}
|
||||
</TableHead>
|
||||
@@ -100,8 +152,9 @@ export function PPOOTable<TData, TValue>({
|
||||
)}
|
||||
</TableBody>
|
||||
</Table>
|
||||
</ScrollArea>
|
||||
</div>
|
||||
<div className="flex items-center justify-end space-x-2 py-4">
|
||||
<div className="flex items-center justify-end space-x-2">
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
@@ -119,6 +172,6 @@ export function PPOOTable<TData, TValue>({
|
||||
Next
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</LstCard>
|
||||
);
|
||||
}
|
||||
|
||||
68
frontend/src/utils/tableData/printers/printerColumns.tsx
Normal file
68
frontend/src/utils/tableData/printers/printerColumns.tsx
Normal file
@@ -0,0 +1,68 @@
|
||||
import { ColumnDef } from "@tanstack/react-table";
|
||||
import { format } from "date-fns";
|
||||
|
||||
// This type is used to define the shape of our data.
|
||||
// You can use a Zod schema here if you want.
|
||||
export type Adjustmnets = {
|
||||
siloAdjust_id: string;
|
||||
currentStockLevel: string;
|
||||
newLevel: number;
|
||||
dateAdjusted: string;
|
||||
lastDateAdjusted: string;
|
||||
comment: string;
|
||||
commentAddedBy: string;
|
||||
commentDate: string;
|
||||
add_user: string;
|
||||
};
|
||||
|
||||
export const notifyColumns: ColumnDef<Adjustmnets>[] = [
|
||||
{
|
||||
accessorKey: "name",
|
||||
header: () => <div className="text-left">Name</div>,
|
||||
},
|
||||
{
|
||||
accessorKey: "description",
|
||||
header: "Description",
|
||||
cell: ({ row }) => {
|
||||
return (
|
||||
<div className="text-left font-medium">
|
||||
<p className="max-w-48 text-pretty">
|
||||
{row.getValue("description")}
|
||||
</p>
|
||||
</div>
|
||||
);
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
accessorKey: "checkInterval",
|
||||
header: "Check Interval",
|
||||
},
|
||||
{
|
||||
accessorKey: "timeType",
|
||||
header: "Time tpye",
|
||||
},
|
||||
{
|
||||
accessorKey: "emails",
|
||||
header: "Emails",
|
||||
},
|
||||
{
|
||||
accessorKey: "active",
|
||||
header: "Active",
|
||||
},
|
||||
{
|
||||
accessorKey: "lastRan",
|
||||
header: "Last Ran",
|
||||
cell: ({ row }) => {
|
||||
if (row.getValue("lastRan")) {
|
||||
const correctDate = format(
|
||||
row.getValue("lastRan"),
|
||||
"M/d/yyyy hh:mm"
|
||||
);
|
||||
return (
|
||||
<div className="text-left font-medium">{correctDate}</div>
|
||||
);
|
||||
}
|
||||
},
|
||||
},
|
||||
];
|
||||
134
frontend/src/utils/tableData/printers/printerData.tsx
Normal file
134
frontend/src/utils/tableData/printers/printerData.tsx
Normal file
@@ -0,0 +1,134 @@
|
||||
import {
|
||||
ColumnDef,
|
||||
flexRender,
|
||||
getCoreRowModel,
|
||||
useReactTable,
|
||||
getPaginationRowModel,
|
||||
} from "@tanstack/react-table";
|
||||
import {
|
||||
Table,
|
||||
TableBody,
|
||||
TableCell,
|
||||
TableHead,
|
||||
TableHeader,
|
||||
TableRow,
|
||||
} from "@/components/ui/table";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { useState } from "react";
|
||||
|
||||
interface DataTableProps<TData, TValue> {
|
||||
columns: ColumnDef<TData, TValue>[];
|
||||
data: TData[];
|
||||
//style: any;
|
||||
}
|
||||
|
||||
export function NotifyTable<TData, TValue>({
|
||||
columns,
|
||||
data,
|
||||
//style,
|
||||
}: DataTableProps<TData, TValue>) {
|
||||
const [pagination, setPagination] = useState({
|
||||
pageIndex: 0, //initial page index
|
||||
pageSize: 5, //default page size
|
||||
});
|
||||
const table = useReactTable({
|
||||
data,
|
||||
columns,
|
||||
getCoreRowModel: getCoreRowModel(),
|
||||
getPaginationRowModel: getPaginationRowModel(),
|
||||
onPaginationChange: setPagination,
|
||||
state: {
|
||||
//...
|
||||
pagination,
|
||||
},
|
||||
});
|
||||
|
||||
// console.log(parseInt(style.height.replace("px", "")) - 50);
|
||||
return (
|
||||
<div
|
||||
// style={{
|
||||
// width: `${parseInt(style.width.replace("px", "")) - 50}px`,
|
||||
// height: `${parseInt(style.height.replace("px", "")) - 150}px`,
|
||||
// cursor: "move",
|
||||
// }}
|
||||
>
|
||||
<div>
|
||||
<Table
|
||||
// style={{
|
||||
// width: `${parseInt(style.width.replace("px", "")) - 50}px`,
|
||||
// height: `${parseInt(style.height.replace("px", "")) - 200}px`,
|
||||
// cursor: "move",
|
||||
// }}
|
||||
>
|
||||
<TableHeader>
|
||||
{table.getHeaderGroups().map((headerGroup) => (
|
||||
<TableRow key={headerGroup.id}>
|
||||
{headerGroup.headers.map((header) => {
|
||||
return (
|
||||
<TableHead key={header.id}>
|
||||
{header.isPlaceholder
|
||||
? null
|
||||
: flexRender(
|
||||
header.column.columnDef
|
||||
.header,
|
||||
header.getContext()
|
||||
)}
|
||||
</TableHead>
|
||||
);
|
||||
})}
|
||||
</TableRow>
|
||||
))}
|
||||
</TableHeader>
|
||||
<TableBody>
|
||||
{table.getRowModel().rows?.length ? (
|
||||
table.getRowModel().rows.map((row) => (
|
||||
<TableRow
|
||||
key={row.id}
|
||||
data-state={
|
||||
row.getIsSelected() && "selected"
|
||||
}
|
||||
>
|
||||
{row.getVisibleCells().map((cell) => (
|
||||
<TableCell key={cell.id}>
|
||||
{flexRender(
|
||||
cell.column.columnDef.cell,
|
||||
cell.getContext()
|
||||
)}
|
||||
</TableCell>
|
||||
))}
|
||||
</TableRow>
|
||||
))
|
||||
) : (
|
||||
<TableRow>
|
||||
<TableCell
|
||||
colSpan={columns.length}
|
||||
className="h-24 text-center"
|
||||
>
|
||||
No results.
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
)}
|
||||
</TableBody>
|
||||
</Table>
|
||||
</div>
|
||||
<div className="flex items-center justify-end space-x-2 py-4">
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
onClick={() => table.previousPage()}
|
||||
disabled={!table.getCanPreviousPage()}
|
||||
>
|
||||
Previous
|
||||
</Button>
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
onClick={() => table.nextPage()}
|
||||
disabled={!table.getCanNextPage()}
|
||||
>
|
||||
Next
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -1,16 +1,22 @@
|
||||
import {defineConfig} from "vite";
|
||||
import { defineConfig } from "vite";
|
||||
import react from "@vitejs/plugin-react-swc";
|
||||
import tailwindcss from "@tailwindcss/vite";
|
||||
import {TanStackRouterVite} from "@tanstack/router-plugin/vite";
|
||||
import { TanStackRouterVite } from "@tanstack/router-plugin/vite";
|
||||
import path from "path";
|
||||
|
||||
import dotenv from "dotenv";
|
||||
import {fileURLToPath} from "url";
|
||||
dotenv.config({path: path.resolve(path.dirname(fileURLToPath(import.meta.url)), "../.env")});
|
||||
import { fileURLToPath } from "url";
|
||||
dotenv.config({
|
||||
path: path.resolve(path.dirname(fileURLToPath(import.meta.url)), "../.env"),
|
||||
});
|
||||
|
||||
// https://vite.dev/config/
|
||||
export default defineConfig({
|
||||
plugins: [react(), tailwindcss(), TanStackRouterVite({target: "react", autoCodeSplitting: true})],
|
||||
plugins: [
|
||||
react(),
|
||||
tailwindcss(),
|
||||
TanStackRouterVite({ target: "react", autoCodeSplitting: true }),
|
||||
],
|
||||
resolve: {
|
||||
alias: {
|
||||
"@": path.resolve(__dirname, "./src"),
|
||||
|
||||
104
package-lock.json
generated
104
package-lock.json
generated
@@ -40,6 +40,7 @@
|
||||
"rimraf": "^6.0.1",
|
||||
"st-ethernet-ip": "^2.7.3",
|
||||
"ws": "^8.18.1",
|
||||
"xlsx": "^0.18.5",
|
||||
"zod": "^3.24.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
@@ -2070,6 +2071,15 @@
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/adler-32": {
|
||||
"version": "1.3.1",
|
||||
"resolved": "https://registry.npmjs.org/adler-32/-/adler-32-1.3.1.tgz",
|
||||
"integrity": "sha512-ynZ4w/nUUv5rrsR8UUGoe1VC9hZj6V5hU9Qw1HlMDJGEJw5S7TfTErWTjMys6M7vr0YWcPqs3qAr4ss0nDfP+A==",
|
||||
"license": "Apache-2.0",
|
||||
"engines": {
|
||||
"node": ">=0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/adm-zip": {
|
||||
"version": "0.5.16",
|
||||
"resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.5.16.tgz",
|
||||
@@ -2452,6 +2462,19 @@
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/cfb": {
|
||||
"version": "1.2.2",
|
||||
"resolved": "https://registry.npmjs.org/cfb/-/cfb-1.2.2.tgz",
|
||||
"integrity": "sha512-KfdUZsSOw19/ObEWasvBP/Ac4reZvAGauZhs6S/gqNhXhI7cKwvlH7ulj+dOEYnca4bm4SGo8C1bTAQvnTjgQA==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"adler-32": "~1.3.0",
|
||||
"crc-32": "~1.2.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/chalk": {
|
||||
"version": "2.4.2",
|
||||
"resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
|
||||
@@ -2532,6 +2555,15 @@
|
||||
"node": ">=0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/codepage": {
|
||||
"version": "1.15.0",
|
||||
"resolved": "https://registry.npmjs.org/codepage/-/codepage-1.15.0.tgz",
|
||||
"integrity": "sha512-3g6NUTPd/YtuuGrhMnOMRjFc+LJw/bnMp3+0r/Wcz3IXUuCosKRJvMphm5+Q+bvTVGcJJuRvVLuYba+WojaFaA==",
|
||||
"license": "Apache-2.0",
|
||||
"engines": {
|
||||
"node": ">=0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/color-convert": {
|
||||
"version": "1.9.3",
|
||||
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
|
||||
@@ -3239,6 +3271,18 @@
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/crc-32": {
|
||||
"version": "1.2.2",
|
||||
"resolved": "https://registry.npmjs.org/crc-32/-/crc-32-1.2.2.tgz",
|
||||
"integrity": "sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==",
|
||||
"license": "Apache-2.0",
|
||||
"bin": {
|
||||
"crc32": "bin/crc32.njs"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/croner": {
|
||||
"version": "9.0.0",
|
||||
"resolved": "https://registry.npmjs.org/croner/-/croner-9.0.0.tgz",
|
||||
@@ -4293,6 +4337,15 @@
|
||||
"node": ">= 6"
|
||||
}
|
||||
},
|
||||
"node_modules/frac": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/frac/-/frac-1.1.2.tgz",
|
||||
"integrity": "sha512-w/XBfkibaTl3YDqASwfDUqkna4Z2p9cFSr1aHDt0WoMTECnRfBOv2WArlZILlqgWlmdIlALXGpM2AOhEk5W3IA==",
|
||||
"license": "Apache-2.0",
|
||||
"engines": {
|
||||
"node": ">=0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/fs-extra": {
|
||||
"version": "11.3.0",
|
||||
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.3.0.tgz",
|
||||
@@ -7781,6 +7834,18 @@
|
||||
"integrity": "sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==",
|
||||
"license": "BSD-3-Clause"
|
||||
},
|
||||
"node_modules/ssf": {
|
||||
"version": "0.11.2",
|
||||
"resolved": "https://registry.npmjs.org/ssf/-/ssf-0.11.2.tgz",
|
||||
"integrity": "sha512-+idbmIXoYET47hH+d7dfm2epdOMUDjqcB4648sTZ+t2JwoyBFL/insLfB/racrDmsKB3diwsDA696pZMieAC5g==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"frac": "~1.1.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/st-ethernet-ip": {
|
||||
"version": "2.7.3",
|
||||
"resolved": "https://registry.npmjs.org/st-ethernet-ip/-/st-ethernet-ip-2.7.3.tgz",
|
||||
@@ -8824,6 +8889,24 @@
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/wmf": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/wmf/-/wmf-1.0.2.tgz",
|
||||
"integrity": "sha512-/p9K7bEh0Dj6WbXg4JG0xvLQmIadrner1bi45VMJTfnbVHsc7yIajZyoSoK60/dtVBs12Fm6WkUI5/3WAVsNMw==",
|
||||
"license": "Apache-2.0",
|
||||
"engines": {
|
||||
"node": ">=0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/word": {
|
||||
"version": "0.3.0",
|
||||
"resolved": "https://registry.npmjs.org/word/-/word-0.3.0.tgz",
|
||||
"integrity": "sha512-OELeY0Q61OXpdUfTp+oweA/vtLVg5VDOXh+3he3PNzLGG/y0oylSOC1xRVj0+l4vQ3tj/bB1HVHv1ocXkQceFA==",
|
||||
"license": "Apache-2.0",
|
||||
"engines": {
|
||||
"node": ">=0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/word-wrap": {
|
||||
"version": "1.2.5",
|
||||
"resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz",
|
||||
@@ -8972,6 +9055,27 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/xlsx": {
|
||||
"version": "0.18.5",
|
||||
"resolved": "https://registry.npmjs.org/xlsx/-/xlsx-0.18.5.tgz",
|
||||
"integrity": "sha512-dmg3LCjBPHZnQp5/F/+nnTa+miPJxUXB6vtk42YjBBKayDNagxGEeIdWApkYPOf3Z3pm3k62Knjzp7lMeTEtFQ==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"adler-32": "~1.3.0",
|
||||
"cfb": "~1.2.1",
|
||||
"codepage": "~1.15.0",
|
||||
"crc-32": "~1.2.1",
|
||||
"ssf": "~0.11.2",
|
||||
"wmf": "~1.0.1",
|
||||
"word": "~0.3.0"
|
||||
},
|
||||
"bin": {
|
||||
"xlsx": "bin/xlsx.njs"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/xtend": {
|
||||
"version": "4.0.2",
|
||||
"resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz",
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
}
|
||||
},
|
||||
"admConfig": {
|
||||
"build": 217,
|
||||
"build": 224,
|
||||
"oldBuild": "backend-0.1.3.zip"
|
||||
},
|
||||
"devDependencies": {
|
||||
@@ -88,6 +88,7 @@
|
||||
"rimraf": "^6.0.1",
|
||||
"st-ethernet-ip": "^2.7.3",
|
||||
"ws": "^8.18.1",
|
||||
"xlsx": "^0.18.5",
|
||||
"zod": "^3.24.2"
|
||||
}
|
||||
}
|
||||
@@ -27,6 +27,7 @@ import { sendEmail } from "./services/notifications/controller/sendMail.js";
|
||||
import notify from "./services/notifications/notifyService.js";
|
||||
import eom from "./services/eom/eomService.js";
|
||||
import dataMart from "./services/dataMart/dataMartService.js";
|
||||
import qualityRequest from "./services/quality/qualityService.js";
|
||||
|
||||
// create the main prodlogin here
|
||||
const username = "lst_user";
|
||||
@@ -104,6 +105,7 @@ const routes = [
|
||||
notify,
|
||||
eom,
|
||||
dataMart,
|
||||
qualityRequest,
|
||||
] as const;
|
||||
|
||||
const appRoutes = routes.forEach((route) => {
|
||||
|
||||
@@ -9,14 +9,14 @@ import { cycleCountCheck } from "../../../../sqlServer/querys/warehouse/cycleCou
|
||||
// setting timer for updating stockCheck on a restart will always check.
|
||||
let lastCheck = 0;
|
||||
|
||||
export const lanes: any = [];
|
||||
export let lanes: any = [];
|
||||
|
||||
export const getLanesToCycleCount = async () => {
|
||||
const currentTime: any = timeZoneFix();
|
||||
// store the lanes in memeory
|
||||
createLog("info", "warehouse", "logistics", "Lane triggered update.");
|
||||
lastCheck = currentTime;
|
||||
const ageQuery = cycleCountCheck.replaceAll("[ageOfRow]", `1000`);
|
||||
const ageQuery = cycleCountCheck.replaceAll("[ageOfRow]", "90");
|
||||
const { data: prodLanes, error: pl } = await tryCatch(
|
||||
query(ageQuery, "Get Stock lane date.")
|
||||
);
|
||||
@@ -39,23 +39,25 @@ export const getLanesToCycleCount = async () => {
|
||||
warehouseName: prodLanes[i]?.warehouseName || "na",
|
||||
Description: prodLanes[i]?.Description,
|
||||
LastMoveDate: prodLanes[i]?.LastMoveDate
|
||||
? format(prodLanes[i]?.LastInv, "M/d/yyyy")
|
||||
? format(prodLanes[i]?.LastMoveDate, "M/d/yyyy")
|
||||
: undefined,
|
||||
LastInv: format(prodLanes[i]?.LastInv, "M/d/yyyy"),
|
||||
rowType: prodLanes[i].rowType,
|
||||
DaysSinceLast:
|
||||
differenceInDays(
|
||||
new Date(prodLanes[i].LastInv),
|
||||
new Date(prodLanes[i].LastMoveDate)
|
||||
) <= 0
|
||||
? 0
|
||||
: differenceInDays(
|
||||
new Date(prodLanes[i].LastInv),
|
||||
new Date(prodLanes[i].LastMoveDate)
|
||||
DaysSinceLast: differenceInDays(
|
||||
new Date(Date.now()),
|
||||
new Date(prodLanes[i].LastInv)
|
||||
),
|
||||
upd_date: format(new Date(Date.now()), "M/d/yyyy"),
|
||||
};
|
||||
|
||||
const existing = lanes.filter(
|
||||
(l: any) => l.laneID === prodLanes[i]?.laneID
|
||||
);
|
||||
|
||||
if (existing) {
|
||||
lanes = lanes.filter((l: any) => l.laneID !== prodLanes[i]?.laneID);
|
||||
}
|
||||
|
||||
lanes.push(createLane);
|
||||
createLog(
|
||||
"debug",
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
import * as XLSX from "xlsx";
|
||||
import { lanes } from "./cyclecountCheck.js";
|
||||
|
||||
export const lanesToExcel = async (age: string | null) => {
|
||||
// Convert JSON data to an array of arrays (AOA)
|
||||
|
||||
let processLanes = lanes;
|
||||
if (age) {
|
||||
processLanes = lanes.filter(
|
||||
(l: any) => l.DaysSinceLast >= parseInt(age)
|
||||
);
|
||||
}
|
||||
|
||||
const headers = Object.keys(processLanes[0]); // Get headers from JSON keys
|
||||
const data = processLanes.map((item: any) =>
|
||||
headers.map((header) => item[header])
|
||||
);
|
||||
|
||||
// Create the workbook and worksheet
|
||||
const wb = XLSX.utils.book_new();
|
||||
const ws = XLSX.utils.aoa_to_sheet([headers, ...data]); // Combine headers and data
|
||||
|
||||
// Auto-resize columns based on the longest content in each column
|
||||
const colWidths = headers.map((_, colIndex) => {
|
||||
let maxLength = 0;
|
||||
data.forEach((row: any) => {
|
||||
const cellValue = row[colIndex] ? row[colIndex].toString() : "";
|
||||
maxLength = Math.max(maxLength, cellValue.length);
|
||||
});
|
||||
return { wch: maxLength + 2 }; // Add a little padding
|
||||
});
|
||||
|
||||
ws["!cols"] = colWidths; // Set the column widths
|
||||
|
||||
// Add the worksheet to the workbook
|
||||
XLSX.utils.book_append_sheet(wb, ws, "CycleCount");
|
||||
|
||||
// Write the workbook to a buffer and return it
|
||||
const excelBuffer = XLSX.write(wb, { bookType: "xlsx", type: "buffer" });
|
||||
|
||||
return excelBuffer;
|
||||
};
|
||||
@@ -1,28 +1,41 @@
|
||||
import { lanes } from "./cyclecountCheck.js";
|
||||
|
||||
export const getCycleCountCheck = async (
|
||||
age: number = 1000,
|
||||
type: string = ""
|
||||
) => {
|
||||
export const getCycleCountCheck = async (age: number = 1000, type: any) => {
|
||||
/**
|
||||
* Get the lane data based on the age and type
|
||||
*/
|
||||
|
||||
let filteredLanes = lanes.filter((t: any) => t.DaysSinceLast >= age);
|
||||
let filteredLanes = lanes;
|
||||
|
||||
if (type === "empty") {
|
||||
let empty = lanes.filter((t: any) => t.rowType === type.toUpperCase());
|
||||
|
||||
if (type != "") {
|
||||
return {
|
||||
sucess: true,
|
||||
message: `${filteredLanes.length} lanes that are of type ${type} and have not been cycle counted in the last ${age} days.`,
|
||||
data: filteredLanes.filter(
|
||||
(t: any) => t.rowType === type.toUpperCase()
|
||||
message: `${empty.length} lanes that are of type ${type}.`,
|
||||
data: empty.sort(
|
||||
(a: any, b: any) => b.DaysSinceLast - a.DaysSinceLast
|
||||
),
|
||||
};
|
||||
} else {
|
||||
}
|
||||
|
||||
if (type != "") {
|
||||
let noType = lanes.filter((t: any) => t.DaysSinceLast >= age);
|
||||
|
||||
return {
|
||||
sucess: true,
|
||||
message: `${noType.length} lanes that are of type ${type} and have not been cycle counted in the last ${age} days.`,
|
||||
data: noType
|
||||
.filter((t: any) => t.rowType === type?.toUpperCase())
|
||||
.sort((a: any, b: any) => b.DaysSinceLast - a.DaysSinceLast),
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
success: true,
|
||||
message: `${filteredLanes.length} lanes grabed that have not been cycle counted in the last ${age} days.`,
|
||||
data: filteredLanes,
|
||||
data: filteredLanes.sort(
|
||||
(a: any, b: any) => b.DaysSinceLast - a.DaysSinceLast
|
||||
),
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
@@ -10,6 +10,7 @@ import getSiloAdjustments from "./route/siloAdjustments/getSiloAdjustments.js";
|
||||
import { getLanesToCycleCount } from "./controller/warehouse/cycleCountChecks/cyclecountCheck.js";
|
||||
import getCycleCountCheck from "./route/getCycleCountChecks.js";
|
||||
import getPPOO from "./route/getPPOO.js";
|
||||
import getcyclecount from "./route/getCycleCountLanes.js";
|
||||
|
||||
const app = new OpenAPIHono();
|
||||
|
||||
@@ -26,6 +27,7 @@ const routes = [
|
||||
getCycleCountCheck,
|
||||
//warehouse
|
||||
getPPOO,
|
||||
getcyclecount,
|
||||
] as const;
|
||||
|
||||
// app.route("/server", modules);
|
||||
|
||||
@@ -37,7 +37,7 @@ app.openapi(
|
||||
return c.json({ success: false, message: "Missing Data." });
|
||||
}
|
||||
|
||||
const check: any = body;
|
||||
const check: any = body ?? { age: 90, type: null };
|
||||
const { data: lanes, error: le } = await tryCatch(
|
||||
getCycleCountCheck(check.age, check.type)
|
||||
);
|
||||
|
||||
66
server/services/logistics/route/getCycleCountLanes.ts
Normal file
66
server/services/logistics/route/getCycleCountLanes.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 { lanesToExcel } from "../controller/warehouse/cycleCountChecks/exportCycleCountData.js";
|
||||
import { format } from "date-fns";
|
||||
|
||||
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 the lanes that need to be counted",
|
||||
method: "get",
|
||||
path: "/getcyclecount",
|
||||
// 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: "api/sqlProd/close" });
|
||||
const defaultFilename = `cycleCount-${format(
|
||||
new Date(Date.now()),
|
||||
"M-d-yyyy"
|
||||
)}.xlsx`;
|
||||
const filename = c.req.query("filename") || defaultFilename;
|
||||
const age = c.req.query("age") || null;
|
||||
const { data, error } = await tryCatch(lanesToExcel(age));
|
||||
|
||||
if (error) {
|
||||
return c.json({
|
||||
success: false,
|
||||
message: "Error getting lane data.",
|
||||
data: error,
|
||||
});
|
||||
}
|
||||
|
||||
return new Response(data, {
|
||||
headers: {
|
||||
"Content-Type":
|
||||
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
|
||||
"Content-Disposition": `attachment; filename="${filename}"`,
|
||||
},
|
||||
});
|
||||
|
||||
// return c.json({
|
||||
// success: data.success,
|
||||
// message: data.message,
|
||||
// data: data.data,
|
||||
// });
|
||||
}
|
||||
);
|
||||
export default app;
|
||||
30
server/services/notifications/controller/getNotifications.ts
Normal file
30
server/services/notifications/controller/getNotifications.ts
Normal file
@@ -0,0 +1,30 @@
|
||||
import { and, desc, eq, gte, inArray, lte, sql } from "drizzle-orm";
|
||||
import { db } from "../../../../database/dbclient.js";
|
||||
import { logs } from "../../../../database/schema/logs.js";
|
||||
import { createLog } from "../../logger/logger.js";
|
||||
import { tryCatch } from "../../../globalUtils/tryCatch.js";
|
||||
import { notifications } from "../../../../database/schema/notifications.js";
|
||||
|
||||
export const getNotifications = async () => {
|
||||
const { data, error } = await tryCatch(db.select().from(notifications));
|
||||
|
||||
if (error) {
|
||||
createLog(
|
||||
"error",
|
||||
"notify",
|
||||
"notify",
|
||||
`Error getting notifications: ${error}`
|
||||
);
|
||||
return {
|
||||
success: false,
|
||||
message: "Error getting notifications.",
|
||||
data: error,
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
sucess: true,
|
||||
message: "Current notifications.",
|
||||
data: data,
|
||||
};
|
||||
};
|
||||
@@ -11,10 +11,11 @@ import { startNotificationMonitor } from "./utils/processNotifications.js";
|
||||
import notifyStats from "./routes/getActiveNotifications.js";
|
||||
import tiTrigger from "./routes/manualTiggerTi.js";
|
||||
import blocking from "./routes/qualityBlocking.js";
|
||||
import notify from "./routes/getNotifications.js";
|
||||
|
||||
const app = new OpenAPIHono();
|
||||
|
||||
const routes = [sendemail, notifyStats, tiTrigger, blocking] as const;
|
||||
const routes = [sendemail, notifyStats, tiTrigger, blocking, notify] as const;
|
||||
|
||||
const appRoutes = routes.forEach((route) => {
|
||||
app.route("/notify", route);
|
||||
|
||||
44
server/services/notifications/routes/getNotifications.ts
Normal file
44
server/services/notifications/routes/getNotifications.ts
Normal file
@@ -0,0 +1,44 @@
|
||||
// an external way to creating logs
|
||||
import { createRoute, OpenAPIHono, z } from "@hono/zod-openapi";
|
||||
//import { apiHit } from "../../../globalUtils/apiHits.js";
|
||||
import { responses } from "../../../globalUtils/routeDefs/responses.js";
|
||||
import { getNotifications } from "../controller/getNotifications.js";
|
||||
import { tryCatch } from "../../../globalUtils/tryCatch.js";
|
||||
|
||||
const app = new OpenAPIHono({ strict: false });
|
||||
|
||||
app.openapi(
|
||||
createRoute({
|
||||
tags: ["notify"],
|
||||
summary: "Gets notifications.",
|
||||
method: "get",
|
||||
path: "/notifications",
|
||||
// description:
|
||||
// "This might be a temp soltuin during the transtion between versions",
|
||||
responses: responses(),
|
||||
}),
|
||||
async (c: any) => {
|
||||
//apiHit(c, { endpoint: `api/logger/logs` });
|
||||
const { data, error } = await tryCatch(getNotifications());
|
||||
|
||||
if (error) {
|
||||
return c.json(
|
||||
{
|
||||
success: false,
|
||||
message: "There was an error clearing the log.",
|
||||
data: error,
|
||||
},
|
||||
400
|
||||
);
|
||||
}
|
||||
return c.json(
|
||||
{
|
||||
success: data?.success,
|
||||
message: data?.message,
|
||||
data: data?.data,
|
||||
},
|
||||
200
|
||||
);
|
||||
}
|
||||
);
|
||||
export default app;
|
||||
@@ -130,7 +130,7 @@ export const createLabel = async (data: any, userPrinted: any) => {
|
||||
|
||||
// check if we can remove labels or not
|
||||
//deleteLabels();
|
||||
return { sucess: true, message: "Label created", data: returnData }; // returning label data to be able to book in if active
|
||||
return { success: true, message: "Label created", data: returnData }; // returning label data to be able to book in if active
|
||||
} catch (error) {
|
||||
createLog(
|
||||
"info",
|
||||
|
||||
@@ -214,15 +214,15 @@ export const labelingProcess = async ({
|
||||
// create the label
|
||||
const label = await createLabel(filteredLot[0], userPrinted);
|
||||
|
||||
// if (!label.success) {
|
||||
// createLog(
|
||||
// "error",
|
||||
// "labeling",
|
||||
// "ocp",
|
||||
// `There was an error creating the label: ${label.message}`
|
||||
// );
|
||||
// return { sucess: false, message: label.message, data: label.data };
|
||||
// }
|
||||
if (!label.success) {
|
||||
createLog(
|
||||
"error",
|
||||
"labeling",
|
||||
"ocp",
|
||||
`There was an error creating the label: ${label.message}`
|
||||
);
|
||||
return { sucess: false, message: label.message, data: label.data };
|
||||
}
|
||||
|
||||
// send over to be booked in if we can do it.
|
||||
const bookin = settingData.filter((s) => s.name === "bookin");
|
||||
|
||||
20
server/services/quality/qualityService.ts
Normal file
20
server/services/quality/qualityService.ts
Normal file
@@ -0,0 +1,20 @@
|
||||
import { OpenAPIHono } from "@hono/zod-openapi";
|
||||
import { qualityRequest } from "../../../database/schema/qualityRequest.js";
|
||||
import { db } from "../../../database/dbclient.js";
|
||||
|
||||
const app = new OpenAPIHono();
|
||||
const routes = [] as const;
|
||||
|
||||
const appRoutes = routes.forEach((route) => {
|
||||
app.route("/quality", route);
|
||||
});
|
||||
app.all("/quality/*", (c) => {
|
||||
return c.json({
|
||||
success: false,
|
||||
message: "You have encounters a quality route that dose not exist.",
|
||||
});
|
||||
});
|
||||
|
||||
await db.select().from(qualityRequest);
|
||||
|
||||
export default app;
|
||||
@@ -1,8 +1,7 @@
|
||||
export const deliveryByDateRange = `
|
||||
|
||||
use AlplaPROD_test1
|
||||
DECLARE @StartDate DATE = ' [startDate] ' -- 2025-1-1
|
||||
DECLARE @EndDate DATE = '[endDate]' -- 2025-1-31
|
||||
DECLARE @StartDate DATE = ' 1990-1-1 ' -- 2025-1-1
|
||||
DECLARE @EndDate DATE = '2025-4-18' -- 2025-1-31
|
||||
select * from
|
||||
(select (select wert from dbo.T_SystemParameter where Bezeichnung = 'Werkskuerzel') as Plant,
|
||||
AuftragsNummer as OrderNumber,
|
||||
@@ -37,7 +36,7 @@ dbo.V_ArtikelKomplett on V_TrackerAuftragsAbrufe.IdArtikelVarianten =
|
||||
dbo.V_ArtikelKomplett.IdArtikelvarianten
|
||||
where GelieferteMengeVPK > 0 AND (
|
||||
AbrufLiefertermin IS NULL
|
||||
OR CONVERT(date, AbrufLiefertermin) BETWEEN @StartDate AND @EndDate
|
||||
OR CONVERT(date, JournalDatum) BETWEEN @StartDate AND @EndDate
|
||||
)
|
||||
|
||||
/*in house*/
|
||||
@@ -69,5 +68,5 @@ where CONVERT(date, Upd_Date) BETWEEN @StartDate AND @EndDate
|
||||
) x
|
||||
|
||||
|
||||
order by DeliveryDate desc
|
||||
order by Bol_PrintDate desc
|
||||
`;
|
||||
|
||||
Reference in New Issue
Block a user