"use client"; import { useRef, useState, useEffect } from "react"; import JsBarcode from "jsbarcode"; import QRCode from "qrcode"; import type { BarcodeRendererProps as BarcodeCanvasRendererProps } from "./types"; interface BarcodeProps { value: string; format: string; width: number; height: number; displayValue: boolean; lineColor: string; background: string; margin: number; } function Barcode1D({ value, format, width, height, displayValue, lineColor, background, margin }: BarcodeProps) { const svgRef = useRef(null); const [error, setError] = useState(null); useEffect(() => { if (!svgRef.current || !value) return; setError(null); try { let isValid = true; let errorMsg = ""; const trimmedValue = value.trim(); if (format === "EAN13" && !/^\d{12,13}$/.test(trimmedValue)) { isValid = false; errorMsg = "EAN-13: 12~13자리 숫자 필요"; } else if (format === "EAN8" && !/^\d{7,8}$/.test(trimmedValue)) { isValid = false; errorMsg = "EAN-8: 7~8자리 숫자 필요"; } else if (format === "UPC" && !/^\d{11,12}$/.test(trimmedValue)) { isValid = false; errorMsg = "UPC: 11~12자리 숫자 필요"; } if (!isValid) { setError(errorMsg); return; } const barcodeFormat = format.toLowerCase(); const bgColor = background === "transparent" ? "" : background; JsBarcode(svgRef.current, trimmedValue, { format: barcodeFormat, width: 2, height: Math.max(30, height - (displayValue ? 30 : 10)), displayValue, lineColor, background: bgColor, margin, fontSize: 12, textMargin: 2, }); } catch (err: any) { setError(err?.message || "바코드 생성 실패"); } }, [value, format, width, height, displayValue, lineColor, background, margin]); return (
{error && (
{error} {value}
)}
); } interface QRProps { value: string; size: number; fgColor: string; bgColor: string; level: "L" | "M" | "Q" | "H"; } function QR({ value, size, fgColor, bgColor, level }: QRProps) { const canvasRef = useRef(null); const [error, setError] = useState(null); useEffect(() => { if (!canvasRef.current || !value) return; setError(null); const lightColor = bgColor === "transparent" ? "#ffffff" : bgColor; QRCode.toCanvas( canvasRef.current, value, { width: Math.max(50, size), margin: 2, color: { dark: fgColor, light: lightColor }, errorCorrectionLevel: level, }, (err) => { if (err) setError(err.message || "QR코드 생성 실패"); }, ); }, [value, size, fgColor, bgColor, level]); return (
{error && (
{error} {value}
)}
); } export function BarcodeCanvasRenderer({ component, getQueryResult }: BarcodeCanvasRendererProps) { const barcodeType = component.barcodeType || "CODE128"; const showBarcodeText = component.showBarcodeText !== false; const barcodeColor = component.barcodeColor || "#000000"; const barcodeBackground = component.barcodeBackground || "transparent"; const barcodeMargin = component.barcodeMargin ?? 10; const qrErrorLevel = component.qrErrorCorrectionLevel || "M"; const getBarcodeValue = (): string => { if ( barcodeType === "QR" && component.qrUseMultiField && component.qrDataFields && component.qrDataFields.length > 0 && component.queryId ) { const queryResult = getQueryResult(component.queryId); if (queryResult && queryResult.rows && queryResult.rows.length > 0) { if (component.qrIncludeAllRows) { const allRowsData: Record[] = []; queryResult.rows.forEach((row) => { const rowData: Record = {}; component.qrDataFields!.forEach((field) => { if (field.fieldName && field.label) { const val = row[field.fieldName]; rowData[field.label] = val !== null && val !== undefined ? String(val) : ""; } }); allRowsData.push(rowData); }); return JSON.stringify(allRowsData); } const row = queryResult.rows[0]; const jsonData: Record = {}; component.qrDataFields.forEach((field) => { if (field.fieldName && field.label) { const val = row[field.fieldName]; jsonData[field.label] = val !== null && val !== undefined ? String(val) : ""; } }); return JSON.stringify(jsonData); } const placeholderData: Record = {}; component.qrDataFields.forEach((field) => { if (field.label) placeholderData[field.label] = `{${field.fieldName || "field"}}`; }); return component.qrIncludeAllRows ? JSON.stringify([placeholderData, { "...": "..." }]) : JSON.stringify(placeholderData); } if (component.barcodeFieldName && component.queryId) { const queryResult = getQueryResult(component.queryId); if (queryResult && queryResult.rows && queryResult.rows.length > 0) { if (barcodeType === "QR" && component.qrIncludeAllRows) { const allValues = queryResult.rows .map((row) => { const val = row[component.barcodeFieldName!]; return val !== null && val !== undefined ? String(val) : ""; }) .filter((v) => v !== ""); return JSON.stringify(allValues); } const row = queryResult.rows[0]; const val = row[component.barcodeFieldName]; if (val !== null && val !== undefined) return String(val); } if (barcodeType === "QR" && component.qrIncludeAllRows) { return JSON.stringify([`{${component.barcodeFieldName}}`, "..."]); } return `{${component.barcodeFieldName}}`; } return component.barcodeValue || "SAMPLE123"; }; const barcodeValue = getBarcodeValue(); const isQR = barcodeType === "QR"; return (
{isQR ? ( ) : ( )}
); }