diff --git a/src/components/production/WorkOrders/SalesOrderSelectModal.tsx b/src/components/production/WorkOrders/SalesOrderSelectModal.tsx index 85abbe12..9820ad9c 100644 --- a/src/components/production/WorkOrders/SalesOrderSelectModal.tsx +++ b/src/components/production/WorkOrders/SalesOrderSelectModal.tsx @@ -19,6 +19,18 @@ import { toast } from 'sonner'; import { getSalesOrdersForWorkOrder } from './actions'; import type { SalesOrder } from './types'; +// Debounce 훅 +function useDebounce(value: T, delay: number): T { + const [debouncedValue, setDebouncedValue] = useState(value); + + useEffect(() => { + const timer = setTimeout(() => setDebouncedValue(value), delay); + return () => clearTimeout(timer); + }, [value, delay]); + + return debouncedValue; +} + interface SalesOrderSelectModalProps { open: boolean; onOpenChange: (open: boolean) => void; @@ -34,12 +46,15 @@ export function SalesOrderSelectModal({ const [salesOrders, setSalesOrders] = useState([]); const [isLoading, setIsLoading] = useState(false); + // 디바운스된 검색어 (300ms 딜레이) + const debouncedSearchTerm = useDebounce(searchTerm, 300); + // API로 수주 목록 로드 const loadSalesOrders = useCallback(async () => { setIsLoading(true); try { const result = await getSalesOrdersForWorkOrder({ - q: searchTerm || undefined, + q: debouncedSearchTerm || undefined, }); if (result.success) { // API 응답을 SalesOrder 타입으로 변환 @@ -63,7 +78,7 @@ export function SalesOrderSelectModal({ } finally { setIsLoading(false); } - }, [searchTerm]); + }, [debouncedSearchTerm]); // 모달이 열릴 때 데이터 로드 useEffect(() => { diff --git a/src/components/production/WorkOrders/WorkOrderDetail.tsx b/src/components/production/WorkOrders/WorkOrderDetail.tsx index c4edb024..e5e61db9 100644 --- a/src/components/production/WorkOrders/WorkOrderDetail.tsx +++ b/src/components/production/WorkOrders/WorkOrderDetail.tsx @@ -21,7 +21,7 @@ import { import { PageLayout } from '@/components/organisms/PageLayout'; import { WorkLogModal } from '../WorkerScreen/WorkLogModal'; import { toast } from 'sonner'; -import { getWorkOrderById } from './actions'; +import { getWorkOrderById, updateWorkOrderStatus } from './actions'; import { PROCESS_TYPE_LABELS, WORK_ORDER_STATUS_LABELS, @@ -191,6 +191,7 @@ export function WorkOrderDetail({ orderId }: WorkOrderDetailProps) { const [isWorkLogOpen, setIsWorkLogOpen] = useState(false); const [order, setOrder] = useState(null); const [isLoading, setIsLoading] = useState(true); + const [isStatusUpdating, setIsStatusUpdating] = useState(false); // API에서 데이터 로드 const loadData = useCallback(async () => { @@ -214,6 +215,32 @@ export function WorkOrderDetail({ orderId }: WorkOrderDetailProps) { loadData(); }, [loadData]); + // 상태 변경 핸들러 + const handleStatusChange = useCallback(async (newStatus: 'waiting' | 'in_progress' | 'completed') => { + if (!order) return; + + setIsStatusUpdating(true); + try { + const result = await updateWorkOrderStatus(orderId, newStatus); + if (result.success && result.data) { + setOrder(result.data); + const statusLabels = { + waiting: '작업대기', + in_progress: '작업중', + completed: '작업완료', + }; + toast.success(`상태가 '${statusLabels[newStatus]}'(으)로 변경되었습니다.`); + } else { + toast.error(result.error || '상태 변경에 실패했습니다.'); + } + } catch (error) { + console.error('[WorkOrderDetail] handleStatusChange error:', error); + toast.error('상태 변경 중 오류가 발생했습니다.'); + } finally { + setIsStatusUpdating(false); + } + }, [order, orderId]); + // 로딩 상태 if (isLoading) { return ( @@ -260,6 +287,35 @@ export function WorkOrderDetail({ orderId }: WorkOrderDetailProps) {

작업지시 상세

+ {/* 상태 변경 버튼 */} + {order.status === 'waiting' && ( + + )} + {order.status === 'in_progress' && ( + + )}