feat(barcode gen): added in lane exports both single and multiple intial release
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import { Cylinder, Package, Truck } from "lucide-react";
|
||||
import { Barcode, Cylinder, Package, Truck } from "lucide-react";
|
||||
import {
|
||||
SidebarGroup,
|
||||
SidebarGroupContent,
|
||||
@@ -15,6 +15,7 @@ const iconMap: any = {
|
||||
Package: Package,
|
||||
Truck: Truck,
|
||||
Cylinder: Cylinder,
|
||||
Barcode: Barcode,
|
||||
};
|
||||
|
||||
export function LogisticsSideBar({
|
||||
|
||||
150
frontend/src/components/logistics/barcodeGenerator/BGPage.tsx
Normal file
150
frontend/src/components/logistics/barcodeGenerator/BGPage.tsx
Normal file
@@ -0,0 +1,150 @@
|
||||
import { LstCard } from "@/components/extendedUI/LstCard";
|
||||
import { CardContent, CardFooter, CardHeader } from "@/components/ui/card";
|
||||
import { Checkbox } from "@/components/ui/checkbox";
|
||||
import { Collapsible, CollapsibleContent } from "@/components/ui/collapsible";
|
||||
import { getLanes } from "@/utils/querys/logistics/getWarehouseLanes";
|
||||
import { CollapsibleTrigger } from "@radix-ui/react-collapsible";
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import { useState } from "react";
|
||||
import Barcode from "react-barcode";
|
||||
import { BarcodePDFExport } from "./BarcodeExport";
|
||||
import { BulkBarcodePDFExport } from "./BulkExport";
|
||||
|
||||
export default function BGPage() {
|
||||
const { data, isError, isLoading } = useQuery(getLanes());
|
||||
const [checked, setChecked] = useState([]);
|
||||
|
||||
if (isLoading) return <div>Loading Data</div>;
|
||||
|
||||
if (isError)
|
||||
return <div>There was an error getting the warehouse lane data.</div>;
|
||||
|
||||
/**
|
||||
* get the warehouse names only
|
||||
*/
|
||||
|
||||
const warhouses = new Map();
|
||||
|
||||
data?.forEach((item: any) => {
|
||||
// if the warhouse is not already included add it to the map
|
||||
if (!warhouses.has(item.warehouseId)) {
|
||||
warhouses.set(item.warehouseId, item.warehouseDescription);
|
||||
}
|
||||
});
|
||||
|
||||
// convert the map to an array
|
||||
const warehouseArray = Array.from(warhouses).map(([wid, wname]) => ({
|
||||
warehouseId: wid,
|
||||
warehouseDescription: wname,
|
||||
}));
|
||||
|
||||
//console.log(warehouseArray);
|
||||
|
||||
// handle the onchange
|
||||
const changeBox = (d: any) => {
|
||||
setChecked((prev: any) => {
|
||||
if (prev.includes(d)) {
|
||||
return prev.filter((name: any) => name !== d);
|
||||
} else {
|
||||
return [...prev, d];
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="flex flex-row m-2">
|
||||
<div className="m-2">
|
||||
<LstCard>
|
||||
<CardHeader>Warehouse Barcodes</CardHeader>
|
||||
<CardContent>
|
||||
{warehouseArray.map((i: any) => {
|
||||
const lanes = data?.filter(
|
||||
(wid: any) => wid.warehouseId === i.warehouseId
|
||||
);
|
||||
return (
|
||||
<div className="m-2" key={i.warehouseId}>
|
||||
<Collapsible>
|
||||
<CollapsibleTrigger>
|
||||
{i.warehouseDescription}
|
||||
</CollapsibleTrigger>
|
||||
<CollapsibleContent>
|
||||
<div className="ml-2">
|
||||
{lanes?.map((l: any) => {
|
||||
return (
|
||||
<div key={l.laneId}>
|
||||
<Checkbox
|
||||
id={l.laneId}
|
||||
// checked={checked.includes(
|
||||
// l
|
||||
// )}
|
||||
onCheckedChange={() =>
|
||||
changeBox(l)
|
||||
}
|
||||
/>
|
||||
<label
|
||||
id={l.laneId}
|
||||
className="ml-2"
|
||||
>
|
||||
{
|
||||
l.laneDescription
|
||||
}
|
||||
</label>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</CollapsibleContent>
|
||||
</Collapsible>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</CardContent>
|
||||
</LstCard>
|
||||
</div>
|
||||
{checked.length > 0 && (
|
||||
<div className="m-2">
|
||||
<LstCard>
|
||||
<CardHeader>Current selected lanes</CardHeader>
|
||||
<CardContent>
|
||||
{checked.map((c: any) => {
|
||||
return (
|
||||
<div
|
||||
className="flex justify-center"
|
||||
key={`${c.warehouseId}-${c.laneId}`}
|
||||
>
|
||||
<div>
|
||||
<Barcode
|
||||
value={`loc#${c.warehouseId}#${c.laneId}`}
|
||||
width={2}
|
||||
height={50}
|
||||
displayValue={false}
|
||||
/>
|
||||
<p className="flex justify-center">
|
||||
Lane: {c.laneDescription}
|
||||
</p>
|
||||
</div>
|
||||
<div className="ml-2 mt-4">
|
||||
<BarcodePDFExport
|
||||
barcodeValue={`loc#${c.warehouseId}#${c.laneId}`}
|
||||
data={c}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</CardContent>
|
||||
<CardFooter>
|
||||
<div className="flex justify-end">
|
||||
{checked.length > 1 && (
|
||||
<div>
|
||||
<BulkBarcodePDFExport data={checked} />
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</CardFooter>
|
||||
</LstCard>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
import { Button } from "@/components/ui/button";
|
||||
import {
|
||||
pdf,
|
||||
Page,
|
||||
Text,
|
||||
View,
|
||||
Document,
|
||||
StyleSheet,
|
||||
Image,
|
||||
} from "@react-pdf/renderer";
|
||||
import JsBarcode from "jsbarcode";
|
||||
|
||||
export const BarcodePDFExport = ({
|
||||
barcodeValue,
|
||||
data,
|
||||
}: {
|
||||
barcodeValue: any;
|
||||
data: any;
|
||||
}) => {
|
||||
const generatePDF = () => {
|
||||
//const barcodeValue = data; // Barcode value
|
||||
const canvas = document.createElement("canvas");
|
||||
|
||||
// Generate barcode on the canvas
|
||||
JsBarcode(canvas, barcodeValue, {
|
||||
format: "CODE128",
|
||||
displayValue: false,
|
||||
});
|
||||
|
||||
// Convert canvas to base64 image data
|
||||
const barcodeImage = canvas.toDataURL("image/png");
|
||||
|
||||
// Define the document styles using @react-pdf/renderer
|
||||
const styles = StyleSheet.create({
|
||||
page: {
|
||||
padding: 30,
|
||||
},
|
||||
centerContent: {
|
||||
display: "flex",
|
||||
justifyContent: "center", // Center horizontally
|
||||
alignItems: "center", // Center vertically
|
||||
flexDirection: "column", // Stack items (barcode and description) vertically
|
||||
height: "75%", // Ensure the container takes full page height
|
||||
textAlign: "center",
|
||||
},
|
||||
section: {
|
||||
marginBottom: 10,
|
||||
textAlign: "center",
|
||||
},
|
||||
barcode: {
|
||||
width: 800, // Width of the barcode
|
||||
height: 200, // Height of the barcode
|
||||
marginBottom: 10,
|
||||
},
|
||||
description: {
|
||||
fontSize: 28,
|
||||
fontWeight: "bold",
|
||||
marginTop: 10,
|
||||
marginBottom: 20, // Ensure there's space below the text
|
||||
},
|
||||
});
|
||||
|
||||
// Create the document
|
||||
const MyDocument = (
|
||||
<Document>
|
||||
<Page style={styles.page} orientation="landscape" size="A4">
|
||||
<View style={styles.centerContent}>
|
||||
<View style={styles.section}>
|
||||
<Image src={barcodeImage} style={styles.barcode} />
|
||||
</View>
|
||||
|
||||
<View style={styles.section}>
|
||||
<Text style={styles.description}>
|
||||
Lane: {data.laneDescription}
|
||||
</Text>
|
||||
</View>
|
||||
</View>
|
||||
</Page>
|
||||
</Document>
|
||||
);
|
||||
|
||||
// Generate the PDF and trigger download
|
||||
pdf(MyDocument)
|
||||
.toBlob()
|
||||
.then((blob) => {
|
||||
const link = document.createElement("a");
|
||||
link.href = URL.createObjectURL(blob);
|
||||
link.download = `${data.warehouseDescription}-${data.laneDescription}.pdf`;
|
||||
link.click();
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Button onClick={() => generatePDF()} color="primary">
|
||||
Export
|
||||
</Button>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,127 @@
|
||||
import { Button } from "@/components/ui/button";
|
||||
import {
|
||||
pdf,
|
||||
Page,
|
||||
Text,
|
||||
View,
|
||||
Document,
|
||||
StyleSheet,
|
||||
Image,
|
||||
} from "@react-pdf/renderer";
|
||||
import JsBarcode from "jsbarcode";
|
||||
|
||||
export const BulkBarcodePDFExport = ({ data }: { data: any }) => {
|
||||
const createBarcode = (barcodeValue: any) => {
|
||||
//const barcodeValue = data; // Barcode value
|
||||
const canvas = document.createElement("canvas");
|
||||
|
||||
// Generate barcode on the canvas
|
||||
JsBarcode(canvas, barcodeValue, {
|
||||
format: "CODE128",
|
||||
displayValue: false,
|
||||
});
|
||||
|
||||
// Convert canvas to base64 image data
|
||||
const barcodeImage = canvas.toDataURL("image/png");
|
||||
|
||||
return barcodeImage;
|
||||
};
|
||||
const generatePDF = () => {
|
||||
// Define the document styles using @react-pdf/renderer
|
||||
const styles = StyleSheet.create({
|
||||
page: {
|
||||
padding: 30,
|
||||
},
|
||||
centerContent: {
|
||||
display: "flex",
|
||||
justifyContent: "flex-start", // Center horizontally
|
||||
alignItems: "center", // Center vertically
|
||||
flexDirection: "row", // Stack items (barcode and description) vertically
|
||||
//height: "5%", // Ensure the container takes full page height
|
||||
textAlign: "center",
|
||||
},
|
||||
section: {
|
||||
marginBottom: 10,
|
||||
textAlign: "center",
|
||||
},
|
||||
barcode: {
|
||||
width: 275, // Width of the barcode
|
||||
height: 75, // Height of the barcode
|
||||
marginBottom: 10,
|
||||
},
|
||||
description: {
|
||||
fontSize: 14,
|
||||
fontWeight: "bold",
|
||||
marginTop: 10,
|
||||
marginBottom: 20, // Ensure there's space below the text
|
||||
},
|
||||
|
||||
headerText: {
|
||||
fontSize: 28,
|
||||
fontWeight: "bold",
|
||||
marginTop: 10,
|
||||
marginBottom: 20, // Ensure there's space below the text
|
||||
display: "flex",
|
||||
justifyContent: "center",
|
||||
//height: "15%", // Ensure the container takes full page height
|
||||
textAlign: "center",
|
||||
},
|
||||
|
||||
horizontalLine: {
|
||||
borderBottom: "#000000",
|
||||
borderBottomWidth: 1,
|
||||
},
|
||||
});
|
||||
|
||||
// Create the document
|
||||
const MyDocument = (
|
||||
<Document>
|
||||
<Page style={styles.page} orientation="portrait" size="A4">
|
||||
<View style={styles.headerText}>
|
||||
<Text>Multi Lane export.</Text>
|
||||
</View>
|
||||
<View style={styles.horizontalLine} />
|
||||
|
||||
{data.map((i: any, index: any) => {
|
||||
return (
|
||||
<View style={styles.centerContent} key={index}>
|
||||
<View style={styles.section}>
|
||||
<Image
|
||||
src={createBarcode(
|
||||
`loc#${i.warehouseId}#${i.laneId}`
|
||||
)}
|
||||
style={styles.barcode}
|
||||
/>
|
||||
</View>
|
||||
|
||||
<View style={styles.section}>
|
||||
<Text style={styles.description}>
|
||||
Lane: {i.laneDescription}
|
||||
</Text>
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
})}
|
||||
</Page>
|
||||
</Document>
|
||||
);
|
||||
|
||||
// Generate the PDF and trigger download
|
||||
pdf(MyDocument)
|
||||
.toBlob()
|
||||
.then((blob) => {
|
||||
const link = document.createElement("a");
|
||||
link.href = URL.createObjectURL(blob);
|
||||
link.download = `MultipleBarcodes.pdf`;
|
||||
link.click();
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Button onClick={() => generatePDF()} color="primary">
|
||||
Export All Selected
|
||||
</Button>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -35,6 +35,7 @@ import { Route as logisticsOpenOrdersIndexImport } from './routes/(logistics)/op
|
||||
import { Route as logisticsMaterialHelperIndexImport } from './routes/(logistics)/materialHelper/index'
|
||||
import { Route as logisticsHelperCommandsIndexImport } from './routes/(logistics)/helperCommands/index'
|
||||
import { Route as logisticsDmIndexImport } from './routes/(logistics)/dm/index'
|
||||
import { Route as logisticsBarcodegenIndexImport } from './routes/(logistics)/barcodegen/index'
|
||||
import { Route as EomArticleAvImport } from './routes/_eom/article/$av'
|
||||
import { Route as logisticsSiloAdjustmentsHistImport } from './routes/(logistics)/siloAdjustments/$hist'
|
||||
import { Route as logisticsMaterialHelperSiloLinkIndexImport } from './routes/(logistics)/materialHelper/siloLink/index'
|
||||
@@ -187,6 +188,12 @@ const logisticsDmIndexRoute = logisticsDmIndexImport.update({
|
||||
getParentRoute: () => rootRoute,
|
||||
} as any)
|
||||
|
||||
const logisticsBarcodegenIndexRoute = logisticsBarcodegenIndexImport.update({
|
||||
id: '/(logistics)/barcodegen/',
|
||||
path: '/barcodegen/',
|
||||
getParentRoute: () => rootRoute,
|
||||
} as any)
|
||||
|
||||
const EomArticleAvRoute = EomArticleAvImport.update({
|
||||
id: '/article/$av',
|
||||
path: '/article/$av',
|
||||
@@ -365,6 +372,13 @@ declare module '@tanstack/react-router' {
|
||||
preLoaderRoute: typeof EomArticleAvImport
|
||||
parentRoute: typeof EomImport
|
||||
}
|
||||
'/(logistics)/barcodegen/': {
|
||||
id: '/(logistics)/barcodegen/'
|
||||
path: '/barcodegen'
|
||||
fullPath: '/barcodegen'
|
||||
preLoaderRoute: typeof logisticsBarcodegenIndexImport
|
||||
parentRoute: typeof rootRoute
|
||||
}
|
||||
'/(logistics)/dm/': {
|
||||
id: '/(logistics)/dm/'
|
||||
path: '/dm'
|
||||
@@ -494,6 +508,7 @@ export interface FileRoutesByFullPath {
|
||||
'/ocp': typeof OcpIndexRoute
|
||||
'/siloAdjustments/$hist': typeof logisticsSiloAdjustmentsHistRoute
|
||||
'/article/$av': typeof EomArticleAvRoute
|
||||
'/barcodegen': typeof logisticsBarcodegenIndexRoute
|
||||
'/dm': typeof logisticsDmIndexRoute
|
||||
'/helperCommands': typeof logisticsHelperCommandsIndexRoute
|
||||
'/materialHelper': typeof logisticsMaterialHelperIndexRoute
|
||||
@@ -524,6 +539,7 @@ export interface FileRoutesByTo {
|
||||
'/ocp': typeof OcpIndexRoute
|
||||
'/siloAdjustments/$hist': typeof logisticsSiloAdjustmentsHistRoute
|
||||
'/article/$av': typeof EomArticleAvRoute
|
||||
'/barcodegen': typeof logisticsBarcodegenIndexRoute
|
||||
'/dm': typeof logisticsDmIndexRoute
|
||||
'/helperCommands': typeof logisticsHelperCommandsIndexRoute
|
||||
'/materialHelper': typeof logisticsMaterialHelperIndexRoute
|
||||
@@ -557,6 +573,7 @@ export interface FileRoutesById {
|
||||
'/ocp/': typeof OcpIndexRoute
|
||||
'/(logistics)/siloAdjustments/$hist': typeof logisticsSiloAdjustmentsHistRoute
|
||||
'/_eom/article/$av': typeof EomArticleAvRoute
|
||||
'/(logistics)/barcodegen/': typeof logisticsBarcodegenIndexRoute
|
||||
'/(logistics)/dm/': typeof logisticsDmIndexRoute
|
||||
'/(logistics)/helperCommands/': typeof logisticsHelperCommandsIndexRoute
|
||||
'/(logistics)/materialHelper/': typeof logisticsMaterialHelperIndexRoute
|
||||
@@ -589,6 +606,7 @@ export interface FileRouteTypes {
|
||||
| '/ocp'
|
||||
| '/siloAdjustments/$hist'
|
||||
| '/article/$av'
|
||||
| '/barcodegen'
|
||||
| '/dm'
|
||||
| '/helperCommands'
|
||||
| '/materialHelper'
|
||||
@@ -618,6 +636,7 @@ export interface FileRouteTypes {
|
||||
| '/ocp'
|
||||
| '/siloAdjustments/$hist'
|
||||
| '/article/$av'
|
||||
| '/barcodegen'
|
||||
| '/dm'
|
||||
| '/helperCommands'
|
||||
| '/materialHelper'
|
||||
@@ -649,6 +668,7 @@ export interface FileRouteTypes {
|
||||
| '/ocp/'
|
||||
| '/(logistics)/siloAdjustments/$hist'
|
||||
| '/_eom/article/$av'
|
||||
| '/(logistics)/barcodegen/'
|
||||
| '/(logistics)/dm/'
|
||||
| '/(logistics)/helperCommands/'
|
||||
| '/(logistics)/materialHelper/'
|
||||
@@ -673,6 +693,7 @@ export interface RootRouteChildren {
|
||||
userPasswordChangeRoute: typeof userPasswordChangeRoute
|
||||
OcpIndexRoute: typeof OcpIndexRoute
|
||||
logisticsSiloAdjustmentsHistRoute: typeof logisticsSiloAdjustmentsHistRoute
|
||||
logisticsBarcodegenIndexRoute: typeof logisticsBarcodegenIndexRoute
|
||||
logisticsDmIndexRoute: typeof logisticsDmIndexRoute
|
||||
logisticsHelperCommandsIndexRoute: typeof logisticsHelperCommandsIndexRoute
|
||||
logisticsMaterialHelperIndexRoute: typeof logisticsMaterialHelperIndexRoute
|
||||
@@ -696,6 +717,7 @@ const rootRouteChildren: RootRouteChildren = {
|
||||
userPasswordChangeRoute: userPasswordChangeRoute,
|
||||
OcpIndexRoute: OcpIndexRoute,
|
||||
logisticsSiloAdjustmentsHistRoute: logisticsSiloAdjustmentsHistRoute,
|
||||
logisticsBarcodegenIndexRoute: logisticsBarcodegenIndexRoute,
|
||||
logisticsDmIndexRoute: logisticsDmIndexRoute,
|
||||
logisticsHelperCommandsIndexRoute: logisticsHelperCommandsIndexRoute,
|
||||
logisticsMaterialHelperIndexRoute: logisticsMaterialHelperIndexRoute,
|
||||
@@ -731,6 +753,7 @@ export const routeTree = rootRoute
|
||||
"/(user)/passwordChange",
|
||||
"/ocp/",
|
||||
"/(logistics)/siloAdjustments/$hist",
|
||||
"/(logistics)/barcodegen/",
|
||||
"/(logistics)/dm/",
|
||||
"/(logistics)/helperCommands/",
|
||||
"/(logistics)/materialHelper/",
|
||||
@@ -826,6 +849,9 @@ export const routeTree = rootRoute
|
||||
"filePath": "_eom/article/$av.tsx",
|
||||
"parent": "/_eom"
|
||||
},
|
||||
"/(logistics)/barcodegen/": {
|
||||
"filePath": "(logistics)/barcodegen/index.tsx"
|
||||
},
|
||||
"/(logistics)/dm/": {
|
||||
"filePath": "(logistics)/dm/index.tsx"
|
||||
},
|
||||
|
||||
14
frontend/src/routes/(logistics)/barcodegen/index.tsx
Normal file
14
frontend/src/routes/(logistics)/barcodegen/index.tsx
Normal file
@@ -0,0 +1,14 @@
|
||||
import BGPage from "@/components/logistics/barcodeGenerator/BGPage";
|
||||
import { createFileRoute } from "@tanstack/react-router";
|
||||
|
||||
export const Route = createFileRoute("/(logistics)/barcodegen/")({
|
||||
component: RouteComponent,
|
||||
});
|
||||
|
||||
function RouteComponent() {
|
||||
return (
|
||||
<div>
|
||||
<BGPage />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
20
frontend/src/utils/querys/logistics/getWarehouseLanes.tsx
Normal file
20
frontend/src/utils/querys/logistics/getWarehouseLanes.tsx
Normal file
@@ -0,0 +1,20 @@
|
||||
import { queryOptions } from "@tanstack/react-query";
|
||||
import axios from "axios";
|
||||
|
||||
export function getLanes() {
|
||||
return queryOptions({
|
||||
queryKey: ["getLanes"],
|
||||
queryFn: () => fetch(),
|
||||
//enabled:
|
||||
staleTime: 1000,
|
||||
refetchInterval: 60 * 1000,
|
||||
refetchOnWindowFocus: true,
|
||||
});
|
||||
}
|
||||
|
||||
const fetch = async () => {
|
||||
const { data } = await axios.get(`/api/logistics/getactivelanes`);
|
||||
// // if we are not localhost ignore the devDir setting.
|
||||
// //const url: string = window.location.host.split(":")[0];
|
||||
return data.data ?? [];
|
||||
};
|
||||
Reference in New Issue
Block a user