'use client'; /** * DevToolbar - 개발/테스트용 플로팅 툴바 * * 화면 하단에 플로팅으로 표시되며, * 각 단계(견적→수주→작업지시→완료→출하)의 폼을 자동으로 채울 수 있습니다. * * 기능: * - 현재 페이지에서 활성화: 버튼 클릭 시 폼 자동 채우기 * - 다른 페이지에서 비활성화: 버튼 클릭 시 해당 페이지로 이동 * * 환경변수로 활성화/비활성화: * NEXT_PUBLIC_DEV_TOOLBAR_ENABLED=true */ import { useState } from 'react'; import { usePathname, useRouter } from 'next/navigation'; import { FileText, // 견적 ClipboardList, // 수주 Wrench, // 작업지시 CheckCircle2, // 완료 Truck, // 출하 ChevronDown, ChevronUp, X, Loader2, Play, RotateCcw, // 회계 아이콘 ArrowDownToLine, // 입금 ArrowUpFromLine, // 출금 Receipt, // 매입(지출결의서) CreditCard, // 카드 } from 'lucide-react'; import { Button } from '@/components/ui/button'; import { Badge } from '@/components/ui/badge'; import { useDevFillContext, type DevFillPageType } from './DevFillContext'; // 페이지 경로와 타입 매핑 const PAGE_PATTERNS: { pattern: RegExp; type: DevFillPageType; label: string }[] = [ // 판매/생산 플로우 { pattern: /\/quote-management\/new/, type: 'quote', label: '견적' }, { pattern: /\/quote-management\/\d+\/edit/, type: 'quote', label: '견적' }, { pattern: /\/order-management-sales\/new/, type: 'order', label: '수주' }, { pattern: /\/order-management-sales\/\d+\/edit/, type: 'order', label: '수주' }, { pattern: /\/work-orders\/create/, type: 'workOrder', label: '작업지시' }, { pattern: /\/work-orders\/\d+\/edit/, type: 'workOrder', label: '작업지시' }, { pattern: /\/work-orders\/\d+$/, type: 'workOrderComplete', label: '작업완료' }, { pattern: /\/shipments\/new/, type: 'shipment', label: '출하' }, { pattern: /\/shipments\/\d+\/edit/, type: 'shipment', label: '출하' }, // 회계 플로우 { pattern: /\/accounting\/deposits\/new/, type: 'deposit', label: '입금' }, { pattern: /\/accounting\/withdrawals\/new/, type: 'withdrawal', label: '출금' }, { pattern: /\/approval\/draft\/new/, type: 'purchaseApproval', label: '매입' }, { pattern: /\/accounting\/card-transactions/, type: 'cardTransaction', label: '카드' }, ]; // 플로우 단계 정의 const FLOW_STEPS: { type: DevFillPageType; label: string; icon: typeof FileText; path: string }[] = [ { type: 'quote', label: '견적', icon: FileText, path: '/sales/quote-management/new' }, { type: 'order', label: '수주', icon: ClipboardList, path: '/sales/order-management-sales/new' }, { type: 'workOrder', label: '작업지시', icon: Wrench, path: '/production/work-orders/create' }, { type: 'workOrderComplete', label: '완료', icon: CheckCircle2, path: '' }, // 상세 페이지에서 처리 { type: 'shipment', label: '출하', icon: Truck, path: '/outbound/shipments/new' }, ]; // 회계 단계 정의 const ACCOUNTING_STEPS: { type: DevFillPageType; label: string; icon: typeof FileText; path: string; fillEnabled: boolean }[] = [ { type: 'deposit', label: '입금', icon: ArrowDownToLine, path: '/accounting/deposits/new', fillEnabled: true }, { type: 'withdrawal', label: '출금', icon: ArrowUpFromLine, path: '/accounting/withdrawals/new', fillEnabled: true }, { type: 'purchaseApproval', label: '매입', icon: Receipt, path: '/approval/draft/new', fillEnabled: true }, { type: 'cardTransaction', label: '카드', icon: CreditCard, path: '/accounting/card-transactions', fillEnabled: false }, // 이동만 ]; export function DevToolbar() { const pathname = usePathname(); const router = useRouter(); const { isEnabled, isVisible, setIsVisible, currentPage, fillForm, hasRegisteredForm, flowData, clearFlowData, } = useDevFillContext(); const [isExpanded, setIsExpanded] = useState(true); const [isLoading, setIsLoading] = useState(null); // 현재 locale 추출 (유효한 locale만 인식) const VALID_LOCALES = ['ko', 'en']; const firstSegment = pathname.split('/')[1]; const locale = VALID_LOCALES.includes(firstSegment) ? firstSegment : ''; // 비활성화 시 렌더링하지 않음 if (!isEnabled) return null; // 숨김 상태일 때 작은 버튼만 표시 if (!isVisible) { return (
); } // 현재 페이지 타입 감지 const detectedPage = PAGE_PATTERNS.find(p => p.pattern.test(pathname)); const activePage = detectedPage?.type || null; // 폼 채우기 실행 const handleFillForm = async (pageType: DevFillPageType) => { if (!hasRegisteredForm(pageType)) { console.warn(`[DevToolbar] Form not registered for: ${pageType}`); return; } setIsLoading(pageType); try { await fillForm(pageType, flowData); } catch (err) { console.error('[DevToolbar] Fill form error:', err); } finally { setIsLoading(null); } }; // 페이지 이동 const handleNavigate = (path: string) => { if (path) { router.push(locale ? `/${locale}${path}` : path); } }; // 플로우 데이터 표시 const hasFlowData = flowData.quoteId || flowData.orderId || flowData.workOrderId || flowData.lotNo; return (
{/* 헤더 */}
DEV MODE {detectedPage && ( 현재: {detectedPage.label} )} {hasFlowData && ( {flowData.quoteId && `견적#${flowData.quoteId}`} {flowData.orderId && ` → 수주#${flowData.orderId}`} {flowData.workOrderId && ` → 작업#${flowData.workOrderId}`} )}
{hasFlowData && ( )}
{/* 판매/생산 플로우 버튼 영역 */} {isExpanded && (
{FLOW_STEPS.map((step, index) => { const Icon = step.icon; const isActive = activePage === step.type; const isRegistered = hasRegisteredForm(step.type); const isCurrentLoading = isLoading === step.type; const hasPath = !!step.path; // 완료 버튼은 상세 페이지에서만 활성화 (이동 경로 없음) if (step.type === 'workOrderComplete' && !isActive) { return (
{index > 0 && }
); } // 활성화된 페이지: 폼 채우기 if (isActive) { return (
{index > 0 && }
); } // 비활성화된 페이지: 해당 페이지로 이동 return (
{index > 0 && }
); })}
)} {/* 회계 플로우 버튼 영역 */} {isExpanded && (
회계: {ACCOUNTING_STEPS.map((step) => { const Icon = step.icon; const isActive = activePage === step.type; const isRegistered = hasRegisteredForm(step.type); const isCurrentLoading = isLoading === step.type; // 활성화된 페이지: 폼 채우기 (fillEnabled가 true인 경우만) if (isActive && step.fillEnabled) { return ( ); } // 비활성화된 페이지 또는 이동만 가능한 버튼: 해당 페이지로 이동 return ( ); })}
)} {/* 안내 메시지 */} {isExpanded && !activePage && (

견적/수주/작업지시/출하/입금/출금/매입 페이지에서 자동 채우기가 활성화됩니다

)}
); } export default DevToolbar;