From 6608e183a1bcc6df431d29c8ea679f41e27076e8 Mon Sep 17 00:00:00 2001 From: gjulivan Date: Fri, 10 Apr 2026 15:25:22 +0200 Subject: [PATCH] fix: code cleanup --- .../src/components/Barcode.tsx | 2 +- .../src/components/QRCode.tsx | 2 +- .../src/config/Barcode.config.ts | 31 ++--------- .../src/utils/download-code.ts | 24 ++++++--- .../src/utils/download-utils.ts | 53 +++++++++++++++++-- 5 files changed, 71 insertions(+), 41 deletions(-) diff --git a/packages/pluggableWidgets/barcode-generator-web/src/components/Barcode.tsx b/packages/pluggableWidgets/barcode-generator-web/src/components/Barcode.tsx index 8f29af1214..77cd3450fe 100644 --- a/packages/pluggableWidgets/barcode-generator-web/src/components/Barcode.tsx +++ b/packages/pluggableWidgets/barcode-generator-web/src/components/Barcode.tsx @@ -28,7 +28,7 @@ export function BarcodeRenderer({ config }: BarcodeRendererProps): ReactElement const button = downloadButton && ( downloadCode(ref, config.type, downloadButton.fileName)} + onClick={() => downloadCode(ref, config, downloadButton.fileName)} ariaLabel={downloadButton.label} caption={downloadButton.caption} /> diff --git a/packages/pluggableWidgets/barcode-generator-web/src/components/QRCode.tsx b/packages/pluggableWidgets/barcode-generator-web/src/components/QRCode.tsx index d07f7b7bc4..8131bab42a 100644 --- a/packages/pluggableWidgets/barcode-generator-web/src/components/QRCode.tsx +++ b/packages/pluggableWidgets/barcode-generator-web/src/components/QRCode.tsx @@ -39,7 +39,7 @@ export function QRCodeRenderer({ config }: QRCodeRendererProps): ReactElement { const button = downloadButton && ( downloadCode(ref, config.type, downloadButton.fileName)} + onClick={() => downloadCode(ref, config, downloadButton.fileName)} ariaLabel={downloadButton.label} caption={downloadButton.caption} /> diff --git a/packages/pluggableWidgets/barcode-generator-web/src/config/Barcode.config.ts b/packages/pluggableWidgets/barcode-generator-web/src/config/Barcode.config.ts index 78a01c19a1..7d772a7df1 100644 --- a/packages/pluggableWidgets/barcode-generator-web/src/config/Barcode.config.ts +++ b/packages/pluggableWidgets/barcode-generator-web/src/config/Barcode.config.ts @@ -9,7 +9,7 @@ import { interface DownloadButtonConfig { caption?: string; label?: string; - fileName: string; + fileName?: string; buttonPosition: "top" | "bottom"; } @@ -65,7 +65,7 @@ export function barcodeConfig(props: BarcodeGeneratorContainerProps): BarcodeCon ? { caption: props.downloadButtonCaption?.value, label: props.downloadButtonAriaLabel?.value, - fileName: generateFileName(props.downloadFileName?.value, format, codeValue), + fileName: getFileName(props.downloadFileName?.value), buttonPosition: props.buttonPosition ?? "bottom" } : undefined; @@ -119,34 +119,11 @@ export function barcodeConfig(props: BarcodeGeneratorContainerProps): BarcodeCon }; } -function generateFileName(customFileName: string | undefined, format: string, codeValue: string): string { +function getFileName(customFileName: string | undefined): string | undefined { // Use custom filename if provided if (customFileName && customFileName.trim()) { return customFileName.trim().endsWith(".png") ? customFileName.trim() : `${customFileName.trim()}.png`; } - // Auto-generate filename with format and hash - const hash = hashCode(codeValue); - if (format === "QRCode") { - return `qrcode_${hash}.png`; - } - return `barcode_${format}_${hash}.png`; -} - -function hashCode(s: string): string { - if (!s) { - return "empty"; - } - - let hash = 0; - for (let i = 0; i < s.length; i++) { - const char = s.charCodeAt(i); - // eslint-disable-next-line no-bitwise - hash = (hash << 5) - hash + char; - // eslint-disable-next-line no-bitwise - hash = hash & hash; // Convert to 32-bit integer - } - - // Convert to base36 and take first 10 characters - return Math.abs(hash).toString(36).substring(0, 10); + return undefined; // Let the download function generate a default filename based on content and timestamp } diff --git a/packages/pluggableWidgets/barcode-generator-web/src/utils/download-code.ts b/packages/pluggableWidgets/barcode-generator-web/src/utils/download-code.ts index 2f6926e2bf..f5685b031d 100644 --- a/packages/pluggableWidgets/barcode-generator-web/src/utils/download-code.ts +++ b/packages/pluggableWidgets/barcode-generator-web/src/utils/download-code.ts @@ -1,11 +1,17 @@ import { RefObject } from "react"; -import { convertSvgToPng, downloadBlob, prepareSvgForDownload, processQRImages } from "./download-utils"; +import { + convertSvgToPng, + downloadBlob, + prepareSvgForDownload, + processQRImages, + generateFileName +} from "./download-utils"; import { BarcodeConfig } from "../config/Barcode.config"; export async function downloadCode( ref: RefObject, - type: BarcodeConfig["type"], - fileName: string + config: BarcodeConfig, + fileName?: string ): Promise { try { const svgElement = ref.current; @@ -15,18 +21,22 @@ export async function downloadCode( } const clonedSvg = prepareSvgForDownload(svgElement); - + let fileNamePrefix: string = config.type; // Process overlay images for QR codes - if (type === "qrcode") { + if (config.type === "qrcode") { await processQRImages(clonedSvg); + } else { + fileNamePrefix = `${config.type}_${config.format}`; } // Convert SVG to PNG with 2x scale for better quality const pngBlob = await convertSvgToPng(clonedSvg, 2); + // Generate filename if not provided + const finalFileName = fileName || generateFileName(fileNamePrefix, config.codeValue); // Trigger download - downloadBlob(pngBlob, fileName); + downloadBlob(pngBlob, finalFileName, ref.current?.ownerDocument || document); } catch (error) { - console.error(`Error downloading ${type}:`, error); + console.error(`Error downloading ${config.type}:`, error); } } diff --git a/packages/pluggableWidgets/barcode-generator-web/src/utils/download-utils.ts b/packages/pluggableWidgets/barcode-generator-web/src/utils/download-utils.ts index 4f27ade4a4..b8383dbccc 100644 --- a/packages/pluggableWidgets/barcode-generator-web/src/utils/download-utils.ts +++ b/packages/pluggableWidgets/barcode-generator-web/src/utils/download-utils.ts @@ -5,6 +5,49 @@ const NAMESPACES = { XLINK: "http://www.w3.org/1999/xlink" } as const; +export function generateFileName(prefix: string, codeValue: string): string { + // Auto-generate filename with format and hash + const timestamp = generateTimestamp(); + const hash = hashCode(codeValue); + return `${prefix}_${hash}_${timestamp}.png`; +} + +function generateTimestamp(): string { + // Get current date and time + const now = new Date(); + + // Format: YYYYMMDD_HHMMSS + const timestamp = + now.getFullYear().toString() + + String(now.getMonth() + 1).padStart(2, "0") + + String(now.getDate()).padStart(2, "0") + + "_" + + String(now.getHours()).padStart(2, "0") + + String(now.getMinutes()).padStart(2, "0") + + String(now.getSeconds()).padStart(2, "0"); + + // Return formatted filename + return timestamp; +} + +function hashCode(s: string): string { + if (!s) { + return "empty"; + } + + let hash = 0; + for (let i = 0; i < s.length; i++) { + const char = s.charCodeAt(i); + // eslint-disable-next-line no-bitwise + hash = (hash << 5) - hash + char; + // eslint-disable-next-line no-bitwise + hash = hash & hash; // Convert to 32-bit integer + } + + // Convert to base36 and take first 10 characters + return Math.abs(hash).toString(36).substring(0, 10); +} + // Prepare SVG for download by setting namespaces export const prepareSvgForDownload = (svgElement: SVGSVGElement): SVGSVGElement => { const clonedSvg = svgElement.cloneNode(true) as SVGSVGElement; @@ -52,14 +95,14 @@ export const processQRImages = async (clonedSvg: SVGSVGElement): Promise = } }; -export const downloadBlob = (blob: Blob, filename: string): void => { +export const downloadBlob = (blob: Blob, filename: string, currentDocument: Document = document): void => { const url = URL.createObjectURL(blob); - const link = document.createElement("a"); + const link = currentDocument.createElement("a"); link.href = url; link.download = filename; - document.body.appendChild(link); + currentDocument.body.appendChild(link); link.click(); - document.body.removeChild(link); + currentDocument.body.removeChild(link); URL.revokeObjectURL(url); }; @@ -73,7 +116,7 @@ export const convertSvgToPng = async (svgElement: SVGSVGElement, scale = 2): Pro const img = new Image(); img.onload = () => { try { - const canvas = document.createElement("canvas"); + const canvas = svgElement.ownerDocument.createElement("canvas"); const ctx = canvas.getContext("2d"); if (!ctx) {