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 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 },
{
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)}
/>
)}
</>
);
}