"use client"; import React, { useState, useEffect, useMemo } from "react"; import { Delete, Trash2, Plus, ArrowLeft } from "lucide-react"; import { Dialog, DialogPortal, DialogOverlay, } from "@/components/ui/dialog"; import * as DialogPrimitive from "@radix-ui/react-dialog"; import { PackageUnitModal, PACKAGE_UNITS, } from "./PackageUnitModal"; import type { CardPackageConfig, PackageEntry } from "../types"; type InputStep = | "quantity" // 기본: 직접 수량 입력 (포장 OFF) | "package_count" // 포장: 포장 수량 (N개) | "quantity_per_unit" // 포장: 개당 수량 (M EA) | "summary"; // 포장: 결과 확인 + 추가/완료 interface NumberInputModalProps { open: boolean; onOpenChange: (open: boolean) => void; unit?: string; initialValue?: number; initialPackageUnit?: string; min?: number; maxValue?: number; /** @deprecated packageConfig 사용 */ showPackageUnit?: boolean; packageConfig?: CardPackageConfig; onConfirm: (value: number, packageUnit?: string, packageEntries?: PackageEntry[]) => void; } export function NumberInputModal({ open, onOpenChange, unit = "EA", initialValue = 0, initialPackageUnit, min = 0, maxValue = 999999, showPackageUnit, packageConfig, onConfirm, }: NumberInputModalProps) { const [displayValue, setDisplayValue] = useState(""); const [step, setStep] = useState("quantity"); const [isPackageModalOpen, setIsPackageModalOpen] = useState(false); // 포장 2단계 플로우용 상태 const [selectedUnit, setSelectedUnit] = useState<{ id: string; label: string } | null>(null); const [packageCount, setPackageCount] = useState(0); const [entries, setEntries] = useState([]); const isPackageEnabled = packageConfig?.enabled ?? showPackageUnit ?? true; const showSummary = packageConfig?.showSummaryMessage !== false; const entriesTotal = useMemo( () => entries.reduce((sum, e) => sum + e.totalQuantity, 0), [entries] ); const remainingQuantity = maxValue - entriesTotal; useEffect(() => { if (open) { setDisplayValue(initialValue > 0 ? String(initialValue) : ""); setStep("quantity"); setSelectedUnit(null); setPackageCount(0); setEntries([]); } }, [open, initialValue]); // --- 키패드 핸들러 --- const currentMax = step === "quantity" ? maxValue : step === "package_count" ? 9999 : step === "quantity_per_unit" ? remainingQuantity > 0 ? remainingQuantity : maxValue : maxValue; const handleNumberClick = (num: string) => { const newStr = displayValue + num; const numericValue = parseInt(newStr, 10); setDisplayValue(numericValue > currentMax ? String(currentMax) : newStr); }; const handleBackspace = () => setDisplayValue((prev) => prev.slice(0, -1)); const handleClear = () => setDisplayValue(""); const handleMax = () => setDisplayValue(String(currentMax)); // --- 확인 버튼: step에 따라 다르게 동작 --- const handleConfirm = () => { const numericValue = parseInt(displayValue, 10) || 0; if (step === "quantity") { const finalValue = Math.max(min, Math.min(maxValue, numericValue)); onConfirm(finalValue, undefined, undefined); onOpenChange(false); return; } if (step === "package_count") { if (numericValue <= 0) return; setPackageCount(numericValue); setDisplayValue(""); setStep("quantity_per_unit"); return; } if (step === "quantity_per_unit") { if (numericValue <= 0 || !selectedUnit) return; const total = packageCount * numericValue; const newEntry: PackageEntry = { unitId: selectedUnit.id, unitLabel: selectedUnit.label, packageCount, quantityPerUnit: numericValue, totalQuantity: total, }; setEntries((prev) => [...prev, newEntry]); setDisplayValue(""); setStep("summary"); return; } }; // --- 포장 단위 선택 콜백 --- const handlePackageUnitSelect = (unitId: string) => { const matched = PACKAGE_UNITS.find((u) => u.value === unitId); const matchedCustom = packageConfig?.customUnits?.find((cu) => cu.id === unitId); const label = matched?.label ?? matchedCustom?.label ?? unitId; setSelectedUnit({ id: unitId, label }); setDisplayValue(""); setStep("package_count"); }; // --- summary 액션 --- const handleAddMore = () => { setIsPackageModalOpen(true); }; const handleRemoveEntry = (index: number) => { setEntries((prev) => prev.filter((_, i) => i !== index)); }; const handleComplete = () => { if (entries.length === 0) return; const total = entries.reduce((sum, e) => sum + e.totalQuantity, 0); const lastUnit = entries[entries.length - 1].unitId; onConfirm(total, lastUnit, entries); onOpenChange(false); }; const handleBack = () => { if (step === "package_count") { setStep("quantity"); setSelectedUnit(null); setDisplayValue(""); } else if (step === "quantity_per_unit") { setStep("package_count"); setDisplayValue(String(packageCount)); } else if (step === "summary") { if (entries.length > 0) { const last = entries[entries.length - 1]; setEntries((prev) => prev.slice(0, -1)); setSelectedUnit({ id: last.unitId, label: last.unitLabel }); setPackageCount(last.packageCount); setDisplayValue(String(last.quantityPerUnit)); setStep("quantity_per_unit"); } else { setStep("quantity"); setDisplayValue(""); } } }; // --- 안내 메시지 --- const guideMessage = useMemo(() => { switch (step) { case "quantity": return "수량을 입력하세요"; case "package_count": return `${selectedUnit?.label || "포장"}을(를) 몇 개 사용하시나요?`; case "quantity_per_unit": return `${selectedUnit?.label || "포장"} 1개에 몇 ${unit} 넣으시나요?`; case "summary": return ""; default: return ""; } }, [step, selectedUnit, unit]); // --- 헤더 정보 --- const headerLabel = useMemo(() => { if (step === "summary") { return `등록: ${entriesTotal.toLocaleString()} ${unit} / 남은: ${remainingQuantity.toLocaleString()} ${unit}`; } if (entries.length > 0) { return `남은 ${remainingQuantity.toLocaleString()} ${unit}`; } return `최대 ${maxValue.toLocaleString()} ${unit}`; }, [step, entriesTotal, remainingQuantity, maxValue, unit, entries.length]); const displayText = displayValue ? parseInt(displayValue, 10).toLocaleString() : ""; const isBackVisible = step !== "quantity"; return ( <> {/* 헤더 */}
{isBackVisible && ( )} {headerLabel}
{isPackageEnabled && step === "quantity" && ( )}
{/* summary 단계: 포장 내역 리스트 */} {step === "summary" ? (
{/* 안내 메시지 - 마지막 등록 결과 */} {showSummary && entries.length > 0 && (
{(() => { const last = entries[entries.length - 1]; return `${last.packageCount}${last.unitLabel} x ${last.quantityPerUnit}${unit} = ${last.totalQuantity.toLocaleString()}${unit}`; })()}
)} {/* 포장 내역 리스트 */}

포장 내역

{entries.map((entry, idx) => (
{entry.packageCount}{entry.unitLabel} x {entry.quantityPerUnit}{unit} = {entry.totalQuantity.toLocaleString()}{unit}
))}
{/* 합계 */}
합계 {entriesTotal.toLocaleString()} {unit}
{/* 남은 수량 */} {remainingQuantity > 0 && (
남은 수량 {remainingQuantity.toLocaleString()} {unit}
)} {/* 액션 버튼 */}
{remainingQuantity > 0 && ( )}
) : ( <> {/* 숫자 표시 영역 */}
{displayText ? ( {displayText} ) : ( 0 )}
{/* 단계별 안내 텍스트 */}

{guideMessage}

{/* 키패드 4x4 */}
{["7", "8", "9"].map((n) => ( ))} {["4", "5", "6"].map((n) => ( ))} {["1", "2", "3"].map((n) => ( ))}
)}
{/* 포장 단위 선택 모달 */} { setIsPackageModalOpen(isOpen); if (!isOpen && step === "summary") { // summary에서 추가 포장 모달 닫힘 -> 단위 선택 안 한 경우 유지 } }} onSelect={(unitId) => { handlePackageUnitSelect(unitId); setIsPackageModalOpen(false); }} enabledUnits={packageConfig?.enabledUnits} customUnits={packageConfig?.customUnits} /> ); }