Portal/rsconcept/frontend/src/features/oss/dialogs/dlg-create-operation/dlg-create-operation.tsx

130 lines
4.2 KiB
TypeScript
Raw Normal View History

2024-07-21 15:17:36 +03:00
'use client';
2025-02-11 12:34:28 +03:00
import { useState } from 'react';
import { FormProvider, useForm, useWatch } from 'react-hook-form';
2025-02-12 21:36:03 +03:00
import { zodResolver } from '@hookform/resolvers/zod';
import { HelpTopic } from '@/features/help';
2024-07-21 15:17:36 +03:00
2025-03-12 12:04:23 +03:00
import { ModalForm } from '@/components/modal';
import { TabLabel, TabList, TabPanel, Tabs } from '@/components/tabs';
import { useDialogsStore } from '@/stores/dialogs';
2024-07-21 15:17:36 +03:00
2025-04-06 15:47:40 +03:00
import { type IOperationCreateDTO, type IOssLayout, OperationType, schemaOperationCreate } from '../../backend/types';
2025-03-12 11:54:32 +03:00
import { useOperationCreate } from '../../backend/use-operation-create';
2025-02-11 20:56:11 +03:00
import { describeOperationType, labelOperationType } from '../../labels';
2025-02-20 20:22:05 +03:00
import { type IOperationSchema } from '../../models/oss';
2025-03-12 11:54:32 +03:00
import { calculateInsertPosition } from '../../models/oss-api';
2025-02-12 21:36:03 +03:00
2025-03-12 11:54:32 +03:00
import { TabInputOperation } from './tab-input-operation';
import { TabSynthesisOperation } from './tab-synthesis-operation';
2024-07-21 15:17:36 +03:00
export interface DlgCreateOperationProps {
2024-07-21 15:17:36 +03:00
oss: IOperationSchema;
2025-04-06 15:47:40 +03:00
layout: IOssLayout;
2025-02-17 15:11:32 +03:00
initialInputs: number[];
2025-02-11 12:34:28 +03:00
defaultX: number;
defaultY: number;
2025-02-17 15:11:32 +03:00
onCreate?: (newID: number) => void;
2024-07-21 15:17:36 +03:00
}
2025-03-14 20:43:30 +03:00
export const TabID = {
INPUT: 0,
SYNTHESIS: 1
} as const;
export type TabID = (typeof TabID)[keyof typeof TabID];
2024-07-21 15:17:36 +03:00
2025-02-19 23:29:45 +03:00
export function DlgCreateOperation() {
2025-02-11 12:34:28 +03:00
const { operationCreate } = useOperationCreate();
2025-01-23 19:41:31 +03:00
2025-04-06 15:47:40 +03:00
const { oss, layout, initialInputs, onCreate, defaultX, defaultY } = useDialogsStore(
2025-02-11 12:34:28 +03:00
state => state.props as DlgCreateOperationProps
);
2024-07-21 15:17:36 +03:00
2025-02-11 12:34:28 +03:00
const methods = useForm<IOperationCreateDTO>({
resolver: zodResolver(schemaOperationCreate),
defaultValues: {
2024-07-21 15:17:36 +03:00
item_data: {
2025-02-11 12:34:28 +03:00
operation_type: initialInputs.length === 0 ? OperationType.INPUT : OperationType.SYNTHESIS,
alias: '',
title: '',
2025-04-06 15:47:40 +03:00
description: '',
result: null,
parent: null
2024-07-21 15:17:36 +03:00
},
2025-04-06 15:47:40 +03:00
position_x: defaultX,
position_y: defaultY,
2025-02-11 12:34:28 +03:00
arguments: initialInputs,
create_schema: false,
2025-04-06 15:47:40 +03:00
layout: layout
2025-02-11 12:34:28 +03:00
},
mode: 'onChange'
});
const alias = useWatch({ control: methods.control, name: 'item_data.alias' });
const [activeTab, setActiveTab] = useState(initialInputs.length === 0 ? TabID.INPUT : TabID.SYNTHESIS);
2025-04-06 15:47:40 +03:00
const isValid = !!alias && !oss.operations.some(operation => operation.alias === alias);
2025-02-11 12:34:28 +03:00
function onSubmit(data: IOperationCreateDTO) {
2025-04-06 15:47:40 +03:00
const target = calculateInsertPosition(oss, data.arguments, layout, {
2025-02-11 12:34:28 +03:00
x: defaultX,
y: defaultY
2025-01-23 19:41:31 +03:00
});
2025-04-06 15:47:40 +03:00
data.position_x = target.x;
data.position_y = target.y;
2025-02-11 20:15:34 +03:00
void operationCreate({ itemID: oss.id, data: data }).then(response => onCreate?.(response.new_operation.id));
2025-02-11 12:34:28 +03:00
}
2024-07-21 15:17:36 +03:00
function handleSelectTab(newTab: TabID, last: TabID) {
if (last === newTab) {
return;
}
if (newTab === TabID.INPUT) {
2025-02-11 12:34:28 +03:00
methods.setValue('item_data.operation_type', OperationType.INPUT);
methods.setValue('item_data.result', null);
methods.setValue('arguments', []);
} else {
2025-02-11 12:34:28 +03:00
methods.setValue('item_data.operation_type', OperationType.SYNTHESIS);
methods.setValue('arguments', initialInputs);
}
setActiveTab(newTab);
}
2024-07-21 15:17:36 +03:00
return (
2025-02-06 20:27:56 +03:00
<ModalForm
2024-07-21 15:17:36 +03:00
header='Создание операции'
submitText='Создать'
canSubmit={isValid}
2025-02-11 12:34:28 +03:00
onSubmit={event => void methods.handleSubmit(onSubmit)(event)}
2025-03-09 21:57:21 +03:00
className='w-160 px-6 h-128'
2024-10-29 12:05:23 +03:00
helpTopic={HelpTopic.CC_OSS}
2024-07-21 15:17:36 +03:00
>
2025-03-14 20:43:30 +03:00
<Tabs
2025-04-12 21:47:46 +03:00
selectedTabClassName='cc-selected'
2025-03-14 20:43:30 +03:00
className='grid'
selectedIndex={activeTab}
onSelect={(index, last) => handleSelectTab(index as TabID, last as TabID)}
>
2025-04-17 14:37:47 +03:00
<TabList className='z-pop mx-auto -mb-5 flex border divide-x rounded-none bg-secondary'>
2024-07-21 15:17:36 +03:00
<TabLabel
title={describeOperationType(OperationType.INPUT)}
label={labelOperationType(OperationType.INPUT)}
/>
<TabLabel
title={describeOperationType(OperationType.SYNTHESIS)}
label={labelOperationType(OperationType.SYNTHESIS)}
/>
</TabList>
2025-02-11 12:34:28 +03:00
<FormProvider {...methods}>
<TabPanel>
2025-02-12 00:14:18 +03:00
<TabInputOperation />
2025-02-11 12:34:28 +03:00
</TabPanel>
<TabPanel>
2025-02-12 00:14:18 +03:00
<TabSynthesisOperation />
2025-02-11 12:34:28 +03:00
</TabPanel>
</FormProvider>
2024-07-21 15:17:36 +03:00
</Tabs>
2025-02-06 20:27:56 +03:00
</ModalForm>
2024-07-21 15:17:36 +03:00
);
}