# OrderDetailForm.tsx 분리 계획서

**생성일**: 2026-01-05
**현재 파일 크기**: 1,273줄
**목표**: 유지보수성 향상을 위한 컴포넌트 분리

---

## 현재 파일 구조 분석

| 영역 | 라인 | 비율 | 내용 |
|------|------|------|------|
| Import & Types | 1-69 | 5% | 의존성 및 타입 import |
| Props Interface | 70-74 | 0.5% | 컴포넌트 props |
| State & Hooks | 76-113 | 3% | 상태 관리 (12개 useState) |
| Handlers | 114-433 | 25% | 핸들러 함수들 (20+개) |
| JSX Render | 435-1271 | 66% | UI 렌더링 |

### 주요 핸들러 분류 (114-433줄)
- **Navigation**: handleBack, handleEdit, handleCancel (114-125)
- **Form Field**: handleFieldChange (127-133)
- **CRUD Operations**: handleSave, handleDelete, handleDuplicate (135-199)
- **Category Operations**: handleAddCategory, handleDeleteCategory, handleCategoryChange (206-247)
- **Item Operations**: handleAddItems, handleDeleteSelectedItems, handleDeleteAllItems, handleItemChange (249-327)
- **Selection**: handleToggleSelection, handleToggleSelectAll (330-357)
- **Calendar**: handleCalendarDateClick, handleCalendarMonthChange (359-385)

### 주요 JSX 영역 (435-1271줄)
- **발주 정보 Card**: 447-559 (112줄)
- **계약 정보 Card**: 561-694 (133줄)
- **발주 스케줄 Calendar**: 696-715 (19줄)
- **발주 상세 테이블**: 717-1172 (455줄) ⚠️ **가장 큰 부분**
- **카테고리 추가 버튼**: 1174-1182 (8줄)
- **비고 Card**: 1184-1198 (14줄)
- **Dialogs**: 1201-1261 (60줄)
- **Document Modal**: 1263-1270 (7줄)

---

## 분리 계획

### Phase 1: 커스텀 훅 분리

**파일**: `hooks/useOrderDetailForm.ts`
**예상 크기**: ~250줄

```typescript
// 추출할 내용
- formData 상태 관리
- selectedItems, addCounts, categoryFilters 상태
- calendarDate, selectedCalendarDate 상태
- 모든 핸들러 함수들
- calendarEvents useMemo
```

**장점**:
- 비즈니스 로직과 UI 분리
- 테스트 용이성 향상
- 재사용 가능

---

### Phase 2: 카드 컴포넌트 분리

#### 2-1. `cards/OrderInfoCard.tsx`
**예상 크기**: ~120줄

```typescript
interface OrderInfoCardProps {
  formData: OrderDetailFormData;
  isViewMode: boolean;
  onFieldChange: (field: keyof OrderDetailFormData, value: any) => void;
}
```

**포함 내용**: 발주번호, 발주일, 구분, 상태, 발주담당자, 화물도착지

---

#### 2-2. `cards/ContractInfoCard.tsx`
**예상 크기**: ~150줄

```typescript
interface ContractInfoCardProps {
  formData: OrderDetailFormData;
  isViewMode: boolean;
  isEditMode: boolean;
  onFieldChange: (field: keyof OrderDetailFormData, value: any) => void;
}
```

**포함 내용**: 거래처명, 현장명, 계약번호, 공사PM, 공사담당자

---

#### 2-3. `cards/OrderScheduleCard.tsx`
**예상 크기**: ~50줄

```typescript
interface OrderScheduleCardProps {
  events: ScheduleEvent[];
  currentDate: Date;
  selectedDate: Date | null;
  onDateClick: (date: Date) => void;
  onMonthChange: (date: Date) => void;
}
```

**포함 내용**: ScheduleCalendar 래핑

---

#### 2-4. `cards/OrderMemoCard.tsx`
**예상 크기**: ~40줄

```typescript
interface OrderMemoCardProps {
  memo: string;
  isViewMode: boolean;
  onMemoChange: (value: string) => void;
}
```

**포함 내용**: 비고 Textarea

---

### Phase 3: 테이블 컴포넌트 분리 (가장 중요)

#### 3-1. `tables/OrderDetailItemTable.tsx`
**예상 크기**: ~350줄

```typescript
interface OrderDetailItemTableProps {
  category: OrderDetailCategory;
  isEditMode: boolean;
  isViewMode: boolean;
  selectedItems: Set<string>;
  addCount: number;
  onAddCountChange: (count: number) => void;
  onAddItems: (count: number) => void;
  onDeleteSelectedItems: () => void;
  onDeleteAllItems: () => void;
  onCategoryChange: (field: keyof OrderDetailCategory, value: string) => void;
  onItemChange: (itemId: string, field: keyof OrderDetailItem, value: any) => void;
  onToggleSelection: (itemId: string) => void;
  onToggleSelectAll: () => void;
}
```

**포함 내용**:
- 카드 헤더 (왼쪽: 발주 상세/N건 선택/삭제, 오른쪽: 숫자/추가/카테고리/🗑️)
- 테이블 전체 (TableHeader + TableBody)
- 합계 행

---

#### 3-2. `tables/OrderDetailItemRow.tsx` (선택적)
**예상 크기**: ~150줄

```typescript
interface OrderDetailItemRowProps {
  item: OrderDetailItem;
  index: number;
  isEditMode: boolean;
  isSelected: boolean;
  onItemChange: (field: keyof OrderDetailItem, value: any) => void;
  onToggleSelection: () => void;
}
```

**포함 내용**: 단일 테이블 행 렌더링

---

### Phase 4: 다이얼로그 분리

#### 4-1. `dialogs/OrderDialogs.tsx`
**예상 크기**: ~80줄

```typescript
interface OrderDialogsProps {
  // 저장 다이얼로그
  showSaveDialog: boolean;
  onSaveDialogChange: (open: boolean) => void;
  onConfirmSave: () => void;
  // 삭제 다이얼로그
  showDeleteDialog: boolean;
  onDeleteDialogChange: (open: boolean) => void;
  onConfirmDelete: () => void;
  // 카테고리 삭제 다이얼로그
  showCategoryDeleteDialog: string | null;
  onCategoryDeleteDialogChange: (categoryId: string | null) => void;
  onConfirmDeleteCategory: () => void;
  // 공통
  isLoading: boolean;
}
```

---

## 분리 후 예상 구조

```
src/components/business/juil/order-management/
├── OrderDetailForm.tsx         (~200줄, 메인 컴포넌트)
├── hooks/
│   └── useOrderDetailForm.ts   (~250줄, 비즈니스 로직)
├── cards/
│   ├── OrderInfoCard.tsx       (~120줄)
│   ├── ContractInfoCard.tsx    (~150줄)
│   ├── OrderScheduleCard.tsx   (~50줄)
│   └── OrderMemoCard.tsx       (~40줄)
├── tables/
│   ├── OrderDetailItemTable.tsx (~350줄)
│   └── OrderDetailItemRow.tsx   (~150줄, 선택적)
├── dialogs/
│   └── OrderDialogs.tsx        (~80줄)
├── modals/
│   └── OrderDocumentModal.tsx  (기존)
├── actions.ts                   (기존)
└── types.ts                     (기존)
```

---

## 분리 전후 비교

| 지표 | Before | After |
|------|--------|-------|
| 메인 파일 크기 | 1,273줄 | ~200줄 |
| 가장 큰 파일 | 1,273줄 | ~350줄 |
| 파일 개수 | 1 | 8-9 |
| 테스트 용이성 | 낮음 | 높음 |
| 재사용성 | 낮음 | 중간 |

---

## 실행 체크리스트

### Phase 1: 커스텀 훅 분리
- [ ] `hooks/useOrderDetailForm.ts` 생성
- [ ] 상태 변수들 이동
- [ ] 핸들러 함수들 이동
- [ ] useMemo 이동
- [ ] OrderDetailForm.tsx에서 훅 사용

### Phase 2: 카드 컴포넌트 분리
- [ ] `cards/OrderInfoCard.tsx` 생성
- [ ] `cards/ContractInfoCard.tsx` 생성
- [ ] `cards/OrderScheduleCard.tsx` 생성
- [ ] `cards/OrderMemoCard.tsx` 생성
- [ ] OrderDetailForm.tsx에서 import 및 사용

### Phase 3: 테이블 컴포넌트 분리
- [ ] `tables/OrderDetailItemTable.tsx` 생성
- [ ] `tables/OrderDetailItemRow.tsx` 생성 (선택적)
- [ ] OrderDetailForm.tsx에서 import 및 사용

### Phase 4: 다이얼로그 분리
- [ ] `dialogs/OrderDialogs.tsx` 생성
- [ ] OrderDetailForm.tsx에서 import 및 사용

### Phase 5: 최종 검증
- [ ] TypeScript 타입 오류 없음
- [ ] ESLint 경고 없음
- [ ] 빌드 성공
- [ ] 기능 테스트 (view/edit 모드)
- [ ] 불필요한 import 제거

---

## 우선순위 권장

1. **Phase 1 (Hook)** + **Phase 3 (Table)** 먼저 진행
   - 가장 큰 효과 (전체 코드의 ~60% 분리)
   - 테이블이 455줄로 가장 큼

2. Phase 2 (Cards) 진행
   - 추가 ~360줄 분리

3. Phase 4 (Dialogs) 진행
   - 마무리 정리

---

## 주의사항

- **타입 export**: 새 컴포넌트에서 사용할 타입들 types.ts에서 export 확인
- **props drilling**: 너무 깊어지면 Context 고려
- **테스트**: 분리 후 view/edit 모드 모두 테스트 필수
- **점진적 진행**: 한 번에 모든 분리보다 단계별 진행 권장
