Portal/rsconcept/frontend/src/dialogs/DlgRelocateConstituents.tsx

138 lines
4.7 KiB
TypeScript
Raw Normal View History

2024-10-23 15:18:46 +03:00
'use client';
import clsx from 'clsx';
import { useState } from 'react';
2024-10-23 15:18:46 +03:00
2025-01-23 19:41:31 +03:00
import { useLibrary } from '@/backend/library/useLibrary';
import { ICstRelocateDTO } from '@/backend/oss/api';
import { useRSForm } from '@/backend/rsform/useRSForm';
2024-10-28 23:55:12 +03:00
import { RelocateUpIcon } from '@/components/DomainIcons';
2024-10-23 15:18:46 +03:00
import PickMultiConstituenta from '@/components/select/PickMultiConstituenta';
import SelectLibraryItem from '@/components/select/SelectLibraryItem';
2025-02-07 10:53:49 +03:00
import { MiniButton } from '@/components/ui/Control';
import Loader from '@/components/ui/Loader';
2025-02-06 20:27:56 +03:00
import { ModalForm } from '@/components/ui/Modal';
2024-10-23 15:18:46 +03:00
import { ILibraryItem, LibraryItemID } from '@/models/library';
2024-10-29 12:05:23 +03:00
import { HelpTopic } from '@/models/miscellaneous';
2025-01-23 19:41:31 +03:00
import { IOperation, IOperationSchema } from '@/models/oss';
2024-10-23 15:18:46 +03:00
import { getRelocateCandidates } from '@/models/ossAPI';
import { ConstituentaID } from '@/models/rsform';
import { useDialogsStore } from '@/stores/dialogs';
2024-10-23 15:18:46 +03:00
export interface DlgRelocateConstituentsProps {
2024-10-23 15:18:46 +03:00
oss: IOperationSchema;
2024-10-28 23:55:12 +03:00
initialTarget?: IOperation;
2025-01-23 19:41:31 +03:00
onSubmit: (data: ICstRelocateDTO) => void;
2024-10-23 15:18:46 +03:00
}
function DlgRelocateConstituents() {
const { oss, initialTarget, onSubmit } = useDialogsStore(state => state.props as DlgRelocateConstituentsProps);
2025-01-23 19:41:31 +03:00
const { items: libraryItems } = useLibrary();
2024-10-23 15:18:46 +03:00
2024-10-28 23:55:12 +03:00
const [directionUp, setDirectionUp] = useState(true);
2024-10-23 15:18:46 +03:00
const [destination, setDestination] = useState<ILibraryItem | undefined>(undefined);
const [selected, setSelected] = useState<ConstituentaID[]>([]);
2024-10-28 23:55:12 +03:00
const [source, setSource] = useState<ILibraryItem | undefined>(
2025-01-23 19:41:31 +03:00
libraryItems.find(item => item.id === initialTarget?.result)
2024-10-28 23:55:12 +03:00
);
const isValid = !!destination && selected.length > 0;
2024-10-28 23:55:12 +03:00
const operation = oss.items.find(item => item.result === source?.id);
2025-01-23 19:41:31 +03:00
const sourceSchemas = libraryItems.filter(item => oss.schemas.includes(item.id));
const destinationSchemas = (() => {
2024-10-28 23:55:12 +03:00
if (!operation) {
return [];
}
const node = oss.graph.at(operation.id)!;
const ids: LibraryItemID[] = directionUp
? node.inputs.map(id => oss.operationByID.get(id)!.result).filter(id => id !== null)
: node.outputs.map(id => oss.operationByID.get(id)!.result).filter(id => id !== null);
2025-01-23 19:41:31 +03:00
return ids.map(id => libraryItems.find(item => item.id === id)).filter(item => item !== undefined);
})();
2024-10-23 15:18:46 +03:00
2025-01-23 19:41:31 +03:00
const sourceData = useRSForm({ itemID: source?.id });
const filteredConstituents = (() => {
2024-10-28 23:55:12 +03:00
if (!sourceData.schema || !destination || !operation) {
2024-10-23 15:18:46 +03:00
return [];
}
const destinationOperation = oss.items.find(item => item.result === destination.id);
2024-10-28 23:55:12 +03:00
return getRelocateCandidates(operation.id, destinationOperation!.id, sourceData.schema, oss);
})();
2024-10-23 15:18:46 +03:00
function toggleDirection() {
2024-10-28 23:55:12 +03:00
setDirectionUp(prev => !prev);
setDestination(undefined);
}
2024-10-23 15:18:46 +03:00
function handleSelectSource(newValue: ILibraryItem | undefined) {
2024-10-28 23:55:12 +03:00
setSource(newValue);
setDestination(undefined);
2024-10-23 15:18:46 +03:00
setSelected([]);
}
2024-10-23 15:18:46 +03:00
function handleSelectDestination(newValue: ILibraryItem | undefined) {
2024-10-23 15:18:46 +03:00
setDestination(newValue);
2024-10-28 23:55:12 +03:00
setSelected([]);
}
2024-10-23 15:18:46 +03:00
function handleSubmit() {
2025-02-06 14:09:20 +03:00
if (destination) {
onSubmit({
destination: destination.id,
items: selected
});
2024-10-28 14:52:30 +03:00
}
2025-02-06 14:09:20 +03:00
return true;
}
2024-10-23 15:18:46 +03:00
return (
2025-02-06 20:27:56 +03:00
<ModalForm
2024-10-29 12:05:23 +03:00
header='Перенос конституент'
2024-10-23 15:18:46 +03:00
submitText='Переместить'
canSubmit={isValid}
onSubmit={handleSubmit}
className={clsx('w-[40rem] h-[33rem]', 'py-3 px-6')}
2024-10-29 12:05:23 +03:00
helpTopic={HelpTopic.UI_RELOCATE_CST}
2024-10-23 15:18:46 +03:00
>
2024-10-28 23:55:12 +03:00
<div className='flex flex-col border'>
<div className='flex gap-1 items-center clr-input border-b rounded-t-md'>
<SelectLibraryItem
noBorder
className='w-1/2'
placeholder='Выберите исходную схему'
items={sourceSchemas}
value={source}
onChange={handleSelectSource}
2024-10-28 23:55:12 +03:00
/>
<MiniButton
title='Направление перемещения'
icon={<RelocateUpIcon value={directionUp} />}
onClick={toggleDirection}
/>
<SelectLibraryItem
noBorder
className='w-1/2'
placeholder='Выберите целевую схему'
items={destinationSchemas}
value={destination}
onChange={handleSelectDestination}
2024-10-23 15:18:46 +03:00
/>
2024-10-28 23:55:12 +03:00
</div>
{sourceData.isLoading ? <Loader /> : null}
{!sourceData.isLoading && sourceData.schema ? (
<PickMultiConstituenta
noBorder
schema={sourceData.schema}
items={filteredConstituents}
rows={12}
value={selected}
onChange={setSelected}
/>
) : null}
2024-10-28 23:55:12 +03:00
</div>
2025-02-06 20:27:56 +03:00
</ModalForm>
2024-10-23 15:18:46 +03:00
);
}
export default DlgRelocateConstituents;