# 유틸리티 함수

---

## cn - 클래스명 병합

```typescript
import { cn } from '@/lib/utils';

// clsx + tailwind-merge
<div className={cn('p-4 bg-white', isActive && 'bg-blue-50', className)} />
```

## safeJsonParse - 안전한 JSON 파싱

```typescript
import { safeJsonParse } from '@/lib/utils';

const data = safeJsonParse<Config>(localStorage.getItem('config'), defaultConfig);
// 파싱 실패 시 fallback 반환
```

---

## 포맷팅 함수

**경로**: `src/lib/formatters.ts`

### 전화번호

```typescript
import { formatPhoneNumber, parsePhoneNumber } from '@/lib/formatters';

formatPhoneNumber('01012345678')  // → "010-1234-5678"
parsePhoneNumber('010-1234-5678') // → "01012345678" (숫자만)
```

### 사업자번호

```typescript
import { formatBusinessNumber, validateBusinessNumber } from '@/lib/formatters';

formatBusinessNumber('1234567890')    // → "123-45-67890"
validateBusinessNumber('1234567890')  // → true/false (체크섬 검증)
```

### 주민번호

```typescript
import { formatPersonalNumber, formatPersonalNumberMasked } from '@/lib/formatters';

formatPersonalNumber('9001011234567')      // → "900101-1234567"
formatPersonalNumberMasked('9001011234567') // → "900101-*******"
```

### 카드/계좌번호

```typescript
import { formatCardNumber, formatAccountNumber } from '@/lib/formatters';

formatCardNumber('1234567890123456')  // → "1234-5678-9012-3456"
formatAccountNumber('12345678901234') // → "1234-5678-9012-34"
```

### 숫자/금액

```typescript
import { formatNumber, parseNumber, extractDigits } from '@/lib/formatters';

formatNumber(1234567)       // → "1,234,567"
parseNumber('1,234,567')    // → 1234567
extractDigits('abc-123-def') // → "123"
```

---

## URL 빌더

**경로**: `src/lib/api/query-params.ts`

```typescript
import { buildApiUrl, buildQueryParams } from '@/lib/api/query-params';

// API URL 생성 (undefined/null/'' 자동 필터링)
const url = buildApiUrl('/api/v1/items', {
  search: 'test',
  status: undefined,  // 제외
  page: 1,
});

// 쿼리 파라미터만 생성
const params = buildQueryParams({ search: 'test', page: 1 });
// → URLSearchParams 객체
```

---

## 인쇄 유틸리티

**경로**: `src/lib/print-utils.ts`

```typescript
import { printElement, printArea } from '@/lib/print-utils';

// 특정 요소 인쇄
printElement(document.getElementById('invoice'));

// .print-area 클래스 영역 인쇄
printArea({ title: '견적서' });

// 옵션
printElement('#invoice', {
  title: '견적서',         // 브라우저 탭 제목
  styles: customCSS,       // 추가 CSS
  closeAfterPrint: true,   // 인쇄 후 창 닫기
});
```

**HTML에서 사용**:
```tsx
<div className="print-area">
  {/* 인쇄될 영역 */}
</div>
```

---

## 인증 헤더

**경로**: `src/lib/api/auth-headers.ts`

```typescript
import { getAuthHeaders, getMultipartHeaders, hasAuthToken } from '@/lib/api/auth-headers';

// JSON 요청 헤더 (프록시 사용 시)
const headers = getAuthHeaders();
// → { 'Content-Type': 'application/json', 'Accept': 'application/json' }

// Multipart FormData 헤더
const headers = getMultipartHeaders();
// → { 'Accept': 'application/json' }

// 인증 상태 확인 (클라이언트)
if (hasAuthToken()) { /* 인증됨 */ }
```

---

## 에러 처리

**경로**: `src/lib/api/errors.ts`

```typescript
import { createErrorResponse, isApiError, isAuthError } from '@/lib/api/errors';

// 에러 응답 생성
const error = createErrorResponse(404, '데이터를 찾을 수 없습니다');

// 에러 타입 확인
if (isApiError(response)) { /* API 에러 */ }
if (isAuthError(response)) { /* 인증 에러 (401) */ }
```

---

## localStorage 접근 (Next.js 호환)

```typescript
// ✅ Next.js Pattern (SSR 안전)
const [data, setData] = useState(() => {
  if (typeof window === 'undefined') return defaultValue;
  const saved = localStorage.getItem('key');
  return saved ? JSON.parse(saved) : defaultValue;
});
```
