From 9859213e19fe16fe14cb4babf594f800f58609ef Mon Sep 17 00:00:00 2001 From: simeng-li Date: Fri, 20 May 2022 09:59:40 +0800 Subject: [PATCH] refactor(ui): refactor terms modal as a promisified function (#897) refactor terms modal as a promisified function --- packages/ui/package.json | 1 + .../ui/src/containers/CreateAccount/index.tsx | 4 +-- .../Passwordless/EmailPasswordless.tsx | 4 +-- .../Passwordless/PhonePasswordless.tsx | 4 +-- .../SocialSignIn/PrimarySocialSignIn.test.tsx | 4 +-- .../SecondarySocialSignIn.test.tsx | 2 +- .../ui/src/containers/TermsOfUse/index.tsx | 17 ++--------- .../TermsOfUsePromiseModal/index.tsx | 28 +++++++++++++++++ .../src/containers/UsernameSignin/index.tsx | 2 +- packages/ui/src/hooks/use-page-context.ts | 9 +----- packages/ui/src/hooks/use-social.ts | 2 +- packages/ui/src/hooks/use-terms.ts | 30 +++++++++---------- packages/ui/src/pages/SignIn/index.test.tsx | 2 +- pnpm-lock.yaml | 12 ++++++++ 14 files changed, 72 insertions(+), 49 deletions(-) create mode 100644 packages/ui/src/containers/TermsOfUsePromiseModal/index.tsx diff --git a/packages/ui/package.json b/packages/ui/package.json index d86bc58af..76dc9bb24 100644 --- a/packages/ui/package.json +++ b/packages/ui/package.json @@ -54,6 +54,7 @@ "react-dom": "^17.0.2", "react-i18next": "^11.15.4", "react-modal": "^3.14.4", + "react-modal-promise": "^1.0.2", "react-phone-number-input": "^3.1.46", "react-router-dom": "^6.2.2", "react-string-replace": "^1.0.0", diff --git a/packages/ui/src/containers/CreateAccount/index.tsx b/packages/ui/src/containers/CreateAccount/index.tsx index 43d0c58cb..477e19c91 100644 --- a/packages/ui/src/containers/CreateAccount/index.tsx +++ b/packages/ui/src/containers/CreateAccount/index.tsx @@ -58,12 +58,12 @@ const CreateAccount = ({ className }: Props) => { const { result, run: asyncRegister } = useApi(register, registerErrorHandlers); - const onSubmitHandler = useCallback(() => { + const onSubmitHandler = useCallback(async () => { if (!validateForm()) { return; } - if (!termsValidation()) { + if (!(await termsValidation())) { return; } diff --git a/packages/ui/src/containers/Passwordless/EmailPasswordless.tsx b/packages/ui/src/containers/Passwordless/EmailPasswordless.tsx index dc38c72ab..3183c36ce 100644 --- a/packages/ui/src/containers/Passwordless/EmailPasswordless.tsx +++ b/packages/ui/src/containers/Passwordless/EmailPasswordless.tsx @@ -53,12 +53,12 @@ const EmailPasswordless = ({ type, className }: Props) => { const sendPasscode = getSendPasscodeApi(type, 'email'); const { result, run: asyncSendPasscode } = useApi(sendPasscode, errorHandlers); - const onSubmitHandler = useCallback(() => { + const onSubmitHandler = useCallback(async () => { if (!validateForm()) { return; } - if (!termsValidation()) { + if (!(await termsValidation())) { return; } diff --git a/packages/ui/src/containers/Passwordless/PhonePasswordless.tsx b/packages/ui/src/containers/Passwordless/PhonePasswordless.tsx index 91c827b97..ab9142922 100644 --- a/packages/ui/src/containers/Passwordless/PhonePasswordless.tsx +++ b/packages/ui/src/containers/Passwordless/PhonePasswordless.tsx @@ -63,12 +63,12 @@ const PhonePasswordless = ({ type, className }: Props) => { [isValidPhoneNumber] ); - const onSubmitHandler = useCallback(() => { + const onSubmitHandler = useCallback(async () => { if (!validateForm()) { return; } - if (!termsValidation()) { + if (!(await termsValidation())) { return; } diff --git a/packages/ui/src/containers/SocialSignIn/PrimarySocialSignIn.test.tsx b/packages/ui/src/containers/SocialSignIn/PrimarySocialSignIn.test.tsx index 1088fc4de..246f33c31 100644 --- a/packages/ui/src/containers/SocialSignIn/PrimarySocialSignIn.test.tsx +++ b/packages/ui/src/containers/SocialSignIn/PrimarySocialSignIn.test.tsx @@ -34,7 +34,7 @@ describe('SecondarySocialSignIn', () => { ); - expect(container.querySelectorAll('button')).toHaveLength(defaultSize); + expect(container.querySelectorAll('button')).toHaveLength(defaultSize + 1); // Expand button const expandButton = container.querySelector('svg'); @@ -42,6 +42,6 @@ describe('SecondarySocialSignIn', () => { fireEvent.click(expandButton); } - expect(container.querySelectorAll('button')).toHaveLength(socialConnectors.length); + expect(container.querySelectorAll('button')).toHaveLength(socialConnectors.length + 1); // Expand button }); }); diff --git a/packages/ui/src/containers/SocialSignIn/SecondarySocialSignIn.test.tsx b/packages/ui/src/containers/SocialSignIn/SecondarySocialSignIn.test.tsx index 99d8553a0..5be4574ab 100644 --- a/packages/ui/src/containers/SocialSignIn/SecondarySocialSignIn.test.tsx +++ b/packages/ui/src/containers/SocialSignIn/SecondarySocialSignIn.test.tsx @@ -61,7 +61,7 @@ describe('SecondarySocialSignIn', () => { ); - expect(container.querySelectorAll('button')).toHaveLength(defaultSize - 1); + expect(container.querySelectorAll('button')).toHaveLength(defaultSize); // Plus Expand button expect(container.querySelector('svg')).not.toBeNull(); }); diff --git a/packages/ui/src/containers/TermsOfUse/index.tsx b/packages/ui/src/containers/TermsOfUse/index.tsx index 7133c6b50..20dc34f6f 100644 --- a/packages/ui/src/containers/TermsOfUse/index.tsx +++ b/packages/ui/src/containers/TermsOfUse/index.tsx @@ -1,7 +1,7 @@ import React from 'react'; +import ModalContainer from 'react-modal-promise'; import PureTermsOfUse from '@/components/TermsOfUse'; -import TermsOfUseModal from '@/components/TermsOfUseModal'; import useTerms from '@/hooks/use-terms'; type Props = { @@ -9,8 +9,7 @@ type Props = { }; const TermsOfUse = ({ className }: Props) => { - const { termsAgreement, setTermsAgreement, termsSettings, showTermsModal, setShowTermsModal } = - useTerms(); + const { termsAgreement, setTermsAgreement, termsSettings } = useTerms(); if (!termsSettings?.enabled || !termsSettings.contentUrl) { return null; @@ -27,17 +26,7 @@ const TermsOfUse = ({ className }: Props) => { setTermsAgreement(checked); }} /> - { - setTermsAgreement(true); - setShowTermsModal(false); - }} - onClose={() => { - setShowTermsModal(false); - }} - /> + ); }; diff --git a/packages/ui/src/containers/TermsOfUsePromiseModal/index.tsx b/packages/ui/src/containers/TermsOfUsePromiseModal/index.tsx new file mode 100644 index 000000000..e051e4e2b --- /dev/null +++ b/packages/ui/src/containers/TermsOfUsePromiseModal/index.tsx @@ -0,0 +1,28 @@ +import React, { useContext } from 'react'; +import { create, InstanceProps } from 'react-modal-promise'; + +import TermsOfUseModal from '@/components/TermsOfUseModal'; +import { PageContext } from '@/hooks/use-page-context'; + +const TermsOfUsePromiseModal = ({ isOpen, onResolve, onReject }: InstanceProps) => { + const { setTermsAgreement, experienceSettings } = useContext(PageContext); + const { termsOfUse } = experienceSettings ?? {}; + + return ( + { + setTermsAgreement(true); + onResolve(true); + }} + onClose={() => { + onReject(false); + }} + /> + ); +}; + +export default TermsOfUsePromiseModal; + +export const termsOfUseModalPromise = create(TermsOfUsePromiseModal); diff --git a/packages/ui/src/containers/UsernameSignin/index.tsx b/packages/ui/src/containers/UsernameSignin/index.tsx index cd98c8bd8..5d3ae77a7 100644 --- a/packages/ui/src/containers/UsernameSignin/index.tsx +++ b/packages/ui/src/containers/UsernameSignin/index.tsx @@ -61,7 +61,7 @@ const UsernameSignin = ({ className }: Props) => { return; } - if (!termsValidation()) { + if (!(await termsValidation())) { return; } diff --git a/packages/ui/src/hooks/use-page-context.ts b/packages/ui/src/hooks/use-page-context.ts index 2e9a7924f..1d335b4f4 100644 --- a/packages/ui/src/hooks/use-page-context.ts +++ b/packages/ui/src/hooks/use-page-context.ts @@ -9,14 +9,12 @@ type Context = { loading: boolean; platform: Platform; termsAgreement: boolean; - showTermsModal: boolean; experienceSettings: SignInExperienceSettings | undefined; setTheme: (theme: Theme) => void; setToast: (message: string) => void; setLoading: (loading: boolean) => void; setPlatform: (platform: Platform) => void; setTermsAgreement: (termsAgreement: boolean) => void; - setShowTermsModal: (showTermsModal: boolean) => void; setExperienceSettings: (settings: SignInExperienceSettings) => void; }; @@ -30,14 +28,12 @@ export const PageContext = createContext({ loading: false, platform: isMobile ? 'mobile' : 'web', termsAgreement: false, - showTermsModal: false, experienceSettings: undefined, setTheme: noop, setToast: noop, setLoading: noop, setPlatform: noop, setTermsAgreement: noop, - setShowTermsModal: noop, setExperienceSettings: noop, }); @@ -48,7 +44,6 @@ const usePageContext = () => { const [platform, setPlatform] = useState(isMobile ? 'mobile' : 'web'); const [experienceSettings, setExperienceSettings] = useState(); const [termsAgreement, setTermsAgreement] = useState(false); - const [showTermsModal, setShowTermsModal] = useState(false); const context = useMemo( () => ({ @@ -57,17 +52,15 @@ const usePageContext = () => { loading, platform, termsAgreement, - showTermsModal, experienceSettings, setTheme, setLoading, setToast, setPlatform, setTermsAgreement, - setShowTermsModal, setExperienceSettings, }), - [experienceSettings, loading, platform, showTermsModal, termsAgreement, theme, toast] + [experienceSettings, loading, platform, termsAgreement, theme, toast] ); return { diff --git a/packages/ui/src/hooks/use-social.ts b/packages/ui/src/hooks/use-social.ts index 1a6713f31..b67182d16 100644 --- a/packages/ui/src/hooks/use-social.ts +++ b/packages/ui/src/hooks/use-social.ts @@ -51,7 +51,7 @@ const useSocial = () => { const invokeSocialSignInHandler = useCallback( async (connectorId: string, callback?: () => void) => { - if (!termsValidation()) { + if (!(await termsValidation())) { return; } diff --git a/packages/ui/src/hooks/use-terms.ts b/packages/ui/src/hooks/use-terms.ts index b2d69f60e..1b679bd6c 100644 --- a/packages/ui/src/hooks/use-terms.ts +++ b/packages/ui/src/hooks/use-terms.ts @@ -1,33 +1,33 @@ import { useContext, useCallback } from 'react'; +import { termsOfUseModalPromise } from '@/containers/TermsOfUsePromiseModal'; + import { PageContext } from './use-page-context'; const useTerms = () => { - const { - termsAgreement, - setTermsAgreement, - showTermsModal, - setShowTermsModal, - experienceSettings, - } = useContext(PageContext); + const { termsAgreement, setTermsAgreement, experienceSettings } = useContext(PageContext); - const termsValidation = useCallback(() => { - if (termsAgreement || !experienceSettings?.termsOfUse.enabled) { + const { termsOfUse } = experienceSettings ?? {}; + + const termsValidation = useCallback(async () => { + if (termsAgreement || !termsOfUse?.enabled || !termsOfUse.contentUrl) { return true; } - setShowTermsModal(true); + try { + await termsOfUseModalPromise(); - return false; - }, [experienceSettings, termsAgreement, setShowTermsModal]); + return true; + } catch { + return false; + } + }, [termsAgreement, termsOfUse]); return { - termsSettings: experienceSettings?.termsOfUse, + termsSettings: termsOfUse, termsAgreement, - showTermsModal, termsValidation, setTermsAgreement, - setShowTermsModal, }; }; diff --git a/packages/ui/src/pages/SignIn/index.test.tsx b/packages/ui/src/pages/SignIn/index.test.tsx index c4691b31e..70784188c 100644 --- a/packages/ui/src/pages/SignIn/index.test.tsx +++ b/packages/ui/src/pages/SignIn/index.test.tsx @@ -56,6 +56,6 @@ describe('', () => { ); - expect(container.querySelectorAll('button')).toHaveLength(3); + expect(container.querySelectorAll('button')).toHaveLength(4); // Plus Expand Button }); }); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 83238e49d..9e37df2c4 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -964,6 +964,7 @@ importers: react-dom: ^17.0.2 react-i18next: ^11.15.4 react-modal: ^3.14.4 + react-modal-promise: ^1.0.2 react-phone-number-input: ^3.1.46 react-router-dom: ^6.2.2 react-string-replace: ^1.0.0 @@ -1010,6 +1011,7 @@ importers: react-dom: 17.0.2_react@17.0.2 react-i18next: 11.15.4_fq32mavcto3l2u7t3zyhvdh4yu react-modal: 3.14.4_sfoxds7t5ydpegc3knd667wn6m + react-modal-promise: 1.0.2_sfoxds7t5ydpegc3knd667wn6m react-phone-number-input: 3.1.46_sfoxds7t5ydpegc3knd667wn6m react-router-dom: 6.2.2_sfoxds7t5ydpegc3knd667wn6m react-string-replace: 1.0.0 @@ -16623,6 +16625,16 @@ packages: - supports-color dev: true + /react-modal-promise/1.0.2_sfoxds7t5ydpegc3knd667wn6m: + resolution: {integrity: sha512-dqT618ROhG8qh1+O6EZkia5ELw3zaZWGpMX2YfEH4bgwYENPuFonqKw1W70LFx3K/SCZvVBcD6UYEI12yzYXzg==} + peerDependencies: + react: '>=16.8.0' + react-dom: '>=16.8.0' + dependencies: + react: 17.0.2 + react-dom: 17.0.2_react@17.0.2 + dev: true + /react-modal/3.14.4_sfoxds7t5ydpegc3knd667wn6m: resolution: {integrity: sha512-8surmulejafYCH9wfUmFyj4UfbSJwjcgbS9gf3oOItu4Hwd6ivJyVBETI0yHRhpJKCLZMUtnhzk76wXTsNL6Qg==} engines: {node: '>=8'}