diff --git a/client/package-lock.json b/client/package-lock.json index 6f599ba..51b1ed3 100644 --- a/client/package-lock.json +++ b/client/package-lock.json @@ -18,6 +18,7 @@ "@tanstack/react-query": "^4.36.1", "@tanstack/react-query-devtools": "^4.36.1", "@types/loadable__component": "^5.13.9", + "@types/uuid": "^9.0.8", "@yudiel/react-qr-scanner": "^1.2.10", "antd": "^5.12.2", "axios": "^1.6.8", @@ -30,6 +31,7 @@ "react-i18next": "^14.1.1", "react-router-dom": "^6.23.0", "react-to-print": "^2.15.1", + "uuid": "^10.0.0", "vite-plugin-svgr": "^4.2.0" }, "devDependencies": { @@ -2932,6 +2934,11 @@ "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.10.tgz", "integrity": "sha512-IfYcSBWE3hLpBg8+X2SEa8LVkJdJEkT2Ese2aaLs3ptGdVtABxndrMaxuFlQ1qdFf9Q5rDvDpxI3WwgvKFAsQA==" }, + "node_modules/@types/uuid": { + "version": "9.0.8", + "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-9.0.8.tgz", + "integrity": "sha512-jg+97EGIcY9AGHJJRaaPVgetKDsrTgbRjQ5Msgjh/DQKEFl0DtyRr/VCOyD1T2R1MNeWPK/u7JoGhlDZnKBAfA==" + }, "node_modules/@typescript-eslint/eslint-plugin": { "version": "7.8.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.8.0.tgz", @@ -9554,6 +9561,18 @@ "node": ">= 0.4.0" } }, + "node_modules/uuid": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-10.0.0.tgz", + "integrity": "sha512-8XkAphELsDnEGrDxUOHB3RGvXz6TeuYSGEZBOjtTtPm2lwhGBjLgOzLHB63IUWfBpNucQjND6d3AOudO+H3RWQ==", + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "bin": { + "uuid": "dist/bin/uuid" + } + }, "node_modules/vary": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", diff --git a/client/package.json b/client/package.json index 6fda8ec..cc4c73e 100644 --- a/client/package.json +++ b/client/package.json @@ -7,7 +7,6 @@ "private": true, "type": "module", "dependencies": { - "axios": "^1.6.8", "@ant-design/icons": "^5.3.7", "@loadable/component": "^5.16.4", "@refinedev/antd": "^5.37.0", @@ -18,8 +17,10 @@ "@tanstack/react-query": "^4.36.1", "@tanstack/react-query-devtools": "^4.36.1", "@types/loadable__component": "^5.13.9", + "@types/uuid": "^9.0.8", "@yudiel/react-qr-scanner": "^1.2.10", "antd": "^5.12.2", + "axios": "^1.6.8", "flag-icons": "^7.2.1", "i18next": "^23.11.4", "i18next-browser-languagedetector": "^7.2.1", @@ -29,6 +30,7 @@ "react-i18next": "^14.1.1", "react-router-dom": "^6.23.0", "react-to-print": "^2.15.1", + "uuid": "^10.0.0", "vite-plugin-svgr": "^4.2.0" }, "devDependencies": { @@ -65,4 +67,4 @@ "last 1 safari version" ] } -} \ No newline at end of file +} diff --git a/client/public/locales/en/common.json b/client/public/locales/en/common.json index 9159501..c705113 100644 --- a/client/public/locales/en/common.json +++ b/client/public/locales/en/common.json @@ -89,7 +89,14 @@ "none": "None", "border": "Border", "grid": "Grid" - } + }, + "settings": "Settings", + "defaultSettings": "Default", + "addSettings": "Add New Setting", + "newSetting": "New", + "deleteSettings": "Delete Current Setting", + "deleteSettingsConfirm": "Are you sure you want to delete this setting?", + "settingsName": "Setting Name" }, "qrcode": { "button": "Print QR Codes", diff --git a/client/src/components/printing/printing.ts b/client/src/components/printing/printing.ts index 52c8e8b..9b1547b 100644 --- a/client/src/components/printing/printing.ts +++ b/client/src/components/printing/printing.ts @@ -1,6 +1,8 @@ import { useGetSetting, useSetSetting } from "../../utils/querySettings"; +import { v4 as uuidv4 } from "uuid"; export interface PrintSettings { + id: string; name?: string; margin?: { top: number; bottom: number; left: number; right: number }; printerMargin?: { top: number; bottom: number; left: number; right: number }; @@ -32,21 +34,18 @@ export interface SpoolQRCodePrintSettings { labelSettings: QRCodePrintSettings; } -function defaultSpoolQRCodePrintSettings(): SpoolQRCodePrintSettings { - return { - labelSettings: { - printSettings: {}, - }, - }; -} - -export function useGetPrintSettings(): SpoolQRCodePrintSettings[] { +export function useGetPrintSettings(): SpoolQRCodePrintSettings[] | undefined { const { data } = useGetSetting("print_settings"); - const parsed = data && data.value ? JSON.parse(data.value) : ([] as SpoolQRCodePrintSettings[]); - if (parsed.length === 0) { - parsed.push(defaultSpoolQRCodePrintSettings()); - } - return parsed; + if (!data) return; + const parsed: SpoolQRCodePrintSettings[] = + data && data.value ? JSON.parse(data.value) : ([] as SpoolQRCodePrintSettings[]); + // Loop through all parsed and generate a new ID field if it's not set + return parsed.map((settings) => { + if (!settings.labelSettings.printSettings.id) { + settings.labelSettings.printSettings.id = uuidv4(); + } + return settings; + }); } export function useSetPrintSettings(): (spoolQRCodePrintSettings: SpoolQRCodePrintSettings[]) => void { diff --git a/client/src/components/printing/printingDialog.tsx b/client/src/components/printing/printingDialog.tsx index 01581ba..44ea19b 100644 --- a/client/src/components/printing/printingDialog.tsx +++ b/client/src/components/printing/printingDialog.tsx @@ -24,6 +24,7 @@ interface PrintingDialogProps { setPrintSettings: (setPrintSettings: PrintSettings) => void; style?: string; extraSettings?: JSX.Element; + extraSettingsStart?: JSX.Element; visible: boolean; onCancel: () => void; title?: string; @@ -67,6 +68,7 @@ const PrintingDialog: React.FC = ({ setPrintSettings, style, extraSettings, + extraSettingsStart, visible, onCancel, title, @@ -195,16 +197,8 @@ const PrintingDialog: React.FC = ({ width={1200} // Set the modal width to accommodate the preview > - - {t("printing.generic.description")} - + {t("printing.generic.description")}
= ({
+ {extraSettingsStart} + diff --git a/client/src/components/printing/qrCodePrintingDialog.tsx b/client/src/components/printing/qrCodePrintingDialog.tsx index fd2a47f..57f36bc 100644 --- a/client/src/components/printing/qrCodePrintingDialog.tsx +++ b/client/src/components/printing/qrCodePrintingDialog.tsx @@ -17,6 +17,7 @@ interface QRCodePrintingDialogProps { setPrintSettings: (setPrintSettings: QRCodePrintSettings) => void; onCancel: () => void; extraSettings?: JSX.Element; + extraSettingsStart?: JSX.Element; } const QRCodePrintingDialog: React.FC = ({ @@ -26,6 +27,7 @@ const QRCodePrintingDialog: React.FC = ({ setPrintSettings, onCancel, extraSettings, + extraSettingsStart, }) => { const t = useTranslate(); @@ -61,6 +63,7 @@ const QRCodePrintingDialog: React.FC = ({ printSettings.printSettings = newSettings; setPrintSettings(printSettings); }} + extraSettingsStart={extraSettingsStart} extraSettings={ <> diff --git a/client/src/components/printing/spoolQrCodePrintingDialog.tsx b/client/src/components/printing/spoolQrCodePrintingDialog.tsx index b2720c8..20cda7c 100644 --- a/client/src/components/printing/spoolQrCodePrintingDialog.tsx +++ b/client/src/components/printing/spoolQrCodePrintingDialog.tsx @@ -1,10 +1,14 @@ -import { Form, Switch } from "antd"; +import { Button, Flex, Form, Input, Modal, Popconfirm, Select, Space, Switch } from "antd"; import { IFilament } from "../../pages/filaments/model"; import { ISpool } from "../../pages/spools/model"; import QRCodePrintingDialog from "./qrCodePrintingDialog"; import { useSavedState } from "../../utils/saveload"; import { useTranslate } from "@refinedev/core"; -import { useGetPrintSettings, useSetPrintSettings } from "./printing"; +import { QRCodePrintSettings, SpoolQRCodePrintSettings, useGetPrintSettings, useSetPrintSettings } from "./printing"; +import { useState } from "react"; +import { DeleteOutlined, EditOutlined, PlusOutlined } from "@ant-design/icons"; +import { v4 as uuidv4 } from "uuid"; +import _ from "lodash"; interface SpoolQRCodePrintingDialog { visible: boolean; @@ -14,16 +18,105 @@ interface SpoolQRCodePrintingDialog { const SpoolQRCodePrintingDialog: React.FC = ({ visible, items, onCancel }) => { const t = useTranslate(); - const printSettings = useGetPrintSettings()[0]; + + // Selected setting state + const [selectedSetting, setSelectedSetting] = useState(); + + const allPrintSettings = useGetPrintSettings(); const setPrintSettings = useSetPrintSettings(); - const showVendor = printSettings?.showVendor; - const showLotNr = printSettings?.showLotNr; - const showSpoolWeight = printSettings?.showSpoolWeight; - const showTemperatures = printSettings?.showTemperatures; - const showSpoolComment = printSettings?.showSpoolComment; - const showFilamentComment = printSettings?.showFilamentComment; - const showVendorComment = printSettings?.showVendorComment; + // Functions to update settings + const addNewPrintSettings = () => { + if (!allPrintSettings) return; + const newId = uuidv4(); + const newSetting = { + labelSettings: { + printSettings: { + id: newId, + name: t("printing.generic.newSetting"), + }, + }, + }; + setPrintSettings([...allPrintSettings, newSetting]); + setSelectedSetting(newId); + return newSetting; + }; + const updateCurrentPrintSettings = (newSettings: SpoolQRCodePrintSettings) => { + if (!allPrintSettings) return; + setPrintSettings( + allPrintSettings.map((settings) => + settings.labelSettings.printSettings.id === newSettings.labelSettings.printSettings.id ? newSettings : settings + ) + ); + }; + const deleteCurrentPrintSettings = () => { + if (!allPrintSettings) return; + setPrintSettings( + allPrintSettings.filter((qSetting) => qSetting.labelSettings.printSettings.id !== selectedSetting) + ); + setSelectedSetting(undefined); + }; + + // Initialize settings + let selectedPrintSetting: SpoolQRCodePrintSettings; + if (allPrintSettings === undefined) { + // DB not loaded yet, use a temporary one + selectedPrintSetting = { + labelSettings: { + printSettings: { + id: "TEMP", + name: t("printing.generic.newSetting"), + }, + }, + }; + } else { + // DB is loaded, find the selected setting + if (allPrintSettings.length === 0) { + // DB loaded, but no settings found, add a new one and select it + const newSetting = addNewPrintSettings(); + if (!newSetting) { + console.error("Error adding new setting, this should never happen"); + return; + } + + // Mutate the allPrintSettings list so that the rest of the UI will work fine + allPrintSettings.push(newSetting); + selectedPrintSetting = newSetting; + } else { + // DB loaded and at least 1 setting exists + if (!selectedSetting) { + // No setting has been selected, select the first one + selectedPrintSetting = allPrintSettings[0]; + setSelectedSetting(allPrintSettings[0].labelSettings.printSettings.id); + } else { + // A setting has been selected, find it + const foundSetting = allPrintSettings.find( + (settings) => settings.labelSettings.printSettings.id === selectedSetting + ); + if (foundSetting) { + selectedPrintSetting = foundSetting; + } else { + // Selected setting not found, select a temp one + selectedPrintSetting = { + labelSettings: { + printSettings: { + id: "TEMP", + name: t("printing.generic.newSetting"), + }, + }, + }; + } + } + } + } + + const showVendor = selectedPrintSetting?.showVendor; + const showLotNr = selectedPrintSetting?.showLotNr; + const showSpoolWeight = selectedPrintSetting?.showSpoolWeight; + const showTemperatures = selectedPrintSetting?.showTemperatures; + const showSpoolComment = selectedPrintSetting?.showSpoolComment; + const showFilamentComment = selectedPrintSetting?.showFilamentComment; + const showVendorComment = selectedPrintSetting?.showVendorComment; const formatFilament = (filament: IFilament) => { let vendorPrefix = ""; @@ -41,11 +134,63 @@ const SpoolQRCodePrintingDialog: React.FC = ({ visibl { - printSettings.labelSettings = newSettings; - setPrintSettings([printSettings]); + selectedPrintSetting.labelSettings = newSettings; + updateCurrentPrintSettings(selectedPrintSetting); }} + extraSettingsStart={ + <> + + + +