diff --git a/survey-frontend/src/Prompt.tsx b/survey-frontend/src/Prompt.tsx new file mode 100644 index 0000000000000000000000000000000000000000..14176ad6c50909cd479be4ac1ce1bb2f384338cf --- /dev/null +++ b/survey-frontend/src/Prompt.tsx @@ -0,0 +1,30 @@ +import React from "react"; +import { unstable_useBlocker as useBlocker } from "react-router-dom"; + +// adapted from https://stackoverflow.com/a/75920683 +// also see https://github.com/remix-run/react-router/blob/496b1fe8253643171ecca6e6a945d98386c4eb00/packages/react-router-dom/index.tsx#L1460C4-L1460C4 +// for the unstable_usePrompt implementation in react router itself +// and https://claritydev.net/blog/display-warning-for-unsaved-form-data-on-page-exit for yet another example +function Prompt(props) { + const block = props.when; + const onPageExit = props.onPageExit; + + // NB gives warning in the browser console but thats a bug: https://github.com/remix-run/react-router/issues/10073 + // apparently the fix of that bug caused a nr of bugs again too... + useBlocker(() => { + if (block()) { + const confirmed = window.confirm(props.message); + if (confirmed) { + onPageExit(); + } + return !confirmed; + } + return false; + }) + + return ( + <div /> + ); +} + +export default Prompt; diff --git a/survey-frontend/src/SurveyContainerComponent.tsx b/survey-frontend/src/SurveyContainerComponent.tsx index 1dbdbc37de1fccf60c9796ebb8274d2c90fb7968..1322ddc4f69ef3984132f086767a65d9f0ea4d20 100644 --- a/survey-frontend/src/SurveyContainerComponent.tsx +++ b/survey-frontend/src/SurveyContainerComponent.tsx @@ -6,6 +6,7 @@ import { useParams } from "react-router-dom"; import SurveyComponent from "./SurveyComponent"; import SurveyNavigationComponent from "./SurveyNavigationComponent"; import { VerificationStatus } from './Schema'; +import Prompt from "./Prompt"; import "survey-core/modern.min.css"; import './survey.scss'; @@ -29,12 +30,15 @@ function SurveyContainerComponent({ loadFrom }) { }, []); const pageHideListener = useCallback(() => { - if (!nren) { - return; - } window.navigator.sendBeacon('/api/response/unlock/' + year + '/' + nren); }, []); + const onPageExitThroughRouter = useCallback(() => { + window.navigator.sendBeacon('/api/response/unlock/' + year + '/' + nren); + removeEventListener("beforeunload", beforeUnloadListener, { capture: true }); + removeEventListener("pagehide", pageHideListener); + }, []); + useEffect(() => { async function getModel() { const response = await fetch(loadFrom + year + (nren ? '/' + nren : '')) @@ -73,7 +77,6 @@ function SurveyContainerComponent({ loadFrom }) { } getModel().catch(error => setError('Error when loading survey: ' + error.message)) - }, []); if (!surveyModel) { @@ -202,6 +205,7 @@ function SurveyContainerComponent({ loadFrom }) { return ( <Container className="survey-container"> <Toaster /> + <Prompt message="Are you sure you want to leave this page? Information you've entered may not be saved." when={() => { return surveyModel.mode == 'edit' && !!nren; }} onPageExit={onPageExitThroughRouter} /> <SurveyNavigationComponent surveyModel={surveyModel} surveyActions={surveyActions} year={year} nren={nren}> <SurveyComponent surveyModel={surveyModel} verificationStatus={verificationStatus} /> </SurveyNavigationComponent>