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

274 lines
8.2 KiB
TypeScript
Raw Normal View History

2024-03-24 19:25:42 +03:00
'use client';
import { useCallback, useMemo, useState } from 'react';
2024-05-16 22:39:28 +03:00
import BadgeConstituenta from '@/components/info/BadgeConstituenta';
import SelectConstituenta from '@/components/select/SelectConstituenta';
2024-03-24 19:25:42 +03:00
import DataTable, { createColumnHelper } from '@/components/ui/DataTable';
import Label from '@/components/ui/Label';
import MiniButton from '@/components/ui/MiniButton';
2024-04-01 19:07:20 +03:00
import { useConceptOptions } from '@/context/OptionsContext';
2024-03-24 19:25:42 +03:00
import { IConstituenta, IRSForm, ISubstitution } from '@/models/rsform';
import { describeConstituenta } from '@/utils/labels';
2024-05-02 19:13:54 +03:00
import {
IconKeepAliasOff,
IconKeepAliasOn,
IconKeepTermOff,
IconKeepTermOn,
IconPageFirst,
IconPageLast,
IconPageLeft,
IconPageRight,
IconRemove,
IconReplace
} from '../Icons';
2024-06-21 19:27:36 +03:00
import NoData from '../ui/NoData';
2024-05-16 22:39:28 +03:00
interface PickSubstitutionsProps {
2024-03-24 19:25:42 +03:00
prefixID: string;
rows?: number;
schema1?: IRSForm;
schema2?: IRSForm;
filter1?: (cst: IConstituenta) => boolean;
filter2?: (cst: IConstituenta) => boolean;
items: ISubstitution[];
setItems: React.Dispatch<React.SetStateAction<ISubstitution[]>>;
}
function SubstitutionIcon({ item }: { item: ISubstitution }) {
if (item.deleteRight) {
if (item.takeLeftTerm) {
2024-05-02 19:13:54 +03:00
return <IconPageRight size='1.2rem' />;
2024-03-24 19:25:42 +03:00
} else {
2024-05-02 19:13:54 +03:00
return <IconPageLast size='1.2rem' />;
2024-03-24 19:25:42 +03:00
}
} else {
if (item.takeLeftTerm) {
2024-05-02 19:13:54 +03:00
return <IconPageFirst size='1.2rem' />;
2024-03-24 19:25:42 +03:00
} else {
2024-05-02 19:13:54 +03:00
return <IconPageLeft size='1.2rem' />;
2024-03-24 19:25:42 +03:00
}
}
}
const columnHelper = createColumnHelper<ISubstitution>();
2024-05-16 22:39:28 +03:00
function PickSubstitutions({
2024-03-24 19:25:42 +03:00
items,
schema1,
schema2,
filter1,
filter2,
rows,
setItems,
prefixID
2024-05-16 22:39:28 +03:00
}: PickSubstitutionsProps) {
2024-04-01 19:07:20 +03:00
const { colors } = useConceptOptions();
2024-03-24 19:25:42 +03:00
const [leftCst, setLeftCst] = useState<IConstituenta | undefined>(undefined);
const [rightCst, setRightCst] = useState<IConstituenta | undefined>(undefined);
const [deleteRight, setDeleteRight] = useState(true);
const [takeLeftTerm, setTakeLeftTerm] = useState(true);
const toggleDelete = () => setDeleteRight(prev => !prev);
const toggleTerm = () => setTakeLeftTerm(prev => !prev);
function addSubstitution() {
if (!leftCst || !rightCst) {
return;
}
const newSubstitution: ISubstitution = {
leftCst: leftCst,
rightCst: rightCst,
deleteRight: deleteRight,
takeLeftTerm: takeLeftTerm
};
setItems([
newSubstitution,
...items.filter(
item =>
(!item.deleteRight && item.leftCst.id !== leftCst.id) ||
(item.deleteRight && item.rightCst.id !== rightCst.id)
)
]);
}
const handleDeleteRow = useCallback(
(row: number) => {
setItems(prev => {
const newItems: ISubstitution[] = [];
prev.forEach((item, index) => {
if (index !== row) {
newItems.push(item);
}
});
return newItems;
});
},
[setItems]
);
const columns = useMemo(
() => [
columnHelper.accessor(item => describeConstituenta(item.leftCst), {
id: 'left_text',
header: 'Описание',
size: 1000,
cell: props => <div className='text-xs text-ellipsis'>{props.getValue()}</div>
}),
columnHelper.accessor(item => item.leftCst.alias, {
id: 'left_alias',
2024-06-04 11:19:21 +03:00
header: () => <span className='pl-3'>Имя</span>,
2024-03-24 19:25:42 +03:00
size: 65,
cell: props => (
2024-05-16 22:39:28 +03:00
<BadgeConstituenta theme={colors} value={props.row.original.leftCst} prefixID={`${prefixID}_1_`} />
2024-03-24 19:25:42 +03:00
)
}),
columnHelper.display({
id: 'status',
header: '',
size: 40,
cell: props => <SubstitutionIcon item={props.row.original} />
}),
columnHelper.accessor(item => item.rightCst.alias, {
id: 'right_alias',
2024-06-04 11:19:21 +03:00
header: () => <span className='pl-3'>Имя</span>,
2024-03-24 19:25:42 +03:00
size: 65,
cell: props => (
2024-05-16 22:39:28 +03:00
<BadgeConstituenta theme={colors} value={props.row.original.rightCst} prefixID={`${prefixID}_2_`} />
2024-03-24 19:25:42 +03:00
)
}),
columnHelper.accessor(item => describeConstituenta(item.rightCst), {
id: 'right_text',
header: 'Описание',
2024-04-03 19:31:26 +03:00
minSize: 1000,
2024-03-25 19:17:18 +03:00
cell: props => <div className='text-xs text-ellipsis text-pretty'>{props.getValue()}</div>
2024-03-24 19:25:42 +03:00
}),
columnHelper.display({
id: 'actions',
cell: props => (
<MiniButton
noHover
title='Удалить'
icon={<IconRemove size='1rem' className='icon-red' />}
2024-03-24 19:25:42 +03:00
onClick={() => handleDeleteRow(props.row.index)}
/>
)
})
],
[handleDeleteRow, colors, prefixID]
);
return (
<div className='flex flex-col w-full'>
2024-03-24 19:25:42 +03:00
<div className='flex items-end gap-3 justify-stretch'>
<div className='flex-grow basis-1/2'>
<div className='flex items-center justify-between'>
<Label text={schema1 !== schema2 ? schema1?.alias ?? 'Схема 1' : ''} />
2024-04-03 19:31:26 +03:00
<div className='cc-icons'>
2024-03-24 19:25:42 +03:00
<MiniButton
title='Сохранить конституенту'
noHover
onClick={toggleDelete}
icon={
deleteRight ? (
2024-05-02 19:13:54 +03:00
<IconKeepAliasOn size='1rem' className='clr-text-green' />
2024-03-24 19:25:42 +03:00
) : (
2024-05-02 19:13:54 +03:00
<IconKeepAliasOff size='1rem' className='clr-text-red' />
2024-03-24 19:25:42 +03:00
)
}
/>
<MiniButton
title='Сохранить термин'
noHover
onClick={toggleTerm}
icon={
takeLeftTerm ? (
2024-05-02 19:13:54 +03:00
<IconKeepTermOn size='1rem' className='clr-text-green' />
2024-03-24 19:25:42 +03:00
) : (
2024-05-02 19:13:54 +03:00
<IconKeepTermOff size='1rem' className='clr-text-red' />
2024-03-24 19:25:42 +03:00
)
}
/>
</div>
</div>
2024-05-16 22:39:28 +03:00
<SelectConstituenta
2024-03-24 19:25:42 +03:00
items={schema1?.items.filter(cst => !filter1 || filter1(cst))}
value={leftCst}
onSelectValue={setLeftCst}
/>
</div>
<MiniButton
noHover
title='Добавить в таблицу отождествлений'
className='mb-[0.375rem] grow-0'
icon={<IconReplace size='1.5rem' className='icon-primary' />}
2024-04-03 19:31:26 +03:00
disabled={!leftCst || !rightCst || leftCst === rightCst}
2024-03-24 19:25:42 +03:00
onClick={addSubstitution}
/>
<div className='flex-grow basis-1/2'>
<div className='flex items-center justify-between'>
<Label text={schema1 !== schema2 ? schema2?.alias ?? 'Схема 2' : ''} />
2024-04-03 19:31:26 +03:00
<div className='cc-icons'>
2024-03-24 19:25:42 +03:00
<MiniButton
title='Сохранить конституенту'
noHover
onClick={toggleDelete}
icon={
!deleteRight ? (
2024-05-02 19:13:54 +03:00
<IconKeepAliasOn size='1rem' className='clr-text-green' />
2024-03-24 19:25:42 +03:00
) : (
2024-05-02 19:13:54 +03:00
<IconKeepAliasOff size='1rem' className='clr-text-red' />
2024-03-24 19:25:42 +03:00
)
}
/>
<MiniButton
title='Сохранить термин'
noHover
onClick={toggleTerm}
icon={
!takeLeftTerm ? (
2024-05-02 19:13:54 +03:00
<IconKeepTermOn size='1rem' className='clr-text-green' />
2024-03-24 19:25:42 +03:00
) : (
2024-05-02 19:13:54 +03:00
<IconKeepTermOff size='1rem' className='clr-text-red' />
2024-03-24 19:25:42 +03:00
)
}
/>
</div>
</div>
2024-05-16 22:39:28 +03:00
<SelectConstituenta
2024-03-24 19:25:42 +03:00
items={schema2?.items.filter(cst => !filter2 || filter2(cst))}
value={rightCst}
onSelectValue={setRightCst}
/>
</div>
</div>
<DataTable
dense
noHeader
2024-03-24 19:25:42 +03:00
noFooter
2024-05-02 21:34:47 +03:00
className='w-full text-sm border select-none cc-scroll-y'
2024-03-24 19:25:42 +03:00
rows={rows}
contentHeight='1.3rem'
data={items}
columns={columns}
headPosition='0'
noDataComponent={
2024-06-21 19:27:36 +03:00
<NoData className='min-h-[2rem]'>
2024-03-24 19:25:42 +03:00
<p>Список пуст</p>
<p>Добавьте отождествление</p>
2024-06-21 19:27:36 +03:00
</NoData>
2024-03-24 19:25:42 +03:00
}
/>
</div>
);
}
2024-05-16 22:39:28 +03:00
export default PickSubstitutions;