From d60000ab55f1e7eec6f503a1a62acbd9e7406ad9 Mon Sep 17 00:00:00 2001 From: "darrel.hong" Date: Wed, 7 Sep 2022 13:30:59 +0800 Subject: [PATCH 1/3] feat(v2): block navigation when public form is dirty --- .../features/public-form/components/FormFields/FormFields.tsx | 3 +++ 1 file changed, 3 insertions(+) diff --git a/frontend/src/features/public-form/components/FormFields/FormFields.tsx b/frontend/src/features/public-form/components/FormFields/FormFields.tsx index e6c31b3943..2d4e7e69d0 100644 --- a/frontend/src/features/public-form/components/FormFields/FormFields.tsx +++ b/frontend/src/features/public-form/components/FormFields/FormFields.tsx @@ -10,6 +10,7 @@ import { FormColorTheme, LogicDto } from '~shared/types/form' import InlineMessage from '~components/InlineMessage' import { FormFieldValues } from '~templates/Field' import { createTableRow } from '~templates/Field/Table/utils/createRow' +import { useNavigationPrompt } from '~templates/NavigationPrompt/useNavigationPrompt' import { augmentWithMyInfo, @@ -100,6 +101,8 @@ export const FormFields = ({ } }, [defaultFormValues, isDirty, reset]) + useNavigationPrompt(isDirty) + return (
From 8955a5e5fbdfc1b83f83d7d06aa035bec34cce86 Mon Sep 17 00:00:00 2001 From: darrelhong Date: Sat, 28 Jan 2023 16:11:24 +0800 Subject: [PATCH 2/3] feat: don't block navigation when switch to angular --- frontend/src/features/env/PublicFeedbackModal.tsx | 7 +++++-- frontend/src/features/public-form/PublicFormContext.tsx | 2 ++ frontend/src/features/public-form/PublicFormProvider.tsx | 3 +++ .../public-form/components/FormFields/FormFields.tsx | 9 ++++++++- 4 files changed, 18 insertions(+), 3 deletions(-) diff --git a/frontend/src/features/env/PublicFeedbackModal.tsx b/frontend/src/features/env/PublicFeedbackModal.tsx index 4f26e70e8a..6322d4b3c1 100644 --- a/frontend/src/features/env/PublicFeedbackModal.tsx +++ b/frontend/src/features/env/PublicFeedbackModal.tsx @@ -34,6 +34,7 @@ import { ModalCloseButton } from '~components/Modal' import Textarea from '~components/Textarea' import { useEnvMutations, useFeedbackMutation } from '~features/env/mutations' +import { usePublicFormContext } from '~features/public-form/PublicFormContext' import { usePublicFeedbackFormView } from './queries' import { isUsableFeedback } from './utils' @@ -50,6 +51,7 @@ export const PublicFeedbackModal = ({ responseMode?: FormResponseMode authType?: FormAuthType }): JSX.Element => { + const { setBlockNavigation } = usePublicFormContext() const modalSize = useBreakpointValue({ base: 'mobile', xs: 'mobile', @@ -68,7 +70,7 @@ export const PublicFeedbackModal = ({ const url = window.location.href const rumSessionId = datadogRum.getInternalContext()?.session_id - const [showThanksPage, setShowThanksPage] = useState(false) + const [showThanksPage, setShowThanksPage] = useState(true) const { publicSwitchEnvMutation } = useEnvMutations() const { data: feedbackForm, isLoading } = usePublicFeedbackFormView() @@ -88,8 +90,9 @@ export const PublicFeedbackModal = ({ }, [onClose]) const handleChangeEnv = useCallback(() => { + setBlockNavigation(false) publicSwitchEnvMutation.mutate() - }, [publicSwitchEnvMutation]) + }, [publicSwitchEnvMutation, setBlockNavigation]) const checkboxInputName = 'attachmentType' diff --git a/frontend/src/features/public-form/PublicFormContext.tsx b/frontend/src/features/public-form/PublicFormContext.tsx index cb352a9bbf..8021a680f0 100644 --- a/frontend/src/features/public-form/PublicFormContext.tsx +++ b/frontend/src/features/public-form/PublicFormContext.tsx @@ -46,6 +46,8 @@ export interface PublicFormContextProps */ onMobileDrawerOpen: () => void onMobileDrawerClose: () => void + blockNavigation: boolean + setBlockNavigation: (val: boolean) => void } export const PublicFormContext = createContext< diff --git a/frontend/src/features/public-form/PublicFormProvider.tsx b/frontend/src/features/public-form/PublicFormProvider.tsx index 317b55f822..7b60f4835f 100644 --- a/frontend/src/features/public-form/PublicFormProvider.tsx +++ b/frontend/src/features/public-form/PublicFormProvider.tsx @@ -103,6 +103,7 @@ export const PublicFormProvider = ({ }: PublicFormProviderProps): JSX.Element => { // Once form has been submitted, submission data will be set here. const [submissionData, setSubmissionData] = useState() + const [blockNavigation, setBlockNavigation] = useState(false) const { data, isLoading, error, ...rest } = usePublicFormView( formId, @@ -323,6 +324,8 @@ export const PublicFormProvider = ({ captchaContainerId: containerId, expiryInMs, isLoading: isLoading || (!!data?.form.hasCaptcha && !hasLoaded), + blockNavigation, + setBlockNavigation, ...commonFormValues, ...data, ...rest, diff --git a/frontend/src/features/public-form/components/FormFields/FormFields.tsx b/frontend/src/features/public-form/components/FormFields/FormFields.tsx index 2d4e7e69d0..54010aefc9 100644 --- a/frontend/src/features/public-form/components/FormFields/FormFields.tsx +++ b/frontend/src/features/public-form/components/FormFields/FormFields.tsx @@ -18,6 +18,7 @@ import { hasExistingFieldValue, } from '~features/myinfo/utils' import { useFetchPrefillQuery } from '~features/public-form/hooks/useFetchPrefillQuery' +import { usePublicFormContext } from '~features/public-form/PublicFormContext' import { PublicFormSubmitButton } from './PublicFormSubmitButton' import { VisibleFormFields } from './VisibleFormFields' @@ -35,6 +36,8 @@ export const FormFields = ({ colorTheme, onSubmit, }: FormFieldsProps): JSX.Element => { + const { blockNavigation, setBlockNavigation } = usePublicFormContext() + useFetchPrefillQuery() const [searchParams] = useSearchParams() @@ -101,7 +104,11 @@ export const FormFields = ({ } }, [defaultFormValues, isDirty, reset]) - useNavigationPrompt(isDirty) + useEffect(() => { + if (isDirty) setBlockNavigation(true) + }, [isDirty, setBlockNavigation]) + + useNavigationPrompt(blockNavigation) return ( From 72d3ef68d112f8dab39714d15d059b34c2dd0f28 Mon Sep 17 00:00:00 2001 From: darrelhong Date: Sat, 28 Jan 2023 16:12:11 +0800 Subject: [PATCH 3/3] feat: use native beforeunload for simplicity --- .../components/FormFields/FormFields.tsx | 4 +++- frontend/src/hooks/useNativeBlocker.ts | 17 +++++++++++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) create mode 100644 frontend/src/hooks/useNativeBlocker.ts diff --git a/frontend/src/features/public-form/components/FormFields/FormFields.tsx b/frontend/src/features/public-form/components/FormFields/FormFields.tsx index 54010aefc9..62bc0a07d8 100644 --- a/frontend/src/features/public-form/components/FormFields/FormFields.tsx +++ b/frontend/src/features/public-form/components/FormFields/FormFields.tsx @@ -7,6 +7,7 @@ import { isEmpty, times } from 'lodash' import { BasicField, FormFieldDto } from '~shared/types/field' import { FormColorTheme, LogicDto } from '~shared/types/form' +import { useNativeBlocker } from '~hooks/useNativeBlocker' import InlineMessage from '~components/InlineMessage' import { FormFieldValues } from '~templates/Field' import { createTableRow } from '~templates/Field/Table/utils/createRow' @@ -108,7 +109,8 @@ export const FormFields = ({ if (isDirty) setBlockNavigation(true) }, [isDirty, setBlockNavigation]) - useNavigationPrompt(blockNavigation) + // useNavigationPrompt(blockNavigation) + useNativeBlocker(blockNavigation) return ( diff --git a/frontend/src/hooks/useNativeBlocker.ts b/frontend/src/hooks/useNativeBlocker.ts new file mode 100644 index 0000000000..7cb319ffdd --- /dev/null +++ b/frontend/src/hooks/useNativeBlocker.ts @@ -0,0 +1,17 @@ +import { useCallback, useEffect } from 'react' + +export const useNativeBlocker = (when: boolean) => { + const listener = useCallback( + (e: BeforeUnloadEvent) => { + if (when) e.returnValue = '' + }, + [when], + ) + + useEffect(() => { + window?.addEventListener('beforeunload', listener) + return () => { + window?.removeEventListener('beforeunload', listener) + } + }, [listener]) +}