872686e855
FormModal получил isDirty: если в форме редактирования существующей записи что-то изменили, крестик, «Отмена» и клик мимо окна сначала показывают диалог «Закрыть без сохранения?». Подключено к редактированию типа заявки, маршрута, шага маршрута и согласующего в заявке. Формы создания не затронуты — их черновик и так сохраняется. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
95 lines
3.5 KiB
TypeScript
95 lines
3.5 KiB
TypeScript
import * as React from 'react';
|
|
import { Alert } from './Alert';
|
|
import { Button } from './Button';
|
|
import { ConfirmDialog } from './ConfirmDialog';
|
|
import { Modal } from './Modal';
|
|
import styles from './Modal.module.scss';
|
|
import { texts } from '../../texts';
|
|
|
|
export interface IFormModalProps {
|
|
title: string;
|
|
/** Текст ошибки: и валидации формы, и ответа бэкенда. */
|
|
error?: string;
|
|
isSaving: boolean;
|
|
/** Подпись кнопки подтверждения — по умолчанию «Сохранить» (см. копирование маршрута). */
|
|
submitLabel?: string;
|
|
/** Подпись той же кнопки во время запроса — по умолчанию «Сохранение...». */
|
|
savingLabel?: string;
|
|
onSubmit: () => void;
|
|
onClose: () => void;
|
|
/**
|
|
* Сбросить черновик формы (см. useFormDraft). Кнопка «Очистить» показывается,
|
|
* только если передан и canReset — «Отмена» и клик мимо окна черновик не трогают.
|
|
*/
|
|
onReset?: () => void;
|
|
canReset?: boolean;
|
|
/**
|
|
* В форме есть несохранённые правки существующей записи: выход (крестик,
|
|
* «Отмена», клик мимо окна) сначала спрашивает подтверждение. Для форм создания
|
|
* не нужен — их черновик сохраняется сам (см. useFormDraft).
|
|
*/
|
|
isDirty?: boolean;
|
|
children: React.ReactNode;
|
|
}
|
|
|
|
/**
|
|
* Модальное окно формы: одинаковая обвязка «ошибка сверху, Отмена/Сохранить снизу»
|
|
* для всех справочников, чтобы экраны описывали только поля.
|
|
*/
|
|
export const FormModal: React.FC<IFormModalProps> = ({
|
|
title,
|
|
error,
|
|
isSaving,
|
|
submitLabel = texts.common.save,
|
|
savingLabel = texts.common.saving,
|
|
onSubmit,
|
|
onClose,
|
|
onReset,
|
|
canReset,
|
|
isDirty,
|
|
children
|
|
}) => {
|
|
const [confirmingClose, setConfirmingClose] = React.useState(false);
|
|
// Во время сохранения не закрываем и не спрашиваем: запрос уже ушёл.
|
|
const requestClose = (): void => {
|
|
if (isSaving) return;
|
|
if (isDirty) setConfirmingClose(true);
|
|
else onClose();
|
|
};
|
|
|
|
return (
|
|
<>
|
|
<Modal
|
|
title={title}
|
|
onClose={requestClose}
|
|
footer={
|
|
<>
|
|
{onReset && canReset && (
|
|
<span className={styles.footerStart}>
|
|
<Button variant="ghost" icon="refresh" onClick={onReset} disabled={isSaving}>{texts.common.resetDraft}</Button>
|
|
</span>
|
|
)}
|
|
<Button variant="secondary" onClick={requestClose} disabled={isSaving}>{texts.common.cancel}</Button>
|
|
<Button variant="accent" icon="check" onClick={onSubmit} disabled={isSaving}>
|
|
{isSaving ? savingLabel : submitLabel}
|
|
</Button>
|
|
</>
|
|
}
|
|
>
|
|
{error && <Alert kind="err">{error}</Alert>}
|
|
{children}
|
|
</Modal>
|
|
{confirmingClose && (
|
|
<ConfirmDialog
|
|
title={texts.common.discardTitle}
|
|
text={texts.common.discardText}
|
|
confirmLabel={texts.common.discardConfirm}
|
|
cancelLabel={texts.common.discardKeepEditing}
|
|
onConfirm={onClose}
|
|
onCancel={() => setConfirmingClose(false)}
|
|
/>
|
|
)}
|
|
</>
|
|
);
|
|
};
|