import { useState } from 'react'; import { motion } from 'framer-motion'; import { Table2, Download, Copy, ArrowUpDown, ChevronLeft, ChevronRight } from 'lucide-react'; import useChatStore from '../../store/useChatStore'; function formatCell(v) { if (v == null) return NULL; if (typeof v === 'number') return Number.isInteger(v) ? v.toLocaleString() : v.toFixed(2); return String(v); } function isNumericCol(rows, col) { return rows.some(r => r[col] != null && Number.isFinite(Number(r[col]))); } function downloadCSV(rows) { if (!rows.length) return; const cols = Object.keys(rows[0]); const csv = [cols.join(','), ...rows.map(r => cols.map(c => JSON.stringify(r[c] ?? '')).join(','))].join('\n'); const blob = new Blob([csv], { type: 'text/csv' }); const a = document.createElement('a'); a.href = URL.createObjectURL(blob); a.download = 'plainsql_result.csv'; a.click(); } export default function ResultTable({ rows }) { const addToast = useChatStore(s => s.addToast); const [sortCol, setSortCol] = useState(null); const [sortDir, setSortDir] = useState('asc'); const [page, setPage] = useState(0); const PAGE_SIZE = 15; if (!rows?.length) return null; const cols = Object.keys(rows[0]); const numericCols = new Set(cols.filter(c => isNumericCol(rows, c))); const sorted = sortCol ? [...rows].sort((a, b) => { const av = a[sortCol], bv = b[sortCol]; const cmp = typeof av === 'number' ? av - bv : String(av ?? '').localeCompare(String(bv ?? '')); return sortDir === 'asc' ? cmp : -cmp; }) : rows; const paged = sorted.slice(page * PAGE_SIZE, (page + 1) * PAGE_SIZE); const totalPages = Math.ceil(rows.length / PAGE_SIZE); const handleSort = (col) => { if (sortCol === col) setSortDir(d => d === 'asc' ? 'desc' : 'asc'); else { setSortCol(col); setSortDir('asc'); } }; const handleCopyJSON = async () => { await navigator.clipboard.writeText(JSON.stringify(rows, null, 2)).catch(() => {}); addToast('Result JSON copied to clipboard', 'success'); }; return ( {/* Header */}
Results {rows.length} rows
{/* Table container */}
{cols.map(col => ( ))} {paged.map((row, ri) => ( {cols.map(col => ( ))} ))}
handleSort(col)} className={` px-4 py-2.5 font-bold text-t3 cursor-pointer hover:text-t2 transition-colors whitespace-nowrap select-none ${numericCols.has(col) ? 'text-right' : 'text-left'} `} >
{col.replace(/_/g, ' ')}
{formatCell(row[col])}
{/* Pagination */} {totalPages > 1 && (
{page * PAGE_SIZE + 1}–{Math.min((page + 1) * PAGE_SIZE, rows.length)} of {rows.length}
{page + 1} / {totalPages}
)}
); }