import React, { useState } from 'react'; import { exportMaterialsToExcel } from '../../../utils/excelExport'; import api from '../../../api'; import { FilterableHeader } from '../shared'; const ValveMaterialsView = ({ materials, selectedMaterials, setSelectedMaterials, userRequirements, setUserRequirements, purchasedMaterials, fileId, user }) => { const [sortConfig, setSortConfig] = useState({ key: null, direction: 'asc' }); const [columnFilters, setColumnFilters] = useState({}); const [showFilterDropdown, setShowFilterDropdown] = useState(null); const parseValveInfo = (material) => { const valveDetails = material.valve_details || {}; const description = material.original_description || ''; // 밸브 타입 파싱 (GATE, BALL, CHECK, GLOBE 등) - 기존 NewMaterialsPage와 동일 let valveType = valveDetails.valve_type || ''; if (!valveType && description) { if (description.includes('GATE')) valveType = 'GATE'; else if (description.includes('BALL')) valveType = 'BALL'; else if (description.includes('CHECK')) valveType = 'CHECK'; else if (description.includes('GLOBE')) valveType = 'GLOBE'; else if (description.includes('BUTTERFLY')) valveType = 'BUTTERFLY'; else if (description.includes('NEEDLE')) valveType = 'NEEDLE'; else if (description.includes('RELIEF')) valveType = 'RELIEF'; } // 연결 방식 파싱 (FLG, SW, THRD 등) - 기존 NewMaterialsPage와 동일 let connectionType = ''; if (description.includes('FLG')) { connectionType = 'FLG'; } else if (description.includes('SW X THRD')) { connectionType = 'SW×THRD'; } else if (description.includes('SW')) { connectionType = 'SW'; } else if (description.includes('THRD')) { connectionType = 'THRD'; } else if (description.includes('BW')) { connectionType = 'BW'; } // 압력 등급 파싱 let pressure = '-'; const pressureMatch = description.match(/(\d+)LB/i); if (pressureMatch) { pressure = `${pressureMatch[1]}LB`; } // 스케줄은 밸브에는 일반적으로 없음 (기본값) let schedule = '-'; return { type: 'VALVE', subtype: `${valveType} ${connectionType}`.trim() || 'VALVE', // 타입과 연결방식 결합 valveType: valveType, connectionType: connectionType, size: material.size_spec || '-', pressure: pressure, schedule: schedule, grade: material.material_grade || '-', quantity: Math.round(material.quantity || 0), unit: '개', isValve: true }; }; // 정렬 처리 const handleSort = (key) => { let direction = 'asc'; if (sortConfig.key === key && sortConfig.direction === 'asc') { direction = 'desc'; } setSortConfig({ key, direction }); }; // 필터링된 및 정렬된 자재 목록 const getFilteredAndSortedMaterials = () => { let filtered = materials.filter(material => { return Object.entries(columnFilters).every(([key, filterValue]) => { if (!filterValue) return true; const info = parseValveInfo(material); const value = info[key]?.toString().toLowerCase() || ''; return value.includes(filterValue.toLowerCase()); }); }); if (sortConfig.key) { filtered.sort((a, b) => { const aInfo = parseValveInfo(a); const bInfo = parseValveInfo(b); const aValue = aInfo[sortConfig.key] || ''; const bValue = bInfo[sortConfig.key] || ''; if (sortConfig.direction === 'asc') { return aValue > bValue ? 1 : -1; } else { return aValue < bValue ? 1 : -1; } }); } return filtered; }; // 전체 선택/해제 (구매신청된 자재 제외) const handleSelectAll = () => { const filteredMaterials = getFilteredAndSortedMaterials(); const selectableMaterials = filteredMaterials.filter(m => !purchasedMaterials.has(m.id)); if (selectedMaterials.size === selectableMaterials.length) { setSelectedMaterials(new Set()); } else { setSelectedMaterials(new Set(selectableMaterials.map(m => m.id))); } }; // 개별 선택 (구매신청된 자재는 선택 불가) const handleMaterialSelect = (materialId) => { if (purchasedMaterials.has(materialId)) { return; // 구매신청된 자재는 선택 불가 } const newSelected = new Set(selectedMaterials); if (newSelected.has(materialId)) { newSelected.delete(materialId); } else { newSelected.add(materialId); } setSelectedMaterials(newSelected); }; // 엑셀 내보내기 const handleExportToExcel = async () => { const selectedMaterialsData = materials.filter(m => selectedMaterials.has(m.id)); if (selectedMaterialsData.length === 0) { alert('내보낼 자재를 선택해주세요.'); return; } const timestamp = new Date().toISOString().slice(0, 19).replace(/:/g, '-'); const excelFileName = `VALVE_Materials_${timestamp}.xlsx`; const dataWithRequirements = selectedMaterialsData.map(material => ({ ...material, user_requirement: userRequirements[material.id] || '' })); try { await api.post('/files/save-excel', { file_id: fileId, category: 'VALVE', materials: dataWithRequirements, filename: excelFileName, user_id: user?.id }); exportMaterialsToExcel(dataWithRequirements, excelFileName, { category: 'VALVE', filename: excelFileName, uploadDate: new Date().toLocaleDateString() }); alert('엑셀 파일이 생성되고 서버에 저장되었습니다.'); } catch (error) { console.error('엑셀 저장 실패:', error); exportMaterialsToExcel(dataWithRequirements, excelFileName, { category: 'VALVE', filename: excelFileName, uploadDate: new Date().toLocaleDateString() }); } }; const filteredMaterials = getFilteredAndSortedMaterials(); return (
{/* 헤더 */}

Valve Materials

{filteredMaterials.length} items • {selectedMaterials.size} selected

{/* 테이블 */}
{/* 헤더 */}
{ const selectableMaterials = filteredMaterials.filter(m => !purchasedMaterials.has(m.id)); return selectedMaterials.size === selectableMaterials.length && selectableMaterials.length > 0; })()} onChange={handleSelectAll} style={{ cursor: 'pointer' }} />
Type Size Pressure Schedule Material Grade Quantity
Unit
User Requirement
{/* 데이터 행들 */}
{filteredMaterials.map((material, index) => { const info = parseValveInfo(material); const isSelected = selectedMaterials.has(material.id); const isPurchased = purchasedMaterials.has(material.id); return (
{ if (!isSelected && !isPurchased) { e.target.style.background = '#f8fafc'; } }} onMouseLeave={(e) => { if (!isSelected && !isPurchased) { e.target.style.background = 'white'; } }} >
handleMaterialSelect(material.id)} disabled={isPurchased} style={{ cursor: isPurchased ? 'not-allowed' : 'pointer', opacity: isPurchased ? 0.5 : 1 }} />
{info.subtype} {isPurchased && ( PURCHASED )}
{info.size}
{info.pressure}
{info.schedule}
{info.grade}
{info.quantity}
{info.unit}
setUserRequirements({ ...userRequirements, [material.id]: e.target.value })} placeholder="Enter requirement..." style={{ width: '100%', padding: '6px 8px', border: '1px solid #d1d5db', borderRadius: '4px', fontSize: '12px' }} />
); })}
{filteredMaterials.length === 0 && (
No Valve Materials Found
{Object.keys(columnFilters).some(key => columnFilters[key]) ? 'Try adjusting your filters' : 'No valve materials available in this BOM'}
)}
); }; export default ValveMaterialsView;