ConceptPortal-public/rsconcept/frontend/src/features/oss/dialogs/DlgRelocateConstituents.tsx

173 lines
6.0 KiB
TypeScript
Raw Normal View History

'use client';
2025-02-10 15:49:56 +03:00
import { zodResolver } from '@hookform/resolvers/zod';
import clsx from 'clsx';
import { useState } from 'react';
2025-02-10 15:49:56 +03:00
import { Controller, useForm, useWatch } from 'react-hook-form';
import { MiniButton } from '@/components/Control';
2024-10-28 23:55:25 +03:00
import { RelocateUpIcon } from '@/components/DomainIcons';
import { Loader } from '@/components/Loader';
import { ModalForm } from '@/components/Modal';
import { HelpTopic } from '@/features/help';
import { useLibrary } from '@/features/library/backend/useLibrary';
import SelectLibraryItem from '@/features/library/components/SelectLibraryItem';
import { ILibraryItem, LibraryItemID } from '@/features/library/models/library';
import { useRSForm } from '@/features/rsform/backend/useRSForm';
import PickMultiConstituenta from '@/features/rsform/components/PickMultiConstituenta';
import { useDialogsStore } from '@/stores/dialogs';
2025-02-10 15:49:56 +03:00
import { ICstRelocateDTO, IOperationPosition, schemaCstRelocate } from '../backend/api';
import { useRelocateConstituents } from '../backend/useRelocateConstituents';
import { useUpdatePositions } from '../backend/useUpdatePositions';
import { IOperation, IOperationSchema } from '../models/oss';
import { getRelocateCandidates } from '../models/ossAPI';
export interface DlgRelocateConstituentsProps {
oss: IOperationSchema;
2024-10-28 23:55:25 +03:00
initialTarget?: IOperation;
2025-02-10 15:49:56 +03:00
positions: IOperationPosition[];
}
function DlgRelocateConstituents() {
2025-02-10 15:49:56 +03:00
const { oss, initialTarget, positions } = useDialogsStore(state => state.props as DlgRelocateConstituentsProps);
const { items: libraryItems } = useLibrary();
2025-02-10 15:49:56 +03:00
const { updatePositions } = useUpdatePositions();
const { relocateConstituents } = useRelocateConstituents();
const {
handleSubmit,
control,
setValue,
resetField,
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-28 23:55:25 +03:00
const [directionUp, setDirectionUp] = useState(true);
const [source, setSource] = useState<ILibraryItem | undefined>(
libraryItems.find(item => item.id === initialTarget?.result)
2024-10-28 23:55:25 +03:00
);
2025-02-10 15:49:56 +03:00
const operation = oss.items.find(item => item.result === source?.id);
const sourceSchemas = libraryItems.filter(item => oss.schemas.includes(item.id));
const destinationSchemas = (() => {
2024-10-28 23:55:25 +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);
return ids.map(id => libraryItems.find(item => item.id === id)).filter(item => item !== undefined);
})();
const sourceData = useRSForm({ itemID: source?.id });
const filteredConstituents = (() => {
2025-02-10 15:49:56 +03:00
if (!sourceData.schema || !destinationItem || !operation) {
return [];
}
2025-02-10 15:49:56 +03:00
const destinationOperation = oss.items.find(item => item.result === destination);
2024-10-28 23:55:25 +03:00
return getRelocateCandidates(operation.id, destinationOperation!.id, sourceData.schema, oss);
})();
function toggleDirection() {
2024-10-28 23:55:25 +03:00
setDirectionUp(prev => !prev);
2025-02-10 15:49:56 +03:00
resetField('destination');
}
function handleSelectSource(newValue: ILibraryItem | undefined) {
2024-10-28 23:55:25 +03:00
setSource(newValue);
2025-02-10 15:49:56 +03:00
resetField('destination');
resetField('items');
}
function handleSelectDestination(newValue: ILibraryItem | undefined) {
2025-02-10 15:49:56 +03:00
if (newValue) {
setValue('destination', newValue.id);
} else {
resetField('destination');
}
resetField('items');
}
2025-02-10 15:49:56 +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) {
return relocateConstituents(data);
2025-02-10 15:49:56 +03:00
} else {
return updatePositions({
isSilent: true,
itemID: oss.id,
positions: positions
}).then(() => relocateConstituents(data));
2024-10-28 14:53:41 +03:00
}
}
return (
<ModalForm
2024-10-29 12:06:43 +03:00
header='Перенос конституент'
submitText='Переместить'
canSubmit={isValid}
2025-02-10 15:49:56 +03:00
onSubmit={event => void handleSubmit(onSubmit)(event)}
className={clsx('w-[40rem] h-[33rem]', 'py-3 px-6')}
2024-10-29 12:06:43 +03:00
helpTopic={HelpTopic.UI_RELOCATE_CST}
>
2024-10-28 23:55:25 +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:25 +03:00
/>
<MiniButton
title='Направление перемещения'
icon={<RelocateUpIcon value={directionUp} />}
onClick={toggleDirection}
/>
<SelectLibraryItem
noBorder
className='w-1/2'
placeholder='Выберите целевую схему'
items={destinationSchemas}
2025-02-10 15:49:56 +03:00
value={destinationItem}
onChange={handleSelectDestination}
/>
2024-10-28 23:55:25 +03:00
</div>
{sourceData.isLoading ? <Loader /> : null}
{!sourceData.isLoading && sourceData.schema ? (
2025-02-10 15:49:56 +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:25 +03:00
</div>
</ModalForm>
);
}
export default DlgRelocateConstituents;