o2o-negosium-original/negodata/front/src/features/partners/components/PartnerTable.tsx
Mina Choi 03322d6ca3 [feat] negodata: 카드 성공률 순위·상품 엑셀 TO-BE 싱크·회사설정 JSON 입출력·목록 포털형 UI
- 협상카드 성공률(사용 세션 대비 타결) 집계 추가, 견적 생성 카드선택 순위 정렬·통계 TOP5
- 상품 엑셀: 품목코드·모델명 라벨화, 리드타임 suffix 제거, 공급사 컬럼 신설(등록 후 supplier_items 매핑)
- 설정 화면 JSON 불러오기/내보내기(빈 값은 미갱신), IMK 설정 JSON 보관
- 설정·회원 페이지 새로고침 forbidden 수정(자식 loader 가 initAuth 대기)
- 협력사·견적 목록도 포털형 카드(툴바+테이블 결합)로 통일
2026-07-22 17:27:23 +09:00

107 lines
3.4 KiB
TypeScript

import { DataTable } from '@/components/ui/data-table';
import { TablePagination } from '@/components/ui/table-pagination';
import { formatPhoneKR } from '@/lib/phone';
import type { Partner } from '../types';
type PartnerTableProps = {
data: Partner[];
selectedIds: string[];
onSelectionChange: (ids: string[]) => void;
onRowClick: (part: Partner) => void;
page: number;
totalPages: number;
totalCount: number;
pageSize: number;
onPageChange: (page: number) => void;
/** 툴바와 한 카드로 붙일 때 테이블 자체 테두리/라운드를 죽이는 용도 */
className?: string;
};
export function PartnerTable({
data,
selectedIds,
onSelectionChange,
onRowClick,
page,
totalPages,
totalCount,
pageSize,
onPageChange,
className,
}: PartnerTableProps) {
return (
<DataTable
className={className}
data={data}
rowKey={(part) => part.supplier_id}
onRowClick={onRowClick}
selection={{ selectedKeys: selectedIds, onSelectionChange }}
empty="협약된 가용 B2B 파트너사가 존재하지 않습니다."
footer={
<TablePagination
page={page}
totalPages={totalPages}
totalCount={totalCount}
pageSize={pageSize}
onPageChange={onPageChange}
label="연동 파트너사"
unit="개사"
/>
}
columns={[
{
header: '협력사명',
align: 'left',
headClassName: 'w-2/5',
cell: (part) => <span className="font-bold text-sm text-foreground">{part.name}</span>,
},
{
header: '협력사코드',
align: 'left',
cellClassName: 'font-mono font-medium text-muted-foreground',
cell: (part) => part.code,
},
{
header: '담당자명 / 담당자 이메일 / 연락처',
align: 'left',
mobileBlock: true, // 여러 줄 블록 → 모바일 카드뷰에서 라벨 아래 풀폭
cell: (part) => (
<div className="space-y-0.5 font-mono text-xs">
<div className="text-foreground font-semibold">{part.manager_name}</div>
<div className="text-[10px] text-muted-foreground">
{part.manager_email} / {part.manager_contact_number ? formatPhoneKR(part.manager_contact_number) : '-'}
</div>
</div>
),
},
{
header: '총매출액',
align: 'right',
cellClassName: 'font-mono text-muted-foreground',
cell: (part) => (part.total_revenue != null ? `₩${Number(part.total_revenue).toLocaleString()}` : '-'),
},
{
header: '채팅 계정',
align: 'center',
cellClassName: 'font-mono whitespace-nowrap',
cell: (part) =>
part.account_login_id ? (
<span className="text-xs text-foreground">
{part.account_login_id}
{part.account_status === 2 && <span className="ml-1 text-[10px] text-rose-500">비활성</span>}
</span>
) : (
<span className="text-[10px] text-muted-foreground">미발급</span>
),
},
{
header: '작성자',
align: 'center',
cellClassName: 'text-muted-foreground whitespace-nowrap',
cell: (part) => part.creator_name ?? '-',
},
]}
/>
);
}