File name
Commit message
Commit date
File name
Commit message
Commit date
File name
Commit message
Commit date
File name
Commit message
Commit date
File name
Commit message
Commit date
File name
Commit message
Commit date
'use client';
import { FoxBadge, type FoxBadgeColor } from '@fox/core/components/fox-badge';
import { FoxIconButton } from '@fox/core/components/fox-icon-button';
import { FoxStatusIndicator } from '@fox/core/components/fox-status-indicator';
import type { FoxListColumn } from '@fox/core/components/fox-list-container';
import type { CommonCode } from '@/lib/domain/common-code';
import { FoxPaperclipIcon } from '@fox/core/icons';
import { formatPhoneNumber } from '@/lib/domain/phone-number';
import {
EMPTY_FIELD_PLACEHOLDER,
formatAnswerStatusLabel,
formatBoardCategoryLabel,
formatFaqTypeLabel,
formatInquiryTypeLabel,
formatOptionalValue,
formatVisibilityLabel,
type BoardPost,
type BoardType,
} from '@/lib/domain/board-post';
import { BoardRowActions } from './board-row-actions';
import { InquiryRowActions } from '../inquiries/_components/inquiry-row-actions';
function numberColumn(page: number, pageSize: number): FoxListColumn<BoardPost> {
return {
key: 'no',
header: '번호',
width: 80,
render: (_row, index) => (page - 1) * pageSize + index + 1,
};
}
function visibilityColumn(): FoxListColumn<BoardPost> {
return {
key: 'isVisible',
header: '사용여부',
width: 120,
render: (row) => (
<FoxStatusIndicator
type={row.isVisible ? 'success' : 'danger'}
label={formatVisibilityLabel(row.isVisible)}
/>
),
};
}
function actionsColumn(
boardType: BoardType,
faqTypes: readonly CommonCode[] = []
): FoxListColumn<BoardPost> {
return {
key: 'actions',
header: '관리',
width: 120,
render: (row) => (
<span onClick={(event) => event.stopPropagation()}>
<BoardRowActions boardType={boardType} post={row} faqTypes={faqTypes} />
</span>
),
};
}
function noticeColumns(page: number, pageSize: number): FoxListColumn<BoardPost>[] {
return [
numberColumn(page, pageSize),
{
key: 'category',
header: '구분',
width: 120,
render: (row) => (
<FoxBadge type="pastel" color="neutral" size="md">
{formatBoardCategoryLabel(row.categoryCode)}
</FoxBadge>
),
},
{ key: 'title', header: '제목', width: 320, emphasis: true },
{
key: 'attachment',
header: '첨부',
width: 100,
render: (row) =>
row.attachmentId ? (
<FoxIconButton
type="default"
size="sm"
icon={<FoxPaperclipIcon />}
label={`${row.title} 첨부파일`}
/>
) : null,
},
{
key: 'authorName',
header: '작성자',
width: 160,
render: (row) => formatOptionalValue(row.authorName),
},
visibilityColumn(),
{
key: 'createdAt',
header: '작성일',
width: 140,
render: (row) => formatOptionalValue(row.createdAt),
},
actionsColumn('notice'),
];
}
function faqColumns(
page: number,
pageSize: number,
faqTypes: readonly CommonCode[]
): FoxListColumn<BoardPost>[] {
const typeOptions = faqTypes.map((code) => ({
value: code.code,
label: code.label,
}));
return [
numberColumn(page, pageSize),
{
key: 'category',
header: '구분',
width: 120,
render: (row) => (
<FoxBadge type="pastel" color="neutral" size="md">
{formatBoardCategoryLabel(row.categoryCode)}
</FoxBadge>
),
},
{
key: 'type',
header: '유형',
width: 120,
render: (row) => formatFaqTypeLabel(row.typeCode, typeOptions),
},
{ key: 'title', header: '제목', width: 320, emphasis: true },
{
key: 'authorName',
header: '작성자',
width: 160,
render: (row) => formatOptionalValue(row.authorName),
},
{
key: 'createdAt',
header: '등록일',
width: 140,
render: (row) => formatOptionalValue(row.createdAt),
},
visibilityColumn(),
actionsColumn('faq', faqTypes),
];
}
// TODO: BBS_ANS_CD의 실제 코드값이 확인되면 코드값 기준 표로 바꾼다(관리자 권한 배지와 같은 방식).
// 이슈: 코드값을 모르고 코드명도 코드관리 화면에서 바뀔 수 있어 코드명으로 색을 고른다.
// 앞에서부터 먼저 걸리는 것을 쓴다 — 「미처리」가 「처리」보다 앞에 있어야 한다.
const ANSWER_STATUS_BADGE_COLORS: readonly (readonly [string, FoxBadgeColor])[] = [
['미답변', 'warning'],
['미처리', 'warning'],
['완료', 'success'],
['반려', 'danger'],
['보류', 'danger'],
['취소', 'danger'],
['처리', 'information'],
['진행', 'information'],
['접수', 'information'],
['대기', 'warning'],
];
function answerStatusBadgeColor(label: string): FoxBadgeColor {
const matched = ANSWER_STATUS_BADGE_COLORS.find(([keyword]) =>
label.includes(keyword)
);
return matched?.[1] ?? 'neutral';
}
function inquiryColumns(
page: number,
pageSize: number,
answerStatuses: readonly CommonCode[]
): FoxListColumn<BoardPost>[] {
const statusOptions = answerStatuses.map((code) => ({
value: code.code,
label: code.label,
}));
return [
numberColumn(page, pageSize),
{
key: 'type',
header: '질문유형',
width: 120,
render: (row) => formatInquiryTypeLabel(row.typeCode),
},
{ key: 'title', header: '질문제목', width: 280, emphasis: true },
{
key: 'authorName',
header: '질문자명',
width: 140,
render: (row) => formatOptionalValue(row.authorName),
},
{
key: 'authorPhoneNumber',
header: '전화번호',
width: 160,
render: (row) => formatOptionalValue(formatPhoneNumber(row.authorPhoneNumber)),
},
{
key: 'createdAt',
header: '질문일',
width: 140,
render: (row) => formatOptionalValue(row.createdAt),
},
{
key: 'answerStatus',
header: '상태',
width: 120,
render: (row) => {
if (!row.answerStatusCode) {
return EMPTY_FIELD_PLACEHOLDER;
}
const label = formatAnswerStatusLabel(row.answerStatusCode, statusOptions);
return (
<FoxBadge type="pastel" color={answerStatusBadgeColor(label)} size="md">
{label}
</FoxBadge>
);
},
},
{
key: 'answeredAt',
header: '답변일',
width: 140,
render: (row) => formatOptionalValue(row.answeredAt),
},
{
key: 'actions',
header: '관리',
width: 160,
render: (row) => (
<InquiryRowActions post={row} answerStatuses={answerStatuses} />
),
},
];
}
export function boardPostColumns(
boardType: BoardType,
page: number,
pageSize: number,
answerStatuses: readonly CommonCode[] = [],
faqTypes: readonly CommonCode[] = []
): FoxListColumn<BoardPost>[] {
if (boardType === 'notice') return noticeColumns(page, pageSize);
if (boardType === 'faq') return faqColumns(page, pageSize, faqTypes);
return inquiryColumns(page, pageSize, answerStatuses);
}