Files
sam-react-prod/claudedocs/guides/badge-commonization-guide.md
유병철 2639724f9f feat(WEB): 상태 뱃지 공통화 및 상세 페이지 훅 시스템 추가
공통화:
- status-config.ts 신규 추가 (상태 설정 중앙 관리)
- StatusBadge 컴포넌트 개선
- 뱃지 공통화 가이드 문서 추가

상세 페이지 훅 시스템:
- useDetailData, useDetailPageState, useDetailPermissions, useCRUDHandlers 훅 신규 추가
- hooks/index.ts 진입점 추가
- BillDetailV2 신규 컴포넌트 추가

리팩토링:
- 회계(매입/어음/거래처), 품목, 단가, 견적, 주문 상태 뱃지 공통화 적용
- 생산(작업지시서/대시보드/작업자화면), 품질(검사관리) 상태 뱃지 적용
- 공사관리(칸반/프로젝트카드) 상태 뱃지 적용
- 고객센터(문의관리), 인사(직원CSV업로드) 개선
- 리스트 페이지 공통화 현황 분석 문서 추가

상수 정리:
- lib/constants/ 디렉토리 추가

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-05 15:57:49 +09:00

7.2 KiB

Badge 공통화 가이드

작성일: 2026-02-05 목적: 리스트 페이지에서 Badge 스타일을 공통 유틸로 통일하는 방법 안내


📦 공통 유틸 위치

src/lib/utils/status-config.ts    ← Badge 스타일 및 상태 설정
src/lib/constants/filter-presets.ts ← 필터 프리셋

🎨 1. 프리셋 스타일 사용하기

사용 가능한 프리셋

프리셋 스타일 용도
default bg-gray-100 text-gray-800 기본/일반
success bg-green-100 text-green-800 완료/성공/활성
warning bg-yellow-100 text-yellow-800 대기/주의
destructive bg-red-100 text-red-800 오류/반려/긴급
info bg-blue-100 text-blue-800 진행중/정보
muted bg-gray-100 text-gray-500 비활성/무효
orange bg-orange-100 text-orange-800 우선/경고
purple bg-purple-100 text-purple-800 제품/특수

기본 사용법

import { getPresetStyle } from '@/lib/utils/status-config';

// 프리셋 스타일 가져오기
const style = getPresetStyle('success'); // "bg-green-100 text-green-800"

// Badge에 적용
<Badge className={getPresetStyle('warning')}>대기</Badge>

🏷️ 2. 우선순위 Badge

공통 유틸 사용

import { getPriorityLabel, getPriorityStyle } from '@/lib/utils/status-config';

// 우선순위 Badge 렌더링
function PriorityBadge({ priority }: { priority: string }) {
  return (
    <Badge variant="outline" className={getPriorityStyle(priority)}>
      {getPriorityLabel(priority)}
    </Badge>
  );
}

// 사용
<PriorityBadge priority="urgent" />  // 긴급 (빨간색)
<PriorityBadge priority="priority" /> // 우선 (주황색)
<PriorityBadge priority="normal" />   // 일반 (회색)

Before (개별 정의)

// 각 페이지마다 반복되던 코드
const PRIORITY_COLORS: Record<string, string> = {
  '긴급': 'bg-red-100 text-red-700',
  '우선': 'bg-orange-100 text-orange-700',
  '일반': 'bg-gray-100 text-gray-700',
};

After (공통 유틸)

import { getPriorityLabel, getPriorityStyle } from '@/lib/utils/status-config';

<Badge className={getPriorityStyle(item.priority)}>
  {getPriorityLabel(item.priority)}
</Badge>

📦 3. 품목 유형 Badge

공통 유틸 사용

import { getItemTypeLabel, getItemTypeStyle } from '@/lib/utils/status-config';

// 품목 유형 Badge 렌더링
function ItemTypeBadge({ itemType }: { itemType: string }) {
  return (
    <Badge variant="outline" className={getItemTypeStyle(itemType)}>
      {getItemTypeLabel(itemType)}
    </Badge>
  );
}

// 사용
<ItemTypeBadge itemType="FG" /> // 제품 (보라색)
<ItemTypeBadge itemType="PT" /> // 부품 (주황색)
<ItemTypeBadge itemType="SM" /> // 부자재 (녹색)
<ItemTypeBadge itemType="RM" /> // 원자재 (파란색)
<ItemTypeBadge itemType="CS" /> // 소모품 (회색)

🔧 4. 커스텀 상태 설정 만들기

createStatusConfig 사용법

import { createStatusConfig } from '@/lib/utils/status-config';

// 도메인별 커스텀 상태 정의
const {
  STATUS_OPTIONS,    // Select 옵션용
  STATUS_LABELS,     // 라벨 맵
  STATUS_STYLES,     // 스타일 맵
  getStatusLabel,    // 라벨 헬퍼
  getStatusStyle,    // 스타일 헬퍼
} = createStatusConfig({
  draft: { label: '임시저장', style: 'muted' },
  pending: { label: '승인대기', style: 'warning' },
  approved: { label: '승인완료', style: 'success' },
  rejected: { label: '반려', style: 'destructive' },
}, { includeAll: true, allLabel: '전체' });

// 사용
<Badge className={getStatusStyle(item.status)}>
  {getStatusLabel(item.status)}
</Badge>

// Select 옵션으로도 사용 가능
<Select>
  {STATUS_OPTIONS.map(opt => (
    <SelectItem key={opt.value} value={opt.value}>{opt.label}</SelectItem>
  ))}
</Select>

5. 미리 정의된 공통 설정 사용하기

바로 사용 가능한 설정들

import {
  COMMON_STATUS_CONFIG,    // 대기/진행/완료
  WORK_STATUS_CONFIG,      // 작업대기/진행중/작업완료
  APPROVAL_STATUS_CONFIG,  // 승인대기/승인완료/반려
  ACTIVE_STATUS_CONFIG,    // 활성/비활성
  SHIPMENT_STATUS_CONFIG,  // 출고예정/대기/중/완료
  RECEIVING_STATUS_CONFIG, // 입고예정/대기/검사중/완료/반품
} from '@/lib/utils/status-config';

// 사용 예시
<Badge className={COMMON_STATUS_CONFIG.getStatusStyle(item.status)}>
  {COMMON_STATUS_CONFIG.getStatusLabel(item.status)}
</Badge>

// 필터 옵션으로 사용
filterConfig: [
  {
    key: 'status',
    label: '상태',
    type: 'single',
    options: WORK_STATUS_CONFIG.STATUS_OPTIONS.filter(opt => opt.value !== 'all'),
  },
],

🔄 6. 마이그레이션 체크리스트

기존 코드에서 공통 유틸로 전환하기

  1. 우선순위 색상 정의 찾기

    # 검색
    grep -r "PRIORITY_COLORS" src/components/
    grep -r "'긴급'" src/components/
    
  2. import 추가

    import { getPriorityLabel, getPriorityStyle } from '@/lib/utils/status-config';
    
  3. 기존 코드 교체

    // Before
    const color = PRIORITY_COLORS[item.priority] || '';
    <Badge className={color}>{item.priority}</Badge>
    
    // After
    <Badge className={getPriorityStyle(item.priority)}>
      {getPriorityLabel(item.priority)}
    </Badge>
    
  4. 기존 상수 정의 삭제

    // 삭제
    const PRIORITY_COLORS: Record<string, string> = { ... };
    

📋 7. 필터 프리셋 함께 사용하기

filter-presets.ts와 연계

import { COMMON_PRIORITY_FILTER, WORK_STATUS_FILTER } from '@/lib/constants/filter-presets';
import { getPriorityStyle, WORK_STATUS_CONFIG } from '@/lib/utils/status-config';

// UniversalListPage config
const config: UniversalListConfig<MyItem> = {
  // ...

  // 필터 설정 (공통 프리셋 사용)
  filterConfig: [
    WORK_STATUS_FILTER,
    COMMON_PRIORITY_FILTER,
  ],

  // 테이블 행에서 Badge 사용 (공통 스타일 사용)
  renderTableRow: (item, index, globalIndex, handlers) => (
    <TableRow>
      {/* ... */}
      <TableCell>
        <Badge className={WORK_STATUS_CONFIG.getStatusStyle(item.status)}>
          {WORK_STATUS_CONFIG.getStatusLabel(item.status)}
        </Badge>
      </TableCell>
      <TableCell>
        <Badge className={getPriorityStyle(item.priority)}>
          {getPriorityLabel(item.priority)}
        </Badge>
      </TableCell>
    </TableRow>
  ),
};

📊 변경 효과

항목 Before After
우선순위 색상 정의 각 페이지 개별 1곳 (status-config.ts)
품목유형 색상 정의 각 페이지 개별 1곳 (status-config.ts)
색상 변경 시 모든 파일 수정 1개 파일만 수정
일관성 파일마다 다를 수 있음 항상 동일
신규 개발 시 기존 코드 복사 필요 import만 하면 됨

🚨 주의사항

  1. 기존 기능 유지: 마이그레이션 시 동작이 동일한지 확인
  2. 점진적 적용: 한 번에 모든 파일 변경하지 말고, 수정하는 파일만 적용
  3. 테스트: Badge 색상이 기존과 동일하게 표시되는지 확인