'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 { FoxArrowsDownUpIcon, FoxPlusIcon, } from '@fox/core/icons'; 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 { kind: ContentKind; columns: FoxListColumn[]; 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({ kind, columns, rows, rowKey, query, currentPage, totalPages, totalCount, schools, gradesBySchool, extraActions, }: ContentListShellProps) { const router = useRouter(); function go(patch: Partial) { router.push(buildContentHref(kind, query, patch)); } return ( title={`콘텐츠 목록 (${CONTENT_KIND_LABEL[kind]})`} breadcrumb={contentBreadcrumb(kind)} caption={`${CONTENT_KIND_LABEL[kind]} 콘텐츠 목록`} columns={columns} rows={rows} rowKey={rowKey} totalCount={totalCount} emptyMessage="등록된 콘텐츠가 없습니다." filter={ } sorts={ <> } options={CONTENT_SORT_OPTIONS.map((option) => ({ value: option.value, label: option.label, }))} value={query.sort} onValueChange={(value) => go({ sort: value as ContentSortOption })} /> ({ 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={ {extraActions} } label="등록" onAction={() => router.push(contentCreatePath(kind))} /> } page={currentPage} totalPages={totalPages} buildHref={(patch) => buildContentHref(kind, query, patch as Partial)} onQueryChange={go} /> ); }