File name
Commit message
Commit date
File name
Commit message
Commit date
File name
Commit message
Commit date
/**
* 콘텐츠관리 도메인 — 금융쇼츠·금융OX퀴즈·4컷금융만화가 공유하는 값과 표기 규칙.
*
* 게시판(`bbs`)과 무관하다. 세 종류는 백엔드 API가 각각 따로 있고 저장되는 테이블도
* 쇼츠·만화(`TB_COM_CNTNTS`)와 퀴즈(`TB_COM_QUIZ`)로 갈린다.
*/
import { EMPTY_FIELD_PLACEHOLDER } from '@/lib/domain/common-code';
export const CONTENT_KINDS = ['shorts', 'quiz', 'comic'] as const;
export type ContentKind = (typeof CONTENT_KINDS)[number];
export const CONTENT_KIND_LABEL: Record<ContentKind, string> = {
shorts: '금융쇼츠',
quiz: '금융OX퀴즈',
comic: '4컷금융만화',
};
// TODO: `TB_COM_CNTNTS.CNTNTS_TYPE` — 만화 'T'만 백엔드 매퍼에서 확인했다. 쇼츠는 미확인 잠정값.
export const CONTENT_TYPE_CODE: Record<'shorts' | 'comic', string> = {
shorts: 'V',
comic: 'T',
};
export type SchoolLevelOption = {
value: string;
label: string;
/** 학년 칩 개수. 0이면 학년을 고르지 않는다(전체연령). */
gradeCount: number;
};
// TODO: 학교급 코드값이 백엔드에 없다(검색 파라미터만 있고 컬럼·SQL이 없음). 잠정값이다.
export const SCHOOL_LEVEL_OPTIONS: readonly SchoolLevelOption[] = [
{ value: 'ELEM', label: '초등학교', gradeCount: 6 },
{ value: 'MIDD', label: '중학교', gradeCount: 3 },
{ value: 'HIGH', label: '고등학교', gradeCount: 3 },
{ value: 'ALL', label: '전체연령', gradeCount: 0 },
];
export const DEFAULT_SCHOOL_LEVEL = SCHOOL_LEVEL_OPTIONS[0].value;
export function findSchoolLevel(value: string): SchoolLevelOption | undefined {
return SCHOOL_LEVEL_OPTIONS.find((option) => option.value === value);
}
export function gradeOptionsOf(schoolLevel: string): readonly string[] {
const count = findSchoolLevel(schoolLevel)?.gradeCount ?? 0;
return Array.from({ length: count }, (_, index) => String(index + 1));
}
/** 난이도 — 백엔드 `MngrQuizVo.quizLev` 주석(1:하, 2:중, 3:상)에서 확인한 실제 코드값. */
export const QUIZ_LEVEL_OPTIONS: ReadonlyArray<{ value: string; label: string }> = [
{ value: '3', label: '상' },
{ value: '2', label: '중' },
{ value: '1', label: '하' },
];
export const QUIZ_ANSWER_OPTIONS = ['O', 'X'] as const;
export type QuizAnswer = (typeof QUIZ_ANSWER_OPTIONS)[number];
/** 정답여부에 함께 노출할 문구. 기타를 고르면 직접 입력한다. */
export const ANSWER_MESSAGE_ETC = 'ETC';
// TODO: 기획이 "추후 정의"로 남긴 기본 3종이다. 확정되면 이 표만 교체한다.
export const ANSWER_MESSAGE_OPTIONS: ReadonlyArray<{ value: string; label: string }> = [
{ value: 'MSG1', label: '사용자에게 노출할 문구1' },
{ value: 'MSG2', label: '사용자에게 노출할 문구2' },
{ value: 'MSG3', label: '사용자에게 노출할 문구3' },
{ value: ANSWER_MESSAGE_ETC, label: '기타' },
];
export type ContentKeyword = {
keyword: string;
description: string;
};
/** 등록 폼이 처음 보여 주는 키워드 줄 수 — 기획 "기본 2줄 제공". */
export const DEFAULT_KEYWORD_ROWS = 2;
/** 4컷금융만화의 최소 컷 수 — 기획 "기본 4컷 제공, 4컷 이상 구성도 가능". */
export const MIN_COMIC_CUTS = 4;
export const THUMBNAIL_HELP_TEXT = '권장 사이즈 : 480x270px';
/** 쇼츠·만화 한 건. 백엔드 `MngrCntntsToonVo`(= `CmmCntntsVo`)를 화면 언어로 옮긴 것. */
export type ContentItem = {
cntntsSn: string;
/** 만화의 「콘텐츠명」. 쇼츠 목록에는 열이 없다. */
name: string;
/** 쇼츠의 「제목」. */
title: string;
subject: string;
message: string;
schoolLevel: string;
grades: string[];
keywords: ContentKeyword[];
/** 만화의 컷 이미지·쇼츠의 영상이 묶인 첨부 ID. */
attachmentId: string | null;
thumbnailFileId: string | null;
isVisible: boolean;
modifiedAt: string | null;
};
/** 금융OX퀴즈 한 건. 백엔드 `MngrQuizVo`. */
export type QuizItem = {
quizSn: string;
/** 백엔드 `quizTitle` — 목록의 「키워드」 열이다(제목이 아니다). */
keywordText: string;
level: string;
question: string;
explanation: string;
answer: string;
points: number | null;
isVisible: boolean;
modifiedAt: string | null;
};
export function formatSchoolLevelLabel(value: string): string {
return findSchoolLevel(value)?.label ?? (value || EMPTY_FIELD_PLACEHOLDER);
}
export function formatGradesLabel(grades: readonly string[]): string {
return grades.length > 0 ? grades.join(',') : EMPTY_FIELD_PLACEHOLDER;
}
export function formatKeywordsLabel(keywords: readonly ContentKeyword[]): string {
const names = keywords.map((item) => item.keyword).filter(Boolean);
return names.length > 0 ? names.join(', ') : EMPTY_FIELD_PLACEHOLDER;
}
export function formatQuizLevelLabel(value: string): string {
return QUIZ_LEVEL_OPTIONS.find((option) => option.value === value)?.label ?? value;
}
/** 목록의 「비공개」 열 — 기획 라벨 그대로다(값은 공개/비공개). */
export function formatVisibilityLabel(isVisible: boolean): string {
return isVisible ? '공개' : '비공개';
}
export function formatContentText(value: string | null | undefined): string {
return value === null || value === undefined || value === ''
? EMPTY_FIELD_PLACEHOLDER
: value;
}