"use client" import { dataGridFeatures, type DataGridFeatures } from "@/components/reui/data-grid" import { useEffect, useMemo, useState } from "react" import { Input } from "@/components/ui/input" import { DataGridContainer, DataGridScrollArea, DataGridTable } from "@/components/reui/data-grid" import { type ColumnDef, useTable, } from "@tanstack/react-table" import type { CommRec } from "@/lib/route-optimizer-data" import { cn } from "@/lib/utils" import { Button } from "@/components/ui/button" import { DataGridShell } from "@/components/data-grids/shared/data-grid-shell" import { DATA_GRID_CELL_PAD, DATA_GRID_CELL_PAD_FIRST, DATA_GRID_CELL_PAD_LAST, } from "@/components/data-grids/shared/data-grid-layout" import { DataGridSortHeader } from "@/components/data-grids/shared/data-grid-sort-header" import { ArrowRightIcon, PinIcon, RefreshCwIcon } from "lucide-react" function Chip({ children, color }: { children: React.ReactNode; color?: string }) { return ( {children} ) } function ProbChip({ prob, best }: { prob: number | null; best?: boolean }) { if (prob === null) return — return ( {prob} б. ) } interface RouteOptimizerCommRecsDataGridProps { recs: CommRec[] homeId: string pinned: Set applied: Set applying: Set onPin: (key: string) => void simulation?: boolean onApply: (community: string, homeId: string) => void } function RouteOptimizerCommRecsDataGrid({ recs, homeId, pinned, applied, applying, onPin, onApply, simulation = false, }: RouteOptimizerCommRecsDataGridProps) { const [query, setQuery] = useState("") const rows = useMemo( () => recs.map((r, idx) => ({ ...r, _rowKey: `${homeId}::${r.community}::${idx}` })), [homeId, recs], ) const filtered = useMemo(() => rows.filter(row => [row.community, row.communityName, row.current?.wan, row.current?.jh, row.current?.exit, row.current?.gateway, row.recommended?.wan, row.recommended?.jh, row.recommended?.exit, row.recommended?.gateway] .join(" ").toLocaleLowerCase().includes(query.trim().toLocaleLowerCase())), [rows, query]) const columns = useMemo[]>( () => [ { id: "community", size: 180, accessorKey: "community", header: ({ column }) => ( ), cell: ({ row }) => ( {row.original.community} {row.original.communityName} ), meta: { headerTitle: "Community", headerClassName: DATA_GRID_CELL_PAD_FIRST, cellClassName: DATA_GRID_CELL_PAD_FIRST, }, }, { id: "current", size: 260, header: () => ( Базовый расчёт (WAN → JH → Exit) ), enableSorting: false, cell: ({ row }) => { const r = row.original if (!r.current) return — return ( {r.current.wan} {r.current.jh} {r.current.exit} ({r.current.gateway}) ) }, meta: { headerClassName: DATA_GRID_CELL_PAD, cellClassName: DATA_GRID_CELL_PAD }, }, { id: "recommended", size: 260, header: () => Рекомендуемый, enableSorting: false, cell: ({ row }) => { const r = row.original const pinKey = `${homeId}::${r.community}` const isPinned = pinned.has(pinKey) if (!r.recommended) return — return ( {r.recommended.wan} {r.recommended.jh} {r.recommended.exit} {r.shouldSwitch && r.current && !isPinned && ( +{r.recommended.prob - r.current.prob} б. )} ) }, meta: { headerClassName: DATA_GRID_CELL_PAD, cellClassName: DATA_GRID_CELL_PAD }, }, { id: "probability", size: 160, header: () => ( Индекс (баз / рек) ), enableSorting: false, cell: ({ row }) => { const r = row.original const pinKey = `${homeId}::${r.community}` return ( / ) }, meta: { headerClassName: cn(DATA_GRID_CELL_PAD, "text-center"), cellClassName: cn(DATA_GRID_CELL_PAD, "text-center"), }, }, { id: "actions", size: 240, header: () => ( Действие ), enableSorting: false, cell: ({ row }) => { const r = row.original const pinKey = `${homeId}::${r.community}` const isPinned = pinned.has(pinKey) const isApplied = simulation && applied.has(pinKey) const isApplying = simulation && applying.has(pinKey) const canApply = simulation && r.shouldSwitch && !isPinned && !isApplied return ( e.stopPropagation()}> {isPinned && } onPin(pinKey)} > {isPinned ? "Открепить" : "Закрепить"} {canApply && ( onApply(r.community, homeId)} > {isApplying ? ( ) : ( "Симулировать" )} )} {isApplied && ( ✓ симуляция завершена )} ) }, meta: { headerClassName: cn(DATA_GRID_CELL_PAD_LAST, "text-right"), cellClassName: DATA_GRID_CELL_PAD_LAST, }, }, ], [applied, applying, homeId, onApply, onPin, pinned, simulation], ) const table = useTable({ features: dataGridFeatures, manualPagination: false, autoResetPageIndex: false, initialState: { pagination: { pageIndex: 0, pageSize: 50 }, columnPinning: { start: ["community"], end: [] } }, data: filtered, columns, getRowId: (row) => row._rowKey, }) const { pageIndex, pageSize } = table.state.pagination useEffect(() => { const lastPage = Math.max(0, Math.ceil(filtered.length / pageSize) - 1) if (pageIndex > lastPage) table.setPageIndex(lastPage) }, [filtered.length, pageIndex, pageSize, table]) return ( Поиск Community { setQuery(event.target.value); table.setPageIndex(0) }} placeholder="Community, название или шлюз" /> Community: {filtered.length} из {rows.length}. Индексы и пути — расчётная модель. 50 || pageSize !== 50} tableClassNames={{ headerRow: "border-b bg-muted/20", bodyRow: cn( "group/row hover:bg-muted/30", "[&:has([data-comm-switch=true])]:bg-warning/5", "[&:has([data-comm-applied=true])]:bg-success/5", ), }} tableLayout={{ dense: true, width: "fixed", columnsPinnable: true }} > ) } export { RouteOptimizerCommRecsDataGrid, type RouteOptimizerCommRecsDataGridProps }
Community: {filtered.length} из {rows.length}. Индексы и пути — расчётная модель.