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 { useRouter } from 'next/navigation';
import type { ReactNode } from 'react';
import { FoxButton } from '@fox/core/components/fox-button';
import { FoxButtonGroup } from '@fox/core/components/fox-button-group';
import { FoxSelectText } from '@fox/core/components/fox-select-text';
import {
FoxListContainer,
type FoxListColumn,
} from '@fox/core/components/fox-list-container';
import { CONTENT_KIND_LABEL, type ContentKind } from '@/lib/domain/content';
import {
CONTENT_PAGE_SIZE_OPTIONS,
CONTENT_SEARCH_FIELDS,
CONTENT_SORT_OPTIONS,
buildContentHref,
contentBreadcrumb,
contentCreatePath,
type ContentPageSize,
type ContentQuery,
type ContentSortOption,
} from '@/lib/domain/content-query';
import { ContentListFilters } from './content-list-filters';
import type { CommonCode } from '@/lib/domain/common-code';
import type { GradesBySchool } from '@/lib/domain/content';
interface ContentListShellProps<T> {
kind: ContentKind;
columns: FoxListColumn<T>[];
rows: T[];
rowKey: (row: T) => string;
query: ContentQuery;
currentPage: number;
totalPages: number;
totalCount: number;
schools: readonly CommonCode[];
gradesBySchool: GradesBySchool;
/** 툴바 오른쪽에 덧붙일 것(금융OX퀴즈의 엑셀 버튼). */
extraActions?: ReactNode;
}
/** 콘텐츠관리 목록 3종이 공유하는 껍데기 — 열만 화면마다 다르다. */
export function ContentListShell<T>({
kind,
columns,
rows,
rowKey,
query,
currentPage,
totalPages,
totalCount,
schools,
gradesBySchool,
extraActions,
}: ContentListShellProps<T>) {
const router = useRouter();
function go(patch: Partial<ContentQuery>) {
router.push(buildContentHref(kind, query, patch));
}
return (
<FoxListContainer<T>
title={`콘텐츠 목록 (${CONTENT_KIND_LABEL[kind]})`}
breadcrumb={contentBreadcrumb(kind)}
caption={`${CONTENT_KIND_LABEL[kind]} 콘텐츠 목록`}
columns={columns}
rows={rows}
rowKey={rowKey}
totalCount={totalCount}
emptyMessage="등록된 콘텐츠가 없습니다."
filter={
<ContentListFilters
query={query}
schools={schools}
gradesBySchool={gradesBySchool}
withLevel={kind === 'quiz'}
onChange={go}
/>
}
sorts={
<>
<FoxSelectText
size="sm"
ariaLabel="정렬"
icon={<i className="fox-ico fox-ico-ArrowsDownUp" aria-hidden="true" />}
options={CONTENT_SORT_OPTIONS.map((option) => ({
value: option.value,
label: option.label,
}))}
value={query.sort}
onValueChange={(value) => go({ sort: value as ContentSortOption })}
/>
<FoxSelectText
size="sm"
ariaLabel="페이지 크기"
options={CONTENT_PAGE_SIZE_OPTIONS.map((size) => ({
value: String(size),
label: `${size}개씩 보기`,
}))}
value={String(query.pageSize)}
onValueChange={(value) =>
go({ pageSize: Number(value) as ContentPageSize, page: 1 })
}
/>
</>
}
searchFields={CONTENT_SEARCH_FIELDS[kind].map((field) => ({
value: field.value,
label: field.label,
}))}
searchField={query.searchField}
keyword={query.keyword}
searchPlaceholder="검색어를 입력하세요."
toolbarActions={
<FoxButtonGroup size="md">
{extraActions}
<FoxButton
type="primary"
size="md"
leadingIcon={<i className="fox-ico fox-ico-Plus" aria-hidden="true" />}
label="등록"
onAction={() => router.push(contentCreatePath(kind))}
/>
</FoxButtonGroup>
}
page={currentPage}
totalPages={totalPages}
buildHref={(patch) => buildContentHref(kind, query, patch as Partial<ContentQuery>)}
onQueryChange={go}
/>
);
}