feat: FAQ 유형을 공통코드 BBS_FAQ_CD의 상세코드명으로 표기
유형을 프론트 상수 표(SIGNUP/PAYMENT/…)로 치환하고 있었다. 그 표를 지우고 공통코드 `BBS_FAQ_CD`를 조회해 상세코드명으로 옮긴다 — 1:1문의 진행상태(BBS_ANS_CD), 학교·학년 (COM_SCHUL_CD·GRD_CD)과 같은 방식이다. 목록의 「유형」 열과 등록·수정 팝업의 유형 선택지, Server Action의 허용 코드 검증이 모두 같은 응답을 본다. 페이지가 한 번 조회해 목록으로 내리고, Server Action은 저장 직전에 다시 조회한다 (화면이 보낸 코드를 그대로 믿지 않기 위해서다). 목록 URL의 `type` 필터만 예외로 뒀다 — `parseBoardPostQuery`는 도메인 계층이라 코드 조회를 할 수 없어 FAQ에서는 값을 그대로 받는다. 모르는 코드면 결과가 비는 것으로 끝나고, 저장 검증은 위에서 코드표로 한다. 코드가 한 건도 없으면 유형 칸을 그리지 않고 검증도 요구하지 않는다 — 빈 셀렉트를 보여 주고 "유형을 선택해 주세요"로 막으면 저장할 방법이 없어진다. 확인: 임시 페이지로 목록의 FAQ01→회원가입&로그인 치환, 표에 없는 코드(ZZZ99)는 코드 그대로 노출, 등록 팝업 선택지가 코드명으로 뜨고 고르면 hidden 필드에 코드값(FAQ01)이 실리는 것을 확인한 뒤 지웠다. Co-Authored-By: Claude Opus 5
@ac0ecaf1b83b23348210f534a1fb0df5a0a6398e
--- app/(protected)/(basic)/boards/_actions.ts
+++ app/(protected)/(basic)/boards/_actions.ts
... | ... | @@ -57,6 +57,15 @@ |
| 57 | 57 |
const SAVE_FAILED_MESSAGE = '저장하지 못했습니다. 잠시 후 다시 시도해 주세요.'; |
| 58 | 58 |
const DELETE_FAILED_MESSAGE = '삭제하지 못했습니다. 잠시 후 다시 시도해 주세요.'; |
| 59 | 59 |
|
| 60 |
+/** FAQ 유형 허용 목록. 화면이 보낸 코드를 그대로 믿지 않기 위해 저장 직전에 다시 조회한다. */ |
|
| 61 |
+async function fetchFaqTypeCodes(boardType: BoardType): Promise<string[]> {
|
|
| 62 |
+ if (boardType !== 'faq') {
|
|
| 63 |
+ return []; |
|
| 64 |
+ } |
|
| 65 |
+ const codes = await fetchCommonCodes(CODE_GROUP.faqType); |
|
| 66 |
+ return codes.map((code) => code.code); |
|
| 67 |
+} |
|
| 68 |
+ |
|
| 60 | 69 |
async function runWrite( |
| 61 | 70 |
write: () => Promise<void>, |
| 62 | 71 |
fallback: string |
... | ... | @@ -149,7 +158,11 @@ |
| 149 | 158 |
|
| 150 | 159 |
const validation = validateBoardPostForm( |
| 151 | 160 |
readPostValues(formData, attachmentId), |
| 152 |
- { boardType, isCategoryEditable: true }
|
|
| 161 |
+ {
|
|
| 162 |
+ boardType, |
|
| 163 |
+ isCategoryEditable: true, |
|
| 164 |
+ allowedTypeCodes: await fetchFaqTypeCodes(boardType), |
|
| 165 |
+ } |
|
| 153 | 166 |
); |
| 154 | 167 |
if (!validation.ok) {
|
| 155 | 168 |
return { status: 'error', errors: validation.errors };
|
... | ... | @@ -192,7 +205,11 @@ |
| 192 | 205 |
|
| 193 | 206 |
const validation = validateBoardPostForm( |
| 194 | 207 |
readPostValues(formData, attachmentId), |
| 195 |
- { boardType, isCategoryEditable: false }
|
|
| 208 |
+ {
|
|
| 209 |
+ boardType, |
|
| 210 |
+ isCategoryEditable: false, |
|
| 211 |
+ allowedTypeCodes: await fetchFaqTypeCodes(boardType), |
|
| 212 |
+ } |
|
| 196 | 213 |
); |
| 197 | 214 |
if (!validation.ok) {
|
| 198 | 215 |
return { status: 'error', errors: validation.errors };
|
--- app/(protected)/(basic)/boards/_components/board-post-columns.tsx
+++ app/(protected)/(basic)/boards/_components/board-post-columns.tsx
... | ... | @@ -44,14 +44,17 @@ |
| 44 | 44 |
}; |
| 45 | 45 |
} |
| 46 | 46 |
|
| 47 |
-function actionsColumn(boardType: BoardType): FoxListColumn<BoardPost> {
|
|
| 47 |
+function actionsColumn( |
|
| 48 |
+ boardType: BoardType, |
|
| 49 |
+ faqTypes: readonly CommonCode[] = [] |
|
| 50 |
+): FoxListColumn<BoardPost> {
|
|
| 48 | 51 |
return {
|
| 49 | 52 |
key: 'actions', |
| 50 | 53 |
header: '관리', |
| 51 | 54 |
width: 120, |
| 52 | 55 |
render: (row) => ( |
| 53 | 56 |
<span onClick={(event) => event.stopPropagation()}>
|
| 54 |
- <BoardRowActions boardType={boardType} post={row} />
|
|
| 57 |
+ <BoardRowActions boardType={boardType} post={row} faqTypes={faqTypes} />
|
|
| 55 | 58 |
</span> |
| 56 | 59 |
), |
| 57 | 60 |
}; |
... | ... | @@ -102,7 +105,16 @@ |
| 102 | 105 |
]; |
| 103 | 106 |
} |
| 104 | 107 |
|
| 105 |
-function faqColumns(page: number, pageSize: number): FoxListColumn<BoardPost>[] {
|
|
| 108 |
+function faqColumns( |
|
| 109 |
+ page: number, |
|
| 110 |
+ pageSize: number, |
|
| 111 |
+ faqTypes: readonly CommonCode[] |
|
| 112 |
+): FoxListColumn<BoardPost>[] {
|
|
| 113 |
+ const typeOptions = faqTypes.map((code) => ({
|
|
| 114 |
+ value: code.code, |
|
| 115 |
+ label: code.label, |
|
| 116 |
+ })); |
|
| 117 |
+ |
|
| 106 | 118 |
return [ |
| 107 | 119 |
numberColumn(page, pageSize), |
| 108 | 120 |
{
|
... | ... | @@ -119,7 +131,7 @@ |
| 119 | 131 |
key: 'type', |
| 120 | 132 |
header: '유형', |
| 121 | 133 |
width: 120, |
| 122 |
- render: (row) => formatFaqTypeLabel(row.typeCode), |
|
| 134 |
+ render: (row) => formatFaqTypeLabel(row.typeCode, typeOptions), |
|
| 123 | 135 |
}, |
| 124 | 136 |
{ key: 'title', header: '제목', width: 320, emphasis: true },
|
| 125 | 137 |
{
|
... | ... | @@ -135,7 +147,7 @@ |
| 135 | 147 |
render: (row) => formatOptionalValue(row.createdAt), |
| 136 | 148 |
}, |
| 137 | 149 |
visibilityColumn(), |
| 138 |
- actionsColumn('faq'),
|
|
| 150 |
+ actionsColumn('faq', faqTypes),
|
|
| 139 | 151 |
]; |
| 140 | 152 |
} |
| 141 | 153 |
|
... | ... | @@ -236,9 +248,10 @@ |
| 236 | 248 |
boardType: BoardType, |
| 237 | 249 |
page: number, |
| 238 | 250 |
pageSize: number, |
| 239 |
- answerStatuses: readonly CommonCode[] = [] |
|
| 251 |
+ answerStatuses: readonly CommonCode[] = [], |
|
| 252 |
+ faqTypes: readonly CommonCode[] = [] |
|
| 240 | 253 |
): FoxListColumn<BoardPost>[] {
|
| 241 | 254 |
if (boardType === 'notice') return noticeColumns(page, pageSize); |
| 242 |
- if (boardType === 'faq') return faqColumns(page, pageSize); |
|
| 255 |
+ if (boardType === 'faq') return faqColumns(page, pageSize, faqTypes); |
|
| 243 | 256 |
return inquiryColumns(page, pageSize, answerStatuses); |
| 244 | 257 |
} |
--- app/(protected)/(basic)/boards/_components/board-post-form-modal.tsx
+++ app/(protected)/(basic)/boards/_components/board-post-form-modal.tsx
... | ... | @@ -12,9 +12,9 @@ |
| 12 | 12 |
import { FoxToggleSwitch } from '@fox/core/components/fox-toggle-switch';
|
| 13 | 13 |
import { submitFormAction } from '@/app/_hooks/submit-form-action';
|
| 14 | 14 |
import { useFeedback } from '@/app/_hooks/use-feedback';
|
| 15 |
+import type { CommonCode } from '@/lib/domain/common-code';
|
|
| 15 | 16 |
import {
|
| 16 | 17 |
BOARD_CATEGORY_OPTIONS, |
| 17 |
- FAQ_TYPE_OPTIONS, |
|
| 18 | 18 |
INQUIRY_TYPE_OPTIONS, |
| 19 | 19 |
type BoardPost, |
| 20 | 20 |
type BoardType, |
... | ... | @@ -31,6 +31,8 @@ |
| 31 | 31 |
boardType: BoardType; |
| 32 | 32 |
mode: 'create' | 'edit'; |
| 33 | 33 |
post?: BoardPost; |
| 34 |
+ /** 공통코드 `BBS_FAQ_CD` — FAQ의 유형 선택지. 다른 게시판에서는 쓰이지 않는다. */ |
|
| 35 |
+ faqTypes?: readonly CommonCode[]; |
|
| 34 | 36 |
onClose: () => void; |
| 35 | 37 |
} |
| 36 | 38 |
|
... | ... | @@ -40,8 +42,9 @@ |
| 40 | 42 |
faq: 'FAQ', |
| 41 | 43 |
}; |
| 42 | 44 |
|
| 43 |
-const TYPE_OPTIONS: Partial<Record<BoardType, readonly { value: string; label: string }[]>> = {
|
|
| 44 |
- faq: FAQ_TYPE_OPTIONS, |
|
| 45 |
+const STATIC_TYPE_OPTIONS: Partial< |
|
| 46 |
+ Record<BoardType, readonly { value: string; label: string }[]>
|
|
| 47 |
+> = {
|
|
| 45 | 48 |
inquiry: INQUIRY_TYPE_OPTIONS, |
| 46 | 49 |
}; |
| 47 | 50 |
|
... | ... | @@ -49,6 +52,7 @@ |
| 49 | 52 |
boardType, |
| 50 | 53 |
mode, |
| 51 | 54 |
post, |
| 55 |
+ faqTypes = [], |
|
| 52 | 56 |
onClose, |
| 53 | 57 |
}: BoardPostFormModalProps) {
|
| 54 | 58 |
const isCreate = mode === 'create'; |
... | ... | @@ -78,7 +82,10 @@ |
| 78 | 82 |
}, [state, showToast, onClose, isCreate]); |
| 79 | 83 |
|
| 80 | 84 |
const errors = state.status === 'error' ? (state.errors ?? {}) : {};
|
| 81 |
- const typeOptions = TYPE_OPTIONS[boardType]; |
|
| 85 |
+ const typeOptions = |
|
| 86 |
+ boardType === 'faq' |
|
| 87 |
+ ? faqTypes.map((code) => ({ value: code.code, label: code.label }))
|
|
| 88 |
+ : STATIC_TYPE_OPTIONS[boardType]; |
|
| 82 | 89 |
const hasNoticeOnlyFields = boardType === 'notice'; |
| 83 | 90 |
|
| 84 | 91 |
return ( |
... | ... | @@ -124,7 +131,7 @@ |
| 124 | 131 |
<input type="hidden" name="categoryCode" value={categoryCode} />
|
| 125 | 132 |
</div> |
| 126 | 133 |
|
| 127 |
- {typeOptions && (
|
|
| 134 |
+ {typeOptions && typeOptions.length > 0 && (
|
|
| 128 | 135 |
<div className={styles.field}>
|
| 129 | 136 |
<FoxSelect |
| 130 | 137 |
size="md" |
--- app/(protected)/(basic)/boards/_components/board-post-list.tsx
+++ app/(protected)/(basic)/boards/_components/board-post-list.tsx
... | ... | @@ -39,6 +39,8 @@ |
| 39 | 39 |
extraToolbar?: ReactNode; |
| 40 | 40 |
/** 공통코드 `BBS_ANS_CD` — 1:1문의 진행상태 표기·선택지. */ |
| 41 | 41 |
answerStatuses?: readonly CommonCode[]; |
| 42 |
+ /** 공통코드 `BBS_FAQ_CD` — FAQ의 유형. */ |
|
| 43 |
+ faqTypes?: readonly CommonCode[]; |
|
| 42 | 44 |
} |
| 43 | 45 |
|
| 44 | 46 |
const SORT_OPTIONS = [{ value: 'recent', label: '최근등록순' }];
|
... | ... | @@ -55,6 +57,7 @@ |
| 55 | 57 |
canCreate = true, |
| 56 | 58 |
extraToolbar, |
| 57 | 59 |
answerStatuses, |
| 60 |
+ faqTypes, |
|
| 58 | 61 |
}: BoardPostListProps) {
|
| 59 | 62 |
const router = useRouter(); |
| 60 | 63 |
const [isCreateOpen, setIsCreateOpen] = useState(false); |
... | ... | @@ -74,7 +77,8 @@ |
| 74 | 77 |
boardType, |
| 75 | 78 |
currentPage, |
| 76 | 79 |
query.pageSize, |
| 77 |
- answerStatuses |
|
| 80 |
+ answerStatuses, |
|
| 81 |
+ faqTypes |
|
| 78 | 82 |
)} |
| 79 | 83 |
rows={items}
|
| 80 | 84 |
rowKey={(row) => row.id}
|
... | ... | @@ -165,6 +169,7 @@ |
| 165 | 169 |
<BoardPostFormModal |
| 166 | 170 |
boardType={boardType}
|
| 167 | 171 |
mode="create" |
| 172 |
+ faqTypes={faqTypes}
|
|
| 168 | 173 |
onClose={() => setIsCreateOpen(false)}
|
| 169 | 174 |
/> |
| 170 | 175 |
)} |
--- app/(protected)/(basic)/boards/_components/board-row-actions.tsx
+++ app/(protected)/(basic)/boards/_components/board-row-actions.tsx
... | ... | @@ -7,12 +7,15 @@ |
| 7 | 7 |
import { FoxPencilSimpleIcon, FoxTrashIcon } from '@fox/core/icons';
|
| 8 | 8 |
import { useFeedback } from '@/app/_hooks/use-feedback';
|
| 9 | 9 |
import type { BoardPost, BoardType } from '@/lib/domain/board-post';
|
| 10 |
+import type { CommonCode } from '@/lib/domain/common-code';
|
|
| 10 | 11 |
import { deleteBoardPostAction } from '../_actions';
|
| 11 | 12 |
import { BoardPostFormModal } from './board-post-form-modal';
|
| 12 | 13 |
|
| 13 | 14 |
interface BoardRowActionsProps {
|
| 14 | 15 |
boardType: BoardType; |
| 15 | 16 |
post: BoardPost; |
| 17 |
+ /** 공통코드 `BBS_FAQ_CD` — FAQ 수정 팝업의 유형 선택지. */ |
|
| 18 |
+ faqTypes?: readonly CommonCode[]; |
|
| 16 | 19 |
} |
| 17 | 20 |
|
| 18 | 21 |
/** |
... | ... | @@ -27,7 +30,11 @@ |
| 27 | 30 |
* 쓴다 — 아이콘은 스스로 크기를 갖지 않고 감싼 슬롯이 정하는데, 그 슬롯 크기를 실제로 정의하는 |
| 28 | 31 |
* 건 @fox 쪽뿐이다(components/ui는 Tailwind 제거 이후 무스타일이다). |
| 29 | 32 |
*/ |
| 30 |
-export function BoardRowActions({ boardType, post }: BoardRowActionsProps) {
|
|
| 33 |
+export function BoardRowActions({
|
|
| 34 |
+ boardType, |
|
| 35 |
+ post, |
|
| 36 |
+ faqTypes, |
|
| 37 |
+}: BoardRowActionsProps) {
|
|
| 31 | 38 |
const { showAlert, hideAlert, showToast } = useFeedback();
|
| 32 | 39 |
const [isEditOpen, setIsEditOpen] = useState(false); |
| 33 | 40 |
const [isDeleting, startDeleting] = useTransition(); |
... | ... | @@ -83,6 +90,7 @@ |
| 83 | 90 |
<BoardPostFormModal |
| 84 | 91 |
boardType={boardType}
|
| 85 | 92 |
mode="edit" |
| 93 |
+ faqTypes={faqTypes}
|
|
| 86 | 94 |
post={post}
|
| 87 | 95 |
onClose={() => setIsEditOpen(false)}
|
| 88 | 96 |
/> |
--- app/(protected)/(basic)/boards/faqs/page.tsx
+++ app/(protected)/(basic)/boards/faqs/page.tsx
... | ... | @@ -1,6 +1,8 @@ |
| 1 | 1 |
import type { Metadata } from 'next';
|
| 2 | 2 |
import { verifySession } from '@/lib/auth/dal';
|
| 3 | 3 |
import { fetchBoardPosts } from '@/lib/data/repositories/board-post-repository';
|
| 4 |
+import { fetchCommonCodes } from '@/lib/data/repositories/common-code-repository';
|
|
| 5 |
+import { CODE_GROUP } from '@/lib/domain/common-code';
|
|
| 4 | 6 |
import { parseBoardPostQuery } from '@/lib/domain/board-post-query';
|
| 5 | 7 |
import { BoardPostList } from '../_components/board-post-list';
|
| 6 | 8 |
|
... | ... | @@ -16,6 +18,7 @@ |
| 16 | 18 |
|
| 17 | 19 |
const query = parseBoardPostQuery('faq', await searchParams);
|
| 18 | 20 |
const { items, totalCount } = await fetchBoardPosts('faq', query);
|
| 21 |
+ const faqTypes = await fetchCommonCodes(CODE_GROUP.faqType); |
|
| 19 | 22 |
|
| 20 | 23 |
const totalPages = Math.max(1, Math.ceil(totalCount / query.pageSize)); |
| 21 | 24 |
const currentPage = Math.min(query.page, totalPages); |
... | ... | @@ -34,6 +37,7 @@ |
| 34 | 37 |
currentPage={currentPage}
|
| 35 | 38 |
totalPages={totalPages}
|
| 36 | 39 |
totalCount={totalCount}
|
| 40 |
+ faqTypes={faqTypes}
|
|
| 37 | 41 |
/> |
| 38 | 42 |
); |
| 39 | 43 |
} |
--- lib/domain/board-post-form.ts
+++ lib/domain/board-post-form.ts
... | ... | @@ -100,7 +100,12 @@ |
| 100 | 100 |
*/ |
| 101 | 101 |
export function validateBoardPostForm( |
| 102 | 102 |
values: BoardPostFormValues, |
| 103 |
- options: { boardType: BoardType; isCategoryEditable: boolean }
|
|
| 103 |
+ options: {
|
|
| 104 |
+ boardType: BoardType; |
|
| 105 |
+ isCategoryEditable: boolean; |
|
| 106 |
+ /** FAQ 유형(`BBS_FAQ_CD`) 코드값. 다른 게시판에서는 쓰이지 않는다. */ |
|
| 107 |
+ allowedTypeCodes?: readonly string[]; |
|
| 108 |
+ } |
|
| 104 | 109 |
): ValidationResult<BoardPostFormValues, BoardPostFormErrors> {
|
| 105 | 110 |
const errors: BoardPostFormErrors = {};
|
| 106 | 111 |
|
... | ... | @@ -116,15 +121,14 @@ |
| 116 | 121 |
} |
| 117 | 122 |
} |
| 118 | 123 |
|
| 119 |
- // 유형은 공지사항에 없는 항목이라 해당 게시판에서만 검증한다. |
|
| 120 |
- const typeOptions = BOARD_TYPE_OPTIONS[options.boardType]; |
|
| 121 |
- if (typeOptions.length > 0) {
|
|
| 122 |
- const isKnownType = typeOptions.some( |
|
| 123 |
- (option) => option.value === values.typeCode |
|
| 124 |
- ); |
|
| 125 |
- if (!isKnownType) {
|
|
| 126 |
- errors.typeCode = '유형을 선택해 주세요.'; |
|
| 127 |
- } |
|
| 124 |
+ // 유형은 공지사항에 없는 항목이라 해당 게시판에서만 검증한다. FAQ는 공통코드라 허용 목록을 |
|
| 125 |
+ // 호출부(Server Action)가 조회해 넘긴다. |
|
| 126 |
+ const allowedTypeCodes = |
|
| 127 |
+ options.boardType === 'faq' |
|
| 128 |
+ ? (options.allowedTypeCodes ?? []) |
|
| 129 |
+ : BOARD_TYPE_OPTIONS[options.boardType].map((option) => option.value); |
|
| 130 |
+ if (allowedTypeCodes.length > 0 && !allowedTypeCodes.includes(values.typeCode)) {
|
|
| 131 |
+ errors.typeCode = '유형을 선택해 주세요.'; |
|
| 128 | 132 |
} |
| 129 | 133 |
|
| 130 | 134 |
if (!title) {
|
--- lib/domain/board-post-query.ts
+++ lib/domain/board-post-query.ts
... | ... | @@ -12,7 +12,6 @@ |
| 12 | 12 |
|
| 13 | 13 |
import {
|
| 14 | 14 |
BOARD_CATEGORY_OPTIONS, |
| 15 |
- FAQ_TYPE_OPTIONS, |
|
| 16 | 15 |
INQUIRY_TYPE_OPTIONS, |
| 17 | 16 |
type BoardType, |
| 18 | 17 |
} from '@/lib/domain/board-post'; |
... | ... | @@ -63,14 +62,17 @@ |
| 63 | 62 |
faq: { category: true, type: true, visibility: false, answered: false },
|
| 64 | 63 |
}; |
| 65 | 64 |
|
| 66 |
-/** 화면별 유형 선택지. 공지사항은 유형 항목이 없다. */ |
|
| 65 |
+/** |
|
| 66 |
+ * 화면별 유형 선택지. 공지사항은 유형 항목이 없고, FAQ는 공통코드(`BBS_FAQ_CD`)라 여기 없다 — |
|
| 67 |
+ * 실행 중에 조회한 목록을 화면이 직접 들고 쓴다. |
|
| 68 |
+ */ |
|
| 67 | 69 |
export const BOARD_TYPE_OPTIONS: Record< |
| 68 | 70 |
BoardType, |
| 69 | 71 |
readonly BoardSearchFieldOption[] |
| 70 | 72 |
> = {
|
| 71 | 73 |
notice: [], |
| 72 | 74 |
inquiry: INQUIRY_TYPE_OPTIONS, |
| 73 |
- faq: FAQ_TYPE_OPTIONS, |
|
| 75 |
+ faq: [], |
|
| 74 | 76 |
}; |
| 75 | 77 |
|
| 76 | 78 |
/** 사용여부 필터(공지사항) — 시안의 「전체/노출/미노출」. */ |
... | ... | @@ -150,8 +152,12 @@ |
| 150 | 152 |
category: fields.category |
| 151 | 153 |
? readOneOf(searchParams, 'category', BOARD_CATEGORY_OPTIONS) |
| 152 | 154 |
: FILTER_ALL, |
| 155 |
+ // FAQ 유형은 공통코드라 허용 목록을 여기서 알 수 없다. 값은 그대로 받고 목록을 거르는 데만 |
|
| 156 |
+ // 쓰며(모르는 코드면 결과가 비는 것으로 끝난다), 저장 검증은 Server Action이 코드표로 한다. |
|
| 153 | 157 |
type: fields.type |
| 154 |
- ? readOneOf(searchParams, 'type', BOARD_TYPE_OPTIONS[boardType]) |
|
| 158 |
+ ? boardType === 'faq' |
|
| 159 |
+ ? (readParam(searchParams, 'type') ?? '').trim().slice(0, MAX_KEYWORD_LENGTH) |
|
| 160 |
+ : readOneOf(searchParams, 'type', BOARD_TYPE_OPTIONS[boardType]) |
|
| 155 | 161 |
: FILTER_ALL, |
| 156 | 162 |
visibility: fields.visibility |
| 157 | 163 |
? readOneOf(searchParams, 'visibility', VISIBILITY_FILTER_OPTIONS) |
--- lib/domain/board-post.ts
+++ lib/domain/board-post.ts
... | ... | @@ -107,16 +107,6 @@ |
| 107 | 107 |
{ value: 'FOXPAY', label: 'FOX PAY' },
|
| 108 | 108 |
]; |
| 109 | 109 |
|
| 110 |
-/** FAQ의 「유형」 — 시안 A_BOA_015_p ②. 시안에도 "추후 재정의 필요"로 적혀 있어 잠정값이다. */ |
|
| 111 |
-export const FAQ_TYPE_OPTIONS: readonly CodeOption[] = [ |
|
| 112 |
- { value: 'SIGNUP', label: '회원가입&로그인' },
|
|
| 113 |
- { value: 'PAYMENT', label: '결제관련' },
|
|
| 114 |
- { value: 'STUDENT_CARD', label: '학생증' },
|
|
| 115 |
- { value: 'DECO_ITEM', label: '꾸미기아이템' },
|
|
| 116 |
- { value: 'MERCHANT', label: '가맹점관련' },
|
|
| 117 |
- { value: 'ETC', label: '기타' },
|
|
| 118 |
-]; |
|
| 119 |
- |
|
| 120 | 110 |
/** 1:1문의의 「질문유형」 — 시안 A_BOA_012. 잠정값이다. */ |
| 121 | 111 |
export const INQUIRY_TYPE_OPTIONS: readonly CodeOption[] = [ |
| 122 | 112 |
{ value: 'SIGNUP', label: '회원가입/로그인' },
|
... | ... | @@ -143,8 +133,12 @@ |
| 143 | 133 |
return formatCode(BOARD_CATEGORY_OPTIONS, code); |
| 144 | 134 |
} |
| 145 | 135 |
|
| 146 |
-export function formatFaqTypeLabel(code: string | null): string {
|
|
| 147 |
- return formatCode(FAQ_TYPE_OPTIONS, code); |
|
| 136 |
+/** FAQ의 「유형」 — 공통코드 `BBS_FAQ_CD`. 코드표는 호출부가 조회해 넘긴다. */ |
|
| 137 |
+export function formatFaqTypeLabel( |
|
| 138 |
+ code: string | null, |
|
| 139 |
+ options: readonly CodeOption[] |
|
| 140 |
+): string {
|
|
| 141 |
+ return formatCode(options, code); |
|
| 148 | 142 |
} |
| 149 | 143 |
|
| 150 | 144 |
export function formatInquiryTypeLabel(code: string | null): string {
|
--- lib/domain/common-code.ts
+++ lib/domain/common-code.ts
... | ... | @@ -23,6 +23,8 @@ |
| 23 | 23 |
decorationItemCategory: 'ITEM_CATE_CD', |
| 24 | 24 |
/** 1:1문의 진행상태. */ |
| 25 | 25 |
inquiryAnswerStatus: 'BBS_ANS_CD', |
| 26 |
+ /** FAQ 유형. */ |
|
| 27 |
+ faqType: 'BBS_FAQ_CD', |
|
| 26 | 28 |
/** 학교(학교급). */ |
| 27 | 29 |
school: 'COM_SCHUL_CD', |
| 28 | 30 |
/** 학년. 학교마다 다르므로 `atrbNm`에 학교 코드를 넣어 조회한다. */ |
Add a comment
Delete comment
Once you delete this comment, you won't be able to recover it. Are you sure you want to delete this comment?