"use client"; import { useState } from "react"; import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogFooter, } from "@/components/ui/dialog"; import { Button } from "@/components/ui/button"; import { Download, Printer, Loader2, AlertCircle } from "lucide-react"; import { BarcodeLabelLayout } from "@/types/barcode"; import { generateZPL } from "@/lib/zplGenerator"; import { printZPLToZebraBLE, isWebBluetoothSupported, getUnsupportedMessage, } from "@/lib/zebraBluetooth"; import { printZPLToBrowserPrint, getBrowserPrintHelpMessage, } from "@/lib/zebraBrowserPrint"; import { useToast } from "@/hooks/use-toast"; import { BarcodeLabelCanvasComponent } from "./BarcodeLabelCanvasComponent"; import { MM_TO_PX } from "@/contexts/BarcodeDesignerContext"; const PREVIEW_MAX_PX = 320; interface BarcodePrintPreviewModalProps { open: boolean; onOpenChange: (open: boolean) => void; layout: BarcodeLabelLayout; labelName?: string; } export function BarcodePrintPreviewModal({ open, onOpenChange, layout, labelName = "라벨", }: BarcodePrintPreviewModalProps) { const { toast } = useToast(); const [printing, setPrinting] = useState(false); const { width_mm, height_mm, components } = layout; const widthPx = width_mm * MM_TO_PX; const heightPx = height_mm * MM_TO_PX; const scale = widthPx > PREVIEW_MAX_PX || heightPx > PREVIEW_MAX_PX ? Math.min(PREVIEW_MAX_PX / widthPx, PREVIEW_MAX_PX / heightPx) : 1; const previewW = Math.round(widthPx * scale); const previewH = Math.round(heightPx * scale); const zpl = generateZPL(layout); const bleSupported = isWebBluetoothSupported(); const unsupportedMsg = getUnsupportedMessage(); const handleDownloadZPL = () => { const blob = new Blob([zpl], { type: "text/plain;charset=utf-8" }); const url = URL.createObjectURL(blob); const a = document.createElement("a"); a.href = url; a.download = `${labelName}.zpl`; a.click(); URL.revokeObjectURL(url); toast({ title: "다운로드", description: "ZPL 파일이 저장되었습니다." }); }; const handlePrintToZebra = async () => { const canUseBle = bleSupported; if (!canUseBle) { // Browser Print만 시도 (스크립트 로드 후 기본 프린터로 전송) setPrinting(true); try { const result = await printZPLToBrowserPrint(zpl); if (result.success) { toast({ title: "전송 완료", description: result.message }); onOpenChange(false); } else { toast({ title: "출력 실패", description: result.message, variant: "destructive", }); toast({ title: "안내", description: getBrowserPrintHelpMessage(), variant: "default", }); } } catch (e: unknown) { toast({ title: "오류", description: (e as Error).message || "Zebra 출력 중 오류가 발생했습니다.", variant: "destructive", }); } finally { setPrinting(false); } return; } // Web Bluetooth 지원 시: Browser Print 먼저 시도, 실패하면 BLE로 폴백 setPrinting(true); try { const bpResult = await printZPLToBrowserPrint(zpl); if (bpResult.success) { toast({ title: "전송 완료", description: bpResult.message }); onOpenChange(false); return; } const bleResult = await printZPLToZebraBLE(zpl); if (bleResult.success) { toast({ title: "전송 완료", description: bleResult.message }); onOpenChange(false); } else { toast({ title: "출력 실패", description: bleResult.message, variant: "destructive", }); toast({ title: "안내", description: getBrowserPrintHelpMessage(), variant: "default", }); } } catch (e: unknown) { toast({ title: "오류", description: (e as Error).message || "Zebra 출력 중 오류가 발생했습니다.", variant: "destructive", }); } finally { setPrinting(false); } }; return ( 인쇄 미리보기

{width_mm}×{height_mm}mm · {components.length}개 요소

{/* 미리보기 캔버스 (축소) */}
{components.map((c) => ( ))}
{!bleSupported && (
Web Bluetooth 미지원 브라우저입니다. Zebra Browser Print 앱을 설치하면 출력할 수 있습니다. {unsupportedMsg && ` ${unsupportedMsg}`}
)}

{bleSupported ? ( <> Zebra 프린터를 Bluetooth LE로 켜 두고, 출력 시 기기 선택에서 프린터를 선택하세요. (Chrome/Edge 권장) {typeof navigator !== "undefined" && /Android/i.test(navigator.userAgent) && ( <> Android에서는 목록에 인근 BLE 기기가 모두 표시되므로, 'ZD421' 등 프린터 이름을 골라 주세요. )} ) : null} {typeof navigator !== "undefined" && /Android/i.test(navigator.userAgent) && ( <> {" "} 목록에 프린터가 안 나오면 지브라 공식 'Zebra Browser Print' 앱을 설치한 뒤, 앱에서 프린터 검색·기본 설정 후 이 사이트를 허용하면 출력할 수 있습니다. )}

); }