'use client'; /** * 자재투입 모달 * API 연동 완료 (2025-12-26) * * 기획 화면에 맞춘 레이아웃: * - FIFO 순위 설명 (1 최우선, 2 차선, 3+ 대기) * - ① 자재 선택 (BOM 기준) 테이블 * - 취소 / 투입 등록 버튼 (전체 너비) */ import { useState, useEffect, useCallback } from 'react'; import { Loader2 } from 'lucide-react'; import { ContentLoadingSpinner } from '@/components/ui/loading-spinner'; import { Dialog, DialogContent, DialogHeader, DialogTitle, } from '@/components/ui/dialog'; import { Button } from '@/components/ui/button'; import { Badge } from '@/components/ui/badge'; import { Checkbox } from '@/components/ui/checkbox'; import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow, } from '@/components/ui/table'; import { toast } from 'sonner'; import { isNextRedirectError } from '@/lib/utils/redirect-error'; import { getMaterialsForWorkOrder, registerMaterialInput, type MaterialForInput } from './actions'; import type { WorkOrder } from '../ProductionDashboard/types'; import type { MaterialInput } from './types'; interface MaterialInputModalProps { open: boolean; onOpenChange: (open: boolean) => void; order: WorkOrder | null; onComplete?: () => void; isCompletionFlow?: boolean; onSaveMaterials?: (orderId: string, materials: MaterialInput[]) => void; savedMaterials?: MaterialInput[]; } export function MaterialInputModal({ open, onOpenChange, order, onComplete, isCompletionFlow = false, onSaveMaterials, }: MaterialInputModalProps) { const [selectedMaterials, setSelectedMaterials] = useState>(new Set()); const [materials, setMaterials] = useState([]); const [isLoading, setIsLoading] = useState(false); const [isSubmitting, setIsSubmitting] = useState(false); // API로 자재 목록 로드 const loadMaterials = useCallback(async () => { if (!order) return; setIsLoading(true); try { const result = await getMaterialsForWorkOrder(order.id); if (result.success) { setMaterials(result.data); } else { toast.error(result.error || '자재 목록 조회에 실패했습니다.'); } } catch (error) { if (isNextRedirectError(error)) throw error; console.error('[MaterialInputModal] loadMaterials error:', error); toast.error('자재 목록 로드 중 오류가 발생했습니다.'); } finally { setIsLoading(false); } }, [order]); // 모달이 열릴 때 데이터 로드 useEffect(() => { if (open && order) { loadMaterials(); } }, [open, order, loadMaterials]); const handleToggleMaterial = (materialId: string) => { setSelectedMaterials((prev) => { const next = new Set(prev); if (next.has(materialId)) { next.delete(materialId); } else { next.add(materialId); } return next; }); }; // 투입 등록 const handleSubmit = async () => { if (!order) return; setIsSubmitting(true); try { // 선택된 자재 ID 배열 const materialIds = materials .filter((m) => selectedMaterials.has(String(m.id))) .map((m) => m.id); const result = await registerMaterialInput(order.id, materialIds); if (result.success) { toast.success('자재 투입이 등록되었습니다.'); // onSaveMaterials 콜백 호출 (기존 호환성) if (onSaveMaterials) { const selectedMaterialList: MaterialInput[] = materials .filter((m) => selectedMaterials.has(String(m.id))) .map((m) => ({ id: String(m.id), materialCode: m.materialCode, materialName: m.materialName, unit: m.unit, currentStock: m.currentStock, fifoRank: m.fifoRank, })); onSaveMaterials(order.id, selectedMaterialList); } resetAndClose(); if (isCompletionFlow && onComplete) { onComplete(); } } else { toast.error(result.error || '자재 투입 등록에 실패했습니다.'); } } catch (error) { if (isNextRedirectError(error)) throw error; console.error('[MaterialInputModal] handleSubmit error:', error); toast.error('자재 투입 등록 중 오류가 발생했습니다.'); } finally { setIsSubmitting(false); } }; // 취소 const handleCancel = () => { resetAndClose(); }; const resetAndClose = () => { setSelectedMaterials(new Set()); onOpenChange(false); }; if (!order) return null; return ( {/* 헤더 */} 투입자재 등록
{/* FIFO 순위 설명 */}
FIFO 순위:
1 최우선 2 차선 3+ 대기
{/* 자재 선택 섹션 */}

① 자재 선택 (BOM 기준)

{isLoading ? ( ) : materials.length === 0 ? (
자재코드 자재명 단위 현재고 선택 이 공정에 배정된 자재가 없습니다.
) : (
자재코드 자재명 단위 현재고 선택 {materials.map((material) => ( {material.materialCode} {material.materialName} {material.unit} {material.currentStock.toLocaleString()} handleToggleMaterial(String(material.id))} /> ))}
)}
{/* 버튼 영역 */}
); }