Compare commits

..

15 Commits

Author SHA1 Message Date
7532c89ae2 test(ppoo): added inn query for ppoo 2025-04-13 08:28:53 -05:00
dd6895fac2 fix(lots): if no sql it crashs due to lots returning a non error 2025-04-13 08:28:30 -05:00
95c869d667 fix(ocp): removed the auto labeler from cycleing due to causuing delay in printing 2025-04-13 08:27:53 -05:00
9325e58551 test(reporting): more reporting tables for different reports 2025-04-13 08:27:28 -05:00
17b6c0ac66 feat(ocp page): changed to resizable panels as its kinda customizable 2025-04-13 08:26:35 -05:00
3241cf810a test(front end): added in card test but removing 2025-04-13 08:26:03 -05:00
b5b57fe3bf refactor(formatting): formatting due to new default settings 2025-04-13 08:25:22 -05:00
08b052ea5a ci(release): bump build number to 215 2025-04-11 14:55:57 -05:00
8ad64bb67a ci(release): bump build number to 214 2025-04-11 14:50:52 -05:00
e0eb26b544 ci(release): bump build number to 213 2025-04-09 20:58:53 -05:00
2090f8ce71 ci(release): bump build number to 212 2025-04-09 20:36:36 -05:00
db1d5f1601 ci(release): bump build number to 211 2025-04-09 20:34:44 -05:00
c5d53e03d3 ci(release): bump build number to 210 2025-04-09 20:24:09 -05:00
fb0b3f06a4 ci(release): bump build number to 209 2025-04-09 18:35:30 -05:00
6e2e17bdde ci(release): bump build number to 208 2025-04-09 18:09:34 -05:00
29 changed files with 862 additions and 274 deletions

View File

@@ -1,6 +1,16 @@
import {text, pgTable, numeric, index, timestamp, boolean, uuid, uniqueIndex, jsonb} from "drizzle-orm/pg-core"; import {
import {createInsertSchema, createSelectSchema} from "drizzle-zod"; text,
import {z} from "zod"; pgTable,
numeric,
index,
timestamp,
boolean,
uuid,
uniqueIndex,
jsonb,
} from "drizzle-orm/pg-core";
import { createInsertSchema, createSelectSchema } from "drizzle-zod";
import { z } from "zod";
export const rfidReaders = pgTable( export const rfidReaders = pgTable(
"rfidReaders", "rfidReaders",
@@ -12,6 +22,7 @@ export const rfidReaders = pgTable(
lastTrigger: timestamp("lastTrigger").defaultNow(), lastTrigger: timestamp("lastTrigger").defaultNow(),
lastTriggerGood: boolean("lastTiggerGood").default(true), lastTriggerGood: boolean("lastTiggerGood").default(true),
active: boolean("active").default(true), active: boolean("active").default(true),
lastTagScanned: text("lastTagScanned"),
}, },
(table) => [ (table) => [
// uniqueIndex('emailUniqueIndex').on(sql`lower(${table.email})`), // uniqueIndex('emailUniqueIndex').on(sql`lower(${table.email})`),

View File

@@ -0,0 +1,58 @@
import { Button } from "@/components/ui/button";
import {
Dialog,
DialogContent,
DialogDescription,
DialogFooter,
DialogHeader,
DialogTitle,
DialogTrigger,
} from "@/components/ui/dialog";
import { useCardStore } from "@/lib/store/useCardStore";
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]">
<DialogHeader>
<DialogTitle>Cards</DialogTitle>
<DialogDescription>
Please add a card below.
</DialogDescription>
</DialogHeader>
<Button onClick={handleAddPPOO} className="w-48">
PPOO
</Button>
<DialogFooter>
<Button type="submit">Save changes</Button>
</DialogFooter>
</DialogContent>
</Dialog>
);
}

View File

@@ -0,0 +1,68 @@
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
// };
// 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
// };
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>
);
}

View File

@@ -1,5 +1,5 @@
import {ReactNode} from "react"; import { ReactNode } from "react";
import {Card} from "../ui/card"; import { Card } from "../ui/card";
interface LstCardProps { interface LstCardProps {
children?: ReactNode; children?: ReactNode;
@@ -7,12 +7,17 @@ interface LstCardProps {
style?: React.CSSProperties; style?: React.CSSProperties;
} }
export function LstCard({children, className = "", style = {}}: LstCardProps) { export function LstCard({
children,
className = "",
style = {},
}: LstCardProps) {
return ( return (
<div className="m-auto"> <Card
<Card className={`border-solid border-1 border-[#00659c] ${className}`} style={style}> className={`border-solid border-1 border-[#00659c] ${className}`}
{children} style={style}
</Card> >
</div> {children}
</Card>
); );
} }

View File

@@ -1,6 +1,6 @@
import { getAdjustments } from "@/utils/querys/logistics/siloAdjustments/getAdjustments"; import { getAdjustments } from "@/utils/querys/logistics/siloAdjustments/getAdjustments";
import { columns } from "@/utils/tableData/siloAdjustmentHist/siloAdjHist"; import { columns } from "@/utils/tableData/siloAdjustmentHist/siloAdjHistColumns";
import { DataTable } from "@/utils/tableData/siloAdjustmentHist/siloDate"; import { SiloTable } from "@/utils/tableData/siloAdjustmentHist/siloData";
import { useQuery } from "@tanstack/react-query"; import { useQuery } from "@tanstack/react-query";
export default function HistoricalData(props: any) { export default function HistoricalData(props: any) {
@@ -18,11 +18,9 @@ export default function HistoricalData(props: any) {
const adjustments: any = data.filter( const adjustments: any = data.filter(
(l: any) => l.locationID === parseInt(props.laneId) (l: any) => l.locationID === parseInt(props.laneId)
); );
console.log(adjustments);
return ( return (
<div className="container mx-auto py-10"> <div className="container mx-auto py-10">
<DataTable columns={columns} data={adjustments} /> <SiloTable columns={columns} data={adjustments} />
</div> </div>
); );
} }

View File

@@ -0,0 +1,50 @@
import { LstCard } from "@/components/extendedUI/LstCard";
import { useCardStore } from "@/lib/store/useCardStore";
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";
export default function PPOO({ style = {} }) {
const { removeCard } = useCardStore();
const { data, isError, isLoading } = useQuery(getPPOO());
if (isLoading) return <div>Loading adjustmnet data...</div>;
if (isError) {
return (
<div>
<p>There was an error getting the adjustments.</p>
</div>
);
}
const handleCloseCard = () => {
removeCard("PPOO");
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>
);
}

View File

@@ -4,56 +4,117 @@ import Lots from "./Lots";
import OcpLogs from "./OcpLogs"; import OcpLogs from "./OcpLogs";
import PrinterStatus from "./PrinterStatus"; import PrinterStatus from "./PrinterStatus";
import { useSettingStore } from "@/lib/store/useSettings"; import { useSettingStore } from "@/lib/store/useSettings";
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
import LabelLog from "./LabelLog"; import LabelLog from "./LabelLog";
import {
ResizableHandle,
ResizablePanel,
ResizablePanelGroup,
} from "@/components/ui/resizable-panels";
export default function OCPPage() { export default function OCPPage() {
const { settings } = useSettingStore(); const { settings } = useSettingStore();
let server = settings.filter((n) => n.name === "server"); let server = settings.filter((n) => n.name === "server");
return (
<div className="h-screen w-full ">
<div className="flex flex-row gap-2">
<div className="flex flex-col w-4/5 h-dvh">
<div className="">
<Lots />
</div>
<div className="w-5/6 h-1/2"> return (
<Tabs defaultValue="ocplogs" className="w-full"> <div className="ml-5 w-11/12 h-9/10">
<TabsList className="grid w-full grid-cols-2"> <ResizablePanelGroup
<TabsTrigger value="ocplogs"> direction="horizontal"
OcpLogs //className="rounded-lg border"
</TabsTrigger> autoSaveId="ocpPage"
<TabsTrigger value="labels">Labels</TabsTrigger> >
</TabsList> <ResizablePanel>
<TabsContent value="ocplogs"> <ResizablePanelGroup direction="vertical">
<div className="w-full"> <ResizablePanel>
<OcpLogs /> <div style={{ overflow: "auto" }}>
</div> <Lots />
</TabsContent> </div>
<TabsContent value="labels"> </ResizablePanel>
<LabelLog /> <ResizableHandle />
</TabsContent> <ResizablePanel>
</Tabs> <ResizablePanelGroup direction="horizontal">
</div> <ResizablePanel className="overflow: auto">
</div> <div style={{ overflow: "auto" }}>
<div className="flex flex-col"> <LabelLog />
{server[0].value === "usday1vms006" && ( </div>
<div> </ResizablePanel>
<WrapperManualTrigger /> <ResizableHandle />
</div> <ResizablePanel>
)} <div style={{ overflow: "auto" }}>
{server[0].value === "localhost" && ( <OcpLogs />
<div> </div>
<WrapperManualTrigger /> </ResizablePanel>
</div> </ResizablePanelGroup>
)} </ResizablePanel>
<div> </ResizablePanelGroup>
<PrinterStatus /> </ResizablePanel>
</div> <ResizableHandle />
</div> <ResizablePanel defaultSize={25}>
</div> <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> </div>
); );
// return (
// <div className="h-screen w-full ">
// <div className="flex flex-row gap-2">
// <div className="flex flex-col w-4/5 h-dvh">
// <div className="">
// <Lots />
// </div>
// <div className="w-5/6 h-1/2">
// <Tabs defaultValue="ocplogs" className="w-full">
// <TabsList className="grid w-full grid-cols-2">
// <TabsTrigger value="ocplogs">
// OcpLogs
// </TabsTrigger>
// <TabsTrigger value="labels">Labels</TabsTrigger>
// </TabsList>
// <TabsContent value="ocplogs">
// <div className="w-full">
// <OcpLogs />
// </div>
// </TabsContent>
// <TabsContent value="labels">
// <LabelLog />
// </TabsContent>
// </Tabs>
// </div>
// </div>
// <div className="flex flex-col">
// {server[0].value === "usday1vms006" && (
// <div>
// <WrapperManualTrigger />
// </div>
// )}
// {server[0].value === "localhost" && (
// <div>
// <WrapperManualTrigger />
// </div>
// )}
// <div>
// <PrinterStatus />
// </div>
// </div>
// </div>
// </div>
// );
} }

View File

@@ -1,6 +1,6 @@
import {useQuery} from "@tanstack/react-query"; import { useQuery } from "@tanstack/react-query";
import {useSessionStore} from "../lib/store/sessionStore"; import { useSessionStore } from "../lib/store/sessionStore";
import {useEffect} from "react"; import { useEffect } from "react";
const fetchSession = async () => { const fetchSession = async () => {
const token = localStorage.getItem("auth_token"); const token = localStorage.getItem("auth_token");
@@ -23,9 +23,6 @@ const fetchSession = async () => {
localStorage.removeItem("auth-storage"); localStorage.removeItem("auth-storage");
localStorage.removeItem("nextauth.message"); localStorage.removeItem("nextauth.message");
localStorage.removeItem("prod"); localStorage.removeItem("prod");
localStorage.removeItem("cards");
localStorage.removeItem("rememberMe");
localStorage.removeItem("username");
throw new Error("Session not found"); throw new Error("Session not found");
} }
@@ -34,10 +31,10 @@ const fetchSession = async () => {
}; };
export const useSession = () => { export const useSession = () => {
const {setSession, clearSession, token} = useSessionStore(); const { setSession, clearSession, token } = useSessionStore();
// Fetch session only if token is available // Fetch session only if token is available
const {data, status, error} = useQuery({ const { data, status, error } = useQuery({
queryKey: ["session"], queryKey: ["session"],
queryFn: fetchSession, queryFn: fetchSession,
enabled: !!token, // Prevents query if token is null enabled: !!token, // Prevents query if token is null
@@ -55,5 +52,9 @@ export const useSession = () => {
} }
}, [data, error]); }, [data, error]);
return {session: data && token ? {user: data.user, token: data.token} : null, status, error}; return {
session: data && token ? { user: data.user, token: data.token } : null,
status,
error,
};
}; };

View File

@@ -0,0 +1,55 @@
import { create } from "zustand";
import { devtools, persist } from "zustand/middleware";
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;
}
interface CardStore {
cards: Card[]; // Array of card objects
addCard: (card: Card) => void;
updateCard: (id: string, updatedCard: Partial<Card>) => void;
removeCard: (id: string) => void;
}
export const useCardStore = create<CardStore>()(
devtools(
persist<CardStore>(
(set) => ({
cards: [],
addCard: (card) =>
set((state) => ({ cards: [...state.cards, card] })),
updateCard: (id, updatedCard) =>
set((state) => ({
cards: state.cards.map((card) =>
card.i === id ? { ...card, ...updatedCard } : card
),
})),
removeCard: (id) =>
set((state) => ({
cards: state.cards.filter((card) => card.i !== id),
})),
}),
{ name: "card-storage" }
)
)
);

View File

@@ -7,12 +7,12 @@ import { ModeToggle } from "../components/layout/mode-toggle";
import { AppSidebar } from "../components/layout/lst-sidebar"; import { AppSidebar } from "../components/layout/lst-sidebar";
import { Avatar, AvatarFallback, AvatarImage } from "../components/ui/avatar"; import { Avatar, AvatarFallback, AvatarImage } from "../components/ui/avatar";
import { import {
DropdownMenu, DropdownMenu,
DropdownMenuContent, DropdownMenuContent,
DropdownMenuItem, DropdownMenuItem,
DropdownMenuLabel, DropdownMenuLabel,
DropdownMenuSeparator, DropdownMenuSeparator,
DropdownMenuTrigger, DropdownMenuTrigger,
} from "../components/ui/dropdown-menu"; } from "../components/ui/dropdown-menu";
import { SessionProvider } from "../components/providers/Providers"; import { SessionProvider } from "../components/providers/Providers";
import { Toaster } from "sonner"; import { Toaster } from "sonner";
@@ -21,74 +21,83 @@ import { Toaster } from "sonner";
import { useSessionStore } from "../lib/store/sessionStore"; import { useSessionStore } from "../lib/store/sessionStore";
import { useSession } from "@/hooks/useSession"; import { useSession } from "@/hooks/useSession";
import { useLogout } from "@/hooks/useLogout"; import { useLogout } from "@/hooks/useLogout";
import { AddCards } from "@/components/dashboard/AddCards";
// same as the layout // same as the layout
export const Route = createRootRoute({ export const Route = createRootRoute({
component: () => { component: () => {
const sidebarState = Cookies.get("sidebar_state") === "true"; const sidebarState = Cookies.get("sidebar_state") === "true";
const { session } = useSession(); const { session } = useSession();
const { user } = useSessionStore(); const { user } = useSessionStore();
const logout = useLogout(); const logout = useLogout();
return ( return (
<> <>
<SessionProvider> <SessionProvider>
<ThemeProvider> <ThemeProvider>
<nav className="flex justify-end"> <nav className="flex justify-end">
<div className="m-2 flex flex-row"> <div className="m-2 flex flex-row">
<div className="m-auto pr-2"> <div className="m-auto pr-2">
<p>Add Card</p> <AddCards />
</div> </div>
<div className="m-1"> <div className="m-1">
<ModeToggle /> <ModeToggle />
</div> </div>
{session ? ( {session ? (
<div className="m-1"> <div className="m-1">
<DropdownMenu> <DropdownMenu>
<DropdownMenuTrigger> <DropdownMenuTrigger>
<Avatar> <Avatar>
<AvatarImage <AvatarImage
src="https://github.com/shadcn.png" src="https://github.com/shadcn.png"
alt="@shadcn" alt="@shadcn"
/> />
<AvatarFallback>CN</AvatarFallback> <AvatarFallback>
</Avatar> CN
</DropdownMenuTrigger> </AvatarFallback>
<DropdownMenuContent> </Avatar>
<DropdownMenuLabel> </DropdownMenuTrigger>
Hello {user?.username} <DropdownMenuContent>
</DropdownMenuLabel> <DropdownMenuLabel>
<DropdownMenuSeparator /> Hello {user?.username}
{/* <DropdownMenuItem>Profile</DropdownMenuItem> </DropdownMenuLabel>
<DropdownMenuSeparator />
{/* <DropdownMenuItem>Profile</DropdownMenuItem>
<DropdownMenuItem>Billing</DropdownMenuItem> <DropdownMenuItem>Billing</DropdownMenuItem>
<DropdownMenuItem>Team</DropdownMenuItem> <DropdownMenuItem>Team</DropdownMenuItem>
<DropdownMenuItem>Subscription</DropdownMenuItem> */} <DropdownMenuItem>Subscription</DropdownMenuItem> */}
<hr className="solid"></hr> <hr className="solid"></hr>
<DropdownMenuItem> <DropdownMenuItem>
<div className="m-auto"> <div className="m-auto">
<button onClick={() => logout()}>Logout</button> <button
</div> onClick={() =>
</DropdownMenuItem> logout()
</DropdownMenuContent> }
</DropdownMenu> >
</div> Logout
) : ( </button>
<div> </div>
<Link to="/login">Login</Link> </DropdownMenuItem>
</div> </DropdownMenuContent>
)} </DropdownMenu>
</div> </div>
</nav> ) : (
<SidebarProvider defaultOpen={sidebarState}> <div>
<AppSidebar /> <Link to="/login">Login</Link>
<Toaster expand={true} richColors closeButton /> </div>
<Outlet /> )}
</SidebarProvider> </div>
</ThemeProvider> </nav>
</SessionProvider> <SidebarProvider defaultOpen={sidebarState}>
<AppSidebar />
<Toaster expand={true} richColors closeButton />
<Outlet />
</SidebarProvider>
</ThemeProvider>
</SessionProvider>
{/* <TanStackRouterDevtools position="bottom-right" /> */} {/* <TanStackRouterDevtools position="bottom-right" /> */}
</> </>
); );
}, },
}); });

View File

@@ -1,51 +1,17 @@
import {createFileRoute} from "@tanstack/react-router"; import { createFileRoute } from "@tanstack/react-router";
//import GridLayout from "react-grid-layout"; //import GridLayout from "react-grid-layout";
import "../../node_modules/react-grid-layout/css/styles.css"; import "../../node_modules/react-grid-layout/css/styles.css";
import "../../node_modules/react-resizable/css/styles.css"; import "../../node_modules/react-resizable/css/styles.css";
import DashBoard from "@/components/dashboard/DashBoard";
export const Route = createFileRoute("/")({ export const Route = createFileRoute("/")({
component: Index, component: Index,
}); });
function Index() { function Index() {
// const [layout, setLayout] = useState([
// {
// i: "PPOO",
// x: 0,
// y: 0,
// w: 5,
// h: 3,
// minW: 2,
// maxW: 6,
// minH: 2,
// maxH: 4,
// isResizable: true,
// isDraggable: true,
// },
// {i: "OCPLogs", x: 2, y: 0, w: 5, h: 3, isResizable: true, isDraggable: true},
// ]);
// const [cardData, setCardData] = useState([
// {i: "card1", name: "PPOO"},
// {i: "card2", name: "OCPLogs"},
// ]);
return ( return (
<> <div className="h-dvh w-dvw">
{/* <AddCards addCard={addCard} cards={cards} /> */} <DashBoard />
{/* <GridLayout className="layout" cols={12} rowHeight={30} width={window.innerWidth}> </div>
<div className="bg-blue-400" key="a" data-grid={{x: 0, y: 0, w: 1, h: 2, static: true}}>
a
</div>
<div className="bg-blue-400" key="b" data-grid={{x: 1, y: 0, w: 3, h: 2, minW: 2, maxW: 4}}>
b
</div>
<div className="bg-blue-400" key="c" data-grid={{x: 4, y: 0, w: 1, h: 2}}>
c
</div>
</GridLayout> */}
<div className="m-auto">
<span>Empty Space why dont you add some cards?</span>
</div>
</>
); );
} }

View File

@@ -1,10 +1,14 @@
import OCPPage from "@/components/production/ocp/OcpPage"; import OCPPage from "@/components/production/ocp/OcpPage";
import {createFileRoute} from "@tanstack/react-router"; import { createFileRoute } from "@tanstack/react-router";
export const Route = createFileRoute("/ocp/")({ export const Route = createFileRoute("/ocp/")({
component: RouteComponent, component: RouteComponent,
}); });
function RouteComponent() { function RouteComponent() {
return <OCPPage />; return (
<div className="h-dvh w-dvw">
<OCPPage />
</div>
);
} }

View File

@@ -0,0 +1,20 @@
import { queryOptions } from "@tanstack/react-query";
import axios from "axios";
export function getPPOO() {
return queryOptions({
queryKey: ["getPPOO"],
queryFn: () => fetchStockSilo(),
//enabled:
staleTime: 1000,
refetchInterval: 2 * 2000,
refetchOnWindowFocus: true,
});
}
const fetchStockSilo = async () => {
const { data } = await axios.get(`/api/logistics/getppoo`);
// if we are not localhost ignore the devDir setting.
//const url: string = window.location.host.split(":")[0];
return data.data ?? [];
};

View File

@@ -4,7 +4,7 @@ import axios from "axios";
export function getStockSilo() { export function getStockSilo() {
const token = localStorage.getItem("auth_token"); const token = localStorage.getItem("auth_token");
return queryOptions({ return queryOptions({
queryKey: ["getUsers"], queryKey: ["getSiloData"],
queryFn: () => fetchStockSilo(token), queryFn: () => fetchStockSilo(token),
enabled: !!token, // Prevents query if token is null enabled: !!token, // Prevents query if token is null
staleTime: 1000, staleTime: 1000,

View File

@@ -0,0 +1,46 @@
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 columns: ColumnDef<Adjustmnets>[] = [
{
accessorKey: "MachineLocation",
header: () => <div className="text-left">Line</div>,
},
{
accessorKey: "ArticleHumanReadableId",
header: "AV",
},
{
accessorKey: "RunningNumber",
header: "Running Number",
},
{
accessorKey: "ProductionDate",
header: "Booked in",
cell: ({ row }) => {
if (row.getValue("ProductionDate")) {
const correctDate = format(
row.getValue("ProductionDate"),
"M/d/yyyy hh:mm"
);
return (
<div className="text-left font-medium">{correctDate}</div>
);
}
},
},
];

View File

@@ -0,0 +1,124 @@
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";
interface DataTableProps<TData, TValue> {
columns: ColumnDef<TData, TValue>[];
data: TData[];
style: any;
}
export function PPOOTable<TData, TValue>({
columns,
data,
style,
}: DataTableProps<TData, TValue>) {
const table = useReactTable({
data,
columns,
getCoreRowModel: getCoreRowModel(),
getPaginationRowModel: getPaginationRowModel(),
});
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>
);
}

View File

@@ -21,7 +21,7 @@ interface DataTableProps<TData, TValue> {
data: TData[]; data: TData[];
} }
export function DataTable<TData, TValue>({ export function SiloTable<TData, TValue>({
columns, columns,
data, data,
}: DataTableProps<TData, TValue>) { }: DataTableProps<TData, TValue>) {

11
package-lock.json generated
View File

@@ -36,6 +36,7 @@
"pino-abstract-transport": "^2.0.0", "pino-abstract-transport": "^2.0.0",
"pino-pretty": "^13.0.0", "pino-pretty": "^13.0.0",
"postgres": "^3.4.5", "postgres": "^3.4.5",
"react-resizable-panels": "^2.1.7",
"rimraf": "^6.0.1", "rimraf": "^6.0.1",
"st-ethernet-ip": "^2.7.3", "st-ethernet-ip": "^2.7.3",
"ws": "^8.18.1", "ws": "^8.18.1",
@@ -7173,6 +7174,16 @@
"react": "^19.1.0" "react": "^19.1.0"
} }
}, },
"node_modules/react-resizable-panels": {
"version": "2.1.7",
"resolved": "https://registry.npmjs.org/react-resizable-panels/-/react-resizable-panels-2.1.7.tgz",
"integrity": "sha512-JtT6gI+nURzhMYQYsx8DKkx6bSoOGFp7A3CwMrOb8y5jFHFyqwo9m68UhmXRw57fRVJksFn1TSlm3ywEQ9vMgA==",
"license": "MIT",
"peerDependencies": {
"react": "^16.14.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc",
"react-dom": "^16.14.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc"
}
},
"node_modules/read-pkg": { "node_modules/read-pkg": {
"version": "3.0.0", "version": "3.0.0",
"resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz", "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz",

View File

@@ -1,92 +1,93 @@
{ {
"name": "lstv2", "name": "lstv2",
"version": "2.13.0", "version": "2.13.0",
"type": "module", "type": "module",
"scripts": { "scripts": {
"dev": "concurrently -n \"server,frontend\" -c \"#007755,#2f6da3\" \"npm run dev:server\" \"cd frontend && npm run dev\"", "dev": "concurrently -n \"server,frontend\" -c \"#007755,#2f6da3\" \"npm run dev:server\" \"cd frontend && npm run dev\"",
"dev:server": "dotenvx run -f .env -- tsx watch server/index.ts", "dev:server": "dotenvx run -f .env -- tsx watch server/index.ts",
"dev:frontend": "cd frontend && npm run dev", "dev:frontend": "cd frontend && npm run dev",
"dev:dbgen": " drizzle-kit generate --config=drizzle-dev.config.ts", "dev:dbgen": " drizzle-kit generate --config=drizzle-dev.config.ts",
"dev:dbmigrate": " drizzle-kit migrate --config=drizzle-dev.config.ts", "dev:dbmigrate": " drizzle-kit migrate --config=drizzle-dev.config.ts",
"build": "npm run build:server && npm run build:frontend", "build": "npm run build:server && npm run build:frontend",
"build:server": "rimraf dist && tsc --build && npm run copy:scripts && xcopy server\\services\\notifications\\utils\\views\\ dist\\server\\services\\notifications\\utils\\views\\ /E /I /Y", "build:server": "rimraf dist && tsc --build && npm run copy:scripts && xcopy server\\services\\notifications\\utils\\views\\ dist\\server\\services\\notifications\\utils\\views\\ /E /I /Y",
"build:frontend": "cd frontend && npm run build", "build:frontend": "cd frontend && npm run build",
"copy:scripts": "tsx server/scripts/copyScripts.ts", "copy:scripts": "tsx server/scripts/copyScripts.ts",
"copy:servers": "xcopy server\\services\\server\\utils\\serverData.json dist\\server\\services\\server\\utils /E /I /Y", "copy:servers": "xcopy server\\services\\server\\utils\\serverData.json dist\\server\\services\\server\\utils /E /I /Y",
"start": "set NODE_ENV=production && npm run start:server", "start": "set NODE_ENV=production && npm run start:server",
"start:server": "dotenvx run -f .env -- node dist/server/index.js", "start:server": "dotenvx run -f .env -- node dist/server/index.js",
"db:generate": "npx drizzle-kit generate", "db:generate": "npx drizzle-kit generate",
"db:migrate": "npx drizzle-kit push", "db:migrate": "npx drizzle-kit push",
"db:dev": "npm run build && npm run db:generate && npm run db:migrate", "db:dev": "npm run build && npm run db:generate && npm run db:migrate",
"deploy": "standard-version --conventional-commits && npm run prodBuild", "deploy": "standard-version --conventional-commits && npm run prodBuild",
"zipServer": "dotenvx run -f .env -- tsx server/scripts/zipUpBuild.ts \"C:\\Users\\matthes01\\Documents\\lstv2\"", "zipServer": "dotenvx run -f .env -- tsx server/scripts/zipUpBuild.ts \"C:\\Users\\matthes01\\Documents\\lstv2\"",
"v1Build": "cd C:\\Users\\matthes01\\Documents\\logisticsSupportTool && npm run oldBuilder", "v1Build": "cd C:\\Users\\matthes01\\Documents\\logisticsSupportTool && npm run oldBuilder",
"scriptBuild": "powershell -ExecutionPolicy Bypass -File server/scripts/build.ps1 -dir \"C:\\Users\\matthes01\\Documents\\lstv2\"", "scriptBuild": "powershell -ExecutionPolicy Bypass -File server/scripts/build.ps1 -dir \"C:\\Users\\matthes01\\Documents\\lstv2\"",
"removeOld": "rimraf dist && rimraf frontend/dist", "removeOld": "rimraf dist && rimraf frontend/dist",
"prodBuild": "npm run v1Build && npm run build && npm run zipServer && npm run dev", "prodBuild": "npm run v1Build && npm run build && npm run zipServer && npm run dev",
"commit": "cz", "commit": "cz",
"prodinstall": "npm i --omit=dev && npm run db:migrate", "prodinstall": "npm i --omit=dev && npm run db:migrate",
"checkupdates": "npx npm-check-updates", "checkupdates": "npx npm-check-updates",
"testingCode": "dotenvx run -f .env -- tsx watch server/services/logistics/controller/warehouse/cycleCountChecks/cyclecountCheck.ts" "testingCode": "dotenvx run -f .env -- tsx watch server/services/logistics/controller/warehouse/cycleCountChecks/cyclecountCheck.ts"
}, },
"config": { "config": {
"commitizen": { "commitizen": {
"path": "./node_modules/cz-conventional-changelog" "path": "./node_modules/cz-conventional-changelog"
}
},
"admConfig": {
"build": 207,
"oldBuild": "backend-0.1.3.zip"
},
"devDependencies": {
"@types/adm-zip": "^0.5.7",
"@types/bcrypt": "^5.0.2",
"@types/fs-extra": "^11.0.4",
"@types/js-cookie": "^3.0.6",
"@types/mssql": "^9.1.7",
"@types/node": "^22.13.11",
"@types/node-cron": "^3.0.11",
"@types/nodemailer": "^6.4.17",
"@types/pg": "^8.11.11",
"@types/ws": "^8.18.0",
"concurrently": "^9.1.2",
"cz-conventional-changelog": "^3.3.0",
"standard-version": "^9.5.0",
"tsx": "^4.19.3",
"typescript": "^5.8.2"
},
"dependencies": {
"@dotenvx/dotenvx": "^1.39.0",
"@hono/node-server": "^1.14.0",
"@hono/zod-openapi": "^0.19.2",
"@scalar/hono-api-reference": "^0.7.2",
"@tanstack/react-form": "^1.2.1",
"@tanstack/react-table": "^8.21.2",
"@types/jsonwebtoken": "^9.0.9",
"@types/nodemailer-express-handlebars": "^4.0.5",
"adm-zip": "^0.5.16",
"axios": "^1.8.4",
"bcryptjs": "^3.0.2",
"croner": "^9.0.0",
"date-fns": "^4.1.0",
"date-fns-tz": "^3.2.0",
"drizzle-kit": "^0.30.5",
"drizzle-orm": "^0.41.0",
"drizzle-zod": "^0.7.0",
"fast-xml-parser": "^5.0.9",
"fs-extra": "^11.3.0",
"jsonwebtoken": "^9.0.2",
"mssql": "^11.0.1",
"nodemailer": "^6.10.0",
"nodemailer-express-handlebars": "^7.0.0",
"pg": "^8.14.1",
"pino": "^9.6.0",
"pino-abstract-transport": "^2.0.0",
"pino-pretty": "^13.0.0",
"postgres": "^3.4.5",
"rimraf": "^6.0.1",
"st-ethernet-ip": "^2.7.3",
"ws": "^8.18.1",
"zod": "^3.24.2"
} }
},
"admConfig": {
"build": 215,
"oldBuild": "backend-0.1.3.zip"
},
"devDependencies": {
"@types/adm-zip": "^0.5.7",
"@types/bcrypt": "^5.0.2",
"@types/fs-extra": "^11.0.4",
"@types/js-cookie": "^3.0.6",
"@types/mssql": "^9.1.7",
"@types/node": "^22.13.11",
"@types/node-cron": "^3.0.11",
"@types/nodemailer": "^6.4.17",
"@types/pg": "^8.11.11",
"@types/ws": "^8.18.0",
"concurrently": "^9.1.2",
"cz-conventional-changelog": "^3.3.0",
"standard-version": "^9.5.0",
"tsx": "^4.19.3",
"typescript": "^5.8.2"
},
"dependencies": {
"@dotenvx/dotenvx": "^1.39.0",
"@hono/node-server": "^1.14.0",
"@hono/zod-openapi": "^0.19.2",
"@scalar/hono-api-reference": "^0.7.2",
"@tanstack/react-form": "^1.2.1",
"@tanstack/react-table": "^8.21.2",
"@types/jsonwebtoken": "^9.0.9",
"@types/nodemailer-express-handlebars": "^4.0.5",
"adm-zip": "^0.5.16",
"axios": "^1.8.4",
"bcryptjs": "^3.0.2",
"croner": "^9.0.0",
"date-fns": "^4.1.0",
"date-fns-tz": "^3.2.0",
"drizzle-kit": "^0.30.5",
"drizzle-orm": "^0.41.0",
"drizzle-zod": "^0.7.0",
"fast-xml-parser": "^5.0.9",
"fs-extra": "^11.3.0",
"jsonwebtoken": "^9.0.2",
"mssql": "^11.0.1",
"nodemailer": "^6.10.0",
"nodemailer-express-handlebars": "^7.0.0",
"pg": "^8.14.1",
"pino": "^9.6.0",
"pino-abstract-transport": "^2.0.0",
"pino-pretty": "^13.0.0",
"postgres": "^3.4.5",
"react-resizable-panels": "^2.1.7",
"rimraf": "^6.0.1",
"st-ethernet-ip": "^2.7.3",
"ws": "^8.18.1",
"zod": "^3.24.2"
}
} }

View File

@@ -14,13 +14,23 @@ export const lanes: any = [];
export const getLanesToCycleCount = async () => { export const getLanesToCycleCount = async () => {
const currentTime: any = timeZoneFix(); const currentTime: any = timeZoneFix();
// store the lanes in memeory // store the lanes in memeory
createLog("info", "warehouse", "logistics", "Empty lane triggered update."); createLog("info", "warehouse", "logistics", "Lane triggered update.");
lastCheck = currentTime; lastCheck = currentTime;
const ageQuery = cycleCountCheck.replaceAll("[ageOfRow]", `1000`); const ageQuery = cycleCountCheck.replaceAll("[ageOfRow]", `1000`);
const { data: prodLanes, error: pl } = await tryCatch( const { data: prodLanes, error: pl } = await tryCatch(
query(ageQuery, "Get Stock lane date.") query(ageQuery, "Get Stock lane date.")
); );
if (pl) {
createLog(
"error",
"warehouse",
"logistics",
`There was an error getting lanes: ${pl}`
);
return;
}
// run the update on the lanes // run the update on the lanes
for (let i = 0; i < prodLanes.length; i++) { for (let i = 0; i < prodLanes.length; i++) {
const createLane = { const createLane = {

View File

@@ -0,0 +1,13 @@
import { tryCatch } from "../../../../../globalUtils/tryCatch.js";
import { query } from "../../../../sqlServer/prodSqlServer.js";
import { ppooQuery } from "../../../../sqlServer/querys/warehouse/ppooQuery.js";
export const getPPOO = async () => {
const { data, error } = await tryCatch(query(ppooQuery, "Get PPOO"));
if (error) {
return { success: false, message: "Error getting ppoo", data: error };
}
return { success: true, message: "Current pallets in PPOO.", data: data };
};

View File

@@ -9,6 +9,7 @@ import { migrateAdjustments } from "./controller/siloAdjustments/migrateAdjustme
import getSiloAdjustments from "./route/siloAdjustments/getSiloAdjustments.js"; import getSiloAdjustments from "./route/siloAdjustments/getSiloAdjustments.js";
import { getLanesToCycleCount } from "./controller/warehouse/cycleCountChecks/cyclecountCheck.js"; import { getLanesToCycleCount } from "./controller/warehouse/cycleCountChecks/cyclecountCheck.js";
import getCycleCountCheck from "./route/getCycleCountChecks.js"; import getCycleCountCheck from "./route/getCycleCountChecks.js";
import getPPOO from "./route/getPPOO.js";
const app = new OpenAPIHono(); const app = new OpenAPIHono();
@@ -23,6 +24,8 @@ const routes = [
getSiloAdjustments, getSiloAdjustments,
//lanes //lanes
getCycleCountCheck, getCycleCountCheck,
//warehouse
getPPOO,
] as const; ] as const;
// app.route("/server", modules); // app.route("/server", modules);

View File

@@ -0,0 +1,53 @@
import { createRoute, OpenAPIHono, z } from "@hono/zod-openapi";
import { responses } from "../../../globalUtils/routeDefs/responses.js";
import { tryCatch } from "../../../globalUtils/tryCatch.js";
import { getCycleCountCheck } from "../controller/warehouse/cycleCountChecks/getCycleCountCheck.js";
import { getPPOO } from "../controller/warehouse/ppoo/getPPOO.js";
const app = new OpenAPIHono();
// const Body = z
// .object({
// age: z.number().optional().openapi({ example: 90 }),
// //email: z.string().optional().openapi({example: "s.smith@example.com"}),
// type: z.string().optional().openapi({ example: "fg" }),
// })
// .openapi("User");
app.openapi(
createRoute({
tags: ["logistics"],
summary: "Returns pallets currently in ppoo",
method: "get",
path: "/getppoo",
// request: {
// body: {
// content: {
// "application/json": { schema: Body },
// },
// },
// },
// description:
// "Provided a running number and lot number you can consume material.",
responses: responses(),
}),
async (c) => {
//apiHit(c, { endpoint: "api/sqlProd/close" });
const { data: ppoo, error } = await tryCatch(getPPOO());
if (error) {
return c.json({
success: false,
message: "Error getting lane data.",
data: error,
});
}
return c.json({
success: ppoo.success,
message: ppoo.message,
data: ppoo.data,
});
}
);
export default app;

View File

@@ -15,6 +15,14 @@ export const getLots = async () => {
}; };
} }
// if (!lotInfo.data.success) {
// return {
// success: false,
// message: "There was an error getting the lots",
// data: lotInfo.data.message,
// };
// }
return { return {
success: true, success: true,
message: "Current active lots that are technically released.", message: "Current active lots that are technically released.",

View File

@@ -84,7 +84,7 @@ export const printerCycle = async () => {
} }
if (p.name === "Autolabeler") { if (p.name === "Autolabeler") {
await autoLabelingStats(p); //await autoLabelingStats(p);
return; return;
} }

View File

@@ -81,7 +81,7 @@ setTimeout(async () => {
await updatePrinters(); await updatePrinters();
await assignedPrinters(); await assignedPrinters();
printerCycle(); printerCycle();
printerCycleAutoLabelers(); // printerCycleAutoLabelers();
} }
}, 10 * 1000); }, 10 * 1000);

View File

@@ -29,11 +29,11 @@ export const assignedPrinters = async () => {
} }
const printers: any = print.data ?? []; const printers: any = print.data ?? [];
const lots: any = l.data ?? []; const lots: any = l.data.length === 0 ? [] : l.data;
for (let i = 0; i < printers.length; i++) { for (let i = 0; i < printers.length; i++) {
// is the printer assinged in alplalabel online? // is the printer assinged in alplalabel online?
const assigned = lots.filter( const assigned = lots?.filter(
(p: any) => p.printerID === parseInt(printers[i].humanReadableId) (p: any) => p.printerID === parseInt(printers[i].humanReadableId)
); );

View File

@@ -0,0 +1,13 @@
export const ppooQuery = `
select MachineLocation,
[RunningNumber],
ArticleHumanReadableId,
ArticleDescription,
convert(Date, ProductionDay) as productionDay,
ProductionDate
FROM [test1_AlplaPROD2.0_Reporting].[reporting_productionControlling].[ScannedUnit] (nolock)
where [RunningNumber] in (select Lfdnr from AlplaPROD_test1.dbo.V_LagerPositionenBarcodes (nolock) where IdLagerAbteilung = 00000)
order by ProductionDate
`;