refactor: 리스트 컴포넌트 UI 및 레이아웃 일관성 개선
- 여러 관리 페이지(영업, 회계, 인사, 결재, 게시판, 설정)의 리스트 UI 통일 - IntegratedListTemplateV2 기반 레이아웃 정리 - PricingHistoryDialog 개선 - 공통 컴포넌트 추출 계획 문서 추가 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,435 @@
|
||||
# 공통 컴포넌트 추출 계획서
|
||||
|
||||
> MVP 완료 후 리팩토링 계획 (2025-12-23)
|
||||
|
||||
## 개요
|
||||
|
||||
| 항목 | 수치 |
|
||||
|-----|------|
|
||||
| 예상 코드 절감 | ~1,900줄 |
|
||||
| 영향 파일 | 50+ 개 |
|
||||
| 유지보수 비용 감소 | 30-40% |
|
||||
| 예상 작업 기간 | 3-4일 |
|
||||
|
||||
---
|
||||
|
||||
## 현재 공통화 현황
|
||||
|
||||
### ✅ 잘 되어있는 것
|
||||
- `SearchFilter` - 검색 입력 + 필터
|
||||
- `TabFilter` - 탭 형태 필터
|
||||
- `DateRangeSelector` - 날짜 범위 선택
|
||||
- `TableActions` - 테이블 행 액션 버튼
|
||||
- `FormActions` - 폼 저장/취소 버튼
|
||||
- `FormField` - 개별 폼 필드
|
||||
- `StatCards` - 통계 카드
|
||||
- `StandardDialog` - 기본 다이얼로그 (but 사용률 저조)
|
||||
|
||||
### ❌ 공통화 필요한 것
|
||||
- 삭제 확인 다이얼로그 (40+ 파일 중복)
|
||||
- 금액 포맷 유틸 (30+ 파일 중복)
|
||||
- 상태 배지 + 색상 상수 (10+ 파일 중복)
|
||||
- 상세정보 카드 (15+ 파일 각자 구현)
|
||||
- 폼 레이아웃 템플릿 (20+ 파일 중복)
|
||||
|
||||
---
|
||||
|
||||
## Phase 1: 핵심 컴포넌트 (1일)
|
||||
|
||||
### 1.1 DeleteDialog 컴포넌트
|
||||
|
||||
**위치**: `src/components/molecules/DeleteDialog.tsx`
|
||||
|
||||
**Props 설계**:
|
||||
```typescript
|
||||
interface DeleteDialogProps {
|
||||
open: boolean;
|
||||
onOpenChange: (open: boolean) => void;
|
||||
itemName?: string; // "거래처", "품목" 등
|
||||
itemLabel?: string; // 삭제 대상 이름 (예: "삼성전자")
|
||||
title?: string; // 커스텀 타이틀
|
||||
description?: string; // 커스텀 설명
|
||||
onConfirm: () => void;
|
||||
isLoading?: boolean;
|
||||
confirmText?: string; // 기본값: "삭제"
|
||||
cancelText?: string; // 기본값: "취소"
|
||||
}
|
||||
```
|
||||
|
||||
**사용 예시**:
|
||||
```typescript
|
||||
<DeleteDialog
|
||||
open={showDeleteDialog}
|
||||
onOpenChange={setShowDeleteDialog}
|
||||
itemName="거래처"
|
||||
itemLabel={selectedVendor?.name}
|
||||
onConfirm={handleDelete}
|
||||
isLoading={isDeleting}
|
||||
/>
|
||||
```
|
||||
|
||||
**체크리스트**:
|
||||
- [ ] DeleteDialog 컴포넌트 생성
|
||||
- [ ] 기본 스타일 (빨간색 삭제 버튼)
|
||||
- [ ] isLoading 상태 처리
|
||||
- [ ] 접근성 (포커스 트랩, ESC 닫기)
|
||||
- [ ] molecules/index.ts export 추가
|
||||
|
||||
**적용 대상 파일** (40+ 파일):
|
||||
- [ ] `accounting/VendorManagement/index.tsx`
|
||||
- [ ] `accounting/BillManagement/index.tsx`
|
||||
- [ ] `accounting/SalesManagement/index.tsx`
|
||||
- [ ] `accounting/PurchaseManagement/index.tsx`
|
||||
- [ ] `accounting/DepositManagement/index.tsx`
|
||||
- [ ] `accounting/WithdrawalManagement/index.tsx`
|
||||
- [ ] `hr/EmployeeManagement/index.tsx`
|
||||
- [ ] `hr/DepartmentManagement/index.tsx`
|
||||
- [ ] `hr/VacationManagement/index.tsx`
|
||||
- [ ] `settings/RankManagement/index.tsx`
|
||||
- [ ] `settings/TitleManagement/index.tsx`
|
||||
- [ ] `settings/PermissionManagement/index.tsx`
|
||||
- [ ] `settings/AccountManagement/index.tsx`
|
||||
- [ ] `board/BoardManagement/index.tsx`
|
||||
- [ ] `items/ItemListClient.tsx`
|
||||
- [ ] (나머지 25+ 파일은 grep으로 검색)
|
||||
|
||||
---
|
||||
|
||||
### 1.2 포맷 유틸 함수
|
||||
|
||||
**위치**: `src/lib/formatters.ts`
|
||||
|
||||
**함수 설계**:
|
||||
```typescript
|
||||
// 금액 포맷
|
||||
export function formatCurrency(amount: number): string;
|
||||
export function formatCurrencyWithSign(amount: number): string; // +/- 표시
|
||||
|
||||
// 금액 셀 (조건부 표시)
|
||||
export function formatCurrencyOrDash(amount: number, dash?: string): string;
|
||||
|
||||
// 날짜 포맷
|
||||
export function formatDate(date: string | Date, format?: string): string;
|
||||
export function formatDateTime(date: string | Date): string;
|
||||
|
||||
// 숫자 포맷
|
||||
export function formatNumber(num: number): string;
|
||||
export function formatPercent(num: number, decimals?: number): string;
|
||||
|
||||
// 전화번호 포맷
|
||||
export function formatPhone(phone: string): string;
|
||||
|
||||
// 사업자번호 포맷
|
||||
export function formatBizNo(bizNo: string): string;
|
||||
```
|
||||
|
||||
**사용 예시**:
|
||||
```typescript
|
||||
formatCurrency(10000) // "10,000원"
|
||||
formatCurrencyOrDash(0) // "-"
|
||||
formatCurrencyWithSign(-5000) // "-5,000원"
|
||||
formatDate('2024-01-15') // "2024-01-15"
|
||||
formatPhone('01012345678') // "010-1234-5678"
|
||||
formatBizNo('1234567890') // "123-45-67890"
|
||||
```
|
||||
|
||||
**체크리스트**:
|
||||
- [ ] formatters.ts 파일 생성
|
||||
- [ ] formatCurrency 함수
|
||||
- [ ] formatCurrencyOrDash 함수
|
||||
- [ ] formatCurrencyWithSign 함수
|
||||
- [ ] formatDate 함수
|
||||
- [ ] formatDateTime 함수
|
||||
- [ ] formatNumber 함수
|
||||
- [ ] formatPercent 함수
|
||||
- [ ] formatPhone 함수
|
||||
- [ ] formatBizNo 함수
|
||||
- [ ] 단위 테스트 (선택)
|
||||
|
||||
**적용 대상 파일** (30+ 파일):
|
||||
- [ ] 모든 accounting/* 컴포넌트
|
||||
- [ ] 모든 테이블에서 금액 표시하는 곳
|
||||
|
||||
---
|
||||
|
||||
## Phase 2: 상태 표시 컴포넌트 (1일)
|
||||
|
||||
### 2.1 상태 색상 중앙화
|
||||
|
||||
**위치**: `src/lib/status-colors.ts`
|
||||
|
||||
**설계**:
|
||||
```typescript
|
||||
// 공통 상태 색상
|
||||
export const STATUS_COLORS = {
|
||||
// 일반 상태
|
||||
active: 'bg-green-100 text-green-800',
|
||||
inactive: 'bg-gray-100 text-gray-800',
|
||||
pending: 'bg-yellow-100 text-yellow-800',
|
||||
completed: 'bg-blue-100 text-blue-800',
|
||||
cancelled: 'bg-red-100 text-red-800',
|
||||
|
||||
// 결제/금융 상태
|
||||
paid: 'bg-green-100 text-green-800',
|
||||
unpaid: 'bg-red-100 text-red-800',
|
||||
partial: 'bg-orange-100 text-orange-800',
|
||||
overdue: 'bg-red-100 text-red-800',
|
||||
|
||||
// 기본값
|
||||
default: 'bg-gray-100 text-gray-800',
|
||||
} as const;
|
||||
|
||||
// 도메인별 상태 색상
|
||||
export const BILL_STATUS_COLORS = { ... };
|
||||
export const VENDOR_CATEGORY_COLORS = { ... };
|
||||
export const ORDER_STATUS_COLORS = { ... };
|
||||
export const INSPECTION_STATUS_COLORS = { ... };
|
||||
```
|
||||
|
||||
**체크리스트**:
|
||||
- [ ] status-colors.ts 파일 생성
|
||||
- [ ] 공통 STATUS_COLORS 정의
|
||||
- [ ] BILL_STATUS_COLORS 이동
|
||||
- [ ] VENDOR_CATEGORY_COLORS 이동
|
||||
- [ ] ORDER_STATUS_COLORS 정의
|
||||
- [ ] INSPECTION_STATUS_COLORS 정의
|
||||
- [ ] PRODUCTION_STATUS_COLORS 정의
|
||||
|
||||
---
|
||||
|
||||
### 2.2 StatusBadge 컴포넌트
|
||||
|
||||
**위치**: `src/components/ui/status-badge.tsx`
|
||||
|
||||
**Props 설계**:
|
||||
```typescript
|
||||
interface StatusBadgeProps {
|
||||
status: string;
|
||||
label?: string;
|
||||
colorMap?: Record<string, string>;
|
||||
size?: 'sm' | 'md' | 'lg';
|
||||
className?: string;
|
||||
}
|
||||
```
|
||||
|
||||
**사용 예시**:
|
||||
```typescript
|
||||
// 색상맵 지정
|
||||
<StatusBadge
|
||||
status="paymentComplete"
|
||||
label="결제완료"
|
||||
colorMap={BILL_STATUS_COLORS}
|
||||
/>
|
||||
|
||||
// 공통 색상 사용
|
||||
<StatusBadge status="active" label="활성" />
|
||||
```
|
||||
|
||||
**체크리스트**:
|
||||
- [ ] StatusBadge 컴포넌트 생성
|
||||
- [ ] 기본 색상 (STATUS_COLORS) 적용
|
||||
- [ ] colorMap prop으로 커스텀 색상 지원
|
||||
- [ ] size 변형 (sm, md, lg)
|
||||
- [ ] ui/index.ts export 추가
|
||||
|
||||
**적용 대상 파일** (10+ 파일):
|
||||
- [ ] `accounting/BillManagement/index.tsx`
|
||||
- [ ] `accounting/SalesManagement/index.tsx`
|
||||
- [ ] `accounting/VendorManagement/index.tsx`
|
||||
- [ ] `production/WorkOrders/WorkOrderList.tsx`
|
||||
- [ ] `quality/InspectionManagement/InspectionList.tsx`
|
||||
- [ ] (나머지 파일)
|
||||
|
||||
---
|
||||
|
||||
## Phase 3: 카드/레이아웃 컴포넌트 (1일)
|
||||
|
||||
### 3.1 DetailInfoCard 컴포넌트
|
||||
|
||||
**위치**: `src/components/molecules/DetailInfoCard.tsx`
|
||||
|
||||
**Props 설계**:
|
||||
```typescript
|
||||
interface InfoItem {
|
||||
label: string;
|
||||
value: React.ReactNode;
|
||||
className?: string;
|
||||
span?: number; // grid span
|
||||
}
|
||||
|
||||
interface DetailInfoCardProps {
|
||||
title?: string;
|
||||
description?: string;
|
||||
items: InfoItem[];
|
||||
columns?: 1 | 2 | 3 | 4;
|
||||
className?: string;
|
||||
headerAction?: React.ReactNode;
|
||||
}
|
||||
```
|
||||
|
||||
**사용 예시**:
|
||||
```typescript
|
||||
<DetailInfoCard
|
||||
title="거래처 정보"
|
||||
columns={2}
|
||||
headerAction={<Button size="sm">수정</Button>}
|
||||
items={[
|
||||
{ label: '상호명', value: data.name },
|
||||
{ label: '사업자번호', value: formatBizNo(data.bizNo) },
|
||||
{ label: '대표자', value: data.ceo },
|
||||
{ label: '연락처', value: formatPhone(data.phone) },
|
||||
{ label: '주소', value: data.address, span: 2 },
|
||||
]}
|
||||
/>
|
||||
```
|
||||
|
||||
**체크리스트**:
|
||||
- [ ] DetailInfoCard 컴포넌트 생성
|
||||
- [ ] columns 1/2/3/4 지원
|
||||
- [ ] span으로 컬럼 병합 지원
|
||||
- [ ] headerAction 슬롯
|
||||
- [ ] 반응형 (모바일에서 1컬럼)
|
||||
- [ ] molecules/index.ts export 추가
|
||||
|
||||
**적용 대상 파일** (15+ 파일):
|
||||
- [ ] `accounting/VendorManagement/VendorDetail.tsx`
|
||||
- [ ] `accounting/BillManagement/BillDetail.tsx`
|
||||
- [ ] `accounting/SalesManagement/SalesDetail.tsx`
|
||||
- [ ] `accounting/PurchaseManagement/PurchaseDetail.tsx`
|
||||
- [ ] `hr/EmployeeManagement/EmployeeDetail.tsx`
|
||||
- [ ] (나머지 Detail 페이지들)
|
||||
|
||||
---
|
||||
|
||||
### 3.2 FormGridLayout 컴포넌트
|
||||
|
||||
**위치**: `src/components/molecules/FormGridLayout.tsx`
|
||||
|
||||
**Props 설계**:
|
||||
```typescript
|
||||
interface FormGridLayoutProps {
|
||||
children: React.ReactNode;
|
||||
columns?: 1 | 2 | 3 | 4;
|
||||
gap?: 'sm' | 'md' | 'lg';
|
||||
className?: string;
|
||||
}
|
||||
|
||||
interface FormSectionProps {
|
||||
title?: string;
|
||||
description?: string;
|
||||
children: React.ReactNode;
|
||||
columns?: 1 | 2 | 3 | 4;
|
||||
}
|
||||
```
|
||||
|
||||
**사용 예시**:
|
||||
```typescript
|
||||
<FormSection title="기본 정보" columns={2}>
|
||||
<FormField label="이름" required value={name} onChange={setName} />
|
||||
<FormField label="이메일" type="email" value={email} onChange={setEmail} />
|
||||
<FormField label="주소" className="col-span-2" value={address} onChange={setAddress} />
|
||||
</FormSection>
|
||||
```
|
||||
|
||||
**체크리스트**:
|
||||
- [ ] FormGridLayout 컴포넌트 생성
|
||||
- [ ] FormSection 컴포넌트 생성
|
||||
- [ ] columns 1/2/3/4 지원
|
||||
- [ ] gap 크기 (sm/md/lg)
|
||||
- [ ] col-span 클래스 지원
|
||||
- [ ] 반응형
|
||||
|
||||
---
|
||||
|
||||
## Phase 4: 마이그레이션 및 검증 (1일)
|
||||
|
||||
### 4.1 기존 코드 마이그레이션
|
||||
|
||||
**체크리스트**:
|
||||
- [ ] DeleteDialog 마이그레이션 (40+ 파일)
|
||||
- [ ] formatCurrency 마이그레이션 (30+ 파일)
|
||||
- [ ] StatusBadge 마이그레이션 (10+ 파일)
|
||||
- [ ] DetailInfoCard 마이그레이션 (15+ 파일)
|
||||
- [ ] 불필요한 import 제거
|
||||
- [ ] 미사용 코드 삭제
|
||||
|
||||
### 4.2 검증
|
||||
|
||||
**체크리스트**:
|
||||
- [ ] 빌드 에러 없음 확인 (`npm run build`)
|
||||
- [ ] 타입 에러 없음 확인 (`npm run type-check`)
|
||||
- [ ] 주요 페이지 동작 테스트
|
||||
- [ ] 거래처 삭제
|
||||
- [ ] 품목 삭제
|
||||
- [ ] 금액 표시 확인
|
||||
- [ ] 상태 배지 표시 확인
|
||||
- [ ] 반응형 테스트 (모바일)
|
||||
|
||||
### 4.3 문서화
|
||||
|
||||
**체크리스트**:
|
||||
- [ ] 컴포넌트 JSDoc 주석
|
||||
- [ ] 사용 예시 코드
|
||||
- [ ] claudedocs 업데이트
|
||||
|
||||
---
|
||||
|
||||
## 파일 구조 (최종)
|
||||
|
||||
```
|
||||
src/
|
||||
├── components/
|
||||
│ ├── ui/
|
||||
│ │ ├── status-badge.tsx # 🆕 Phase 2
|
||||
│ │ └── ...
|
||||
│ ├── molecules/
|
||||
│ │ ├── StandardDialog.tsx # 기존
|
||||
│ │ ├── DeleteDialog.tsx # 🆕 Phase 1
|
||||
│ │ ├── DetailInfoCard.tsx # 🆕 Phase 3
|
||||
│ │ ├── FormGridLayout.tsx # 🆕 Phase 3
|
||||
│ │ └── index.ts
|
||||
│ └── ...
|
||||
├── lib/
|
||||
│ ├── formatters.ts # 🆕 Phase 1
|
||||
│ ├── status-colors.ts # 🆕 Phase 2
|
||||
│ └── ...
|
||||
└── ...
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 예상 효과
|
||||
|
||||
| Phase | 컴포넌트 | 절감 라인 | 영향 파일 |
|
||||
|-------|---------|----------|----------|
|
||||
| 1 | DeleteDialog | ~800줄 | 40+ |
|
||||
| 1 | formatters | ~150줄 | 30+ |
|
||||
| 2 | status-colors | ~200줄 | 10+ |
|
||||
| 2 | StatusBadge | ~100줄 | 10+ |
|
||||
| 3 | DetailInfoCard | ~400줄 | 15+ |
|
||||
| 3 | FormGridLayout | ~250줄 | 20+ |
|
||||
| **합계** | | **~1,900줄** | **50+** |
|
||||
|
||||
---
|
||||
|
||||
## 우선순위 정리
|
||||
|
||||
### 🔴 필수 (Phase 1)
|
||||
1. **DeleteDialog** - 가장 많은 중복, 즉시 효과
|
||||
2. **formatters** - 유틸 함수, 간단히 적용
|
||||
|
||||
### 🟡 권장 (Phase 2)
|
||||
3. **status-colors** - 색상 상수 중앙화
|
||||
4. **StatusBadge** - 일관된 상태 표시
|
||||
|
||||
### 🟢 선택 (Phase 3)
|
||||
5. **DetailInfoCard** - 상세 페이지 통일
|
||||
6. **FormGridLayout** - 폼 레이아웃 통일
|
||||
|
||||
---
|
||||
|
||||
## 변경 이력
|
||||
|
||||
| 날짜 | 변경 내용 |
|
||||
|-----|----------|
|
||||
| 2025-12-23 | 최초 작성 - 공통 컴포넌트 추출 계획 |
|
||||
Reference in New Issue
Block a user