"use client"; import React, { useState, useCallback, useEffect } from "react"; import type { PackageUnit } from "./PackagingModal"; /* ------------------------------------------------------------------ */ /* Types */ /* ------------------------------------------------------------------ */ export interface PackageEntry { unit: PackageUnit; count: number; qtyPerUnit: number; } interface NumberPadModalProps { open: boolean; onClose: () => void; onConfirm: (qty: number, packages: PackageEntry[]) => void; maxQty: number; itemName: string; initialQty?: number; initialPackages?: PackageEntry[]; } /* ------------------------------------------------------------------ */ /* Packaging options (inline, no separate modal needed) */ /* ------------------------------------------------------------------ */ const PACKAGE_UNITS: PackageUnit[] = [ { label: "박스", icon: "\uD83D\uDCE6", value: "box" }, { label: "포대", icon: "\uD83D\uDECD\uFE0F", value: "bag" }, { label: "팩", icon: "\uD83D\uDCCB", value: "pack" }, { label: "묶음", icon: "\uD83D\uDD17", value: "bundle" }, { label: "롤", icon: "\uD83E\uDDFB", value: "roll" }, { label: "통", icon: "\uD83E\uDEB3", value: "barrel" }, ]; type Step = "packaging" | "pkg-count" | "qty-per-pkg" | "direct-qty" | "confirm"; /* ------------------------------------------------------------------ */ /* Numpad Keys */ /* ------------------------------------------------------------------ */ const KEYS = [ { label: "7", action: "7" }, { label: "8", action: "8" }, { label: "9", action: "9" }, { label: "\u2190", action: "backspace" }, { label: "4", action: "4" }, { label: "5", action: "5" }, { label: "6", action: "6" }, { label: "C", action: "clear" }, { label: "1", action: "1" }, { label: "2", action: "2" }, { label: "3", action: "3" }, { label: "MAX", action: "max" }, ]; /* ------------------------------------------------------------------ */ /* Component */ /* ------------------------------------------------------------------ */ export function NumberPadModal({ open, onClose, onConfirm, maxQty, itemName, initialQty, initialPackages, }: NumberPadModalProps) { const [step, setStep] = useState("packaging"); const [selectedUnit, setSelectedUnit] = useState(null); const [pkgCount, setPkgCount] = useState("0"); const [qtyPerPkg, setQtyPerPkg] = useState("0"); const [directQty, setDirectQty] = useState("0"); /* Reset on open */ useEffect(() => { if (open) { if (initialPackages && initialPackages.length > 0) { // Editing existing -- go to confirm const p = initialPackages[0]; setSelectedUnit(p.unit); setPkgCount(String(p.count)); setQtyPerPkg(String(p.qtyPerUnit)); setDirectQty("0"); setStep("confirm"); } else if (initialQty !== undefined && initialQty > 0) { setDirectQty(String(initialQty)); setSelectedUnit(null); setStep("confirm"); } else { setStep("packaging"); setSelectedUnit(null); setPkgCount("0"); setQtyPerPkg("0"); setDirectQty("0"); } } }, [open, initialQty, initialPackages]); /* Computed values */ const pkgCountNum = parseInt(pkgCount, 10) || 0; const qtyPerPkgNum = parseInt(qtyPerPkg, 10) || 0; const directQtyNum = parseInt(directQty, 10) || 0; const totalQty = selectedUnit ? pkgCountNum * qtyPerPkgNum : directQtyNum; const isOverMax = totalQty > maxQty; /* Generic numpad input handler */ const handleInput = useCallback( (key: string, setter: React.Dispatch>, max?: number) => { setter((prev) => { switch (key) { case "backspace": return prev.length <= 1 ? "0" : prev.slice(0, -1); case "clear": return "0"; case "max": return String(max ?? maxQty); default: { const next = prev === "0" ? key : prev + key; const num = parseInt(next, 10); if (isNaN(num)) return prev; if (max !== undefined) return String(Math.min(num, max)); return next; } } }); }, [maxQty] ); /* Step handlers */ const handleSelectPackaging = (unit: PackageUnit) => { setSelectedUnit(unit); setPkgCount("0"); setQtyPerPkg("0"); setStep("pkg-count"); }; const handleSkipPackaging = () => { setSelectedUnit(null); setDirectQty("0"); setStep("direct-qty"); }; const handlePkgCountConfirm = () => { if (pkgCountNum <= 0) return; setStep("qty-per-pkg"); }; const handleQtyPerPkgConfirm = () => { if (qtyPerPkgNum <= 0) return; setStep("confirm"); }; const handleDirectQtyConfirm = () => { if (directQtyNum <= 0) return; setStep("confirm"); }; const handleEdit = () => { if (selectedUnit) { setStep("packaging"); } else { setStep("direct-qty"); } }; const handleFinalConfirm = () => { if (totalQty <= 0) return; const finalQty = Math.min(totalQty, maxQty); const packages: PackageEntry[] = selectedUnit ? [{ unit: selectedUnit, count: pkgCountNum, qtyPerUnit: qtyPerPkgNum }] : []; onConfirm(finalQty, packages); onClose(); }; if (!open) return null; /* Render numpad grid */ const renderNumpad = ( currentValue: string, onKey: (key: string) => void, onConfirmStep: () => void, confirmLabel: string, confirmDisabled: boolean, ) => ( <> {/* Display */} {/* Numpad grid: 4x3 + bottom row */}
{KEYS.map((key) => ( ))} {/* Bottom row: 0 (span 2) + Confirm (span 2) */}
); return (
{/* Overlay */}
{/* Panel */}
{/* Header - blue gradient */}
{step !== "packaging" && ( )} 최대 {maxQty.toLocaleString()} EA
{/* Step indicator */}
{(selectedUnit ? ["packaging", "pkg-count", "qty-per-pkg", "confirm"] as Step[] : ["packaging", "direct-qty", "confirm"] as Step[] ).map((s) => (
))}
{/* Body */}
{/* ====== Step 1: Packaging Selection ====== */} {step === "packaging" && ( <>

포장 단위를 선택하세요

{PACKAGE_UNITS.map((unit) => ( ))}
{/* Skip button */} )} {/* ====== Step 2: Package Count ====== */} {step === "pkg-count" && selectedUnit && ( <>

{selectedUnit.icon} {selectedUnit.label} 몇 개?

포장 개수를 입력하세요

{renderNumpad( pkgCount, (key) => handleInput(key, setPkgCount, 9999), handlePkgCountConfirm, "다음", pkgCountNum <= 0, )} )} {/* ====== Step 3: Qty per Package ====== */} {step === "qty-per-pkg" && selectedUnit && ( <>

{selectedUnit.icon} {selectedUnit.label} 1개당 수량?

개당 수량(EA)을 입력하세요

{renderNumpad( qtyPerPkg, (key) => handleInput(key, setQtyPerPkg), handleQtyPerPkgConfirm, "다음", qtyPerPkgNum <= 0, )} {/* Live calculation preview */} {pkgCountNum > 0 && qtyPerPkgNum > 0 && (
maxQty ? "bg-red-50 text-red-600 border border-red-200" : "bg-blue-50 text-blue-700 border border-blue-200" }`}> {pkgCountNum}{selectedUnit.label} x {qtyPerPkgNum.toLocaleString()}EA = {(pkgCountNum * qtyPerPkgNum).toLocaleString()}EA {pkgCountNum * qtyPerPkgNum > maxQty && ( 최대 수량({maxQty.toLocaleString()}EA)을 초과합니다 )}
)} )} {/* ====== Step: Direct Qty (skip packaging) ====== */} {step === "direct-qty" && ( <>

입고 수량 입력

수량(EA)을 직접 입력하세요

{renderNumpad( directQty, (key) => handleInput(key, setDirectQty, maxQty), handleDirectQtyConfirm, "다음", directQtyNum <= 0, )} )} {/* ====== Step: Confirm ====== */} {step === "confirm" && ( <>

최종 확인

{selectedUnit ? (

{selectedUnit.icon}

{pkgCountNum}{selectedUnit.label} x {qtyPerPkgNum.toLocaleString()}EA

= {totalQty.toLocaleString()} EA

{isOverMax && (

최대 수량({maxQty.toLocaleString()}EA)을 초과합니다. {maxQty.toLocaleString()}EA로 적용됩니다.

)}
) : (

입고 수량

{directQtyNum.toLocaleString()} EA

)}

{itemName}

{/* Action buttons */}
)}
); }