test(ocp): more work on the dashboard
This commit is contained in:
@@ -1,5 +1,92 @@
|
||||
import {LstCard} from "@/components/extendedUI/LstCard";
|
||||
import {CardHeader} from "@/components/ui/card";
|
||||
import {Skeleton} from "@/components/ui/skeleton";
|
||||
import {Table, TableBody, TableCell, TableHead, TableHeader, TableRow} from "@/components/ui/table";
|
||||
// import {useSessionStore} from "@/lib/store/sessionStore";
|
||||
// import {useSettingStore} from "@/lib/store/useSettings";
|
||||
import {useQuery} from "@tanstack/react-query";
|
||||
import {getlabels} from "@/utils/querys/production/labels";
|
||||
import {format} from "date-fns";
|
||||
|
||||
const labelLogs = [
|
||||
{key: "line", label: "Line"},
|
||||
{key: "printerName", label: "Printer"},
|
||||
{key: "runningNr", label: "Running #"},
|
||||
{key: "upd_date", label: "Label date"},
|
||||
{key: "status", label: "Label Status"},
|
||||
//{key: "reprint", label: "Reprint"}, // removing the reprint button for now until repritning is working as intended
|
||||
];
|
||||
export default function LabelLog() {
|
||||
return <LstCard className="m-2 p-2"> label logs here</LstCard>;
|
||||
const {data, isError, error, isLoading} = useQuery(getlabels("4"));
|
||||
//const {user} = useSessionStore();
|
||||
//const {settings} = useSettingStore();
|
||||
//const server = settings.filter((n) => n.name === "server")[0]?.value || "";
|
||||
|
||||
//const roles = ["admin", "manager", "operator"];
|
||||
|
||||
if (isError) {
|
||||
return (
|
||||
<div>
|
||||
<LstCard>
|
||||
<CardHeader>There was an error loading the lots</CardHeader>
|
||||
{JSON.stringify(error)}
|
||||
</LstCard>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<LstCard className="m-2 p-2 min-h-2/5">
|
||||
<Table>
|
||||
<TableHeader>
|
||||
<TableRow>
|
||||
{labelLogs.map((l) => (
|
||||
<TableHead key={l.key}>{l.label}</TableHead>
|
||||
))}
|
||||
</TableRow>
|
||||
</TableHeader>
|
||||
{isLoading ? (
|
||||
<>
|
||||
<TableBody>
|
||||
{Array(7)
|
||||
.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>
|
||||
<TableCell>
|
||||
<Skeleton className="h-4" />
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
))}
|
||||
</TableBody>
|
||||
</>
|
||||
) : (
|
||||
<TableBody>
|
||||
{data?.map((label: any) => (
|
||||
<TableRow key={label.runningNr}>
|
||||
<TableCell className="font-medium">{label.line}</TableCell>
|
||||
<TableCell className="font-medium">{label.printerName}</TableCell>
|
||||
<TableCell className="font-medium">{label.runningNr}</TableCell>
|
||||
<TableCell className="font-medium">
|
||||
{format(label.upd_date, "M/d/yyyy hh:mm")}
|
||||
</TableCell>
|
||||
<TableCell className="font-medium">{label.status}</TableCell>
|
||||
</TableRow>
|
||||
))}
|
||||
</TableBody>
|
||||
)}
|
||||
</Table>
|
||||
</LstCard>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,9 +1,177 @@
|
||||
import {LstCard} from "@/components/extendedUI/LstCard";
|
||||
import {CardHeader} from "@/components/ui/card";
|
||||
import {Skeleton} from "@/components/ui/skeleton";
|
||||
import {Table, TableBody, TableCell, TableHead, TableHeader, TableRow} from "@/components/ui/table";
|
||||
import {useSessionStore} from "@/lib/store/sessionStore";
|
||||
import {useSettingStore} from "@/lib/store/useSettings";
|
||||
import {LotType} from "@/types/lots";
|
||||
import {getlots} from "@/utils/querys/production/lots";
|
||||
import {useQuery} from "@tanstack/react-query";
|
||||
import ManualPrint from "./ManualPrinting/ManualPrint";
|
||||
import ManualPrintForm from "./ManualPrinting/ManualPrintForm";
|
||||
|
||||
let lotColumns = [
|
||||
{
|
||||
key: "MachineDescription",
|
||||
label: "Machine",
|
||||
},
|
||||
{
|
||||
key: "AV",
|
||||
label: "AV",
|
||||
},
|
||||
{
|
||||
key: "Alias",
|
||||
label: "AvDescription",
|
||||
},
|
||||
{
|
||||
key: "LOT",
|
||||
label: "LotNumber",
|
||||
},
|
||||
{
|
||||
key: "ProlinkLot",
|
||||
label: "ProlinkLot",
|
||||
},
|
||||
{
|
||||
key: "PlannedQTY",
|
||||
label: "PlannedQTY",
|
||||
},
|
||||
{
|
||||
key: "Produced",
|
||||
label: "Produced",
|
||||
},
|
||||
{
|
||||
key: "Remaining",
|
||||
label: "Remaining",
|
||||
},
|
||||
{
|
||||
key: "overPrinting",
|
||||
label: "Overprinting",
|
||||
},
|
||||
// {
|
||||
// key: "lastProlinkUpdate",
|
||||
// label: "Last ProlinkCheck",
|
||||
// },
|
||||
// {
|
||||
// key: "printLabel",
|
||||
// label: "Print Label",
|
||||
// },
|
||||
];
|
||||
export default function Lots() {
|
||||
const {data, isError, error, isLoading} = useQuery(getlots());
|
||||
const {user} = useSessionStore();
|
||||
const {settings} = useSettingStore();
|
||||
const server = settings.filter((n) => n.name === "server")[0]?.value || "";
|
||||
|
||||
console.log(server);
|
||||
|
||||
const roles = ["admin", "manager", "operator"];
|
||||
|
||||
if (user && roles.includes(user.role)) {
|
||||
//width = 1280;
|
||||
const checkCol = lotColumns.some((l) => l.key === "printLabel");
|
||||
if (!checkCol) {
|
||||
lotColumns = [
|
||||
...lotColumns,
|
||||
{
|
||||
key: "printLabel",
|
||||
label: "Print Label",
|
||||
},
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
if (isError) {
|
||||
return (
|
||||
<div>
|
||||
<LstCard>
|
||||
<CardHeader>There was an error loading the lots</CardHeader>
|
||||
{JSON.stringify(error)}
|
||||
</LstCard>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<LstCard className="m-2 p-2 min-h-2/5">
|
||||
<h1>Lots</h1>
|
||||
<Table>
|
||||
<TableHeader>
|
||||
<TableRow>
|
||||
{lotColumns.map((l) => (
|
||||
<TableHead key={l.key}>{l.label}</TableHead>
|
||||
))}
|
||||
</TableRow>
|
||||
</TableHeader>
|
||||
{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>
|
||||
<TableCell>
|
||||
<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>
|
||||
</>
|
||||
) : (
|
||||
<TableBody>
|
||||
{data?.map((lot: LotType) => (
|
||||
<TableRow key={lot.LabelOnlineID}>
|
||||
<TableCell className="font-medium">{lot.MachineLocation}</TableCell>
|
||||
<TableCell className="font-medium">{lot.AV}</TableCell>
|
||||
<TableCell className="font-medium">{lot.Alias}</TableCell>
|
||||
<TableCell className="font-medium">{lot.LOT}</TableCell>
|
||||
<TableCell className="font-medium">{lot.ProlinkLot}</TableCell>
|
||||
<TableCell className="font-medium">{lot.PlannedQTY}</TableCell>
|
||||
<TableCell className="font-medium">{lot.Produced}</TableCell>
|
||||
<TableCell className="font-medium">{lot.Remaining}</TableCell>
|
||||
<TableCell className="font-medium">{lot.overPrinting}</TableCell>
|
||||
{user && roles.includes(user.role) && (
|
||||
<>
|
||||
{server === "usday1vms006" || server === "localhost" ? (
|
||||
<>
|
||||
<TableCell className="flex justify-center">
|
||||
<ManualPrintForm lot={lot} />
|
||||
</TableCell>
|
||||
</>
|
||||
) : (
|
||||
<TableCell className="flex justify-center">
|
||||
<ManualPrint lot={lot} />
|
||||
</TableCell>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</TableRow>
|
||||
))}
|
||||
</TableBody>
|
||||
)}
|
||||
</Table>
|
||||
</LstCard>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
import {Button} from "@/components/ui/button";
|
||||
import {useSessionStore} from "@/lib/store/sessionStore";
|
||||
//import {useSettingStore} from "@/lib/store/useSettings";
|
||||
import {LotType} from "@/types/lots";
|
||||
import {Tag} from "lucide-react";
|
||||
import {toast} from "sonner";
|
||||
import {manualPrintLabels} from "./ManualPrintLabel";
|
||||
|
||||
export default function ManualPrint({lot}: {lot: LotType}) {
|
||||
const {user} = useSessionStore();
|
||||
//const {settings} = useSettingStore();
|
||||
//const server = settings.filter((n) => n.name === "server")[0]?.value;
|
||||
//const serverPort = settings.filter((n) => n.name === "serverPort")[0]?.value;
|
||||
//const serverUrl = `http://${server}:${serverPort}`;
|
||||
|
||||
const handlePrintLabel = async (lot: LotType) => {
|
||||
//console.log(lot);
|
||||
|
||||
const labels: any = await manualPrintLabels(lot, user);
|
||||
|
||||
if (labels.success) {
|
||||
toast.success(labels.message);
|
||||
} else {
|
||||
toast.error(labels.message);
|
||||
}
|
||||
};
|
||||
return (
|
||||
<Button variant="outline" size="icon" onClick={() => handlePrintLabel(lot)}>
|
||||
<Tag className="h-[16px] w-[16px]" />
|
||||
</Button>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,217 @@
|
||||
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 {
|
||||
Select,
|
||||
SelectContent,
|
||||
SelectGroup,
|
||||
SelectItem,
|
||||
SelectLabel,
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
} from "@/components/ui/select";
|
||||
import {Textarea} from "@/components/ui/textarea";
|
||||
import {useSessionStore} from "@/lib/store/sessionStore";
|
||||
import {useSettingStore} from "@/lib/store/useSettings";
|
||||
import {LotType} from "@/types/lots";
|
||||
import axios from "axios";
|
||||
import {Tag} from "lucide-react";
|
||||
import {useState} from "react";
|
||||
import {Controller, useForm} from "react-hook-form";
|
||||
import {toast} from "sonner";
|
||||
import {manualPrintLabels} from "./ManualPrintLabel";
|
||||
|
||||
const printReason = [
|
||||
{key: "printerIssue", label: "Printer Related"},
|
||||
{key: "strapper", label: "Strapper Error"},
|
||||
{key: "manualCheck", label: "20th pallet check"},
|
||||
{key: "outOfSync", label: "Labeler Out of Sync"},
|
||||
];
|
||||
|
||||
export default function ManualPrintForm({lot}: {lot: LotType}) {
|
||||
const {user} = useSessionStore();
|
||||
const token = localStorage.getItem("auth_token");
|
||||
const {settings} = useSettingStore();
|
||||
const [open, setOpen] = useState(false);
|
||||
const server = settings.filter((n) => n.name === "server")[0]?.value;
|
||||
// const serverPort = settings.filter((n) => n.name === "serverPort")[0]?.value;
|
||||
// const serverUrl = `http://${server}:${serverPort}`;
|
||||
const {
|
||||
register,
|
||||
handleSubmit,
|
||||
//watch,
|
||||
formState: {errors},
|
||||
reset,
|
||||
control,
|
||||
} = useForm();
|
||||
|
||||
const handlePrintLabel = async (lot: LotType) => {
|
||||
//console.log(lot);
|
||||
const labels: any = await manualPrintLabels(lot, user);
|
||||
|
||||
if (labels.success) {
|
||||
toast.success(labels.message);
|
||||
} else {
|
||||
toast.error(labels.message);
|
||||
}
|
||||
};
|
||||
|
||||
const handleManualPrintLog = async (logData: any, lot: LotType) => {
|
||||
// toast.success(`A new label was sent to printer: ${lot.PrinterName} for line ${lot.MachineDescription} `);
|
||||
const logdataUrl = `/api/ocp/manualLabelLog`;
|
||||
axios
|
||||
.post(logdataUrl, logData, {headers: {Authorization: `Bearer ${token}`}})
|
||||
.then((d) => {
|
||||
//console.log(d);
|
||||
toast.success(d.data.message);
|
||||
handlePrintLabel(lot);
|
||||
reset();
|
||||
})
|
||||
.catch((e) => {
|
||||
if (e.response.status === 500) {
|
||||
toast.error(`Internal Server error please try again.`);
|
||||
return {sucess: false};
|
||||
}
|
||||
|
||||
if (e.response.status === 401) {
|
||||
//console.log(e.response);
|
||||
toast.error(`You are not authorized to do this.`);
|
||||
return {sucess: false};
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const onSubmit = (data: any) => {
|
||||
console.log(data);
|
||||
|
||||
handleManualPrintLog(data, lot);
|
||||
};
|
||||
return (
|
||||
<Dialog
|
||||
open={open}
|
||||
onOpenChange={(isOpen) => {
|
||||
if (!open) {
|
||||
reset();
|
||||
}
|
||||
setOpen(isOpen);
|
||||
// toast.message("Model was something", {
|
||||
// description: isOpen ? "Modal is open" : "Modal is closed",
|
||||
// });
|
||||
}}
|
||||
>
|
||||
<DialogTrigger asChild>
|
||||
<Button variant="outline" size="icon">
|
||||
<Tag className="h-[16px] w-[16px]" />
|
||||
</Button>
|
||||
</DialogTrigger>
|
||||
<DialogContent className="sm:max-w-[425px]">
|
||||
<DialogHeader>
|
||||
<DialogTitle>Edit profile</DialogTitle>
|
||||
<DialogDescription>
|
||||
Make changes to your profile here. Click save when you're done.
|
||||
</DialogDescription>
|
||||
</DialogHeader>
|
||||
<form onSubmit={handleSubmit(onSubmit)}>
|
||||
<p>
|
||||
To manually print a label you must complete all the required fields below.
|
||||
<br />
|
||||
If you clicked this in error just click close
|
||||
</p>
|
||||
<hr className="mt-2 mb-2" />
|
||||
{server == "usday1vms006" ? (
|
||||
<Controller
|
||||
control={control}
|
||||
name="printReason"
|
||||
defaultValue={""}
|
||||
render={({
|
||||
field: {onChange},
|
||||
fieldState: {},
|
||||
//formState,
|
||||
}) => (
|
||||
<Select onValueChange={onChange}>
|
||||
<SelectTrigger className="w-[180px]">
|
||||
<SelectValue placeholder="Select Reason" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectGroup>
|
||||
<SelectLabel>Print Reasons</SelectLabel>
|
||||
{printReason.map((printReason: any) => (
|
||||
<SelectItem value={printReason.key}>{printReason.label}</SelectItem>
|
||||
))}
|
||||
</SelectGroup>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
)}
|
||||
/>
|
||||
) : (
|
||||
<div>
|
||||
<Label htmlFor="printRason" className="m-1">
|
||||
Why are you manually printing?
|
||||
</Label>
|
||||
<Input
|
||||
type="text"
|
||||
className={errors.printReason ? "border-red-500" : ""}
|
||||
aria-invalid={!!errors.printReason}
|
||||
{...register("printReason", {
|
||||
required: true,
|
||||
minLength: {
|
||||
value: 5,
|
||||
message: "To short of a reason please try again!",
|
||||
},
|
||||
})}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
<div>
|
||||
<Label htmlFor="line" className="m-1">
|
||||
"What is the line number you are printing?"
|
||||
</Label>
|
||||
<Input
|
||||
//variant="underlined"
|
||||
type="number"
|
||||
className={errors.line ? "border-red-500" : ""}
|
||||
aria-invalid={!!errors.line}
|
||||
{...register("line", {required: true})}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<Label htmlFor="initials" className="m-1">
|
||||
Enter intials
|
||||
</Label>
|
||||
<Input
|
||||
//variant="underlined"
|
||||
//label="Enter intials"
|
||||
|
||||
{...register("initials", {required: true})}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<Textarea
|
||||
//label="Comments"
|
||||
placeholder="add more info as needed."
|
||||
{...register("additionalComments")}
|
||||
/>
|
||||
|
||||
<DialogFooter>
|
||||
<Button color="danger" variant="default" onClick={() => setOpen(!open)}>
|
||||
Close
|
||||
</Button>
|
||||
<Button color="primary" type="submit">
|
||||
Print
|
||||
</Button>
|
||||
</DialogFooter>
|
||||
</form>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
import {LotType} from "@/types/lots";
|
||||
import axios from "axios";
|
||||
|
||||
export const manualPrintLabels = async (lot: LotType, user: any) => {
|
||||
//console.log(lot);
|
||||
const labelUrl = `/ocp/manualPrintAndFollow`;
|
||||
|
||||
try {
|
||||
const res = await axios.post(
|
||||
labelUrl,
|
||||
{line: lot.MachineLocation, printerName: lot.PrinterName},
|
||||
{headers: {Authorization: `Basic ${user?.prod}`}}
|
||||
);
|
||||
|
||||
if (res.data.success) {
|
||||
return {
|
||||
success: true,
|
||||
message: `A new label was printed for ${lot.MachineDescription} to printer: ${lot.PrinterName}`,
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
success: true,
|
||||
message: `Line ${lot.MachineDescription} encountered an error printing labels: ${res.data.message}`,
|
||||
};
|
||||
}
|
||||
} catch (error: any) {
|
||||
if (error.response.status === 500) {
|
||||
//toast.error(`Internal Server error please try again.`);
|
||||
return {
|
||||
success: false,
|
||||
message: `Internal Server error please try again.`,
|
||||
};
|
||||
}
|
||||
|
||||
if (error.response.status === 401) {
|
||||
//console.log(e.response);
|
||||
//toast.error(`You are not authorized to do this.`);
|
||||
return {
|
||||
success: false,
|
||||
message: `You are not authorized to do this.`,
|
||||
};
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -1,16 +1,19 @@
|
||||
import {QueryClient, QueryClientProvider} from "@tanstack/react-query";
|
||||
import {useModuleStore} from "../../lib/store/useModuleStore";
|
||||
import {useEffect} from "react";
|
||||
import {useSettingStore} from "@/lib/store/useSettings";
|
||||
//import {useGetUserRoles} from "@/lib/store/useGetRoles";
|
||||
|
||||
const queryClient = new QueryClient();
|
||||
|
||||
export const SessionProvider = ({children}: {children: React.ReactNode}) => {
|
||||
const {fetchModules} = useModuleStore();
|
||||
const {fetchSettings} = useSettingStore();
|
||||
//const {fetchUserRoles} = useGetUserRoles();
|
||||
|
||||
useEffect(() => {
|
||||
fetchModules();
|
||||
fetchSettings();
|
||||
//fetchUserRoles();
|
||||
}, []);
|
||||
return <QueryClientProvider client={queryClient}>{children}</QueryClientProvider>;
|
||||
|
||||
183
frontend/src/components/ui/select.tsx
Normal file
183
frontend/src/components/ui/select.tsx
Normal file
@@ -0,0 +1,183 @@
|
||||
import * as React from "react"
|
||||
import * as SelectPrimitive from "@radix-ui/react-select"
|
||||
import { CheckIcon, ChevronDownIcon, ChevronUpIcon } from "lucide-react"
|
||||
|
||||
import { cn } from "@/lib/utils"
|
||||
|
||||
function Select({
|
||||
...props
|
||||
}: React.ComponentProps<typeof SelectPrimitive.Root>) {
|
||||
return <SelectPrimitive.Root data-slot="select" {...props} />
|
||||
}
|
||||
|
||||
function SelectGroup({
|
||||
...props
|
||||
}: React.ComponentProps<typeof SelectPrimitive.Group>) {
|
||||
return <SelectPrimitive.Group data-slot="select-group" {...props} />
|
||||
}
|
||||
|
||||
function SelectValue({
|
||||
...props
|
||||
}: React.ComponentProps<typeof SelectPrimitive.Value>) {
|
||||
return <SelectPrimitive.Value data-slot="select-value" {...props} />
|
||||
}
|
||||
|
||||
function SelectTrigger({
|
||||
className,
|
||||
size = "default",
|
||||
children,
|
||||
...props
|
||||
}: React.ComponentProps<typeof SelectPrimitive.Trigger> & {
|
||||
size?: "sm" | "default"
|
||||
}) {
|
||||
return (
|
||||
<SelectPrimitive.Trigger
|
||||
data-slot="select-trigger"
|
||||
data-size={size}
|
||||
className={cn(
|
||||
"border-input data-[placeholder]:text-muted-foreground [&_svg:not([class*='text-'])]:text-muted-foreground focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive dark:bg-input/30 dark:hover:bg-input/50 flex w-fit items-center justify-between gap-2 rounded-md border bg-transparent px-3 py-2 text-sm whitespace-nowrap shadow-xs transition-[color,box-shadow] outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50 data-[size=default]:h-9 data-[size=sm]:h-8 *:data-[slot=select-value]:line-clamp-1 *:data-[slot=select-value]:flex *:data-[slot=select-value]:items-center *:data-[slot=select-value]:gap-2 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
{children}
|
||||
<SelectPrimitive.Icon asChild>
|
||||
<ChevronDownIcon className="size-4 opacity-50" />
|
||||
</SelectPrimitive.Icon>
|
||||
</SelectPrimitive.Trigger>
|
||||
)
|
||||
}
|
||||
|
||||
function SelectContent({
|
||||
className,
|
||||
children,
|
||||
position = "popper",
|
||||
...props
|
||||
}: React.ComponentProps<typeof SelectPrimitive.Content>) {
|
||||
return (
|
||||
<SelectPrimitive.Portal>
|
||||
<SelectPrimitive.Content
|
||||
data-slot="select-content"
|
||||
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 relative z-50 max-h-(--radix-select-content-available-height) min-w-[8rem] origin-(--radix-select-content-transform-origin) overflow-x-hidden overflow-y-auto rounded-md border shadow-md",
|
||||
position === "popper" &&
|
||||
"data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1",
|
||||
className
|
||||
)}
|
||||
position={position}
|
||||
{...props}
|
||||
>
|
||||
<SelectScrollUpButton />
|
||||
<SelectPrimitive.Viewport
|
||||
className={cn(
|
||||
"p-1",
|
||||
position === "popper" &&
|
||||
"h-[var(--radix-select-trigger-height)] w-full min-w-[var(--radix-select-trigger-width)] scroll-my-1"
|
||||
)}
|
||||
>
|
||||
{children}
|
||||
</SelectPrimitive.Viewport>
|
||||
<SelectScrollDownButton />
|
||||
</SelectPrimitive.Content>
|
||||
</SelectPrimitive.Portal>
|
||||
)
|
||||
}
|
||||
|
||||
function SelectLabel({
|
||||
className,
|
||||
...props
|
||||
}: React.ComponentProps<typeof SelectPrimitive.Label>) {
|
||||
return (
|
||||
<SelectPrimitive.Label
|
||||
data-slot="select-label"
|
||||
className={cn("text-muted-foreground px-2 py-1.5 text-xs", className)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
function SelectItem({
|
||||
className,
|
||||
children,
|
||||
...props
|
||||
}: React.ComponentProps<typeof SelectPrimitive.Item>) {
|
||||
return (
|
||||
<SelectPrimitive.Item
|
||||
data-slot="select-item"
|
||||
className={cn(
|
||||
"focus:bg-accent focus:text-accent-foreground [&_svg:not([class*='text-'])]:text-muted-foreground relative flex w-full cursor-default items-center gap-2 rounded-sm py-1.5 pr-8 pl-2 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 *:[span]:last:flex *:[span]:last:items-center *:[span]:last:gap-2",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
<span className="absolute right-2 flex size-3.5 items-center justify-center">
|
||||
<SelectPrimitive.ItemIndicator>
|
||||
<CheckIcon className="size-4" />
|
||||
</SelectPrimitive.ItemIndicator>
|
||||
</span>
|
||||
<SelectPrimitive.ItemText>{children}</SelectPrimitive.ItemText>
|
||||
</SelectPrimitive.Item>
|
||||
)
|
||||
}
|
||||
|
||||
function SelectSeparator({
|
||||
className,
|
||||
...props
|
||||
}: React.ComponentProps<typeof SelectPrimitive.Separator>) {
|
||||
return (
|
||||
<SelectPrimitive.Separator
|
||||
data-slot="select-separator"
|
||||
className={cn("bg-border pointer-events-none -mx-1 my-1 h-px", className)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
function SelectScrollUpButton({
|
||||
className,
|
||||
...props
|
||||
}: React.ComponentProps<typeof SelectPrimitive.ScrollUpButton>) {
|
||||
return (
|
||||
<SelectPrimitive.ScrollUpButton
|
||||
data-slot="select-scroll-up-button"
|
||||
className={cn(
|
||||
"flex cursor-default items-center justify-center py-1",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
<ChevronUpIcon className="size-4" />
|
||||
</SelectPrimitive.ScrollUpButton>
|
||||
)
|
||||
}
|
||||
|
||||
function SelectScrollDownButton({
|
||||
className,
|
||||
...props
|
||||
}: React.ComponentProps<typeof SelectPrimitive.ScrollDownButton>) {
|
||||
return (
|
||||
<SelectPrimitive.ScrollDownButton
|
||||
data-slot="select-scroll-down-button"
|
||||
className={cn(
|
||||
"flex cursor-default items-center justify-center py-1",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
<ChevronDownIcon className="size-4" />
|
||||
</SelectPrimitive.ScrollDownButton>
|
||||
)
|
||||
}
|
||||
|
||||
export {
|
||||
Select,
|
||||
SelectContent,
|
||||
SelectGroup,
|
||||
SelectItem,
|
||||
SelectLabel,
|
||||
SelectScrollDownButton,
|
||||
SelectScrollUpButton,
|
||||
SelectSeparator,
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
}
|
||||
18
frontend/src/components/ui/textarea.tsx
Normal file
18
frontend/src/components/ui/textarea.tsx
Normal file
@@ -0,0 +1,18 @@
|
||||
import * as React from "react"
|
||||
|
||||
import { cn } from "@/lib/utils"
|
||||
|
||||
function Textarea({ className, ...props }: React.ComponentProps<"textarea">) {
|
||||
return (
|
||||
<textarea
|
||||
data-slot="textarea"
|
||||
className={cn(
|
||||
"border-input placeholder:text-muted-foreground focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive dark:bg-input/30 flex field-sizing-content min-h-16 w-full rounded-md border bg-transparent px-3 py-2 text-base shadow-xs transition-[color,box-shadow] outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50 md:text-sm",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
export { Textarea }
|
||||
@@ -1,9 +0,0 @@
|
||||
import { createFileRoute } from '@tanstack/react-router'
|
||||
|
||||
export const Route = createFileRoute('/ocp/lots')({
|
||||
component: RouteComponent,
|
||||
})
|
||||
|
||||
function RouteComponent() {
|
||||
return <div>Hello "/ocp/lots"!</div>
|
||||
}
|
||||
19
frontend/src/types/lots.ts
Normal file
19
frontend/src/types/lots.ts
Normal file
@@ -0,0 +1,19 @@
|
||||
export type LotType = {
|
||||
AV: number;
|
||||
Alias: string;
|
||||
LOT: number;
|
||||
LabelOnlineID: number;
|
||||
MachineDescription: string;
|
||||
MachineID: number;
|
||||
MachineLocation: number;
|
||||
PlannedQTY: number;
|
||||
PrinterName: string;
|
||||
Produced: number;
|
||||
ProlinkLot: number;
|
||||
Remaining: number;
|
||||
machineID: number;
|
||||
overPrinting: string;
|
||||
pallerCopies: number;
|
||||
palletLabel: string;
|
||||
printerID: number;
|
||||
};
|
||||
20
frontend/src/utils/querys/production/labels.tsx
Normal file
20
frontend/src/utils/querys/production/labels.tsx
Normal file
@@ -0,0 +1,20 @@
|
||||
import {queryOptions} from "@tanstack/react-query";
|
||||
import axios from "axios";
|
||||
|
||||
export function getlabels(hours: string) {
|
||||
return queryOptions({
|
||||
queryKey: ["labels"],
|
||||
queryFn: () => fetchSettings(hours),
|
||||
|
||||
staleTime: 1000,
|
||||
refetchInterval: 2500,
|
||||
refetchOnWindowFocus: true,
|
||||
});
|
||||
}
|
||||
|
||||
const fetchSettings = async (hours: string) => {
|
||||
const {data} = await axios.get(`/api/v1/ocp/labels?hours=${hours}`);
|
||||
// if we are not localhost ignore the devDir setting.
|
||||
//const url: string = window.location.host.split(":")[0];
|
||||
return data.data;
|
||||
};
|
||||
21
frontend/src/utils/querys/production/lots.tsx
Normal file
21
frontend/src/utils/querys/production/lots.tsx
Normal file
@@ -0,0 +1,21 @@
|
||||
import {queryOptions} from "@tanstack/react-query";
|
||||
import axios from "axios";
|
||||
|
||||
export function getlots() {
|
||||
return queryOptions({
|
||||
queryKey: ["lots"],
|
||||
queryFn: () => fetchSettings(),
|
||||
|
||||
staleTime: 10 * 1000,
|
||||
refetchInterval: 10 * 1000,
|
||||
refetchOnWindowFocus: true,
|
||||
});
|
||||
}
|
||||
|
||||
const fetchSettings = async () => {
|
||||
const {data} = await axios.get("/api/v1/ocp/lots");
|
||||
// if we are not localhost ignore the devDir setting.
|
||||
//const url: string = window.location.host.split(":")[0];
|
||||
let lotData = data.data;
|
||||
return lotData;
|
||||
};
|
||||
Reference in New Issue
Block a user