"use client"; import { useRef, useState, useEffect } from "react"; import { BarcodeLabelComponent } from "@/types/barcode"; import { useBarcodeDesigner } from "@/contexts/BarcodeDesignerContext"; import JsBarcode from "jsbarcode"; import QRCode from "qrcode"; import { getFullImageUrl } from "@/lib/api/client"; import { MM_TO_PX } from "@/contexts/BarcodeDesignerContext"; interface Props { component: BarcodeLabelComponent; } // 1D 바코드 렌더 function Barcode1DRender({ value, format, width, height, showText, }: { value: string; format: string; width: number; height: number; showText: boolean; }) { const svgRef = useRef(null); useEffect(() => { if (!svgRef.current || !value.trim()) return; try { JsBarcode(svgRef.current, value.trim(), { format: format.toLowerCase(), width: 2, height: Math.max(20, height - (showText ? 14 : 4)), displayValue: showText, margin: 2, }); } catch { // ignore } }, [value, format, height, showText]); return (
); } // QR 렌더 function QRRender({ value, size }: { value: string; size: number }) { const canvasRef = useRef(null); useEffect(() => { if (!canvasRef.current || !value.trim()) return; QRCode.toCanvas(canvasRef.current, value.trim(), { width: Math.max(40, size), margin: 1, }); }, [value, size]); return (
); } export function BarcodeLabelCanvasComponent({ component }: Props) { const { updateComponent, removeComponent, selectComponent, selectedComponentId, snapValueToGrid, } = useBarcodeDesigner(); const [isDragging, setIsDragging] = useState(false); const [dragStart, setDragStart] = useState({ x: 0, y: 0, compX: 0, compY: 0 }); const [isResizing, setIsResizing] = useState(false); const [resizeStart, setResizeStart] = useState({ x: 0, y: 0, w: 0, h: 0 }); const ref = useRef(null); const selected = selectedComponentId === component.id; const handleMouseDown = (e: React.MouseEvent) => { e.stopPropagation(); selectComponent(component.id); if ((e.target as HTMLElement).closest("[data-resize-handle]")) { setIsResizing(true); setResizeStart({ x: e.clientX, y: e.clientY, w: component.width, h: component.height, }); } else { setIsDragging(true); setDragStart({ x: e.clientX, y: e.clientY, compX: component.x, compY: component.y }); } }; useEffect(() => { if (!isDragging && !isResizing) return; const onMove = (e: MouseEvent) => { if (isDragging) { const dx = e.clientX - dragStart.x; const dy = e.clientY - dragStart.y; updateComponent(component.id, { x: Math.max(0, snapValueToGrid(dragStart.compX + dx)), y: Math.max(0, snapValueToGrid(dragStart.compY + dy)), }); } else if (isResizing) { const dx = e.clientX - resizeStart.x; const dy = e.clientY - resizeStart.y; updateComponent(component.id, { width: Math.max(20, resizeStart.w + dx), height: Math.max(10, resizeStart.h + dy), }); } }; const onUp = () => { setIsDragging(false); setIsResizing(false); }; document.addEventListener("mousemove", onMove); document.addEventListener("mouseup", onUp); return () => { document.removeEventListener("mousemove", onMove); document.removeEventListener("mouseup", onUp); }; }, [ isDragging, isResizing, dragStart, resizeStart, component.id, updateComponent, snapValueToGrid, ]); const style: React.CSSProperties = { position: "absolute", left: component.x, top: component.y, width: component.width, height: component.height, zIndex: component.zIndex, }; const border = selected ? "2px solid #2563eb" : "1px solid transparent"; const isBarcode = component.type === "barcode"; const isQR = component.barcodeType === "QR"; const content = () => { switch (component.type) { case "text": return (
{component.content || "텍스트"}
); case "barcode": if (isQR) { return ( ); } return ( ); case "image": return component.imageUrl ? ( ) : (
이미지
); case "line": return (
); case "rectangle": return (
); default: return null; } }; return (
{content()} {selected && component.type !== "line" && (
{ e.stopPropagation(); setIsResizing(true); setResizeStart({ x: e.clientX, y: e.clientY, w: component.width, h: component.height, }); }} /> )}
); }