ConceptPortal-public/rsconcept/frontend/src/components/select/PickMultiConstituenta.tsx

138 lines
4.4 KiB
TypeScript
Raw Normal View History

2024-03-20 15:03:53 +03:00
'use client';
import clsx from 'clsx';
2024-04-04 20:03:41 +03:00
import { useLayoutEffect, useMemo, useState } from 'react';
2024-03-20 15:03:53 +03:00
2024-03-20 15:27:32 +03:00
import DataTable, { createColumnHelper, RowSelectionState } from '@/components/ui/DataTable';
import { useConceptOptions } from '@/context/ConceptOptionsContext';
import { CstMatchMode } from '@/models/miscellaneous';
2024-03-20 15:03:53 +03:00
import { ConstituentaID, IConstituenta, IRSForm } from '@/models/rsform';
import { isBasicConcept, matchConstituenta } from '@/models/rsformAPI';
2024-03-20 15:03:53 +03:00
import { describeConstituenta } from '@/utils/labels';
2024-05-16 22:39:28 +03:00
import BadgeConstituenta from '../info/BadgeConstituenta';
2024-06-21 19:27:36 +03:00
import NoData from '../ui/NoData';
import SearchBar from '../ui/SearchBar';
import ToolbarGraphSelection from './ToolbarGraphSelection';
2024-03-20 15:03:53 +03:00
2024-05-16 22:39:28 +03:00
interface PickMultiConstituentaProps {
2024-03-20 15:03:53 +03:00
id?: string;
schema?: IRSForm;
prefixID: string;
rows?: number;
selected: ConstituentaID[];
2024-04-04 20:03:41 +03:00
setSelected: React.Dispatch<React.SetStateAction<ConstituentaID[]>>;
2024-03-20 15:03:53 +03:00
}
const columnHelper = createColumnHelper<IConstituenta>();
2024-05-16 22:39:28 +03:00
function PickMultiConstituenta({ id, schema, prefixID, rows, selected, setSelected }: PickMultiConstituentaProps) {
2024-04-01 19:07:20 +03:00
const { colors } = useConceptOptions();
2024-03-20 15:03:53 +03:00
const [rowSelection, setRowSelection] = useState<RowSelectionState>({});
const [filtered, setFiltered] = useState<IConstituenta[]>(schema?.items ?? []);
const [filterText, setFilterText] = useState('');
2024-03-20 15:03:53 +03:00
useLayoutEffect(() => {
if (filtered.length === 0) {
2024-03-20 15:03:53 +03:00
setRowSelection({});
return;
}
const newRowSelection: RowSelectionState = {};
filtered.forEach((cst, index) => {
newRowSelection[String(index)] = selected.includes(cst.id);
});
setRowSelection(newRowSelection);
}, [filtered, setRowSelection, selected]);
useLayoutEffect(() => {
if (!schema || schema.items.length === 0) {
setFiltered([]);
} else if (filterText) {
setFiltered(schema.items.filter(cst => matchConstituenta(cst, filterText, CstMatchMode.ALL)));
2024-03-20 15:03:53 +03:00
} else {
setFiltered(schema.items);
2024-03-20 15:03:53 +03:00
}
}, [filterText, schema?.items, schema]);
2024-03-20 15:03:53 +03:00
function handleRowSelection(updater: React.SetStateAction<RowSelectionState>) {
if (!schema) {
setSelected([]);
} else {
const newRowSelection = typeof updater === 'function' ? updater(rowSelection) : updater;
const newSelection: ConstituentaID[] = [];
filtered.forEach((cst, index) => {
2024-03-20 15:03:53 +03:00
if (newRowSelection[String(index)] === true) {
newSelection.push(cst.id);
}
});
setSelected(prev => [...prev.filter(cst_id => !filtered.find(cst => cst.id === cst_id)), ...newSelection]);
2024-03-20 15:03:53 +03:00
}
}
const columns = useMemo(
() => [
columnHelper.accessor('alias', {
id: 'alias',
2024-06-04 11:19:21 +03:00
header: () => <span className='pl-3'>Имя</span>,
2024-03-20 15:03:53 +03:00
size: 65,
2024-05-16 22:39:28 +03:00
cell: props => <BadgeConstituenta theme={colors} value={props.row.original} prefixID={prefixID} />
2024-03-20 15:03:53 +03:00
}),
columnHelper.accessor(cst => describeConstituenta(cst), {
id: 'description',
size: 1000,
header: 'Описание'
})
],
[colors, prefixID]
);
return (
<div>
<div className='flex justify-between items-center gap-3 clr-input px-3 border-x border-t rounded-t-md'>
<div className='w-[24ch] select-none whitespace-nowrap'>
2024-03-20 15:03:53 +03:00
Выбраны {selected.length} из {schema?.items.length ?? 0}
</div>
<SearchBar
id='dlg_constituents_search'
noBorder
className='min-w-[6rem] pr-2 flex-grow'
value={filterText}
onChange={setFilterText}
/>
2024-04-04 20:03:41 +03:00
{schema ? (
<ToolbarGraphSelection
2024-04-06 23:09:25 +03:00
graph={schema.graph}
2024-08-21 20:21:23 +03:00
isCore={cstID => isBasicConcept(schema.cstByID.get(cstID)?.cst_type)}
2024-08-21 20:32:17 +03:00
isOwned={cstID => !schema.cstByID.get(cstID)?.is_inherited}
2024-04-04 20:03:41 +03:00
setSelected={setSelected}
2024-05-23 13:36:16 +03:00
emptySelection={selected.length === 0}
className='w-fit'
2024-03-20 15:03:53 +03:00
/>
2024-04-04 20:03:41 +03:00
) : null}
2024-03-20 15:03:53 +03:00
</div>
<DataTable
id={id}
dense
noFooter
rows={rows}
contentHeight='1.3rem'
2024-05-02 21:19:23 +03:00
className={clsx('cc-scroll-y', 'border', 'text-sm', 'select-none')}
data={filtered}
2024-03-20 15:03:53 +03:00
columns={columns}
headPosition='0rem'
enableRowSelection
rowSelection={rowSelection}
onRowSelectionChange={handleRowSelection}
noDataComponent={
2024-06-21 19:27:36 +03:00
<NoData>
2024-03-20 15:03:53 +03:00
<p>Список пуст</p>
2024-06-21 19:27:36 +03:00
</NoData>
2024-03-20 15:03:53 +03:00
}
/>
</div>
);
}
2024-05-16 22:39:28 +03:00
export default PickMultiConstituenta;