File name
Commit message
Commit date
File name
Commit message
Commit date
File name
Commit message
Commit date
/**
* 꾸미기 아이템 도메인 타입 — 순수 데이터 표현, 외부 의존 없음.
*
* 데이터 출처는 백엔드(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 = '-';
/** 사용여부 → 화면 표기(시안 ADM_ITM_101: 점 + "사용"/"미사용"). */
export function formatDecorationItemActiveLabel(isActive: boolean): string {
return isActive ? '사용' : '미사용';
}
/** 포인트 → 화면 표기(시안: "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;
}