ConceptPortal-public/rsconcept/frontend/src/pages/RSFormPage/ViewConstituents/TableSideConstituents.tsx

175 lines
4.7 KiB
TypeScript
Raw Normal View History

'use client';
2023-12-08 19:24:08 +03:00
import { useCallback, useLayoutEffect, useMemo, useState } from 'react';
2024-05-16 22:39:28 +03:00
import BadgeConstituenta from '@/components/info/BadgeConstituenta';
2024-03-20 15:27:32 +03:00
import DataTable, { createColumnHelper, IConditionalStyle, VisibilityState } from '@/components/ui/DataTable';
2024-06-21 19:27:36 +03:00
import NoData from '@/components/ui/NoData';
import { useConceptOptions } from '@/context/ConceptOptionsContext';
import useWindowSize from '@/hooks/useWindowSize';
2024-03-17 19:24:12 +03:00
import { ConstituentaID, IConstituenta } from '@/models/rsform';
import { isMockCst } from '@/models/rsformAPI';
2024-05-23 13:36:16 +03:00
import { PARAMETER, prefixes } from '@/utils/constants';
import { describeConstituenta } from '@/utils/labels';
2023-12-08 19:24:08 +03:00
interface TableSideConstituentsProps {
2023-12-28 14:04:44 +03:00
items: IConstituenta[];
2024-05-23 13:36:16 +03:00
activeCst?: IConstituenta;
2024-03-17 19:24:12 +03:00
onOpenEdit: (cstID: ConstituentaID) => void;
2023-12-28 14:04:44 +03:00
denseThreshold?: number;
maxHeight: string;
2023-12-08 19:24:08 +03:00
}
const columnHelper = createColumnHelper<IConstituenta>();
function TableSideConstituents({
items,
activeCst,
onOpenEdit,
maxHeight,
denseThreshold = 9999
}: TableSideConstituentsProps) {
2024-04-01 19:07:20 +03:00
const { colors } = useConceptOptions();
2023-12-08 19:24:08 +03:00
const windowSize = useWindowSize();
2023-12-28 14:04:44 +03:00
const [columnVisibility, setColumnVisibility] = useState<VisibilityState>({ expression: true });
2023-12-08 19:24:08 +03:00
2024-05-23 13:36:16 +03:00
useLayoutEffect(() => {
if (!activeCst) {
return;
}
setTimeout(() => {
const element = document.getElementById(`${prefixes.cst_side_table}${activeCst.alias}`);
if (element) {
element.scrollIntoView({
behavior: 'smooth',
2024-06-18 19:55:23 +03:00
block: 'center',
2024-05-23 13:36:16 +03:00
inline: 'end'
});
}
}, PARAMETER.refreshTimeout);
}, [activeCst]);
2023-12-28 14:04:44 +03:00
useLayoutEffect(() => {
2023-12-08 19:24:08 +03:00
setColumnVisibility(prev => {
const newValue = (windowSize.width ?? 0) >= denseThreshold;
2024-08-06 14:39:00 +03:00
if (newValue === prev.expression) {
2023-12-08 19:24:08 +03:00
return prev;
} else {
2023-12-28 14:04:44 +03:00
return { expression: newValue };
2023-12-08 19:24:08 +03:00
}
});
}, [windowSize, denseThreshold]);
const handleRowClicked = useCallback(
2023-12-28 14:04:44 +03:00
(cst: IConstituenta) => {
if (!isMockCst(cst)) {
onOpenEdit(cst.id);
}
},
[onOpenEdit]
);
2023-12-08 19:24:08 +03:00
const columns = useMemo(
2023-12-28 14:04:44 +03:00
() => [
columnHelper.accessor('alias', {
id: 'alias',
2024-06-04 11:19:21 +03:00
header: () => <span className='pl-3'>Имя</span>,
2023-12-28 14:04:44 +03:00
size: 65,
minSize: 65,
footer: undefined,
cell: props => (
2024-05-16 22:39:28 +03:00
<BadgeConstituenta theme={colors} value={props.row.original} prefixID={prefixes.cst_side_table} />
2023-12-28 14:04:44 +03:00
)
}),
columnHelper.accessor(cst => describeConstituenta(cst), {
id: 'description',
header: 'Описание',
size: 1000,
minSize: 250,
maxSize: 1000,
cell: props => (
<div
style={{
2024-03-25 19:17:18 +03:00
textWrap: 'pretty',
2023-12-28 14:04:44 +03:00
fontSize: 12,
color: isMockCst(props.row.original) ? colors.fgWarning : undefined
}}
>
{props.getValue()}
</div>
)
}),
columnHelper.accessor('definition_formal', {
id: 'expression',
header: 'Выражение',
size: 2000,
minSize: 0,
maxSize: 2000,
enableHiding: true,
cell: props => (
<div
style={{
2024-03-25 19:17:18 +03:00
textWrap: 'pretty',
2023-12-28 14:04:44 +03:00
fontSize: 12,
color: isMockCst(props.row.original) ? colors.fgWarning : undefined
}}
>
{props.getValue()}
</div>
)
})
],
[colors]
);
const conditionalRowStyles = useMemo(
2023-12-08 19:24:08 +03:00
(): IConditionalStyle<IConstituenta>[] => [
{
2024-05-23 13:36:16 +03:00
when: (cst: IConstituenta) => cst.id === activeCst?.id,
2023-12-08 19:24:08 +03:00
style: {
backgroundColor: colors.bgSelected
2023-12-28 14:04:44 +03:00
}
2024-04-05 20:04:12 +03:00
},
{
2024-05-23 13:36:16 +03:00
when: (cst: IConstituenta) => cst.parent === activeCst?.id && cst.id !== activeCst?.id,
2024-04-05 20:04:12 +03:00
style: {
backgroundColor: colors.bgOrange50
}
},
{
2024-05-23 13:36:16 +03:00
when: (cst: IConstituenta) => activeCst?.id !== undefined && cst.children.includes(activeCst.id),
2024-04-05 20:04:12 +03:00
style: {
backgroundColor: colors.bgGreen50
}
2023-12-08 19:24:08 +03:00
}
2023-12-28 14:04:44 +03:00
],
2024-05-23 13:36:16 +03:00
[activeCst, colors]
2023-12-28 14:04:44 +03:00
);
2023-12-08 19:24:08 +03:00
2023-12-28 14:04:44 +03:00
return (
<DataTable
dense
noFooter
2024-05-02 21:34:47 +03:00
className='text-sm select-none cc-scroll-y'
2023-12-28 14:04:44 +03:00
style={{ maxHeight: maxHeight }}
data={items}
columns={columns}
conditionalRowStyles={conditionalRowStyles}
headPosition='0'
enableHiding
columnVisibility={columnVisibility}
onColumnVisibilityChange={setColumnVisibility}
noDataComponent={
2024-06-21 19:27:36 +03:00
<NoData className='min-h-[5rem]'>
2023-12-28 14:04:44 +03:00
<p>Список конституент пуст</p>
<p>Измените параметры фильтра</p>
2024-06-21 19:27:36 +03:00
</NoData>
2023-12-28 14:04:44 +03:00
}
onRowClicked={handleRowClicked}
/>
);
2023-12-08 19:24:08 +03:00
}
export default TableSideConstituents;