'use client'; // D6 §5.1 — 종목행(StockRow) 열 구성 빌더 + StockDataTable 편의 래퍼. // 한 줄 완결: 종목명+코드 | 현재가 | 등락률(색+부호) | 거래대금 | 시가총액 | 시장. // 정렬: 종목명·현재가·등락률·거래대금·시가총액 헤더 클릭 → SSR 재조회(URL sort/order). 기본 시가총액 desc. // 거래대금/시총 등 우선순위 낮은 열은 mobile drop (data-priority='low'). import Link from 'next/link'; import { useRouter } from 'next/navigation'; import { useCallback, useTransition } from 'react'; import DataTable, { DataTableColumn } from '@/components/table/DataTable'; import PriceChange from '@/components/table/PriceChange'; import { StockListRow, StockSortKey, StockSortOrder } from '@/types/stock'; import { formatKrwCompact, formatNumber, tradingStatusLabel } from '@/lib/utils/stock'; // 활성 정렬 컬럼만 방향, 나머지 정렬 가능 컬럼은 null(비활성) function colSort(key: StockSortKey, activeSort: StockSortKey, order: StockSortOrder): StockSortOrder|null { return key === activeSort ? order : null; } export function buildStockColumns(sort: StockSortKey, order: StockSortOrder): DataTableColumn[] { return [ { key: 'name', header: '종목명', align: 'left', priority: 'high', sort: colSort('name', sort, order), cellClassName: 'data-table__cell--name', cell: (row) => { const status = tradingStatusLabel(row.tradingStatus); return ( {row.name} {row.code} {status && ( {status} )} ); } }, { key: 'price', header: <>현재가 (전일종가), align: 'right', priority: 'high', sort: colSort('price', sort, order), cell: (row) => formatNumber(row.closePrice) }, { key: 'change', header: '등락률', align: 'right', priority: 'high', sort: colSort('change', sort, order), cell: (row) => }, { key: 'value', header: '거래대금', align: 'right', priority: 'low', sort: colSort('value', sort, order), cell: (row) => formatKrwCompact(row.tradingValue) }, { key: 'cap', header: '시가총액', align: 'right', priority: 'low', sort: colSort('cap', sort, order), cell: (row) => formatKrwCompact(row.marketCap) }, { key: 'market', header: '시장', align: 'center', priority: 'medium', cell: (row) => {row.market} } ]; } interface StockDataTableProps { rows: StockListRow[]; sort: StockSortKey; order: StockSortOrder; // 정렬 URL 재구성 시 유지할 현재 필터 market?: string; q?: string; caption?: string; emptyMessage?: string; } // 종목 목록 편의 래퍼 — 정렬 헤더 클릭 시 sort/order URL 로 SSR 재조회(필터 유지·페이지 1로 리셋). // useTransition 으로 재조회 중 현재 표 유지(스켈레톤 플래시 없이) + 흐림 표시. export default function StockDataTable({ rows, sort, order, market, q, caption, emptyMessage }: StockDataTableProps) { const router = useRouter(); const [isPending, startTransition] = useTransition(); const handleSort = useCallback((key: string) => { const k = key as StockSortKey; // 같은 컬럼 재클릭 → 방향 토글, 새 컬럼 → 기본 방향(종목명 asc, 숫자열 desc) const nextOrder: StockSortOrder = k === sort ? (order === 'desc' ? 'asc' : 'desc') : (k === 'name' ? 'asc' : 'desc'); const params = new URLSearchParams(); if (market) { params.set('market', market); } if (q) { params.set('q', q); } params.set('sort', k); params.set('order', nextOrder); startTransition(() => { router.push(`/stock?${params.toString()}`); }); }, [router, sort, order, market, q]); return (
caption={caption ?? '종목 목록 — 종목명, 현재가(전일 종가), 등락률, 거래대금, 시가총액, 시장'} columns={buildStockColumns(sort, order)} rows={rows} rowKey={(row) => row.code} onSort={handleSort} emptyMessage={emptyMessage} />
); }