112 lines
4.4 KiB
TypeScript
112 lines
4.4 KiB
TypeScript
import type { ReactNode } from 'react';
|
|
import { DataTable } from '@/components/ui/data-table';
|
|
import { renderEmphasis } from '@/lib/emphasis';
|
|
import type { NegotiationCard } from '../types';
|
|
|
|
type CardTableProps = {
|
|
data: NegotiationCard[];
|
|
onEdit: (card: NegotiationCard) => void;
|
|
footer?: ReactNode;
|
|
};
|
|
|
|
export function CardTable({ data, onEdit, footer }: CardTableProps) {
|
|
return (
|
|
<DataTable
|
|
data={data}
|
|
rowKey={(card) => card.id}
|
|
onRowClick={onEdit}
|
|
empty="데이터가 없습니다."
|
|
footer={footer}
|
|
columns={[
|
|
{
|
|
header: '구분',
|
|
headClassName: 'w-24',
|
|
cell: (card) => (
|
|
<div className="flex flex-col items-start gap-1">
|
|
{card.isWildcard ? (
|
|
<span className="inline-flex items-center px-1.5 py-0.5 rounded text-[10px] font-bold bg-rose-50 text-rose-700 dark:bg-rose-950/20 dark:text-rose-400 border border-rose-200/40">
|
|
와일드카드
|
|
</span>
|
|
) : (
|
|
<span className="inline-flex items-center px-1.5 py-0.5 rounded text-[10px] font-bold bg-blue-50 text-blue-700 dark:bg-blue-950/20 dark:text-blue-400 border border-blue-200/40">
|
|
협상카드
|
|
</span>
|
|
)}
|
|
{card.isShared && (
|
|
<span className="inline-flex items-center px-1.5 py-0.5 rounded text-[10px] font-bold bg-violet-50 text-violet-700 dark:bg-violet-950/20 dark:text-violet-400 border border-violet-200/40">
|
|
전체
|
|
</span>
|
|
)}
|
|
</div>
|
|
),
|
|
},
|
|
{
|
|
header: '카드번호',
|
|
headClassName: 'w-28',
|
|
cellClassName: 'font-mono font-semibold text-foreground',
|
|
cell: (card) => card.code,
|
|
},
|
|
{
|
|
header: '카드이름',
|
|
headClassName: 'w-52',
|
|
mobileHeader: true, // 모바일 카드뷰 제목(첫 컬럼 '구분' 배지 대신)
|
|
cell: (card) => (
|
|
<>
|
|
<div className="font-semibold text-foreground text-sm">{card.title}</div>
|
|
{card.memo && (
|
|
<div className="text-[10px] text-muted-foreground font-mono mt-0.5 max-w-[200px] truncate">
|
|
{card.memo}
|
|
</div>
|
|
)}
|
|
</>
|
|
),
|
|
},
|
|
{
|
|
header: '스크립트',
|
|
headClassName: 'w-[22rem]', // 컬럼 폭 고정 → 긴 스크립트가 표를 늘리지 않게
|
|
cellClassName: 'font-mono text-muted-foreground',
|
|
mobileBlock: true, // 긴 미리보기 블록 → 모바일 카드뷰에서 라벨 아래 풀폭
|
|
cell: (card) => (
|
|
<div className="max-w-[22rem] truncate bg-muted/20 px-2 py-1 rounded border border-border/30 text-[11px] leading-snug">
|
|
{/* 마커(**굵게**·{{색}})를 스타일로 렌더 — 표 미리보기에 원시 마커가 보이지 않게 */}
|
|
{renderEmphasis(card.scriptPreview)}
|
|
</div>
|
|
),
|
|
},
|
|
{
|
|
header: '사용 조건 (와일드 전용)',
|
|
headClassName: 'w-40',
|
|
cellClassName: 'font-mono text-xs font-semibold text-rose-600 dark:text-rose-400',
|
|
cell: (card) => (card.isWildcard ? card.triggerCondition || '조건 없음' : '-'),
|
|
},
|
|
{
|
|
header: '상태',
|
|
align: 'center',
|
|
headClassName: 'w-24',
|
|
cell: (card) =>
|
|
card.isWildcard ? (
|
|
<span
|
|
className={`inline-flex items-center px-2 py-0.5 text-[10px] font-semibold rounded-full border ${
|
|
card.status === 'ACTIVE'
|
|
? 'bg-emerald-50 text-emerald-700 dark:bg-emerald-950/20 dark:text-emerald-400 border-emerald-300/40'
|
|
: 'bg-amber-50 text-amber-700 dark:bg-amber-950/20 dark:text-amber-400 border-amber-300/45'
|
|
}`}
|
|
>
|
|
{card.status === 'ACTIVE' ? '협상적용 가능' : '적용 대기(수동)'}
|
|
</span>
|
|
) : (
|
|
<span className="text-muted-foreground font-mono font-medium opacity-65">-</span>
|
|
),
|
|
},
|
|
{
|
|
header: '작성자',
|
|
align: 'center',
|
|
headClassName: 'w-24',
|
|
cellClassName: 'text-muted-foreground whitespace-nowrap',
|
|
cell: (card) => (card.isShared ? '공용' : card.creatorName ?? '-'),
|
|
},
|
|
]}
|
|
/>
|
|
);
|
|
}
|