'use client'; /** * 수주 선택 모달 * * 기획서 기반 신규 생성: * - 검색 입력 * - 체크박스 테이블 (수주번호, 현장명, 납품일, 개소) * - 취소/선택 버튼 */ import { useState, useCallback, useEffect } from 'react'; import { Search, Loader2 } from 'lucide-react'; import { Button } from '@/components/ui/button'; import { Input } from '@/components/ui/input'; import { Checkbox } from '@/components/ui/checkbox'; import { Dialog, DialogContent, DialogFooter, DialogHeader, DialogTitle, } from '@/components/ui/dialog'; import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow, } from '@/components/ui/table'; import { toast } from 'sonner'; import { getOrderSelectList } from './actions'; import { isNextRedirectError } from '@/lib/utils/redirect-error'; import type { OrderSelectItem } from './types'; interface OrderSelectModalProps { open: boolean; onOpenChange: (open: boolean) => void; onSelect: (items: OrderSelectItem[]) => void; /** 이미 선택된 항목 ID 목록 (중복 선택 방지) */ excludeIds?: string[]; } export function OrderSelectModal({ open, onOpenChange, onSelect, excludeIds = [], }: OrderSelectModalProps) { const [searchTerm, setSearchTerm] = useState(''); const [items, setItems] = useState([]); const [isLoading, setIsLoading] = useState(false); const [selectedIds, setSelectedIds] = useState>(new Set()); // 데이터 로드 const loadItems = useCallback(async (q?: string) => { setIsLoading(true); try { const result = await getOrderSelectList({ q: q || undefined }); if (result.success) { // 이미 선택된 항목 제외 const filtered = result.data.filter((item) => !excludeIds.includes(item.id)); setItems(filtered); } else { toast.error(result.error || '수주 목록을 불러오는데 실패했습니다.'); } } catch (error) { if (isNextRedirectError(error)) throw error; console.error('[OrderSelectModal] loadItems error:', error); toast.error('수주 목록 로드 중 오류가 발생했습니다.'); } finally { setIsLoading(false); } }, [excludeIds]); // 모달 열릴 때 데이터 로드 & 상태 초기화 useEffect(() => { if (open) { setSearchTerm(''); setSelectedIds(new Set()); loadItems(); } }, [open, loadItems]); // 검색 const handleSearch = useCallback(() => { loadItems(searchTerm); }, [searchTerm, loadItems]); const handleSearchKeyDown = useCallback((e: React.KeyboardEvent) => { if (e.key === 'Enter') { handleSearch(); } }, [handleSearch]); // 체크박스 토글 const handleToggle = useCallback((id: string) => { setSelectedIds((prev) => { const next = new Set(prev); if (next.has(id)) { next.delete(id); } else { next.add(id); } return next; }); }, []); // 전체 선택/해제 const handleToggleAll = useCallback(() => { setSelectedIds((prev) => { if (prev.size === items.length) { return new Set(); } return new Set(items.map((item) => item.id)); }); }, [items]); // 선택 확인 const handleConfirm = useCallback(() => { const selectedItems = items.filter((item) => selectedIds.has(item.id)); onSelect(selectedItems); onOpenChange(false); }, [items, selectedIds, onSelect, onOpenChange]); const isAllSelected = items.length > 0 && selectedIds.size === items.length; return ( 수주 선택 {/* 검색 */}
setSearchTerm(e.target.value)} onKeyDown={handleSearchKeyDown} placeholder="수주번호, 현장명 검색..." className="pl-9" />
{/* 테이블 */}
{isLoading ? (
) : ( 수주번호 현장명 납품일 개소 {items.map((item) => ( handleToggle(item.id)} > e.stopPropagation()}> handleToggle(item.id)} /> {item.orderNumber} {item.siteName} {item.deliveryDate} {item.locationCount} ))} {items.length === 0 && ( {searchTerm ? '검색 결과가 없습니다.' : '수주 데이터가 없습니다.'} )}
)}
); }