diff --git a/src/app/Configuration/Configuration.tsx b/src/app/Configuration/Configuration.tsx index d2ef6af..405bbbe 100755 --- a/src/app/Configuration/Configuration.tsx +++ b/src/app/Configuration/Configuration.tsx @@ -15,6 +15,7 @@ import { ConfigurationForm } from "./ConfigurationForm"; import { ConfigurationAllUsers } from "./ConfigurationAllUsers"; import { useLayoutConfig } from "~/components/Layout/LayoutService"; import { Config } from "~/shared/Config"; +import { useChangeRouteAlertModal } from "~/components/Modal/ChangeRouteAlertModal"; export const Configuration = observer(() => { const state = useLocalStore(() => ({ @@ -195,6 +196,7 @@ export const Configuration = observer(() => { } }, })); + const changeRouteModal = useChangeRouteAlertModal(state.isDirty); useOnLoad(state.load); useIsDirty(state, "config"); @@ -210,6 +212,7 @@ export const Configuration = observer(() => { return ( <> + {changeRouteModal}
diff --git a/src/app/Settings/Settings.tsx b/src/app/Settings/Settings.tsx index bdc3505..70bb983 100755 --- a/src/app/Settings/Settings.tsx +++ b/src/app/Settings/Settings.tsx @@ -16,6 +16,7 @@ import { AccordionToggle } from "~/components/Accordion/AccordionToggle"; import { Typeahead } from "~/components/Typeahead/Typeahead"; import { Toggle } from "~/components/Toggle/Toggle"; import { AlertModal } from "~/components/Modal/AlertModal"; +import { useChangeRouteAlertModal } from "~/components/Modal/ChangeRouteAlertModal"; interface SettingsState { isDirty: boolean; @@ -460,6 +461,7 @@ export const Settings = observer(() => { state.settings.secretKey = keyPair.secretKey; }, })); + const changeRouteModal = useChangeRouteAlertModal(state.isDirty); useOnLoad(state.load); useIsDirty(state, "settings"); @@ -474,6 +476,7 @@ export const Settings = observer(() => { return ( <> + {changeRouteModal}
diff --git a/src/components/Modal/AlertModal.tsx b/src/components/Modal/AlertModal.tsx index 51d2a45..ba9c138 100644 --- a/src/components/Modal/AlertModal.tsx +++ b/src/components/Modal/AlertModal.tsx @@ -4,7 +4,7 @@ import FocusTrap from "focus-trap-react"; import { Modal } from "./Modal"; import { useKeyPress } from "~/hooks"; -const AlertModalContent: React.FC<{ +export const AlertModalContent: React.FC<{ accept: () => void; close: () => void; title: any; diff --git a/src/components/Modal/ChangeRouteAlertModal.tsx b/src/components/Modal/ChangeRouteAlertModal.tsx new file mode 100644 index 0000000..072dc7c --- /dev/null +++ b/src/components/Modal/ChangeRouteAlertModal.tsx @@ -0,0 +1,55 @@ +import React from "react"; +import { Modal } from "./Modal"; +import { AlertModalContent } from "./AlertModal"; +import { useHistory } from "react-router-dom"; + +export const useChangeRouteAlertModal = (shouldCheck: boolean) => { + const history = useHistory(); + const [approveState, setApproveState] = React.useState(() => ({ + shouldBlock: true, + isOpen: false, + location: null as any, + })); + React.useEffect(() => { + const currentPathname = history.location.pathname; + return history.block((location) => { + if ( + shouldCheck && + approveState.shouldBlock && + location.pathname !== currentPathname + ) { + setApproveState({ + ...approveState, + isOpen: true, + location, + }); + return false; + } + }); + }, [approveState, history, shouldCheck]); + const onCancelApprove = React.useCallback(() => { + setApproveState({ + ...approveState, + isOpen: false, + }); + }, [setApproveState, approveState]); + const onOkApprove = React.useCallback(() => { + approveState.shouldBlock = false; + history.push(approveState.location); + }, [approveState, history]); + + return ( + ( + + )} + /> + ); +}; diff --git a/src/components/Modal/Modal.tsx b/src/components/Modal/Modal.tsx index ca0b0c9..c3d3413 100644 --- a/src/components/Modal/Modal.tsx +++ b/src/components/Modal/Modal.tsx @@ -9,6 +9,7 @@ import { useKeyPress } from "~/hooks"; export const Modal: React.FC<{ className?: string; focusEl?: string; + isOpen?: boolean; children?: (props: { open: () => void; close: () => void; @@ -19,7 +20,7 @@ export const Modal: React.FC<{ close: () => void; isOpen: boolean; }) => JSX.Element; -}> = observer(({ content, children, className, focusEl }) => { +}> = observer(({ content, isOpen, children, className, focusEl }) => { const service = React.useContext(LayoutService); const ref = React.useRef(null); const state = useLocalStore(() => ({ @@ -63,14 +64,15 @@ export const Modal: React.FC<{ close(); } }); + const isOpenState = isOpen || state.isOpen; React.useEffect(() => { return () => { - if (state.isOpen) { + if (isOpenState) { service.nonScrollableStack--; } }; - }, [state, service]); - const transitions = useTransition(state.isOpen, null, { + }, [isOpenState, service]); + const transitions = useTransition(isOpenState, null, { config: { duration: 100, }, @@ -102,7 +104,7 @@ export const Modal: React.FC<{ right: 0, }, }); - const innerTransitions = useTransition(state.isOpen, null, { + const innerTransitions = useTransition(isOpenState, null, { config: { duration: 100, }, @@ -112,7 +114,7 @@ export const Modal: React.FC<{ enter: { transform: "scale(1)" }, leave: { transform: "scale(0.9)" }, }); - const controller = { open, close, isOpen: state.isOpen }; + const controller = { open, close, isOpen: isOpenState }; return ( <> {!!children && children(controller)}