feat: barcode templates
This commit is contained in:
63
src/modals/PrintBarcodeModal/PrintBarcodeContainer.tsx
Normal file
63
src/modals/PrintBarcodeModal/PrintBarcodeContainer.tsx
Normal file
@@ -0,0 +1,63 @@
|
||||
import {BarcodeAttributeSchema} from "../../client";
|
||||
import {forwardRef} from "react";
|
||||
import styles from "./PrintBarcodeModal.module.css";
|
||||
import {Flex, Text} from "@mantine/core";
|
||||
import Barcode from "react-barcode";
|
||||
|
||||
type Props = {
|
||||
attributes: BarcodeAttributeSchema[]
|
||||
barcode?: string;
|
||||
quantity: number;
|
||||
}
|
||||
type Ref = HTMLDivElement;
|
||||
const PrintBarcodeContainer = forwardRef<Ref, Props>(function PrintBarcodeContainer(props: Props, ref) {
|
||||
const {attributes, barcode, quantity} = props;
|
||||
|
||||
const MAX_ATTRIBUTES = 6;
|
||||
const MIN_BARCODE_SIZE = 30;
|
||||
const MAX_BARCODE_SIZE = 100;
|
||||
const STEP = (MAX_BARCODE_SIZE - MIN_BARCODE_SIZE) / MAX_ATTRIBUTES;
|
||||
const MAX_ATTRIBUTE_LENGTH = 35;
|
||||
|
||||
const getBarcodeHeight = () => {
|
||||
return MIN_BARCODE_SIZE + (MAX_ATTRIBUTES - attributes.length) * STEP;
|
||||
}
|
||||
const getAttributeText = (attribute: BarcodeAttributeSchema) => {
|
||||
let result = `${attribute.name}: ${attribute.value}`;
|
||||
if (result.length > MAX_ATTRIBUTE_LENGTH) {
|
||||
result = result.slice(0, MAX_ATTRIBUTE_LENGTH - 1) + ".";
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={styles['print-only']} ref={ref}>
|
||||
{barcode && Array.from({length: quantity}).map((_, index) => (
|
||||
<>
|
||||
<Flex
|
||||
className={styles['barcode-container']}
|
||||
key={index}
|
||||
justify={"center"}
|
||||
direction={"column"}
|
||||
>
|
||||
<Flex align={"center"} justify={"center"}>
|
||||
<Barcode margin={0} height={getBarcodeHeight()} value={barcode}/>
|
||||
</Flex>
|
||||
{attributes.slice(0, MAX_ATTRIBUTES).map((attr) => (
|
||||
<Text
|
||||
key={attr.name}
|
||||
className={styles['barcode-attribute-text']}
|
||||
size={"xs"}
|
||||
>
|
||||
{getAttributeText(attr)}
|
||||
</Text>
|
||||
))}
|
||||
</Flex>
|
||||
</>
|
||||
))}
|
||||
</div>
|
||||
|
||||
)
|
||||
});
|
||||
|
||||
export default PrintBarcodeContainer;
|
||||
@@ -6,4 +6,16 @@
|
||||
.print-only {
|
||||
display: block;
|
||||
}
|
||||
|
||||
|
||||
.barcode-container {
|
||||
text-align: left;
|
||||
margin: 1.25mm;
|
||||
padding: 1.25mm;
|
||||
background-color: white;
|
||||
}
|
||||
|
||||
.barcode-attribute-text {
|
||||
line-height: 1;
|
||||
}
|
||||
}
|
||||
@@ -1,12 +1,11 @@
|
||||
import {ContextModalProps, modals} from "@mantine/modals";
|
||||
import {Button, Divider, Flex, NumberInput, rem, Select, Spoiler} from "@mantine/core";
|
||||
import Barcode from "react-barcode";
|
||||
import {Button, Divider, Flex, NumberInput, rem, Select} from "@mantine/core";
|
||||
import {useEffect, useRef, useState} from "react";
|
||||
import {useReactToPrint} from "react-to-print";
|
||||
import {ProductService} from "../../client";
|
||||
import styles from "./PrintBarcodeModal.module.css";
|
||||
import {BarcodeSchema, ProductService} from "../../client";
|
||||
import {useGetProductById} from "../../api/product/useGetProductById.tsx";
|
||||
import {notifications} from "../../shared/lib/notifications.ts";
|
||||
import PrintBarcodeContainer from "./PrintBarcodeContainer.tsx";
|
||||
|
||||
type Props = {
|
||||
productId: number;
|
||||
@@ -18,6 +17,7 @@ const PrintBarcodeModal = ({
|
||||
const {productId, defaultQuantity = 1} = innerProps;
|
||||
const [quantity, setQuantity] = useState(defaultQuantity);
|
||||
const [barcode, setBarcode] = useState<string | undefined>()
|
||||
const [barcodeData, setBarcodeData] = useState<BarcodeSchema | undefined>();
|
||||
|
||||
const {product, refetch} = useGetProductById(productId);
|
||||
|
||||
@@ -55,11 +55,26 @@ const PrintBarcodeModal = ({
|
||||
setBarcode(barcode);
|
||||
})
|
||||
}
|
||||
const fetchBarcodeData = () => {
|
||||
if (!barcode) return;
|
||||
ProductService.getProductBarcode({
|
||||
requestBody:
|
||||
{barcode, productId}
|
||||
}).then(({barcode}) => {
|
||||
setBarcodeData(barcode);
|
||||
})
|
||||
}
|
||||
useEffect(() => {
|
||||
if (!product) return;
|
||||
if (product.barcodes.length === 1)
|
||||
setBarcode(product.barcodes[0]);
|
||||
}, [product]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!barcode) return;
|
||||
fetchBarcodeData();
|
||||
}, [barcode]);
|
||||
|
||||
return (
|
||||
<>
|
||||
<Flex
|
||||
@@ -80,21 +95,7 @@ const PrintBarcodeModal = ({
|
||||
onChange={(value) => typeof value === "number" && setQuantity(value)}
|
||||
min={1}
|
||||
/>
|
||||
<Spoiler
|
||||
w={"100%"}
|
||||
style={{
|
||||
textAlign: "center",
|
||||
}}
|
||||
styles={{control: {width: "100%"}}}
|
||||
showLabel={"Показать предпросмотр"}
|
||||
hideLabel={"Скрыть предпросмотр"}
|
||||
maxHeight={0}>
|
||||
<div>
|
||||
{barcode &&
|
||||
<Barcode value={barcode}/>
|
||||
}
|
||||
</div>
|
||||
</Spoiler>
|
||||
|
||||
<Divider
|
||||
my={rem(10)}
|
||||
/>
|
||||
@@ -120,11 +121,13 @@ const PrintBarcodeModal = ({
|
||||
>Печать</Button>
|
||||
</Flex>
|
||||
</Flex>
|
||||
<div className={styles['print-only']} ref={barcodeRef}>
|
||||
{barcode && Array.from({length: quantity}).map((_, index) => (
|
||||
<Barcode key={index} value={barcode}/>
|
||||
))}
|
||||
</div>
|
||||
<PrintBarcodeContainer
|
||||
barcode={barcode}
|
||||
quantity={quantity}
|
||||
ref={barcodeRef}
|
||||
attributes={barcodeData?.attributes || []}
|
||||
|
||||
/>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user