From defeab0a86fb8b2ff0a8872b4bc288ac47e1fe4c Mon Sep 17 00:00:00 2001 From: Paul Girard Date: Mon, 10 Jun 2024 17:41:55 +0200 Subject: [PATCH] [modals] preserve data form loss by disabling auto close on escape/outside click events - disabling only when a onsubmit props is set - add exceptions with a doNotPreserveData props for confirmation modals fixes #147 --- src/components/modals.tsx | 11 ++++++++--- src/views/graphPage/modals/ConfirmModal.tsx | 1 + src/views/graphPage/modals/FunctionEditorModal.tsx | 8 ++------ src/views/graphPage/modals/open/RemoteFileModal.tsx | 7 ++++++- src/views/graphPage/modals/save/ExportPNGModal.tsx | 1 + 5 files changed, 18 insertions(+), 10 deletions(-) diff --git a/src/components/modals.tsx b/src/components/modals.tsx index 69d3607..418fc3b 100644 --- a/src/components/modals.tsx +++ b/src/components/modals.tsx @@ -8,7 +8,8 @@ import { useKeyboardShortcuts } from "../hooks/useKeyboardShortcuts"; interface Props { title?: ReactNode; onClose?: () => void; - onSubmit?: () => void; + onSubmit?: () => void; // if set echap and click outside the modal does not close it + doNotPreserveData?: boolean; // if set, even if a onSubmit is set it's possible to close the modal by escape/click outside to cancel showHeader?: boolean; footerAlignLeft?: boolean; className?: string; @@ -20,6 +21,7 @@ interface Props { export const Modal: FC> = ({ onClose, onSubmit, + doNotPreserveData, title, children, showHeader = true, @@ -36,7 +38,8 @@ export const Modal: FC> = ({ { code: "Escape", handler: () => { - if (onClose) onClose(); + // don't close the modal on click outside if there is a form in it to avoid data loss + if (onClose && (doNotPreserveData || !onSubmit)) onClose(); }, }, ]); @@ -81,7 +84,9 @@ export const Modal: FC> = ({ className="modal fade show" style={{ display: "block" }} onClick={(e) => { - if (onClose && e.target === e.currentTarget) onClose(); + // don't close the modal on click outside if there is a form in it to avoid data loss + // we could do better bu tracking changes but there are already a cancel AND a x icon to close the modal + if (onClose && (doNotPreserveData || !onSubmit) && e.target === e.currentTarget) onClose(); }} >
cancel()} + doNotPreserveData onSubmit={() => { submit({}); notify({ message: successMsg, type: "success" }); diff --git a/src/views/graphPage/modals/FunctionEditorModal.tsx b/src/views/graphPage/modals/FunctionEditorModal.tsx index 13dad7a..62f62fd 100644 --- a/src/views/graphPage/modals/FunctionEditorModal.tsx +++ b/src/views/graphPage/modals/FunctionEditorModal.tsx @@ -51,6 +51,7 @@ export function FunctionEditorModal(props: ModalProps } onClose={() => cancel()} + onSubmit={() => save(true, code)} > <> {error &&

{error}

} @@ -107,12 +108,7 @@ export function FunctionEditorModal(props: ModalProps {withSaveAndRun && ( - diff --git a/src/views/graphPage/modals/open/RemoteFileModal.tsx b/src/views/graphPage/modals/open/RemoteFileModal.tsx index 7a330e9..c2061d5 100644 --- a/src/views/graphPage/modals/open/RemoteFileModal.tsx +++ b/src/views/graphPage/modals/open/RemoteFileModal.tsx @@ -42,7 +42,12 @@ export const RemoteFileModal: FC> = ({ cancel }) => { }, [isFormValid, url, cancel, notify, t, importFile]); return ( - cancel()} onSubmit={openRemote}> + cancel()} + onSubmit={openRemote} + doNotPreserveData + > <> {fileStateType === "error" && (

{t("graph.open.remote.error").toString()}

diff --git a/src/views/graphPage/modals/save/ExportPNGModal.tsx b/src/views/graphPage/modals/save/ExportPNGModal.tsx index 46449a7..42ba70e 100644 --- a/src/views/graphPage/modals/save/ExportPNGModal.tsx +++ b/src/views/graphPage/modals/save/ExportPNGModal.tsx @@ -50,6 +50,7 @@ export const ExportPNGModal: FC> = ({ cancel }) => { title={t("graph.export.png.title").toString()} onClose={() => cancel()} onSubmit={handleSubmit} + doNotPreserveData className="modal" > <>