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
File name
Commit message
Commit date
'use client';
import { useState } from 'react';
import { useRouter } from 'next/navigation';
import { FoxButton } from '@fox/core/components/fox-button';
import { FoxButtonGroup } from '@fox/core/components/fox-button-group';
import {
FoxListContainer,
type FoxListColumn,
} from '@fox/core/components/fox-list-container';
import { FoxSelectText } from '@fox/core/components/fox-select-text';
import { FoxStatusIndicator } from '@fox/core/components/fox-status-indicator';
import {
formatActiveLabel,
formatDuplicableLabel,
formatLimitPoint,
formatOptionalValue,
formatPoint,
type PointStandard,
} from '@/lib/domain/point-standard';
import { formatCommonCode, type CommonCode } from '@/lib/domain/common-code';
import {
POINT_STANDARDS_PATH,
POINT_STANDARD_PAGE_SIZE_OPTIONS,
buildPointStandardHref,
type PointStandardPageSize,
type PointStandardQuery,
} from '@/lib/domain/point-standard-query';
import { PointStandardFormModal } from './point-standard-form-modal';
import { PointStandardRowActions } from './point-standard-row-actions';
interface PointStandardListProps {
items: PointStandard[];
query: PointStandardQuery;
currentPage: number;
totalPages: number;
totalCount: number;
/** 공통코드 `CODE_GROUP.pointEvent` — 등록 팝업의 이벤트 선택지. */
eventCodes: readonly CommonCode[];
}
export function PointStandardList({
items,
query,
currentPage,
totalPages,
totalCount,
eventCodes,
}: PointStandardListProps) {
const router = useRouter();
const [isCreateOpen, setIsCreateOpen] = useState(false);
function go(patch: Partial<PointStandardQuery>) {
router.replace(buildPointStandardHref(query, { ...patch, page: 1 }));
}
const columns: FoxListColumn<PointStandard>[] = [
{
key: 'no',
header: '번호',
width: 80,
render: (_row, index) => (currentPage - 1) * query.pageSize + index + 1,
},
{
key: 'eventCode',
header: '이벤트/구분',
width: 140,
emphasis: true,
// 표에 없는 코드는 지어내지 않고 코드 그대로 보여준다(formatCommonCode 규칙).
render: (row) => formatCommonCode(eventCodes, row.eventCode),
},
{
key: 'point',
header: '포인트',
width: 100,
align: 'end',
render: (row) => formatPoint(row.point),
},
{
key: 'limitPoint',
header: '제한포인트',
width: 120,
align: 'end',
render: (row) => formatLimitPoint(row.limitPoint),
},
{
key: 'isDuplicable',
header: '중복여부',
width: 120,
render: (row) => (
<FoxStatusIndicator
type={row.isDuplicable ? 'success' : 'default'}
label={formatDuplicableLabel(row.isDuplicable)}
/>
),
},
{ key: 'description', header: '설명', width: 320 },
{
key: 'isActive',
header: '사용여부',
width: 120,
render: (row) => (
<FoxStatusIndicator
type={row.isActive ? 'success' : 'danger'}
label={formatActiveLabel(row.isActive)}
/>
),
},
{
key: 'updatedAt',
header: '수정일시',
width: 160,
render: (row) => formatOptionalValue(row.updatedAt),
},
{
key: 'actions',
header: '관리',
width: 120,
render: (row) => <PointStandardRowActions standard={row} eventCodes={eventCodes} />,
},
];
return (
<>
<FoxListContainer<PointStandard>
title="포인트 기준관리 목록"
breadcrumb={[
{ label: '홈', href: '/' },
{ label: '포인트관리' },
{ label: '포인트 기준관리' },
]}
caption="포인트 기준관리 목록"
columns={columns}
rows={items}
rowKey={(row) => row.id}
totalCount={totalCount}
emptyMessage="검색 결과가 없습니다. 다른 검색어로 다시 시도해 주세요."
sorts={
<FoxSelectText
size="sm"
ariaLabel="페이지 크기"
options={POINT_STANDARD_PAGE_SIZE_OPTIONS.map((size) => ({
value: String(size),
label: `${size}개씩 보기`,
}))}
value={String(query.pageSize)}
onValueChange={(value) =>
go({ pageSize: Number(value) as PointStandardPageSize })
}
/>
}
searchFields={[]}
keyword={query.keyword}
searchPlaceholder="검색어를 입력하세요."
toolbarActions={
<FoxButtonGroup size="md">
<FoxButton
type="default"
size="md"
label="초기화"
onAction={() => router.replace(POINT_STANDARDS_PATH)}
/>
<FoxButton
type="primary"
size="md"
leadingIcon={<i className="fox-ico fox-ico-Plus" aria-hidden="true" />}
label="신규 등록"
onAction={() => setIsCreateOpen(true)}
/>
</FoxButtonGroup>
}
page={currentPage}
totalPages={totalPages}
buildHref={(patch) =>
buildPointStandardHref(query, { page: Number(patch.page ?? 1) })
}
onQueryChange={(patch) => {
if (patch.keyword !== undefined) {
go({ keyword: String(patch.keyword ?? '') });
}
}}
/>
{isCreateOpen && (
<PointStandardFormModal
eventCodes={eventCodes}
onClose={() => setIsCreateOpen(false)}
/>
)}
</>
);
}