ConceptPortal-public/rsconcept/frontend/src/features/library/dialogs/DlgEditVersions/DlgEditVersions.tsx

133 lines
4.4 KiB
TypeScript
Raw Normal View History

2025-02-07 15:30:47 +03:00
'use no memo'; // TODO: remove when react hook forms are compliant with react compiler
'use client';
2025-02-07 15:30:47 +03:00
import { useMemo } from 'react';
import { useForm, useWatch } from 'react-hook-form';
2025-02-12 21:36:25 +03:00
import { zodResolver } from '@hookform/resolvers/zod';
import { useRSFormSuspense } from '@/features/rsform';
import { MiniButton } from '@/components/Control';
import { IconReset, IconSave } from '@/components/Icons';
import { TextArea, TextInput } from '@/components/Input';
import { ModalView } from '@/components/Modal';
import { useDialogsStore } from '@/stores/dialogs';
import { errorMsg } from '@/utils/labels';
import { IVersionUpdateDTO, schemaVersionUpdate } from '../../backend/types';
2025-02-12 15:13:37 +03:00
import { useMutatingLibrary } from '../../backend/useMutatingLibrary';
import { useVersionDelete } from '../../backend/useVersionDelete';
import { useVersionUpdate } from '../../backend/useVersionUpdate';
2025-02-12 21:36:25 +03:00
import TableVersions from './TableVersions';
export interface DlgEditVersionsProps {
2025-02-12 15:13:37 +03:00
itemID: number;
afterDelete: (targetVersion: number) => void;
}
function DlgEditVersions() {
2025-02-07 15:30:47 +03:00
const { itemID, afterDelete } = useDialogsStore(state => state.props as DlgEditVersionsProps);
const hideDialog = useDialogsStore(state => state.hideDialog);
const { schema } = useRSFormSuspense({ itemID });
const isProcessing = useMutatingLibrary();
const { versionDelete } = useVersionDelete();
const { versionUpdate } = useVersionUpdate();
2025-02-07 15:30:47 +03:00
const {
register,
handleSubmit,
control,
reset,
2025-02-07 20:45:32 +03:00
formState: { isDirty, errors: formErrors }
2025-02-07 15:30:47 +03:00
} = useForm<IVersionUpdateDTO>({
resolver: zodResolver(schemaVersionUpdate),
2025-02-07 15:30:47 +03:00
defaultValues: {
2025-02-15 15:37:19 +03:00
id: schema.versions[schema.versions.length - 1].id,
version: schema.versions[schema.versions.length - 1].version,
description: schema.versions[schema.versions.length - 1].description
2025-02-07 20:45:32 +03:00
},
context: { schema: schema }
2025-02-07 15:30:47 +03:00
});
const versionID = useWatch({ control, name: 'id' });
const versionName = useWatch({ control, name: 'version' });
2025-02-07 15:30:47 +03:00
const isValid = useMemo(
() => schema.versions.every(ver => ver.id === versionID || ver.version != versionName),
[schema, versionID, versionName]
);
2025-02-12 15:13:37 +03:00
function handleSelectVersion(targetVersion: number) {
2025-02-07 15:30:47 +03:00
const ver = schema.versions.find(ver => ver.id === targetVersion);
if (!ver) {
return;
}
2025-02-07 15:30:47 +03:00
reset({ ...ver });
}
2025-02-12 15:13:37 +03:00
function handleDeleteVersion(targetVersion: number) {
2025-02-07 15:30:47 +03:00
const nextVer = schema.versions.find(ver => ver.id !== targetVersion);
void versionDelete({ itemID: itemID, versionID: targetVersion }).then(() => {
2025-02-07 15:30:47 +03:00
if (!nextVer) {
hideDialog();
} else if (targetVersion === versionID) {
reset({ id: nextVer.id, version: nextVer.version, description: nextVer.description });
}
2025-02-07 15:30:47 +03:00
afterDelete(targetVersion);
});
}
2025-02-07 15:30:47 +03:00
function onUpdate(data: IVersionUpdateDTO) {
if (!isDirty || isProcessing || !isValid) {
return;
}
void versionUpdate({ itemID: itemID, version: data }).then(() => reset({ ...data }));
}
return (
<ModalView header='Редактирование версий' className='flex flex-col w-[40rem] px-6 gap-3 pb-6'>
<TableVersions
2025-02-07 15:30:47 +03:00
processing={isProcessing}
2025-02-15 15:37:19 +03:00
items={schema.versions.reverse()}
onDelete={handleDeleteVersion}
2025-02-07 15:30:47 +03:00
onSelect={handleSelectVersion}
selected={versionID}
/>
2025-02-07 15:30:47 +03:00
<form className='flex' onSubmit={event => void handleSubmit(onUpdate)(event)}>
2025-02-07 20:45:32 +03:00
<TextInput
id='dlg_version'
{...register('version')}
dense
label='Версия'
className='w-[16rem] mr-3'
error={formErrors.version}
/>
<div className='cc-icons'>
<MiniButton
2025-02-07 15:30:47 +03:00
type='submit'
title={isValid ? 'Сохранить изменения' : errorMsg.versionTaken}
2025-02-07 15:30:47 +03:00
disabled={!isDirty || !isValid || isProcessing}
icon={<IconSave size='1.25rem' className='icon-primary' />}
/>
<MiniButton
title='Сбросить несохраненные изменения'
2025-02-07 15:30:47 +03:00
disabled={!isDirty}
onClick={() => reset()}
icon={<IconReset size='1.25rem' className='icon-primary' />}
/>
</div>
2025-02-07 15:30:47 +03:00
</form>
<TextArea
2025-02-07 15:30:47 +03:00
id='dlg_description' //
{...register('description')}
spellCheck
label='Описание'
rows={3}
/>
</ModalView>
);
}
export default DlgEditVersions;