Compare commits
2 Commits
50cf87380d
...
71a951a9f2
| Author | SHA1 | Date | |
|---|---|---|---|
| 71a951a9f2 | |||
| fda0719d87 |
22
database/schema/eom.ts
Normal file
22
database/schema/eom.ts
Normal file
@@ -0,0 +1,22 @@
|
||||
import {date, pgTable, text} from "drizzle-orm/pg-core";
|
||||
import {createSelectSchema} from "drizzle-zod";
|
||||
|
||||
export const eom = pgTable(
|
||||
"eom",
|
||||
{
|
||||
eomMonth: date().notNull(),
|
||||
article: text().notNull(),
|
||||
articleDescription: text().notNull(),
|
||||
}
|
||||
// (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(eom);
|
||||
95
frontend/package-lock.json
generated
95
frontend/package-lock.json
generated
@@ -15,8 +15,10 @@
|
||||
"@radix-ui/react-dialog": "^1.1.6",
|
||||
"@radix-ui/react-dropdown-menu": "^2.1.6",
|
||||
"@radix-ui/react-label": "^2.1.2",
|
||||
"@radix-ui/react-popover": "^1.1.6",
|
||||
"@radix-ui/react-separator": "^1.1.2",
|
||||
"@radix-ui/react-slot": "^1.1.2",
|
||||
"@radix-ui/react-tabs": "^1.1.3",
|
||||
"@radix-ui/react-tooltip": "^1.1.8",
|
||||
"@tailwindcss/vite": "^4.0.9",
|
||||
"@tanstack/react-query": "^5.66.9",
|
||||
@@ -24,6 +26,7 @@
|
||||
"@tanstack/react-table": "^8.21.2",
|
||||
"class-variance-authority": "^0.7.1",
|
||||
"clsx": "^2.1.1",
|
||||
"date-fns": "^4.1.0",
|
||||
"dotenv": "^16.4.7",
|
||||
"hono": "^4.7.2",
|
||||
"js-cookie": "^3.0.5",
|
||||
@@ -31,6 +34,7 @@
|
||||
"lucide-react": "^0.476.0",
|
||||
"next-themes": "^0.4.4",
|
||||
"react": "^19.0.0",
|
||||
"react-day-picker": "^8.10.1",
|
||||
"react-dom": "^19.0.0",
|
||||
"react-grid-layout": "^1.5.0",
|
||||
"react-hook-form": "^7.54.2",
|
||||
@@ -1546,6 +1550,43 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@radix-ui/react-popover": {
|
||||
"version": "1.1.6",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-popover/-/react-popover-1.1.6.tgz",
|
||||
"integrity": "sha512-NQouW0x4/GnkFJ/pRqsIS3rM/k97VzKnVb2jB7Gq7VEGPy5g7uNV1ykySFt7eWSp3i2uSGFwaJcvIRJBAHmmFg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@radix-ui/primitive": "1.1.1",
|
||||
"@radix-ui/react-compose-refs": "1.1.1",
|
||||
"@radix-ui/react-context": "1.1.1",
|
||||
"@radix-ui/react-dismissable-layer": "1.1.5",
|
||||
"@radix-ui/react-focus-guards": "1.1.1",
|
||||
"@radix-ui/react-focus-scope": "1.1.2",
|
||||
"@radix-ui/react-id": "1.1.0",
|
||||
"@radix-ui/react-popper": "1.2.2",
|
||||
"@radix-ui/react-portal": "1.1.4",
|
||||
"@radix-ui/react-presence": "1.1.2",
|
||||
"@radix-ui/react-primitive": "2.0.2",
|
||||
"@radix-ui/react-slot": "1.1.2",
|
||||
"@radix-ui/react-use-controllable-state": "1.1.0",
|
||||
"aria-hidden": "^1.2.4",
|
||||
"react-remove-scroll": "^2.6.3"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/react": "*",
|
||||
"@types/react-dom": "*",
|
||||
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
|
||||
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/react": {
|
||||
"optional": true
|
||||
},
|
||||
"@types/react-dom": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@radix-ui/react-popper": {
|
||||
"version": "1.2.2",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-popper/-/react-popper-1.2.2.tgz",
|
||||
@@ -1721,6 +1762,36 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@radix-ui/react-tabs": {
|
||||
"version": "1.1.3",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-tabs/-/react-tabs-1.1.3.tgz",
|
||||
"integrity": "sha512-9mFyI30cuRDImbmFF6O2KUJdgEOsGh9Vmx9x/Dh9tOhL7BngmQPQfwW4aejKm5OHpfWIdmeV6ySyuxoOGjtNng==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@radix-ui/primitive": "1.1.1",
|
||||
"@radix-ui/react-context": "1.1.1",
|
||||
"@radix-ui/react-direction": "1.1.0",
|
||||
"@radix-ui/react-id": "1.1.0",
|
||||
"@radix-ui/react-presence": "1.1.2",
|
||||
"@radix-ui/react-primitive": "2.0.2",
|
||||
"@radix-ui/react-roving-focus": "1.1.2",
|
||||
"@radix-ui/react-use-controllable-state": "1.1.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/react": "*",
|
||||
"@types/react-dom": "*",
|
||||
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
|
||||
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/react": {
|
||||
"optional": true
|
||||
},
|
||||
"@types/react-dom": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@radix-ui/react-tooltip": {
|
||||
"version": "1.1.8",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-tooltip/-/react-tooltip-1.1.8.tgz",
|
||||
@@ -3579,6 +3650,16 @@
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/date-fns": {
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/date-fns/-/date-fns-4.1.0.tgz",
|
||||
"integrity": "sha512-Ukq0owbQXxa/U3EGtsdVBkR1w7KOQ5gIBqdH2hkvknzZPYvBxb/aa6E8L7tmjFtkwZBu3UXBbjIgPo/Ez4xaNg==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/kossnocorp"
|
||||
}
|
||||
},
|
||||
"node_modules/debug": {
|
||||
"version": "4.4.0",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz",
|
||||
@@ -5038,6 +5119,20 @@
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/react-day-picker": {
|
||||
"version": "8.10.1",
|
||||
"resolved": "https://registry.npmjs.org/react-day-picker/-/react-day-picker-8.10.1.tgz",
|
||||
"integrity": "sha512-TMx7fNbhLk15eqcMt+7Z7S2KF7mfTId/XJDjKE8f+IUcFn0l08/kI4FiYTL/0yuOLmEcbR4Fwe3GJf/NiiMnPA==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "individual",
|
||||
"url": "https://github.com/sponsors/gpbl"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"date-fns": "^2.28.0 || ^3.0.0",
|
||||
"react": "^16.8.0 || ^17.0.0 || ^18.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/react-dom": {
|
||||
"version": "19.0.0",
|
||||
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.0.0.tgz",
|
||||
|
||||
@@ -18,8 +18,10 @@
|
||||
"@radix-ui/react-dialog": "^1.1.6",
|
||||
"@radix-ui/react-dropdown-menu": "^2.1.6",
|
||||
"@radix-ui/react-label": "^2.1.2",
|
||||
"@radix-ui/react-popover": "^1.1.6",
|
||||
"@radix-ui/react-separator": "^1.1.2",
|
||||
"@radix-ui/react-slot": "^1.1.2",
|
||||
"@radix-ui/react-tabs": "^1.1.3",
|
||||
"@radix-ui/react-tooltip": "^1.1.8",
|
||||
"@tailwindcss/vite": "^4.0.9",
|
||||
"@tanstack/react-query": "^5.66.9",
|
||||
@@ -27,6 +29,7 @@
|
||||
"@tanstack/react-table": "^8.21.2",
|
||||
"class-variance-authority": "^0.7.1",
|
||||
"clsx": "^2.1.1",
|
||||
"date-fns": "^4.1.0",
|
||||
"dotenv": "^16.4.7",
|
||||
"hono": "^4.7.2",
|
||||
"js-cookie": "^3.0.5",
|
||||
@@ -34,6 +37,7 @@
|
||||
"lucide-react": "^0.476.0",
|
||||
"next-themes": "^0.4.4",
|
||||
"react": "^19.0.0",
|
||||
"react-day-picker": "^8.10.1",
|
||||
"react-dom": "^19.0.0",
|
||||
"react-grid-layout": "^1.5.0",
|
||||
"react-hook-form": "^7.54.2",
|
||||
|
||||
@@ -6,6 +6,7 @@ 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 = {
|
||||
settings_id?: string;
|
||||
@@ -28,9 +29,9 @@ export default function SettingsPage() {
|
||||
|
||||
const {data, isError, error, isLoading} = useQuery(getSettings(token ?? ""));
|
||||
|
||||
if (isLoading) {
|
||||
return <div>Loading.....</div>;
|
||||
}
|
||||
// if (isLoading) {
|
||||
// return <div>Loading.....</div>;
|
||||
// }
|
||||
if (isError) {
|
||||
return <div>{JSON.stringify(error)}</div>;
|
||||
}
|
||||
@@ -43,21 +44,47 @@ export default function SettingsPage() {
|
||||
<TableRow>
|
||||
<TableHead>Name</TableHead>
|
||||
<TableHead>Value</TableHead>
|
||||
<TableHead>Description</TableHead>
|
||||
<TableHead>Change</TableHead>
|
||||
</TableRow>
|
||||
</TableHeader>
|
||||
<TableBody>
|
||||
{data?.map((setting: Settings) => (
|
||||
<TableRow key={setting.settings_id}>
|
||||
<TableCell className="font-medium">{setting.name}</TableCell>
|
||||
<TableCell className="font-medium">{setting.value}</TableCell>
|
||||
<TableCell className="font-medium">{setting.description}</TableCell>
|
||||
<TableCell className="font-medium">
|
||||
<ChangeSetting setting={setting} />
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
))}
|
||||
</TableBody>
|
||||
{isLoading ? (
|
||||
<>
|
||||
<TableBody>
|
||||
{Array(10)
|
||||
.fill(0)
|
||||
.map((_, i) => (
|
||||
<TableRow key={i}>
|
||||
<TableCell className="font-medium">
|
||||
<Skeleton className="h-4" />
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<Skeleton className="h-4" />
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<Skeleton className="h-4" />
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<Skeleton className="h-4" />
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
))}
|
||||
</TableBody>
|
||||
</>
|
||||
) : (
|
||||
<TableBody>
|
||||
{data?.map((setting: Settings) => (
|
||||
<TableRow key={setting.settings_id}>
|
||||
<TableCell className="font-medium">{setting.name}</TableCell>
|
||||
<TableCell className="font-medium">{setting.value}</TableCell>
|
||||
<TableCell className="font-medium">{setting.description}</TableCell>
|
||||
<TableCell className="font-medium">
|
||||
<ChangeSetting setting={setting} />
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
))}
|
||||
</TableBody>
|
||||
)}
|
||||
</Table>
|
||||
</LstCard>
|
||||
);
|
||||
|
||||
131
frontend/src/components/eom/EomPage.tsx
Normal file
131
frontend/src/components/eom/EomPage.tsx
Normal file
@@ -0,0 +1,131 @@
|
||||
import {useSessionStore} from "@/lib/store/sessionStore";
|
||||
import {LstCard} from "../extendedUI/LstCard";
|
||||
import {Tabs, TabsContent, TabsList, TabsTrigger} from "../ui/tabs";
|
||||
import {useModuleStore} from "@/lib/store/useModuleStore";
|
||||
import {Table, TableBody, TableCell, TableHead, TableHeader, TableRow} from "../ui/table";
|
||||
import {Skeleton} from "../ui/skeleton";
|
||||
|
||||
import {Link, useRouter} from "@tanstack/react-router";
|
||||
import {Popover, PopoverContent, PopoverTrigger} from "../ui/popover";
|
||||
import {Button} from "../ui/button";
|
||||
import {cn} from "@/lib/utils";
|
||||
import {CalendarIcon} from "lucide-react";
|
||||
import {format, startOfMonth} from "date-fns";
|
||||
import {Calendar} from "../ui/calendar";
|
||||
import {useState} from "react";
|
||||
import {toast} from "sonner";
|
||||
import KFP from "./KFP";
|
||||
|
||||
export default function EomPage() {
|
||||
const {modules} = useModuleStore();
|
||||
const {user} = useSessionStore();
|
||||
const router = useRouter();
|
||||
const [date, setDate] = useState<Date>();
|
||||
|
||||
if (!user) {
|
||||
router.navigate({to: "/"});
|
||||
}
|
||||
const eomMod = modules.filter((m) => m.name === "eom");
|
||||
// the users current role for eom is?
|
||||
const role: any = user?.roles.filter((r) => r.module_id === eomMod[0].module_id) || "";
|
||||
|
||||
const tabs = [
|
||||
{key: "kfp", label: "Key Figures", roles: ["admin", "systemAdmin"], content: <KFP />},
|
||||
{key: "fg", label: "Finished Goods", roles: ["admin", "systemAdmin"], content: <DummyContent />},
|
||||
{key: "mm", label: "Main Material", roles: ["admin", "systemAdmin"], content: <DummyContent />},
|
||||
{key: "mb", label: "Master Batch", roles: ["admin", "systemAdmin"], content: <DummyContent />},
|
||||
{key: "ab", label: "Additive", roles: ["admin", "systemAdmin"], content: <DummyContent />},
|
||||
{key: "pp", label: "Purchased Preforms", roles: ["admin", "systemAdmin"], content: <DummyContent />},
|
||||
{key: "pre", label: "Preforms", roles: ["admin", "systemAdmin"], content: <DummyContent />},
|
||||
{key: "pkg", label: "Packaging", roles: ["admin", "systemAdmin"], content: <DummyContent />},
|
||||
{key: "ui", label: "Undefined Items", roles: ["admin"], content: <DummyContent />},
|
||||
];
|
||||
return (
|
||||
<div className="m-2 w-screen">
|
||||
<div className="mb-2 flex flex-row">
|
||||
<Popover>
|
||||
<PopoverTrigger asChild>
|
||||
<Button
|
||||
variant={"outline"}
|
||||
className={cn(
|
||||
"w-[280px] justify-start text-left font-normal",
|
||||
!date && "text-muted-foreground"
|
||||
)}
|
||||
>
|
||||
<CalendarIcon className="mr-2 h-4 w-4" />
|
||||
{date ? format(date, "PPP") : <span>Pick a date</span>}
|
||||
</Button>
|
||||
</PopoverTrigger>
|
||||
<PopoverContent className="w-auto p-0">
|
||||
<Calendar mode="single" selected={date} onSelect={setDate} initialFocus />
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
<div className="ml-2">
|
||||
<Button onClick={() => toast.success(`Getting data for ${startOfMonth(date!)}-${date}`)}>
|
||||
<span className="text-sm">Update Data</span>
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Tabs defaultValue="mm">
|
||||
<TabsList>
|
||||
{tabs.map((tab) => {
|
||||
if (tab.roles.includes(role[0].role))
|
||||
return <TabsTrigger value={tab.key}>{tab.label}</TabsTrigger>;
|
||||
})}
|
||||
</TabsList>
|
||||
{tabs.map((tab) => {
|
||||
if (tab.roles.includes(role[0].role))
|
||||
return <TabsContent value={tab.key}>{tab.content}</TabsContent>;
|
||||
})}
|
||||
</Tabs>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function DummyContent() {
|
||||
return (
|
||||
<LstCard className="w-5/6">
|
||||
<Table>
|
||||
<TableHeader>
|
||||
<TableRow>
|
||||
<TableHead>Av</TableHead>
|
||||
<TableHead>Description</TableHead>
|
||||
<TableHead>Material Type</TableHead>
|
||||
<TableHead>Waste</TableHead>
|
||||
<TableHead>Loss / Gain $$</TableHead>
|
||||
</TableRow>
|
||||
</TableHeader>
|
||||
|
||||
<TableBody>
|
||||
{Array(10)
|
||||
.fill(0)
|
||||
.map((_, i) => (
|
||||
<TableRow key={i}>
|
||||
<TableCell className="font-medium m-2">
|
||||
<Link to="/article/$av" params={{av: `${i}`}}>
|
||||
{i}
|
||||
</Link>
|
||||
</TableCell>
|
||||
<TableCell className="font-medium">
|
||||
<Skeleton className="h-4" />
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<Skeleton className="h-4" />
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<Skeleton className="h-4" />
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<Skeleton className="h-4" />
|
||||
</TableCell>
|
||||
{/* <TableCell>
|
||||
<Skeleton className="h-4" />
|
||||
</TableCell> */}
|
||||
</TableRow>
|
||||
))}
|
||||
</TableBody>
|
||||
</Table>
|
||||
</LstCard>
|
||||
);
|
||||
}
|
||||
68
frontend/src/components/eom/KFP.tsx
Normal file
68
frontend/src/components/eom/KFP.tsx
Normal file
@@ -0,0 +1,68 @@
|
||||
import {useModuleStore} from "@/lib/store/useModuleStore";
|
||||
import {LstCard} from "../extendedUI/LstCard";
|
||||
import {CardHeader} from "../ui/card";
|
||||
import {Tabs, TabsContent, TabsList, TabsTrigger} from "../ui/tabs";
|
||||
import {useSessionStore} from "@/lib/store/sessionStore";
|
||||
|
||||
export default function KFP() {
|
||||
const {modules} = useModuleStore();
|
||||
const {user} = useSessionStore();
|
||||
const eomMod = modules.filter((m) => m.name === "eom");
|
||||
// the users current role for eom is?
|
||||
const role: any = user?.roles.filter((r) => r.module_id === eomMod[0].module_id) || "";
|
||||
const tabs = [
|
||||
{key: "mat", label: "Materials", roles: ["admin", "systemAdmin"], content: <Materials />},
|
||||
{key: "sbm", label: "Stretch Blow", roles: ["admin", "systemAdmin"]},
|
||||
];
|
||||
return (
|
||||
<div className="flex flex-row w-full">
|
||||
<Tabs defaultValue="mat">
|
||||
<TabsList>
|
||||
{tabs.map((tab) => {
|
||||
if (tab.roles.includes(role[0].role))
|
||||
return <TabsTrigger value={tab.key}>{tab.label}</TabsTrigger>;
|
||||
})}
|
||||
</TabsList>
|
||||
{tabs.map((tab) => {
|
||||
if (tab.roles.includes(role[0].role))
|
||||
return (
|
||||
<TabsContent value={tab.key} className="w-screen">
|
||||
{tab.content}
|
||||
</TabsContent>
|
||||
);
|
||||
})}
|
||||
</Tabs>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function Materials() {
|
||||
return (
|
||||
<div className="flex flex-row w-[90%]">
|
||||
<div className="w-1/5">
|
||||
<LstCard className="m-1">
|
||||
<CardHeader>Resin</CardHeader>
|
||||
</LstCard>
|
||||
<LstCard className="m-1">
|
||||
<CardHeader>MasterBatch</CardHeader>
|
||||
</LstCard>
|
||||
<LstCard className="m-1">
|
||||
<CardHeader>Additive</CardHeader>
|
||||
</LstCard>
|
||||
<LstCard className="m-1">
|
||||
<CardHeader>Dose cups / Spigots / Spouts</CardHeader>
|
||||
</LstCard>
|
||||
</div>
|
||||
<div className="w-1/2">
|
||||
<LstCard className="m-1">
|
||||
<CardHeader>Pre-Emis Material Consistency report</CardHeader>
|
||||
</LstCard>
|
||||
</div>
|
||||
<div className="w-1/6">
|
||||
<LstCard className="m-1">
|
||||
<CardHeader>Regrind Report in kg</CardHeader>
|
||||
</LstCard>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
import {Printer} from "lucide-react";
|
||||
import {FileText} from "lucide-react";
|
||||
import {
|
||||
SidebarGroup,
|
||||
SidebarGroupContent,
|
||||
@@ -10,9 +10,9 @@ import {
|
||||
|
||||
const items = [
|
||||
{
|
||||
title: "Qaulity Request",
|
||||
url: "#",
|
||||
icon: Printer,
|
||||
title: "End Of Month",
|
||||
url: "/eom",
|
||||
icon: FileText,
|
||||
},
|
||||
];
|
||||
|
||||
|
||||
73
frontend/src/components/ui/calendar.tsx
Normal file
73
frontend/src/components/ui/calendar.tsx
Normal file
@@ -0,0 +1,73 @@
|
||||
import * as React from "react"
|
||||
import { ChevronLeft, ChevronRight } from "lucide-react"
|
||||
import { DayPicker } from "react-day-picker"
|
||||
|
||||
import { cn } from "@/lib/utils"
|
||||
import { buttonVariants } from "@/components/ui/button"
|
||||
|
||||
function Calendar({
|
||||
className,
|
||||
classNames,
|
||||
showOutsideDays = true,
|
||||
...props
|
||||
}: React.ComponentProps<typeof DayPicker>) {
|
||||
return (
|
||||
<DayPicker
|
||||
showOutsideDays={showOutsideDays}
|
||||
className={cn("p-3", className)}
|
||||
classNames={{
|
||||
months: "flex flex-col sm:flex-row gap-2",
|
||||
month: "flex flex-col gap-4",
|
||||
caption: "flex justify-center pt-1 relative items-center w-full",
|
||||
caption_label: "text-sm font-medium",
|
||||
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",
|
||||
nav_button_next: "absolute right-1",
|
||||
table: "w-full border-collapse space-x-1",
|
||||
head_row: "flex",
|
||||
head_cell:
|
||||
"text-muted-foreground rounded-md w-8 font-normal text-[0.8rem]",
|
||||
row: "flex w-full mt-2",
|
||||
cell: cn(
|
||||
"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",
|
||||
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"
|
||||
: "[&:has([aria-selected])]:rounded-md"
|
||||
),
|
||||
day: cn(
|
||||
buttonVariants({ variant: "ghost" }),
|
||||
"size-8 p-0 font-normal aria-selected:opacity-100"
|
||||
),
|
||||
day_range_start:
|
||||
"day-range-start aria-selected:bg-primary aria-selected:text-primary-foreground",
|
||||
day_range_end:
|
||||
"day-range-end aria-selected:bg-primary aria-selected:text-primary-foreground",
|
||||
day_selected:
|
||||
"bg-primary text-primary-foreground hover:bg-primary hover:text-primary-foreground focus:bg-primary focus:text-primary-foreground",
|
||||
day_today: "bg-accent text-accent-foreground",
|
||||
day_outside:
|
||||
"day-outside text-muted-foreground aria-selected:text-muted-foreground",
|
||||
day_disabled: "text-muted-foreground opacity-50",
|
||||
day_range_middle:
|
||||
"aria-selected:bg-accent aria-selected:text-accent-foreground",
|
||||
day_hidden: "invisible",
|
||||
...classNames,
|
||||
}}
|
||||
components={{
|
||||
IconLeft: ({ className, ...props }) => (
|
||||
<ChevronLeft className={cn("size-4", className)} {...props} />
|
||||
),
|
||||
IconRight: ({ className, ...props }) => (
|
||||
<ChevronRight className={cn("size-4", className)} {...props} />
|
||||
),
|
||||
}}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
export { Calendar }
|
||||
52
frontend/src/components/ui/passwordInput.tsx
Normal file
52
frontend/src/components/ui/passwordInput.tsx
Normal file
@@ -0,0 +1,52 @@
|
||||
"use client";
|
||||
|
||||
import * as React from "react";
|
||||
import {EyeIcon, EyeOffIcon} from "lucide-react";
|
||||
|
||||
import {Button} from "@/components/ui/button";
|
||||
import {Input} from "@/components/ui/input";
|
||||
import {cn} from "@/lib/utils";
|
||||
|
||||
const PasswordInput = React.forwardRef<HTMLInputElement, any>(({className, ...props}, ref) => {
|
||||
const [showPassword, setShowPassword] = React.useState(false);
|
||||
const disabled = props.value === "" || props.value === undefined || props.disabled;
|
||||
|
||||
return (
|
||||
<div className="relative">
|
||||
<Input
|
||||
type={showPassword ? "text" : "password"}
|
||||
className={cn("hide-password-toggle pr-10", className)}
|
||||
ref={ref}
|
||||
{...props}
|
||||
/>
|
||||
<Button
|
||||
type="button"
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
className="absolute right-0 top-0 h-full px-3 py-2 hover:bg-transparent"
|
||||
onClick={() => setShowPassword((prev) => !prev)}
|
||||
disabled={disabled}
|
||||
>
|
||||
{showPassword && !disabled ? (
|
||||
<EyeIcon className="h-4 w-4" aria-hidden="true" />
|
||||
) : (
|
||||
<EyeOffIcon className="h-4 w-4" aria-hidden="true" />
|
||||
)}
|
||||
<span className="sr-only">{showPassword ? "Hide password" : "Show password"}</span>
|
||||
</Button>
|
||||
|
||||
{/* hides browsers password toggles */}
|
||||
<style>{`
|
||||
.hide-password-toggle::-ms-reveal,
|
||||
.hide-password-toggle::-ms-clear {
|
||||
visibility: hidden;
|
||||
pointer-events: none;
|
||||
display: none;
|
||||
}
|
||||
`}</style>
|
||||
</div>
|
||||
);
|
||||
});
|
||||
PasswordInput.displayName = "PasswordInput";
|
||||
|
||||
export {PasswordInput};
|
||||
46
frontend/src/components/ui/popover.tsx
Normal file
46
frontend/src/components/ui/popover.tsx
Normal file
@@ -0,0 +1,46 @@
|
||||
import * as React from "react"
|
||||
import * as PopoverPrimitive from "@radix-ui/react-popover"
|
||||
|
||||
import { cn } from "@/lib/utils"
|
||||
|
||||
function Popover({
|
||||
...props
|
||||
}: React.ComponentProps<typeof PopoverPrimitive.Root>) {
|
||||
return <PopoverPrimitive.Root data-slot="popover" {...props} />
|
||||
}
|
||||
|
||||
function PopoverTrigger({
|
||||
...props
|
||||
}: React.ComponentProps<typeof PopoverPrimitive.Trigger>) {
|
||||
return <PopoverPrimitive.Trigger data-slot="popover-trigger" {...props} />
|
||||
}
|
||||
|
||||
function PopoverContent({
|
||||
className,
|
||||
align = "center",
|
||||
sideOffset = 4,
|
||||
...props
|
||||
}: React.ComponentProps<typeof PopoverPrimitive.Content>) {
|
||||
return (
|
||||
<PopoverPrimitive.Portal>
|
||||
<PopoverPrimitive.Content
|
||||
data-slot="popover-content"
|
||||
align={align}
|
||||
sideOffset={sideOffset}
|
||||
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",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
</PopoverPrimitive.Portal>
|
||||
)
|
||||
}
|
||||
|
||||
function PopoverAnchor({
|
||||
...props
|
||||
}: React.ComponentProps<typeof PopoverPrimitive.Anchor>) {
|
||||
return <PopoverPrimitive.Anchor data-slot="popover-anchor" {...props} />
|
||||
}
|
||||
|
||||
export { Popover, PopoverTrigger, PopoverContent, PopoverAnchor }
|
||||
64
frontend/src/components/ui/tabs.tsx
Normal file
64
frontend/src/components/ui/tabs.tsx
Normal file
@@ -0,0 +1,64 @@
|
||||
import * as React from "react"
|
||||
import * as TabsPrimitive from "@radix-ui/react-tabs"
|
||||
|
||||
import { cn } from "@/lib/utils"
|
||||
|
||||
function Tabs({
|
||||
className,
|
||||
...props
|
||||
}: React.ComponentProps<typeof TabsPrimitive.Root>) {
|
||||
return (
|
||||
<TabsPrimitive.Root
|
||||
data-slot="tabs"
|
||||
className={cn("flex flex-col gap-2", className)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
function TabsList({
|
||||
className,
|
||||
...props
|
||||
}: React.ComponentProps<typeof TabsPrimitive.List>) {
|
||||
return (
|
||||
<TabsPrimitive.List
|
||||
data-slot="tabs-list"
|
||||
className={cn(
|
||||
"bg-muted text-muted-foreground inline-flex h-9 w-fit items-center justify-center rounded-lg p-1",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
function TabsTrigger({
|
||||
className,
|
||||
...props
|
||||
}: React.ComponentProps<typeof TabsPrimitive.Trigger>) {
|
||||
return (
|
||||
<TabsPrimitive.Trigger
|
||||
data-slot="tabs-trigger"
|
||||
className={cn(
|
||||
"data-[state=active]:bg-background data-[state=active]:text-foreground focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:outline-ring inline-flex flex-1 items-center justify-center gap-1.5 rounded-md px-2 py-1 text-sm font-medium whitespace-nowrap transition-[color,box-shadow] focus-visible:ring-[3px] focus-visible:outline-1 disabled:pointer-events-none disabled:opacity-50 data-[state=active]:shadow-sm [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
function TabsContent({
|
||||
className,
|
||||
...props
|
||||
}: React.ComponentProps<typeof TabsPrimitive.Content>) {
|
||||
return (
|
||||
<TabsPrimitive.Content
|
||||
data-slot="tabs-content"
|
||||
className={cn("flex-1 outline-none", className)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
export { Tabs, TabsList, TabsTrigger, TabsContent }
|
||||
@@ -13,14 +13,17 @@
|
||||
import { Route as rootRoute } from './routes/__root'
|
||||
import { Route as LoginImport } from './routes/login'
|
||||
import { Route as AboutImport } from './routes/about'
|
||||
import { Route as EomImport } from './routes/_eom'
|
||||
import { Route as AuthImport } from './routes/_auth'
|
||||
import { Route as AdminImport } from './routes/_admin'
|
||||
import { Route as IndexImport } from './routes/index'
|
||||
import { Route as OcpIndexImport } from './routes/ocp/index'
|
||||
import { Route as OcpLotsImport } from './routes/ocp/lots'
|
||||
import { Route as EomEomImport } from './routes/_eom/eom'
|
||||
import { Route as AuthProfileImport } from './routes/_auth/profile'
|
||||
import { Route as AdminSettingsImport } from './routes/_admin/settings'
|
||||
import { Route as AdminModulesImport } from './routes/_admin/modules'
|
||||
import { Route as EomArticleAvImport } from './routes/_eom/article/$av'
|
||||
|
||||
// Create/Update Routes
|
||||
|
||||
@@ -36,6 +39,11 @@ const AboutRoute = AboutImport.update({
|
||||
getParentRoute: () => rootRoute,
|
||||
} as any)
|
||||
|
||||
const EomRoute = EomImport.update({
|
||||
id: '/_eom',
|
||||
getParentRoute: () => rootRoute,
|
||||
} as any)
|
||||
|
||||
const AuthRoute = AuthImport.update({
|
||||
id: '/_auth',
|
||||
getParentRoute: () => rootRoute,
|
||||
@@ -64,6 +72,12 @@ const OcpLotsRoute = OcpLotsImport.update({
|
||||
getParentRoute: () => rootRoute,
|
||||
} as any)
|
||||
|
||||
const EomEomRoute = EomEomImport.update({
|
||||
id: '/eom',
|
||||
path: '/eom',
|
||||
getParentRoute: () => EomRoute,
|
||||
} as any)
|
||||
|
||||
const AuthProfileRoute = AuthProfileImport.update({
|
||||
id: '/profile',
|
||||
path: '/profile',
|
||||
@@ -82,6 +96,12 @@ const AdminModulesRoute = AdminModulesImport.update({
|
||||
getParentRoute: () => AdminRoute,
|
||||
} as any)
|
||||
|
||||
const EomArticleAvRoute = EomArticleAvImport.update({
|
||||
id: '/article/$av',
|
||||
path: '/article/$av',
|
||||
getParentRoute: () => EomRoute,
|
||||
} as any)
|
||||
|
||||
// Populate the FileRoutesByPath interface
|
||||
|
||||
declare module '@tanstack/react-router' {
|
||||
@@ -107,6 +127,13 @@ declare module '@tanstack/react-router' {
|
||||
preLoaderRoute: typeof AuthImport
|
||||
parentRoute: typeof rootRoute
|
||||
}
|
||||
'/_eom': {
|
||||
id: '/_eom'
|
||||
path: ''
|
||||
fullPath: ''
|
||||
preLoaderRoute: typeof EomImport
|
||||
parentRoute: typeof rootRoute
|
||||
}
|
||||
'/about': {
|
||||
id: '/about'
|
||||
path: '/about'
|
||||
@@ -142,6 +169,13 @@ declare module '@tanstack/react-router' {
|
||||
preLoaderRoute: typeof AuthProfileImport
|
||||
parentRoute: typeof AuthImport
|
||||
}
|
||||
'/_eom/eom': {
|
||||
id: '/_eom/eom'
|
||||
path: '/eom'
|
||||
fullPath: '/eom'
|
||||
preLoaderRoute: typeof EomEomImport
|
||||
parentRoute: typeof EomImport
|
||||
}
|
||||
'/ocp/lots': {
|
||||
id: '/ocp/lots'
|
||||
path: '/ocp/lots'
|
||||
@@ -156,6 +190,13 @@ declare module '@tanstack/react-router' {
|
||||
preLoaderRoute: typeof OcpIndexImport
|
||||
parentRoute: typeof rootRoute
|
||||
}
|
||||
'/_eom/article/$av': {
|
||||
id: '/_eom/article/$av'
|
||||
path: '/article/$av'
|
||||
fullPath: '/article/$av'
|
||||
preLoaderRoute: typeof EomArticleAvImport
|
||||
parentRoute: typeof EomImport
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -183,28 +224,44 @@ const AuthRouteChildren: AuthRouteChildren = {
|
||||
|
||||
const AuthRouteWithChildren = AuthRoute._addFileChildren(AuthRouteChildren)
|
||||
|
||||
interface EomRouteChildren {
|
||||
EomEomRoute: typeof EomEomRoute
|
||||
EomArticleAvRoute: typeof EomArticleAvRoute
|
||||
}
|
||||
|
||||
const EomRouteChildren: EomRouteChildren = {
|
||||
EomEomRoute: EomEomRoute,
|
||||
EomArticleAvRoute: EomArticleAvRoute,
|
||||
}
|
||||
|
||||
const EomRouteWithChildren = EomRoute._addFileChildren(EomRouteChildren)
|
||||
|
||||
export interface FileRoutesByFullPath {
|
||||
'/': typeof IndexRoute
|
||||
'': typeof AuthRouteWithChildren
|
||||
'': typeof EomRouteWithChildren
|
||||
'/about': typeof AboutRoute
|
||||
'/login': typeof LoginRoute
|
||||
'/modules': typeof AdminModulesRoute
|
||||
'/settings': typeof AdminSettingsRoute
|
||||
'/profile': typeof AuthProfileRoute
|
||||
'/eom': typeof EomEomRoute
|
||||
'/ocp/lots': typeof OcpLotsRoute
|
||||
'/ocp': typeof OcpIndexRoute
|
||||
'/article/$av': typeof EomArticleAvRoute
|
||||
}
|
||||
|
||||
export interface FileRoutesByTo {
|
||||
'/': typeof IndexRoute
|
||||
'': typeof AuthRouteWithChildren
|
||||
'': typeof EomRouteWithChildren
|
||||
'/about': typeof AboutRoute
|
||||
'/login': typeof LoginRoute
|
||||
'/modules': typeof AdminModulesRoute
|
||||
'/settings': typeof AdminSettingsRoute
|
||||
'/profile': typeof AuthProfileRoute
|
||||
'/eom': typeof EomEomRoute
|
||||
'/ocp/lots': typeof OcpLotsRoute
|
||||
'/ocp': typeof OcpIndexRoute
|
||||
'/article/$av': typeof EomArticleAvRoute
|
||||
}
|
||||
|
||||
export interface FileRoutesById {
|
||||
@@ -212,13 +269,16 @@ export interface FileRoutesById {
|
||||
'/': typeof IndexRoute
|
||||
'/_admin': typeof AdminRouteWithChildren
|
||||
'/_auth': typeof AuthRouteWithChildren
|
||||
'/_eom': typeof EomRouteWithChildren
|
||||
'/about': typeof AboutRoute
|
||||
'/login': typeof LoginRoute
|
||||
'/_admin/modules': typeof AdminModulesRoute
|
||||
'/_admin/settings': typeof AdminSettingsRoute
|
||||
'/_auth/profile': typeof AuthProfileRoute
|
||||
'/_eom/eom': typeof EomEomRoute
|
||||
'/ocp/lots': typeof OcpLotsRoute
|
||||
'/ocp/': typeof OcpIndexRoute
|
||||
'/_eom/article/$av': typeof EomArticleAvRoute
|
||||
}
|
||||
|
||||
export interface FileRouteTypes {
|
||||
@@ -231,8 +291,10 @@ export interface FileRouteTypes {
|
||||
| '/modules'
|
||||
| '/settings'
|
||||
| '/profile'
|
||||
| '/eom'
|
||||
| '/ocp/lots'
|
||||
| '/ocp'
|
||||
| '/article/$av'
|
||||
fileRoutesByTo: FileRoutesByTo
|
||||
to:
|
||||
| '/'
|
||||
@@ -242,20 +304,25 @@ export interface FileRouteTypes {
|
||||
| '/modules'
|
||||
| '/settings'
|
||||
| '/profile'
|
||||
| '/eom'
|
||||
| '/ocp/lots'
|
||||
| '/ocp'
|
||||
| '/article/$av'
|
||||
id:
|
||||
| '__root__'
|
||||
| '/'
|
||||
| '/_admin'
|
||||
| '/_auth'
|
||||
| '/_eom'
|
||||
| '/about'
|
||||
| '/login'
|
||||
| '/_admin/modules'
|
||||
| '/_admin/settings'
|
||||
| '/_auth/profile'
|
||||
| '/_eom/eom'
|
||||
| '/ocp/lots'
|
||||
| '/ocp/'
|
||||
| '/_eom/article/$av'
|
||||
fileRoutesById: FileRoutesById
|
||||
}
|
||||
|
||||
@@ -263,6 +330,7 @@ export interface RootRouteChildren {
|
||||
IndexRoute: typeof IndexRoute
|
||||
AdminRoute: typeof AdminRouteWithChildren
|
||||
AuthRoute: typeof AuthRouteWithChildren
|
||||
EomRoute: typeof EomRouteWithChildren
|
||||
AboutRoute: typeof AboutRoute
|
||||
LoginRoute: typeof LoginRoute
|
||||
OcpLotsRoute: typeof OcpLotsRoute
|
||||
@@ -273,6 +341,7 @@ const rootRouteChildren: RootRouteChildren = {
|
||||
IndexRoute: IndexRoute,
|
||||
AdminRoute: AdminRouteWithChildren,
|
||||
AuthRoute: AuthRouteWithChildren,
|
||||
EomRoute: EomRouteWithChildren,
|
||||
AboutRoute: AboutRoute,
|
||||
LoginRoute: LoginRoute,
|
||||
OcpLotsRoute: OcpLotsRoute,
|
||||
@@ -292,6 +361,7 @@ export const routeTree = rootRoute
|
||||
"/",
|
||||
"/_admin",
|
||||
"/_auth",
|
||||
"/_eom",
|
||||
"/about",
|
||||
"/login",
|
||||
"/ocp/lots",
|
||||
@@ -314,6 +384,13 @@ export const routeTree = rootRoute
|
||||
"/_auth/profile"
|
||||
]
|
||||
},
|
||||
"/_eom": {
|
||||
"filePath": "_eom.tsx",
|
||||
"children": [
|
||||
"/_eom/eom",
|
||||
"/_eom/article/$av"
|
||||
]
|
||||
},
|
||||
"/about": {
|
||||
"filePath": "about.tsx"
|
||||
},
|
||||
@@ -332,11 +409,19 @@ export const routeTree = rootRoute
|
||||
"filePath": "_auth/profile.tsx",
|
||||
"parent": "/_auth"
|
||||
},
|
||||
"/_eom/eom": {
|
||||
"filePath": "_eom/eom.tsx",
|
||||
"parent": "/_eom"
|
||||
},
|
||||
"/ocp/lots": {
|
||||
"filePath": "ocp/lots.tsx"
|
||||
},
|
||||
"/ocp/": {
|
||||
"filePath": "ocp/index.tsx"
|
||||
},
|
||||
"/_eom/article/$av": {
|
||||
"filePath": "_eom/article/$av.tsx",
|
||||
"parent": "/_eom"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
13
frontend/src/routes/_eom.tsx
Normal file
13
frontend/src/routes/_eom.tsx
Normal file
@@ -0,0 +1,13 @@
|
||||
import {createFileRoute, redirect} from "@tanstack/react-router";
|
||||
|
||||
export const Route = createFileRoute("/_eom")({
|
||||
//component: RouteComponent,
|
||||
beforeLoad: async () => {
|
||||
const auth = localStorage.getItem("auth_token");
|
||||
if (!auth) {
|
||||
throw redirect({
|
||||
to: "/login",
|
||||
});
|
||||
}
|
||||
},
|
||||
});
|
||||
125
frontend/src/routes/_eom/article/$av.tsx
Normal file
125
frontend/src/routes/_eom/article/$av.tsx
Normal file
@@ -0,0 +1,125 @@
|
||||
import {LstCard} from "@/components/extendedUI/LstCard";
|
||||
import {CardFooter, CardHeader} from "@/components/ui/card";
|
||||
import {Input} from "@/components/ui/input";
|
||||
import {Label} from "@radix-ui/react-dropdown-menu";
|
||||
import {createFileRoute} from "@tanstack/react-router";
|
||||
|
||||
export const Route = createFileRoute("/_eom/article/$av")({
|
||||
component: RouteComponent,
|
||||
loader: () => {
|
||||
return [{id: 1}, {id: 2}, {id: 3}, {id: 4}, {id: 5}];
|
||||
},
|
||||
});
|
||||
|
||||
function RouteComponent() {
|
||||
const {av} = Route.useParams();
|
||||
const loaded = Route.useLoaderData();
|
||||
|
||||
console.log(loaded, av);
|
||||
return (
|
||||
<div className="w-full m-2">
|
||||
<form className="w-1/2">
|
||||
<div>
|
||||
<h1>AV - Description</h1>
|
||||
</div>
|
||||
<hr className="w-48"></hr>
|
||||
<LstCard className="m-2">
|
||||
<CardHeader className="place-content-center">
|
||||
<h3>Inventory Data</h3>
|
||||
</CardHeader>
|
||||
<div className="flex flex-row">
|
||||
<div className="w-96 m-2">
|
||||
<Label>Starting Inv</Label>
|
||||
<Input></Input>
|
||||
</div>
|
||||
<div className="w-96 m-2">
|
||||
<Label>At The Line</Label>
|
||||
<Input></Input>
|
||||
</div>
|
||||
<div className="w-96 m-2">
|
||||
<Label>Inhouse endinging</Label>
|
||||
<Input></Input>
|
||||
</div>
|
||||
<div className="w-96 m-2">
|
||||
<Label>In transit</Label>
|
||||
<Input></Input>
|
||||
</div>
|
||||
<div className="w-96 m-2">
|
||||
<Label>Comments</Label>
|
||||
<Input></Input>
|
||||
</div>
|
||||
</div>
|
||||
<CardFooter>
|
||||
<div className="flex justify-end">
|
||||
<Label>Total Inv</Label>
|
||||
</div>
|
||||
</CardFooter>
|
||||
</LstCard>
|
||||
<LstCard className="m-2">
|
||||
<CardHeader className="place-content-center">
|
||||
<h3>Purchasing</h3>
|
||||
</CardHeader>
|
||||
<div className="flex flex-row">
|
||||
<div className="w-96 m-2">
|
||||
<Label>Purchased</Label>
|
||||
<Input></Input>
|
||||
</div>
|
||||
<div className="w-96 m-2">
|
||||
<Label>Recived in GP</Label>
|
||||
<Input></Input>
|
||||
</div>
|
||||
<div className="w-96 m-2">
|
||||
<Label>Varation</Label>
|
||||
<Input></Input>
|
||||
</div>
|
||||
<div className="w-96 m-2">
|
||||
<Label>Comments</Label>
|
||||
<Input></Input>
|
||||
</div>
|
||||
</div>
|
||||
</LstCard>
|
||||
<LstCard className="m-2">
|
||||
<CardHeader className="place-content-center">
|
||||
<h3>Transfers</h3>
|
||||
</CardHeader>
|
||||
<div className="flex flex-row">
|
||||
<div className="w-96 m-2">
|
||||
<Label>Transfered in</Label>
|
||||
<Input></Input>
|
||||
</div>
|
||||
<div className="w-96 m-2">
|
||||
<Label>Transfered out</Label>
|
||||
<Input></Input>
|
||||
</div>
|
||||
|
||||
<div className="w-96 m-2">
|
||||
<Label>Comments</Label>
|
||||
<Input></Input>
|
||||
</div>
|
||||
</div>
|
||||
</LstCard>
|
||||
<LstCard className="m-2">
|
||||
<CardHeader className="place-content-center">
|
||||
<h3>Calculations</h3>
|
||||
</CardHeader>
|
||||
<div className="flex flex-row">
|
||||
<div className="w-96 m-2 flex flex-col">
|
||||
<Label>Actual Consumption: 1452541</Label>
|
||||
<Label>Production Consumption: 146854</Label>
|
||||
</div>
|
||||
|
||||
<div className="w-96 m-2 flex flex-col">
|
||||
<Label>Difference: -2541</Label>
|
||||
<Label>Waste: -5%</Label>
|
||||
</div>
|
||||
|
||||
<div className="w-96 m-2 flex flex-col">
|
||||
<Label>Price/Kg: $2.20</Label>
|
||||
<Label>$Loss/$Gain: $35.00</Label>
|
||||
</div>
|
||||
</div>
|
||||
</LstCard>
|
||||
</form>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
14
frontend/src/routes/_eom/eom.tsx
Normal file
14
frontend/src/routes/_eom/eom.tsx
Normal file
@@ -0,0 +1,14 @@
|
||||
import EomPage from "@/components/eom/EomPage";
|
||||
import {createFileRoute} from "@tanstack/react-router";
|
||||
|
||||
export const Route = createFileRoute("/_eom/eom")({
|
||||
component: RouteComponent,
|
||||
});
|
||||
|
||||
function RouteComponent() {
|
||||
return (
|
||||
<div>
|
||||
<EomPage />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -13,5 +13,6 @@ export function getSettings(token: string) {
|
||||
|
||||
const fetchSettings = async (token: string) => {
|
||||
const {data} = await axios.get("/api/server/settings", {headers: {Authorization: `Bearer ${token}`}});
|
||||
|
||||
return data.data;
|
||||
};
|
||||
|
||||
5
server/services/eom/eomService.ts
Normal file
5
server/services/eom/eomService.ts
Normal file
@@ -0,0 +1,5 @@
|
||||
import {OpenAPIHono} from "@hono/zod-openapi";
|
||||
|
||||
const app = new OpenAPIHono();
|
||||
|
||||
export default app;
|
||||
Reference in New Issue
Block a user