Предупреждение при выходе из формы редактирования с несохранёнными правками
Tests / frontend-test (pull_request) Successful in 1m31s
Tests / backend-test (pull_request) Successful in 1m35s

FormModal получил isDirty: если в форме редактирования существующей
записи что-то изменили, крестик, «Отмена» и клик мимо окна сначала
показывают диалог «Закрыть без сохранения?». Подключено к редактированию
типа заявки, маршрута, шага маршрута и согласующего в заявке. Формы
создания не затронуты — их черновик и так сохраняется.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
gorbenko.pavel
2026-10-16 10:02:40 +05:00
parent b94e6e60f5
commit 872686e855
7 changed files with 84 additions and 33 deletions
@@ -1,6 +1,7 @@
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';
@@ -22,6 +23,12 @@ export interface IFormModalProps {
*/
onReset?: () => void;
canReset?: boolean;
/**
* В форме есть несохранённые правки существующей записи: выход (крестик,
* «Отмена», клик мимо окна) сначала спрашивает подтверждение. Для форм создания
* не нужен — их черновик сохраняется сам (см. useFormDraft).
*/
isDirty?: boolean;
children: React.ReactNode;
}
@@ -39,26 +46,49 @@ export const FormModal: React.FC<IFormModalProps> = ({
onClose,
onReset,
canReset,
isDirty,
children
}) => (
<Modal
title={title}
onClose={onClose}
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={onClose} 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>
);
}) => {
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)}
/>
)}
</>
);
};