# 유틸리티 함수 --- ## cn - 클래스명 병합 ```typescript import { cn } from '@/lib/utils'; // clsx + tailwind-merge
``` ## safeJsonParse - 안전한 JSON 파싱 ```typescript import { safeJsonParse } from '@/lib/utils'; const data = safeJsonParse(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
{/* 인쇄될 영역 */}
``` --- ## 인증 헤더 **경로**: `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; }); ```