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

170 lines
5.8 KiB
TypeScript
Raw Normal View History

2024-10-23 15:18:46 +03:00
'use client';
import { useState } from 'react';
2025-02-10 15:48:58 +03:00
import { Controller, useForm, useWatch } from 'react-hook-form';
2025-02-12 21:36:03 +03:00
import { zodResolver } from '@hookform/resolvers/zod';
import clsx from 'clsx';
import { HelpTopic } from '@/features/help';
import { ILibraryItem, SelectLibraryItem, useLibrary } from '@/features/library';
import { PickMultiConstituenta, useRSForm } from '@/features/rsform';
2024-10-23 15:18:46 +03:00
import { MiniButton } from '@/components/Control';
2024-10-28 23:55:12 +03:00
import { RelocateUpIcon } from '@/components/DomainIcons';
import { Loader } from '@/components/Loader';
import { ModalForm } from '@/components/Modal';
import { useDialogsStore } from '@/stores/dialogs';
2024-10-23 15:18:46 +03:00
import { ICstRelocateDTO, IOperationPosition, schemaCstRelocate } from '../backend/types';
2025-02-10 15:48:58 +03:00
import { useRelocateConstituents } from '../backend/useRelocateConstituents';
import { useUpdatePositions } from '../backend/useUpdatePositions';
import { IOperation, IOperationSchema } from '../models/oss';
import { getRelocateCandidates } from '../models/ossAPI';
export interface DlgRelocateConstituentsProps {
2024-10-23 15:18:46 +03:00
oss: IOperationSchema;
2024-10-28 23:55:12 +03:00
initialTarget?: IOperation;
2025-02-10 15:48:58 +03:00
positions: IOperationPosition[];
2024-10-23 15:18:46 +03:00
}
function DlgRelocateConstituents() {
2025-02-10 15:48:58 +03:00
const { oss, initialTarget, positions } = useDialogsStore(state => state.props as DlgRelocateConstituentsProps);
2025-01-23 19:41:31 +03:00
const { items: libraryItems } = useLibrary();
2025-02-10 15:48:58 +03:00
const { updatePositions } = useUpdatePositions();
const { relocateConstituents } = useRelocateConstituents();
const {
handleSubmit,
control,
setValue,
formState: { isValid }
} = useForm<ICstRelocateDTO>({
resolver: zodResolver(schemaCstRelocate),
defaultValues: {
items: []
},
mode: 'onChange'
});
const destination = useWatch({ control, name: 'destination' });
const destinationItem = destination ? libraryItems.find(item => item.id === destination) : undefined;
2024-10-23 15:18:46 +03:00
2024-10-28 23:55:12 +03:00
const [directionUp, setDirectionUp] = useState(true);
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
);
2025-02-10 15:48:58 +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)!;
2025-02-12 15:12:59 +03:00
const schemaIds: number[] = directionUp
2024-10-28 23:55:12 +03:00
? 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-02-12 15:12:59 +03:00
return schemaIds.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 = (() => {
2025-02-10 15:48:58 +03:00
if (!sourceData.schema || !destinationItem || !operation) {
2024-10-23 15:18:46 +03:00
return [];
}
2025-02-10 15:48:58 +03:00
const destinationOperation = oss.items.find(item => item.result === destination);
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);
setValue('destination', null);
}
2024-10-23 15:18:46 +03:00
function handleSelectSource(newValue: ILibraryItem | undefined) {
2024-10-28 23:55:12 +03:00
setSource(newValue);
setValue('destination', null);
setValue('items', []);
}
2024-10-23 15:18:46 +03:00
function handleSelectDestination(newValue: ILibraryItem | undefined) {
2025-02-10 15:48:58 +03:00
if (newValue) {
setValue('destination', newValue.id);
} else {
setValue('destination', null);
2025-02-10 15:48:58 +03:00
}
setValue('items', []);
}
2024-10-23 15:18:46 +03:00
2025-02-10 15:48:58 +03:00
function onSubmit(data: ICstRelocateDTO) {
const positionsUnchanged = positions.every(item => {
const operation = oss.operationByID.get(item.id)!;
return operation.position_x === item.position_x && operation.position_y === item.position_y;
});
if (positionsUnchanged) {
2025-02-11 20:15:34 +03:00
return relocateConstituents(data);
2025-02-10 15:48:58 +03:00
} else {
2025-02-11 20:15:34 +03:00
return updatePositions({
isSilent: true,
itemID: oss.id,
positions: positions
}).then(() => relocateConstituents(data));
2024-10-28 14:52:30 +03:00
}
}
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 && destinationItem !== undefined}
2025-02-10 15:48:58 +03:00
onSubmit={event => void handleSubmit(onSubmit)(event)}
2024-10-23 15:18:46 +03:00
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}
2025-02-10 15:48:58 +03:00
value={destinationItem}
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 ? (
2025-02-10 15:48:58 +03:00
<Controller
name='items'
control={control}
render={({ field }) => (
<PickMultiConstituenta
noBorder
schema={sourceData.schema!}
items={filteredConstituents}
rows={12}
value={field.value}
onChange={field.onChange}
/>
)}
/>
) : 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;