Label printing page updates

No longer a modal
Use flex divs instead of a table
This commit is contained in:
Donkie
2024-08-04 23:23:13 +02:00
parent 9aa9479a14
commit 9318ef5c19
9 changed files with 154 additions and 173 deletions

View File

@@ -192,6 +192,7 @@ function App() {
/>
<Route path="edit/:id" element={<LoadableResourcePage resource="spools" page="edit" />} />
<Route path="show/:id" element={<LoadableResourcePage resource="spools" page="show" />} />
<Route path="print" element={<LoadablePage name="printing" />} />
</Route>
<Route path="/filament">
<Route index element={<LoadableResourcePage resource="filaments" page="list" />} />

View File

@@ -1,50 +0,0 @@
// React FC that combines the functionality of first selecting what spools to print QR code for, and then opens up the QR code printing dialog.
import React from "react";
import SpoolSelectModal from "./spoolSelectModal";
import { Button } from "antd";
import { ISpool } from "../pages/spools/model";
import { PrinterOutlined } from "@ant-design/icons";
import { useTranslate } from "@refinedev/core";
import SpoolQRCodePrintingDialog from "./printing/spoolQrCodePrintingDialog";
const SelectAndPrint: React.FC = () => {
const t = useTranslate();
const [step, setStep] = React.useState(0);
const [selectedSpools, setSelectedSpools] = React.useState<ISpool[]>([]);
return (
<>
<Button
type="primary"
icon={<PrinterOutlined />}
onClick={() => {
setStep(1);
}}
>
{t("printing.qrcode.button")}
</Button>
<SpoolSelectModal
visible={step === 1}
description={t("printing.spoolSelect.description")}
onCancel={() => {
setStep(0);
}}
onContinue={(spools) => {
setSelectedSpools(spools);
setStep(2);
}}
/>
<SpoolQRCodePrintingDialog
visible={step === 2}
onCancel={() => {
setStep(0);
}}
items={selectedSpools}
/>
</>
);
};
export default SelectAndPrint;

View File

@@ -0,0 +1,50 @@
import React from "react";
import { IResourceComponentsProps, useTranslate } from "@refinedev/core";
import dayjs from "dayjs";
import utc from "dayjs/plugin/utc";
import { Content } from "antd/es/layout/layout";
import { theme } from "antd";
import SpoolQRCodePrintingDialog from "./spoolQrCodePrintingDialog";
import SpoolSelectModal from "./spoolSelectModal";
import { ISpool } from "../spools/model";
dayjs.extend(utc);
const { useToken } = theme;
export const Printing: React.FC<IResourceComponentsProps> = () => {
const { token } = useToken();
const t = useTranslate();
const [step, setStep] = React.useState<0 | 1>(0);
const [selectedSpools, setSelectedSpools] = React.useState<ISpool[]>([]);
return (
<Content
style={{
padding: 20,
minHeight: 280,
margin: "0 auto",
backgroundColor: token.colorBgContainer,
borderRadius: token.borderRadiusLG,
color: token.colorText,
fontFamily: token.fontFamily,
fontSize: token.fontSizeLG,
lineHeight: 1.5,
}}
>
{step === 0 && (
<SpoolSelectModal
description={t("printing.spoolSelect.description")}
onContinue={(spools) => {
setSelectedSpools(spools);
setStep(1);
}}
/>
)}
{step === 1 && <SpoolQRCodePrintingDialog items={selectedSpools} />}
</Content>
);
};
export default Printing;

View File

@@ -1,5 +1,5 @@
import React, { ReactNode } from "react";
import { ISpool } from "../../pages/spools/model";
import { ISpool } from "../spools/model";
import { useGetSetting, useSetSetting } from "../../utils/querySettings";
import { v4 as uuidv4 } from "uuid";

View File

@@ -25,9 +25,6 @@ interface PrintingDialogProps {
style?: string;
extraSettings?: JSX.Element;
extraSettingsStart?: JSX.Element;
visible: boolean;
onCancel: () => void;
title?: string;
}
interface PaperDimensions {
@@ -69,9 +66,6 @@ const PrintingDialog: React.FC<PrintingDialogProps> = ({
style,
extraSettings,
extraSettingsStart,
visible,
onCancel,
title,
}) => {
const t = useTranslate();
@@ -98,7 +92,7 @@ const PrintingDialog: React.FC<PrintingDialogProps> = ({
const itemHeight = (paperHeight - margin.top - margin.bottom - spacing.vertical) / paperRows - spacing.vertical;
const itemsPerRow = paperColumns;
const rowsPerPage = paperRows;
const itemsPerPage = itemsPerRow * paperRows;
const itemsIncludingSkipped = [...Array(skipItems).fill(<></>)];
for (const item of items) {
@@ -107,42 +101,33 @@ const PrintingDialog: React.FC<PrintingDialogProps> = ({
}
}
const rowsOfItems = [];
for (let row_idx = 0; row_idx < itemsIncludingSkipped.length / itemsPerRow; row_idx += 1) {
rowsOfItems.push(itemsIncludingSkipped.slice(row_idx * itemsPerRow, (row_idx + 1) * itemsPerRow));
}
const pageBlocks = [];
for (let page_idx = 0; page_idx < rowsOfItems.length / rowsPerPage; page_idx += 1) {
pageBlocks.push(rowsOfItems.slice(page_idx * rowsPerPage, (page_idx + 1) * rowsPerPage));
for (let page_idx = 0; page_idx < itemsIncludingSkipped.length / itemsPerPage; page_idx += 1) {
pageBlocks.push(itemsIncludingSkipped.slice(page_idx * itemsPerPage, (page_idx + 1) * itemsPerPage));
}
const pages = pageBlocks.map(function (rows, pageIdx) {
const itemRows = rows.map((row, rowIdx) => {
const pages = pageBlocks.map(function (items, pageIdx) {
const itemDivs = items.map((item, itemIdx) => {
const isFirstColumn = itemIdx % itemsPerRow === 0;
const isLastColumn = (itemIdx + 1) % itemsPerRow === 0;
const isFirstRow = itemIdx < itemsPerRow;
const isLastRow = itemsPerPage - itemIdx <= itemsPerRow;
return (
<tr key={rowIdx}>
{row.map(function (item, colIdx) {
return (
<td key={colIdx}>
<div
key={itemIdx}
style={{
width: `${itemWidth}mm`,
height: `${itemHeight}mm`,
border: borderShowMode === "grid" ? "1px solid #000" : "none",
paddingLeft: colIdx === 0 ? `${Math.max(printerMargin.left - margin.left, 0)}mm` : 0,
paddingRight:
colIdx === paperColumns - 1 ? `${Math.max(printerMargin.right - margin.right, 0)}mm` : 0,
paddingTop: rowIdx === 0 ? `${Math.max(printerMargin.top - margin.top, 0)}mm` : 0,
paddingBottom:
rowIdx === paperRows - 1 ? `${Math.max(printerMargin.bottom - margin.bottom, 0)}mm` : 0,
paddingLeft: isFirstColumn ? `${Math.max(printerMargin.left - margin.left, 0)}mm` : 0,
paddingRight: isLastColumn ? `${Math.max(printerMargin.right - margin.right, 0)}mm` : 0,
paddingTop: isFirstRow ? `${Math.max(printerMargin.top - margin.top, 0)}mm` : 0,
paddingBottom: isLastRow ? `${Math.max(printerMargin.bottom - margin.bottom, 0)}mm` : 0,
}}
>
{item}
</div>
</td>
);
})}
</tr>
);
});
@@ -160,7 +145,8 @@ const PrintingDialog: React.FC<PrintingDialogProps> = ({
<div
className="print-page-area"
style={{
border: borderShowMode !== "none" ? "1px solid #000" : "none",
outline: borderShowMode !== "none" ? "1px solid #000" : "none",
outlineOffset: "-1px",
height: `${paperHeight - margin.top - margin.bottom}mm`,
width: `${paperWidth - margin.left - margin.right}mm`,
marginTop: `calc(${margin.top}mm - ${borderShowMode !== "none" ? "1px" : "0px"})`,
@@ -169,35 +155,27 @@ const PrintingDialog: React.FC<PrintingDialogProps> = ({
marginBottom: `calc(${margin.bottom}mm - ${borderShowMode !== "none" ? "1px" : "0px"})`,
}}
>
<table
<div
style={{
alignContent: "flex-start",
display: "flex",
flexWrap: "wrap",
rowGap: `${spacing.vertical}mm`,
columnGap: `${spacing.horizontal}mm`,
paddingTop: `${spacing.vertical}mm`,
paddingLeft: `${spacing.horizontal}mm`,
}}
>
{itemRows}
</table>
{itemDivs}
</div>
</div>
</div>
);
});
return (
<Modal
open={visible}
title={title ?? t("printing.generic.title")}
onCancel={onCancel}
footer={[
<ReactToPrint
key="print-button"
trigger={() => <Button type="primary">{t("printing.generic.print")}</Button>}
content={() => printRef.current}
/>,
]}
width={1200} // Set the modal width to accommodate the preview
>
<>
<Row gutter={16}>
<Col span={14}>
{t("printing.generic.description")}
<div
style={{
transform: "translateZ(0)",
@@ -211,12 +189,17 @@ const PrintingDialog: React.FC<PrintingDialogProps> = ({
style={{
transform: `scale(${previewScale})`,
transformOrigin: "top left",
display: "block",
}}
>
<style>
{`
@media print {
html, body {
height: initial !important;
overflow: initial !important;
-webkit-print-color-adjust: exact;
}
@page {
size: auto;
margin: 0;
@@ -235,14 +218,15 @@ const PrintingDialog: React.FC<PrintingDialogProps> = ({
}
}
.print-page table {
border-spacing: ${spacing.horizontal}mm ${spacing.vertical}mm;
border-collapse: separate;
.print-page {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, 'Noto Sans', sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji';
line-height: 1.2;
}
.print-page td {
padding: 0;
.print-page * {
box-sizing: border-box;
}
${style ?? ""}
`}
</style>
@@ -367,6 +351,8 @@ const PrintingDialog: React.FC<PrintingDialogProps> = ({
{extraSettings}
</Collapse.Panel>
<Collapse.Panel header={t("printing.generic.layoutSettings")} key="2">
{t("printing.generic.description")}
<Divider />
<Form.Item label={t("printing.generic.paperSize")}>
<Select
value={paperSize}
@@ -786,7 +772,16 @@ const PrintingDialog: React.FC<PrintingDialogProps> = ({
</Form>
</Col>
</Row>
</Modal>
<Row justify={"end"}>
<Col>
<ReactToPrint
key="print-button"
trigger={() => <Button type="primary">{t("printing.generic.print")}</Button>}
content={() => printRef.current}
/>
</Col>
</Row>
</>
);
};

View File

@@ -11,28 +11,24 @@ interface QRCodeData {
}
interface QRCodePrintingDialogProps {
visible: boolean;
items: QRCodeData[];
printSettings: QRCodePrintSettings;
setPrintSettings: (setPrintSettings: QRCodePrintSettings) => void;
onCancel: () => void;
extraSettings?: JSX.Element;
extraSettingsStart?: JSX.Element;
}
const QRCodePrintingDialog: React.FC<QRCodePrintingDialogProps> = ({
visible,
items,
printSettings,
setPrintSettings,
onCancel,
extraSettings,
extraSettingsStart,
}) => {
const t = useTranslate();
const showContent = printSettings?.showContent === undefined ? true : printSettings?.showContent;
const textSize = printSettings?.textSize || 5;
const textSize = printSettings?.textSize || 3;
const showSpoolmanIcon = printSettings?.showSpoolmanIcon === undefined ? true : printSettings?.showSpoolmanIcon;
const elements = items.map((item) => {
@@ -55,8 +51,6 @@ const QRCodePrintingDialog: React.FC<QRCodePrintingDialogProps> = ({
return (
<PrintingDialog
visible={visible}
title={t("printing.qrcode.title")}
items={elements}
printSettings={printSettings.printSettings}
setPrintSettings={(newSettings) => {
@@ -123,7 +117,7 @@ const QRCodePrintingDialog: React.FC<QRCodePrintingDialogProps> = ({
.print-page .print-qrcode-item {
display: flex;
width: 100%;
max-height: 100%;
height: 100%;
justify-content: center;
}
@@ -135,6 +129,7 @@ const QRCodePrintingDialog: React.FC<QRCodePrintingDialogProps> = ({
.print-page .print-qrcode {
width: auto !important;
height: auto !important;
padding: 2mm;
}
.print-page .print-qrcode-title {
@@ -153,7 +148,6 @@ const QRCodePrintingDialog: React.FC<QRCodePrintingDialogProps> = ({
max-width: 100%;
}
`}
onCancel={onCancel}
/>
);
};

View File

@@ -1,6 +1,6 @@
import { Button, Flex, Form, Input, Modal, Popconfirm, Select, Space, Switch, Table, Typography } from "antd";
import { IFilament } from "../../pages/filaments/model";
import { ISpool } from "../../pages/spools/model";
import { IFilament } from "../filaments/model";
import { ISpool } from "../spools/model";
import QRCodePrintingDialog from "./qrCodePrintingDialog";
import { useSavedState } from "../../utils/saveload";
import { useTranslate } from "@refinedev/core";
@@ -21,12 +21,10 @@ import { EntityType, useGetFields } from "../../utils/queryFields";
const { Text } = Typography;
interface SpoolQRCodePrintingDialog {
visible: boolean;
items: ISpool[];
onCancel: () => void;
}
const SpoolQRCodePrintingDialog: React.FC<SpoolQRCodePrintingDialog> = ({ visible, items, onCancel }) => {
const SpoolQRCodePrintingDialog: React.FC<SpoolQRCodePrintingDialog> = ({ items }) => {
const t = useTranslate();
// Selected setting state
@@ -210,8 +208,6 @@ Lot Nr: {lot_nr}
return (
<QRCodePrintingDialog
visible={visible}
onCancel={onCancel}
printSettings={selectedPrintSetting.labelSettings}
setPrintSettings={(newSettings) => {
selectedPrintSetting.labelSettings = newSettings;
@@ -276,6 +272,7 @@ Lot Nr: {lot_nr}
<p
style={{
padding: "1mm 1mm 1mm 0",
margin: 0,
whiteSpace: "pre-wrap",
}}
>

View File

@@ -1,18 +1,16 @@
import React, { useState } from "react";
import { Modal, Table, Checkbox, Space, Row, Col, message } from "antd";
import { ISpool } from "../pages/spools/model";
import { FilteredQueryColumn, SortedColumn, SpoolIconColumn } from "./column";
import { TableState } from "../utils/saveload";
import { Modal, Table, Checkbox, Space, Row, Col, message, Button } from "antd";
import { ISpool } from "../spools/model";
import { FilteredQueryColumn, SortedColumn, SpoolIconColumn } from "../../components/column";
import { TableState } from "../../utils/saveload";
import { useTable } from "@refinedev/antd";
import { t } from "i18next";
import { useSpoolmanFilamentFilter, useSpoolmanMaterials } from "./otherModels";
import { removeUndefined } from "../utils/filtering";
import { useSpoolmanFilamentFilter, useSpoolmanMaterials } from "../../components/otherModels";
import { removeUndefined } from "../../utils/filtering";
import { useNavigate } from "react-router-dom";
interface Props {
visible: boolean;
description?: string;
onCancel: () => void;
onContinue: (selectedSpools: ISpool[]) => void;
}
@@ -37,13 +35,14 @@ function collapseSpool(element: ISpool): ISpoolCollapsed {
};
}
const SpoolSelectModal: React.FC<Props> = ({ visible, description, onCancel, onContinue }) => {
const SpoolSelectModal: React.FC<Props> = ({ description, onContinue }) => {
const [selectedItems, setSelectedItems] = useState<number[]>([]);
const [showArchived, setShowArchived] = useState(false);
const [messageApi, contextHolder] = message.useMessage();
const navigate = useNavigate();
const { tableProps, sorters, filters, current, pageSize } = useTable<ISpoolCollapsed>({
resource: "spool",
meta: {
queryParams: {
["allow_archived"]: showArchived,
@@ -116,22 +115,7 @@ const SpoolSelectModal: React.FC<Props> = ({ visible, description, onCancel, onC
};
return (
<Modal
title={t("printing.spoolSelect.title")}
open={visible}
onCancel={onCancel}
onOk={() => {
if (selectedItems.length === 0) {
messageApi.open({
type: "error",
content: t("printing.spoolSelect.noSpoolsSelected"),
});
return;
}
onContinue(dataSource.filter((spool) => selectedItems.includes(spool.id)));
}}
width={600}
>
<>
{contextHolder}
<Space direction="vertical" style={{ width: "100%" }}>
{description && <div>{description}</div>}
@@ -210,7 +194,19 @@ const SpoolSelectModal: React.FC<Props> = ({ visible, description, onCancel, onC
</Col>
</Row>
</Space>
</Modal>
<Button
onClick={() => {
if (selectedItems.length === 0) {
messageApi.open({
type: "error",
content: t("printing.spoolSelect.noSpoolsSelected"),
});
return;
}
onContinue(dataSource.filter((spool) => selectedItems.includes(spool.id)));
}}
></Button>
</>
);
};

View File

@@ -26,7 +26,6 @@ import {
CustomFieldColumn,
} from "../../components/column";
import { setSpoolArchived } from "./functions";
import SelectAndPrint from "../../components/selectAndPrintDialog";
import {
useSpoolmanFilamentFilter,
useSpoolmanLocations,
@@ -254,7 +253,6 @@ export const SpoolList: React.FC<IResourceComponentsProps> = () => {
<List
headerButtons={({ defaultButtons }) => (
<>
<SelectAndPrint />
<Button
type="primary"
icon={<InboxOutlined />}