import { useCallback, useMemo, useState } from 'react' import { flexRender, getCoreRowModel, getPaginationRowModel, useReactTable, } from '@tanstack/react-table' import { Loader2, Search } from 'lucide-react' import { useTranslation } from 'react-i18next' import { Input } from '@/components/ui/input' import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from '@/components/ui/select' import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow, } from '@/components/ui/table' import { DataTablePagination } from '@/components/data-table/pagination' import type { DifferencesMap, RatioType } from '../types' import { RATIO_TYPE_OPTIONS } from './constants' import { useUpstreamRatioSyncColumns } from './upstream-ratio-sync-columns' import { getOrderedRatioTypes, getPreferredSyncField, isSelectableUpstreamValue, RATIO_SYNC_FIELDS, type ModelRow, type ResolutionsMap, } from './upstream-ratio-sync-helpers' type UpstreamRatioSyncTableProps = { differences: DifferencesMap resolutions: ResolutionsMap isDisabled: boolean isSyncing: boolean onSelectValue: ( model: string, ratioType: RatioType, value: number | string, sourceName: string ) => void onUnselectValue: (model: string, ratioType: RatioType) => void } export function UpstreamRatioSyncTable({ differences, resolutions, isDisabled, isSyncing, onSelectValue, onUnselectValue, }: UpstreamRatioSyncTableProps) { const { t } = useTranslation() const [search, setSearch] = useState('') const [ratioTypeFilter, setRatioTypeFilter] = useState('') const dataSource = useMemo(() => { return Object.entries(differences).map(([model, ratioTypes]) => { const hasPrice = 'model_price' in ratioTypes const hasOtherRatio = RATIO_SYNC_FIELDS.some((rt) => rt in ratioTypes) return { key: model, model, ratioTypes, billingConflict: hasPrice && hasOtherRatio, } }) }, [differences]) const filteredData = useMemo(() => { let data = dataSource if (search.trim()) { const lower = search.toLowerCase() data = data.filter((row) => row.model.toLowerCase().includes(lower)) } if (ratioTypeFilter && ratioTypeFilter !== '__all__') { data = data.filter((row) => ratioTypeFilter in row.ratioTypes) } return data }, [dataSource, search, ratioTypeFilter]) const upstreamNames = useMemo(() => { const set = new Set() filteredData.forEach((row) => { getOrderedRatioTypes(row.ratioTypes, ratioTypeFilter).forEach( (ratioType) => { Object.keys(row.ratioTypes[ratioType]?.upstreams || {}).forEach( (name) => set.add(name) ) } ) }) return Array.from(set) }, [filteredData, ratioTypeFilter]) const handleBulkSelect = useCallback( (upstream: string, rows: ModelRow[]) => { rows.forEach((row) => { getOrderedRatioTypes(row.ratioTypes, ratioTypeFilter).forEach( (ratioType) => { const upstreamVal = row.ratioTypes[ratioType]?.upstreams?.[upstream] const preferredField = getPreferredSyncField( row.ratioTypes, ratioType, upstream ) if ( preferredField === ratioType && isSelectableUpstreamValue(upstreamVal) ) { onSelectValue( row.model, ratioType, upstreamVal as number | string, upstream ) } } ) }) }, [ratioTypeFilter, onSelectValue] ) const handleBulkUnselect = useCallback( (upstream: string, rows: ModelRow[]) => { rows.forEach((row) => { getOrderedRatioTypes(row.ratioTypes, ratioTypeFilter).forEach( (ratioType) => { if ( row.ratioTypes[ratioType]?.upstreams?.[upstream] !== undefined ) { onUnselectValue(row.model, ratioType) } } ) }) }, [ratioTypeFilter, onUnselectValue] ) const columns = useUpstreamRatioSyncColumns( upstreamNames, resolutions, ratioTypeFilter, isDisabled, onSelectValue, onUnselectValue, handleBulkSelect, handleBulkUnselect ) const table = useReactTable({ data: filteredData, columns, getCoreRowModel: getCoreRowModel(), getPaginationRowModel: getPaginationRowModel(), getRowId: (row) => row.key, initialState: { pagination: { pageSize: 10 }, }, }) if (dataSource.length === 0) { if (isSyncing) { return (

{t('Fetching upstream prices...')}

) } return (

{t('No upstream price differences found')}

{t('Select sync channels to compare prices')}

) } return (
setSearch(e.target.value)} disabled={isDisabled} className='ps-8' />
{table.getHeaderGroups().map((headerGroup) => ( {headerGroup.headers.map((header) => ( {header.isPlaceholder ? null : flexRender( header.column.columnDef.header, header.getContext() )} ))} ))} {table.getRowModel().rows.length > 0 ? ( table.getRowModel().rows.map((row) => ( {row.getVisibleCells().map((cell) => ( {flexRender( cell.column.columnDef.cell, cell.getContext() )} ))} )) ) : ( {t('No results found')} )}
) }