/** * 꾸미기 아이템 도메인 타입 — 순수 데이터 표현, 외부 의존 없음. * * 데이터 출처는 백엔드(edupay-backend)의 `/api/v1/mngr/item/**`(ROLE_ADMIN 전용)이며, * `lib/data/repositories/decoration-item-repository.ts`가 응답을 이 타입으로 매핑한다. * 백엔드 테이블은 `TB_COM_ITEM`이다. */ /** * 유형 — 개별아이템 / 셋트아이템. 시안(ADM_ITM_101, ADM_ITM_102_p) 두 곳 모두 "셋트아이템도 * 동일한 항목으로 처리하며 별도 화면이 없다"고 명시한다 — 목록의 유형 탭과 등록/수정 폼의 값이 * 모두 이 타입 하나를 공유한다. * * 값 자체는 화면·URL용 표현이고, 백엔드 코드값(개별 `N` / 셋트 `S`, 사용자 확정 사항)으로의 * 변환은 Repository가 담당한다 — URL(`?itemType=set`)을 읽을 수 있게 유지하기 위해서다. */ export type DecorationItemType = 'individual' | 'set'; export const DECORATION_ITEM_TYPE_OPTIONS: ReadonlyArray<{ value: DecorationItemType; label: string; }> = [ { value: 'individual', label: '개별아이템' }, { value: 'set', label: '셋트아이템' }, ]; export const DEFAULT_DECORATION_ITEM_TYPE: DecorationItemType = 'individual'; /** * 카테고리 — **임시 값이다.** 백엔드는 공통코드테이블(`TB_SYS_COM_CD_DTL`, `COM_CD='ITEM_CATE_CD'`)을 * 조인해 `itemCateNm`을 내려주지만 그 코드가 아직 정비되지 않아, 사용자 지시에 따라 프론트에서 * 임의 코드로 개발한다(시안 등록 팝업의 예시값 계절/축하/시즌을 그대로 씀). * * **백엔드에 코드가 추가되면 이 상수를 지우고 `GET /api/v1/common/code/ITEM_CATE_CD`(인증 불필요) * 응답으로 교체한다.** 그때까지 저장되는 `itemCateCd`는 여기 정의된 임시 코드라, 실제 코드 체계가 * 정해지면 기존 데이터의 코드값 마이그레이션이 필요하다. */ export const DECORATION_ITEM_CATEGORIES: ReadonlyArray<{ code: string; label: string; }> = [ { code: 'CATE01', label: '계절' }, { code: 'CATE02', label: '축하' }, { code: 'CATE03', label: '시즌' }, ]; export const DEFAULT_DECORATION_ITEM_CATEGORY_CODE = DECORATION_ITEM_CATEGORIES[0].code; export type DecorationItem = { /** * 백엔드 `itemSn` — 자동증가 PK이자 화면의 "아이템ID"로 그대로 노출하는 값(사용자 확정 사항). * 시안은 `ITEM-HAT-001` 형식의 자동발급 ID를 그리지만 백엔드에 그런 컬럼이 없다. * 목록 행의 key이자 수정/삭제 API의 경로 변수다. */ itemSn: number; itemType: DecorationItemType; name: string; /** 백엔드 `itemCateCd` — 저장·전송에 쓰는 코드값. */ categoryCode: string; /** * 백엔드 `itemCateNm` — 공통코드테이블 조인 결과. 코드가 코드테이블에 없으면 null로 온다 * (지금은 임시 코드를 쓰므로 대개 null이다 — 화면은 `formatDecorationItemCategory`로 보완한다). */ categoryName: string | null; /** 백엔드 `itemAmount` — 오픈 가능한 포인트. */ points: number; /** 백엔드 `itemExplan`. */ description: string | null; /** 백엔드 `useYn`('Y'/'N') — 표에서는 O/X로 표기한다. */ isActive: boolean; /** 백엔드 `sortOrdr` — 목록 기본 정렬 기준(시안 ADM_ITM_101). */ sortOrder: number; /** 백엔드 `atchFileId` — 업로드된 이미지의 파일 ID. 등록하지 않았으면 null. */ imageFileId: string | null; /** 위 파일 ID로 만든 백엔드 이미지 URL(공개 GET). 파일이 없으면 null. */ imageUrl: string | null; /** 백엔드 `lastMdfcnDt` — `YYYY-MM-DD`(백엔드가 이 형식으로 포맷해 내려준다). 미수정이면 null. */ updatedAt: string | null; }; /** 값이 없는 항목의 화면 표기. */ export const EMPTY_FIELD_PLACEHOLDER = '-'; /** 사용여부 → 화면 표기(시안: O/X). */ export function formatDecorationItemActiveLabel(isActive: boolean): string { return isActive ? 'O' : 'X'; } /** 포인트 → 화면 표기(시안: "100 P" 형태). */ export function formatDecorationItemPoints(points: number): string { return `${points.toLocaleString('ko-KR')} P`; } /** * 카테고리 표기 — 백엔드가 코드테이블에서 찾은 이름을 우선 쓰고, 없으면 프론트 임시 목록에서 * 찾고, 그것도 없으면 코드값 자체를 보여준다. 임시 코드 단계에서는 두 번째 경로가 주로 쓰이고, * 백엔드 코드가 정비되면 자연스럽게 첫 번째 경로로 넘어간다. */ export function formatDecorationItemCategory(item: DecorationItem): string { if (item.categoryName) { return item.categoryName; } const known = DECORATION_ITEM_CATEGORIES.find( (category) => category.code === item.categoryCode ); return known?.label ?? item.categoryCode ?? EMPTY_FIELD_PLACEHOLDER; } /** 수정일시 표기 — 백엔드가 이미 `YYYY-MM-DD`로 포맷해 주므로 그대로 쓰고 null만 보완한다. */ export function formatDecorationItemUpdatedAt( updatedAt: string | null ): string { return updatedAt ?? EMPTY_FIELD_PLACEHOLDER; }