'use client'; import { useRouter } from 'next/navigation'; import { useState } from 'react'; import { FoxButton } from '@fox/core/components/fox-button'; import { FoxListContainer, type FoxListColumn, } from '@fox/core/components/fox-list-container'; import { FoxSelect } from '@fox/core/components/fox-select'; import { FoxSelectText } from '@fox/core/components/fox-select-text'; import { FoxStatusIndicator } from '@fox/core/components/fox-status-indicator'; import { formatAddressSummary, formatCategoryLabel, formatOptionalValue, formatVisibilityLabel, type Merchant, } from '@/lib/domain/merchant'; import { MERCHANTS_EXCEL_PATH, MERCHANTS_PATH, MERCHANT_PAGE_SIZE_OPTIONS, MERCHANT_SEARCH_FIELD_OPTIONS, MERCHANT_VISIBILITY_OPTIONS, buildMerchantHref, type MerchantPageSize, type MerchantQuery, type MerchantSearchField, } from '@/lib/domain/merchant-query'; import { MerchantFormModal } from './merchant-form-modal'; import { MerchantRowActions } from './merchant-row-actions'; import styles from './merchant-filter.module.scss'; interface MerchantListProps { items: Merchant[]; query: MerchantQuery; currentPage: number; totalPages: number; totalCount: number; } /** 기획 MCH_001 ④ — 정렬은 최근등록순 하나뿐이라 선택지가 아니라 표시다. */ const SORT_OPTIONS = [{ value: 'recent', label: '최근등록순' }]; export function MerchantList({ items, query, currentPage, totalPages, totalCount, }: MerchantListProps) { const router = useRouter(); const [isCreateOpen, setIsCreateOpen] = useState(false); function go(patch: Partial) { router.replace(buildMerchantHref(query, { ...patch, page: 1 })); } const columns: FoxListColumn[] = [ { key: 'no', header: '번호', width: 80, render: (_row, index) => (currentPage - 1) * query.pageSize + index + 1, }, { key: 'code', header: '가맹점코드', width: 140 }, { key: 'brandName', header: '브랜드명', width: 120, render: (row) => formatOptionalValue(row.brandName), }, { key: 'name', header: '가맹점명', width: 240, emphasis: true }, { key: 'categoryCode', header: '업종', width: 100, render: (row) => formatCategoryLabel(row.categoryCode), }, { key: 'phoneNumber', header: '전화번호', width: 160, render: (row) => formatOptionalValue(row.phoneNumber), }, { key: 'address', header: '주소', width: 280, render: formatAddressSummary, }, { key: 'isVisible', header: '사용여부', width: 120, render: (row) => ( ), }, { key: 'createdAt', header: '등록일', width: 140, render: (row) => formatOptionalValue(row.createdAt), }, { key: 'actions', header: '관리', width: 120, render: (row) => , }, ]; return ( <> title="가맹점 목록" breadcrumb={[ { label: '홈', href: '/' }, { label: '관리자관리' }, { label: '가맹점 관리' }, ]} caption="가맹점 목록" columns={columns} rows={items} rowKey={(row) => row.id} totalCount={totalCount} emptyMessage="검색 결과가 없습니다." sorts={ <> ({ value: String(size), label: `${size}개씩`, }))} value={String(query.pageSize)} onValueChange={(value) => go({ pageSize: Number(value) as MerchantPageSize }) } /> } filter={
({ value: option.value, label: option.label, })), ]} value={query.visibility} onValueChange={(value) => go({ visibility: value })} />
} searchFields={MERCHANT_SEARCH_FIELD_OPTIONS.map((option) => ({ value: option.value, label: option.label, }))} searchField={query.searchField} keyword={query.keyword} searchPlaceholder="검색어를 입력하세요." toolbarActions={ <> {/* TODO(기획): 엑셀등록 양식·검증 규칙이 정해지지 않았다. 규칙이 나오면 금칙어 화면처럼 업로드 모달을 붙인다. */}