'use client'; /** * 재고 실사 모달 * * 기능: * - 재고 목록 표시 (품목코드, 품목명, 규격, 단위, 실제 재고량) * - 실제 재고량 입력/수정 * - 저장 시 일괄 업데이트 */ import { useState, useEffect, useCallback } from 'react'; import { Loader2 } from 'lucide-react'; import { ContentSkeleton } from '@/components/ui/skeleton'; import { Dialog, DialogContent, DialogHeader, DialogTitle, } from '@/components/ui/dialog'; import { Button } from '@/components/ui/button'; import { Input } from '@/components/ui/input'; import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow, } from '@/components/ui/table'; import { toast } from 'sonner'; import { isNextRedirectError } from '@/lib/utils/redirect-error'; import { updateStockAudit } from './actions'; import type { StockItem } from './types'; interface StockAuditModalProps { open: boolean; onOpenChange: (open: boolean) => void; stocks: StockItem[]; onComplete?: () => void; } interface AuditItem { id: string; itemCode: string; itemName: string; specification: string; unit: string; actualQty: number; newActualQty: number; } export function StockAuditModal({ open, onOpenChange, stocks, onComplete, }: StockAuditModalProps) { const [auditItems, setAuditItems] = useState([]); const [isLoading, setIsLoading] = useState(false); const [isSubmitting, setIsSubmitting] = useState(false); // 모달이 열릴 때 데이터 초기화 useEffect(() => { if (open && stocks.length > 0) { setAuditItems( stocks.map((stock) => ({ id: stock.id, itemCode: stock.itemCode, itemName: stock.itemName, specification: stock.specification || '', unit: stock.unit, actualQty: stock.actualQty, newActualQty: stock.actualQty, })) ); } }, [open, stocks]); // 실제 재고량 변경 핸들러 const handleQtyChange = useCallback((id: string, value: string) => { const numValue = value === '' ? 0 : parseFloat(value); if (isNaN(numValue)) return; setAuditItems((prev) => prev.map((item) => item.id === id ? { ...item, newActualQty: numValue } : item ) ); }, []); // 저장 const handleSubmit = async () => { // 변경된 항목만 필터링 const changedItems = auditItems.filter( (item) => item.actualQty !== item.newActualQty ); if (changedItems.length === 0) { toast.info('변경된 항목이 없습니다.'); return; } setIsSubmitting(true); try { const updates = changedItems.map((item) => ({ id: item.id, actualQty: item.newActualQty, })); const result = await updateStockAudit(updates); if (result.success) { toast.success(`${changedItems.length}개 항목의 재고가 업데이트되었습니다.`); onOpenChange(false); onComplete?.(); } else { toast.error(result.error || '재고 실사 저장에 실패했습니다.'); } } catch (error) { if (isNextRedirectError(error)) throw error; console.error('[StockAuditModal] handleSubmit error:', error); toast.error('재고 실사 저장 중 오류가 발생했습니다.'); } finally { setIsSubmitting(false); } }; // 취소 const handleCancel = () => { onOpenChange(false); }; return ( {/* 헤더 */} 재고 실사
{/* 테이블 */} {isLoading ? ( ) : auditItems.length === 0 ? (
품목코드 품목명 규격 단위 실제 재고량 재고 데이터가 없습니다.
) : (
품목코드 품목명 규격 단위 실제 재고량 {auditItems.map((item) => ( {item.itemCode} {item.itemName} {item.specification || '-'} {item.unit} handleQtyChange(item.id, e.target.value)} className="w-24 text-center mx-auto" min={0} step={1} /> ))}
)} {/* 버튼 영역 */}
); }