'use client'; import clsx from 'clsx'; import { useEffect, useState } from 'react'; import BadgeConstituenta from '@/components/info/BadgeConstituenta'; import { CProps } from '@/components/props'; import DataTable, { createColumnHelper, RowSelectionState } from '@/components/ui/DataTable'; import NoData from '@/components/ui/NoData'; import SearchBar from '@/components/ui/SearchBar'; import { Graph } from '@/models/Graph'; import { CstMatchMode } from '@/models/miscellaneous'; import { ConstituentaID, IConstituenta, IRSForm } from '@/models/rsform'; import { isBasicConcept, matchConstituenta } from '@/models/rsformAPI'; import { describeConstituenta } from '@/utils/labels'; import ToolbarGraphSelection from './ToolbarGraphSelection'; interface PickMultiConstituentaProps extends CProps.Styling { id?: string; schema: IRSForm; data: IConstituenta[]; prefixID: string; rows?: number; noBorder?: boolean; selected: ConstituentaID[]; setSelected: React.Dispatch>; } const columnHelper = createColumnHelper(); function PickMultiConstituenta({ id, schema, data, prefixID, rows, noBorder, selected, setSelected, className, ...restProps }: PickMultiConstituentaProps) { const [rowSelection, setRowSelection] = useState({}); const [filtered, setFiltered] = useState(data); const [filterText, setFilterText] = useState(''); // TODO: extract graph fold logic to separate function const foldedGraph = (() => { if (data.length === schema.items.length) { return schema.graph; } const newGraph = new Graph(); schema.graph.nodes.forEach(node => { newGraph.addNode(node.id); node.outputs.forEach(output => { newGraph.addEdge(node.id, output); }); }); schema.items .filter(item => data.find(cst => cst.id === item.id) === undefined) .forEach(item => { newGraph.foldNode(item.id); }); return newGraph; })(); useEffect(() => { if (filtered.length === 0) { setRowSelection({}); return; } const newRowSelection: RowSelectionState = {}; filtered.forEach((cst, index) => { newRowSelection[String(index)] = selected.includes(cst.id); }); setRowSelection(newRowSelection); }, [filtered, setRowSelection, selected]); useEffect(() => { if (data.length === 0) { setFiltered([]); } else if (filterText) { setFiltered(data.filter(cst => matchConstituenta(cst, filterText, CstMatchMode.ALL))); } else { setFiltered(data); } }, [filterText, data]); function handleRowSelection(updater: React.SetStateAction) { if (!data) { setSelected([]); } else { const newRowSelection = typeof updater === 'function' ? updater(rowSelection) : updater; const newSelection: ConstituentaID[] = []; filtered.forEach((cst, index) => { if (newRowSelection[String(index)] === true) { newSelection.push(cst.id); } }); setSelected(prev => [...prev.filter(cst_id => !filtered.find(cst => cst.id === cst_id)), ...newSelection]); } } const columns = [ columnHelper.accessor('alias', { id: 'alias', header: () => Имя, size: 65, cell: props => }), columnHelper.accessor(cst => describeConstituenta(cst), { id: 'description', size: 1000, header: 'Описание' }) ]; return (
{data.length > 0 ? `Выбраны ${selected.length} из ${data.length}` : 'Конституенты'}
isBasicConcept(schema.cstByID.get(cstID)?.cst_type)} isOwned={cstID => !schema.cstByID.get(cstID)?.is_inherited} selected={selected} setSelected={setSelected} emptySelection={selected.length === 0} className='w-fit' />

Список пуст

} />
); } export default PickMultiConstituenta;