"use client"; import { useState, useCallback } from "react"; import { apiClient } from "@/lib/api/client"; import { ProcessWorkStandardConfig, ItemData, RoutingVersion, WorkItem, WorkItemDetail, SelectionState, } from "../types"; const API_BASE = "/process-work-standard"; export function useProcessWorkStandard(config: ProcessWorkStandardConfig) { const [items, setItems] = useState([]); const [routings, setRoutings] = useState([]); const [workItems, setWorkItems] = useState([]); // 섹션(phase)별 독립적인 선택 상태 관리 const [selectedWorkItemIdByPhase, setSelectedWorkItemIdByPhase] = useState>({}); const [selectedDetailsByPhase, setSelectedDetailsByPhase] = useState>({}); const [loading, setLoading] = useState(false); const [saving, setSaving] = useState(false); const [selection, setSelection] = useState({ itemCode: null, itemName: null, routingVersionId: null, routingVersionName: null, routingDetailId: null, processName: null, }); // 품목 목록 조회 const fetchItems = useCallback( async (search?: string) => { try { setLoading(true); const ds = config.dataSource; const params = new URLSearchParams({ tableName: ds.itemTable, nameColumn: ds.itemNameColumn, codeColumn: ds.itemCodeColumn, routingTable: ds.routingVersionTable, routingFkColumn: ds.routingFkColumn, ...(search ? { search } : {}), }); const res = await apiClient.get(`${API_BASE}/items?${params}`); if (res.data?.success) { setItems(res.data.data); } } catch (err) { console.error("품목 조회 실패", err); } finally { setLoading(false); } }, [config.dataSource] ); // 라우팅 + 공정 조회 const fetchRoutings = useCallback( async (itemCode: string) => { try { const ds = config.dataSource; const params = new URLSearchParams({ routingVersionTable: ds.routingVersionTable, routingDetailTable: ds.routingDetailTable, routingFkColumn: ds.routingFkColumn, processTable: ds.processTable, processNameColumn: ds.processNameColumn, processCodeColumn: ds.processCodeColumn, }); const res = await apiClient.get( `${API_BASE}/items/${encodeURIComponent(itemCode)}/routings?${params}` ); if (res.data?.success) { setRoutings(res.data.data); } } catch (err) { console.error("라우팅 조회 실패", err); } }, [config.dataSource] ); // 작업 항목 조회 const fetchWorkItems = useCallback(async (routingDetailId: string) => { try { setLoading(true); const res = await apiClient.get( `${API_BASE}/routing-detail/${routingDetailId}/work-items` ); if (res.data?.success) { setWorkItems(res.data.items || []); } } catch (err) { console.error("작업 항목 조회 실패", err); } finally { setLoading(false); } }, []); // 작업 항목 상세 조회 (phase별 독립 저장) const fetchWorkItemDetails = useCallback(async (workItemId: string, phaseKey: string) => { try { const res = await apiClient.get( `${API_BASE}/work-items/${workItemId}/details` ); if (res.data?.success) { setSelectedDetailsByPhase(prev => ({ ...prev, [phaseKey]: res.data.data })); setSelectedWorkItemIdByPhase(prev => ({ ...prev, [phaseKey]: workItemId })); } } catch (err) { console.error("상세 조회 실패", err); } }, []); // 품목 선택 const selectItem = useCallback( async (itemCode: string, itemName: string) => { setSelection((prev) => ({ ...prev, itemCode, itemName, routingVersionId: null, routingVersionName: null, routingDetailId: null, processName: null, })); setWorkItems([]); setSelectedDetailsByPhase({}); setSelectedWorkItemIdByPhase({}); await fetchRoutings(itemCode); }, [fetchRoutings] ); // 공정 선택 const selectProcess = useCallback( async ( routingDetailId: string, processName: string, routingVersionId: string, routingVersionName: string ) => { setSelection((prev) => ({ ...prev, routingVersionId, routingVersionName, routingDetailId, processName, })); setSelectedDetailsByPhase({}); setSelectedWorkItemIdByPhase({}); await fetchWorkItems(routingDetailId); }, [fetchWorkItems] ); // 작업 항목 추가 const createWorkItem = useCallback( async (data: { work_phase: string; title: string; is_required: string; description?: string; details?: Array<{ detail_type?: string; content: string; is_required: string; sort_order: number; }>; }) => { if (!selection.routingDetailId) return null; try { const nextOrder = workItems.filter((wi) => wi.work_phase === data.work_phase).length + 1; const res = await apiClient.post(`${API_BASE}/work-items`, { routing_detail_id: selection.routingDetailId, work_phase: data.work_phase, title: data.title, is_required: data.is_required, sort_order: nextOrder, description: data.description, }); if (res.data?.success && res.data.data) { const newItem = res.data.data; // 상세 항목도 함께 생성 if (data.details && data.details.length > 0) { for (const detail of data.details) { await apiClient.post(`${API_BASE}/work-item-details`, { work_item_id: newItem.id, ...detail, }); } } await fetchWorkItems(selection.routingDetailId); return newItem; } } catch (err) { console.error("작업 항목 생성 실패", err); } return null; }, [selection.routingDetailId, workItems, fetchWorkItems] ); // 작업 항목 수정 const updateWorkItem = useCallback( async (id: string, data: Partial) => { try { const res = await apiClient.put(`${API_BASE}/work-items/${id}`, data); if (res.data?.success && selection.routingDetailId) { await fetchWorkItems(selection.routingDetailId); } } catch (err) { console.error("작업 항목 수정 실패", err); } }, [selection.routingDetailId, fetchWorkItems] ); // 작업 항목 삭제 const deleteWorkItem = useCallback( async (id: string) => { try { const res = await apiClient.delete(`${API_BASE}/work-items/${id}`); if (res.data?.success && selection.routingDetailId) { await fetchWorkItems(selection.routingDetailId); // 삭제된 항목이 선택되어 있던 phase의 선택 상태 초기화 setSelectedWorkItemIdByPhase(prev => { const next = { ...prev }; for (const phaseKey of Object.keys(next)) { if (next[phaseKey] === id) { next[phaseKey] = null; } } return next; }); setSelectedDetailsByPhase(prev => { const next = { ...prev }; for (const phaseKey of Object.keys(next)) { if (selectedWorkItemIdByPhase[phaseKey] === id) { next[phaseKey] = []; } } return next; }); } } catch (err) { console.error("작업 항목 삭제 실패", err); } }, [selection.routingDetailId, selectedWorkItemIdByPhase, fetchWorkItems] ); // 상세 추가 const createDetail = useCallback( async (workItemId: string, data: Partial, phaseKey: string) => { try { const res = await apiClient.post(`${API_BASE}/work-item-details`, { work_item_id: workItemId, ...data, }); if (res.data?.success) { await fetchWorkItemDetails(workItemId, phaseKey); if (selection.routingDetailId) { await fetchWorkItems(selection.routingDetailId); } } } catch (err) { console.error("상세 생성 실패", err); } }, [fetchWorkItemDetails, fetchWorkItems, selection.routingDetailId] ); // 상세 수정 const updateDetail = useCallback( async (id: string, data: Partial, phaseKey: string) => { try { const res = await apiClient.put( `${API_BASE}/work-item-details/${id}`, data ); if (res.data?.success) { const workItemId = selectedWorkItemIdByPhase[phaseKey]; if (workItemId) { await fetchWorkItemDetails(workItemId, phaseKey); } } } catch (err) { console.error("상세 수정 실패", err); } }, [selectedWorkItemIdByPhase, fetchWorkItemDetails] ); // 상세 삭제 const deleteDetail = useCallback( async (id: string, phaseKey: string) => { try { const res = await apiClient.delete( `${API_BASE}/work-item-details/${id}` ); if (res.data?.success) { const workItemId = selectedWorkItemIdByPhase[phaseKey]; if (workItemId) { await fetchWorkItemDetails(workItemId, phaseKey); } if (selection.routingDetailId) { await fetchWorkItems(selection.routingDetailId); } } } catch (err) { console.error("상세 삭제 실패", err); } }, [ selectedWorkItemIdByPhase, selection.routingDetailId, fetchWorkItemDetails, fetchWorkItems, ] ); return { items, routings, workItems, selectedWorkItemIdByPhase, selectedDetailsByPhase, selection, loading, saving, fetchItems, selectItem, selectProcess, fetchWorkItems, fetchWorkItemDetails, createWorkItem, updateWorkItem, deleteWorkItem, createDetail, updateDetail, deleteDetail, }; }