Files
sam-react-prod/claudedocs/guides/[PLAN-2025-12-23] common-component-extraction-plan.md
byeongcheolryu c1abf89d80 refactor: 리스트 컴포넌트 UI 및 레이아웃 일관성 개선
- 여러 관리 페이지(영업, 회계, 인사, 결재, 게시판, 설정)의 리스트 UI 통일
- IntegratedListTemplateV2 기반 레이아웃 정리
- PricingHistoryDialog 개선
- 공통 컴포넌트 추출 계획 문서 추가

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-24 11:34:42 +09:00

11 KiB

공통 컴포넌트 추출 계획서

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 설계:

interface DeleteDialogProps {
  open: boolean;
  onOpenChange: (open: boolean) => void;
  itemName?: string;        // "거래처", "품목" 등
  itemLabel?: string;       // 삭제 대상 이름 (예: "삼성전자")
  title?: string;           // 커스텀 타이틀
  description?: string;     // 커스텀 설명
  onConfirm: () => void;
  isLoading?: boolean;
  confirmText?: string;     // 기본값: "삭제"
  cancelText?: string;      // 기본값: "취소"
}

사용 예시:

<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

함수 설계:

// 금액 포맷
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;

사용 예시:

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

설계:

// 공통 상태 색상
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 설계:

interface StatusBadgeProps {
  status: string;
  label?: string;
  colorMap?: Record<string, string>;
  size?: 'sm' | 'md' | 'lg';
  className?: string;
}

사용 예시:

// 색상맵 지정
<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 설계:

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;
}

사용 예시:

<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 설계:

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;
}

사용 예시:

<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)

  1. status-colors - 색상 상수 중앙화
  2. StatusBadge - 일관된 상태 표시

🟢 선택 (Phase 3)

  1. DetailInfoCard - 상세 페이지 통일
  2. FormGridLayout - 폼 레이아웃 통일

변경 이력

날짜 변경 내용
2025-12-23 최초 작성 - 공통 컴포넌트 추출 계획