From 091cd724ea56df6c3e6b7ec6c3d1790a8aadc3d4 Mon Sep 17 00:00:00 2001 From: amina-deriv <84661147+amina-deriv@users.noreply.github.com> Date: Fri, 19 Jul 2024 19:12:14 +0400 Subject: [PATCH] fix: revert_phone_number_verification_flow (#16138) --- package-lock.json | 11 +- packages/account/jest.config.js | 3 +- packages/account/package.json | 2 +- .../account/src/Constants/routes-config.tsx | 10 - .../src/Containers/__tests__/routes.spec.tsx | 13 -- packages/account/src/Containers/routes.tsx | 11 +- packages/account/src/Helpers/utils.tsx | 7 - .../__tests__/personal-details-form.spec.tsx | 3 - .../__tests__/verify-button.spec.tsx | 103 ---------- .../PersonalDetails/personal-details-form.tsx | 6 - .../PersonalDetails/verify-button.scss | 41 ---- .../Profile/PersonalDetails/verify-button.tsx | 86 -------- .../cancel-phone-verification-modal.spec.tsx | 68 ------- .../__test__/confirm-phone-number.spec.tsx | 165 ---------------- .../didnt-get-the-code-modal.spec.tsx | 114 ----------- .../__test__/otp-verification.spec.tsx | 184 ------------------ .../phone-number-verified-modal.spec.tsx | 56 ------ .../__test__/phone-verification-card.spec.tsx | 19 -- .../__test__/phone-verification-page.spec.tsx | 94 --------- .../__test__/resend-code-timer.spec.tsx | 109 ----------- .../__test__/validation.spec.tsx | 58 ------ .../verification-link-expired-modal.spec.tsx | 80 -------- .../cancel-phone-verification-modal.tsx | 62 ------ .../confirm-phone-number.tsx | 118 ----------- .../didnt-get-the-code-modal.tsx | 135 ------------- .../Profile/PhoneVerification/index.ts | 3 - .../PhoneVerification/otp-verification.tsx | 158 --------------- .../phone-number-verified-modal.tsx | 51 ----- .../phone-verification-card.tsx | 14 -- .../phone-verification-page.tsx | 92 --------- .../PhoneVerification/phone-verification.scss | 133 ------------- .../PhoneVerification/resend-code-timer.tsx | 61 ------ .../Profile/PhoneVerification/validation.ts | 17 -- .../verification-link-expired-modal.tsx | 75 ------- packages/account/src/Styles/account.scss | 7 - packages/api/types.ts | 91 --------- packages/cashier-v2/package.json | 2 +- packages/core/package.json | 3 +- .../notifications-list.tsx | 2 +- .../src/App/Containers/Redirect/redirect.jsx | 7 - .../Containers/app-notification-messages.jsx | 1 - packages/core/src/Services/socket-general.js | 1 - packages/core/src/Stores/client-store.js | 11 +- .../core/src/Stores/notification-store.js | 28 +-- packages/core/src/Stores/ui-store.js | 16 -- packages/hooks/package.json | 2 - ...sePhoneNumberVerificationSetTimer.spec.tsx | 76 -------- .../useRequestPhoneNumberOTP.spec.tsx | 164 ---------------- .../useSendOTPVerificationCode.spec.tsx | 115 ----------- .../hooks/src/__tests__/useSettings.spec.tsx | 94 --------- packages/hooks/src/index.ts | 4 - .../usePhoneNumberVerificationSetTimer.tsx | 89 --------- .../hooks/src/useRequestPhoneNumberOTP.tsx | 111 ----------- .../hooks/src/useSendOTPVerificationCode.ts | 85 -------- packages/hooks/src/useSettings.ts | 31 --- packages/hooks/src/useVerifyEmail.ts | 9 +- .../integration/src/mocks/auth/getSettings.ts | 4 - packages/shared/package.json | 3 +- packages/shared/src/styles/constants.scss | 1 - packages/shared/src/utils/constants/index.ts | 1 - .../constants/phone-number-verification.ts | 13 -- packages/shared/src/utils/routes/routes.ts | 1 - packages/stores/src/mockStore.ts | 5 - packages/stores/types.ts | 11 -- packages/trader/package.json | 2 +- packages/wallets/package.json | 2 +- 66 files changed, 26 insertions(+), 3128 deletions(-) delete mode 100644 packages/account/src/Sections/Profile/PersonalDetails/__tests__/verify-button.spec.tsx delete mode 100644 packages/account/src/Sections/Profile/PersonalDetails/verify-button.scss delete mode 100644 packages/account/src/Sections/Profile/PersonalDetails/verify-button.tsx delete mode 100644 packages/account/src/Sections/Profile/PhoneVerification/__test__/cancel-phone-verification-modal.spec.tsx delete mode 100644 packages/account/src/Sections/Profile/PhoneVerification/__test__/confirm-phone-number.spec.tsx delete mode 100644 packages/account/src/Sections/Profile/PhoneVerification/__test__/didnt-get-the-code-modal.spec.tsx delete mode 100644 packages/account/src/Sections/Profile/PhoneVerification/__test__/otp-verification.spec.tsx delete mode 100644 packages/account/src/Sections/Profile/PhoneVerification/__test__/phone-number-verified-modal.spec.tsx delete mode 100644 packages/account/src/Sections/Profile/PhoneVerification/__test__/phone-verification-card.spec.tsx delete mode 100644 packages/account/src/Sections/Profile/PhoneVerification/__test__/phone-verification-page.spec.tsx delete mode 100644 packages/account/src/Sections/Profile/PhoneVerification/__test__/resend-code-timer.spec.tsx delete mode 100644 packages/account/src/Sections/Profile/PhoneVerification/__test__/validation.spec.tsx delete mode 100644 packages/account/src/Sections/Profile/PhoneVerification/__test__/verification-link-expired-modal.spec.tsx delete mode 100644 packages/account/src/Sections/Profile/PhoneVerification/cancel-phone-verification-modal.tsx delete mode 100644 packages/account/src/Sections/Profile/PhoneVerification/confirm-phone-number.tsx delete mode 100644 packages/account/src/Sections/Profile/PhoneVerification/didnt-get-the-code-modal.tsx delete mode 100644 packages/account/src/Sections/Profile/PhoneVerification/index.ts delete mode 100644 packages/account/src/Sections/Profile/PhoneVerification/otp-verification.tsx delete mode 100644 packages/account/src/Sections/Profile/PhoneVerification/phone-number-verified-modal.tsx delete mode 100644 packages/account/src/Sections/Profile/PhoneVerification/phone-verification-card.tsx delete mode 100644 packages/account/src/Sections/Profile/PhoneVerification/phone-verification-page.tsx delete mode 100644 packages/account/src/Sections/Profile/PhoneVerification/phone-verification.scss delete mode 100644 packages/account/src/Sections/Profile/PhoneVerification/resend-code-timer.tsx delete mode 100644 packages/account/src/Sections/Profile/PhoneVerification/validation.ts delete mode 100644 packages/account/src/Sections/Profile/PhoneVerification/verification-link-expired-modal.tsx delete mode 100644 packages/hooks/src/__tests__/usePhoneNumberVerificationSetTimer.spec.tsx delete mode 100644 packages/hooks/src/__tests__/useRequestPhoneNumberOTP.spec.tsx delete mode 100644 packages/hooks/src/__tests__/useSendOTPVerificationCode.spec.tsx delete mode 100644 packages/hooks/src/__tests__/useSettings.spec.tsx delete mode 100644 packages/hooks/src/usePhoneNumberVerificationSetTimer.tsx delete mode 100644 packages/hooks/src/useRequestPhoneNumberOTP.tsx delete mode 100644 packages/hooks/src/useSendOTPVerificationCode.ts delete mode 100644 packages/hooks/src/useSettings.ts delete mode 100644 packages/shared/src/utils/constants/phone-number-verification.ts diff --git a/package-lock.json b/package-lock.json index 875c67c1eb15..80dc6c9f23b5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -25,7 +25,7 @@ "@deriv/deriv-charts": "^2.1.24", "@deriv/js-interpreter": "^3.0.0", "@deriv/quill-design": "^1.3.2", - "@deriv/quill-icons": "^1.23.3", + "@deriv/quill-icons": "1.23.3", "@deriv/ui": "^0.6.0", "@livechat/customer-sdk": "^2.0.4", "@lottiefiles/dotlottie-react": "0.7.2", @@ -94,7 +94,6 @@ "css-hot-loader": "^1.4.4", "css-loader": "^5.0.1", "css-minimizer-webpack-plugin": "^3.0.1", - "dayjs": "^1.11.11", "deep-diff": "^1.0.2", "dompurify": "^3.1.0", "dotenv": "^8.2.0", @@ -2965,7 +2964,7 @@ "resolved": "https://registry.npmjs.org/@deriv-com/quill-ui/-/quill-ui-1.13.17.tgz", "integrity": "sha512-CTwfMMYiSe1XgQQ5NMe+lZhV8aPyRcW/TGSzaQBpfcQxFH+0Vgpdi90AGJJrENaDWPvh5qvpaV8XM/lhwIurUg==", "dependencies": { - "@deriv-com/quill-tokens": "^2.0.8", + "@deriv-com/quill-tokens": "^2.0.7", "@deriv/quill-icons": "^1.22.10", "@headlessui/react": "1.7.18", "dayjs": "^1.11.11", @@ -3148,9 +3147,9 @@ } }, "node_modules/@deriv-com/ui": { - "version": "1.29.2", - "resolved": "https://registry.npmjs.org/@deriv-com/ui/-/ui-1.29.2.tgz", - "integrity": "sha512-mbYMaLj30P6g/9FarP9EVMdXQGf8yR2c2aUKg8awLMJ2x+BsO7CxE1LLWPWQAHCSyzdNWR9NxyF09SLwd3n1jQ==", + "version": "1.29.3", + "resolved": "https://registry.npmjs.org/@deriv-com/ui/-/ui-1.29.3.tgz", + "integrity": "sha512-GhIqgGffNPPihv9S/+FWFpY6RdOm15/663kCcHKDQueiXFwv5ZCU88kTTIE1vfU5QFU2PB7PPNpmb5p6T2hUQA==", "dependencies": { "@popperjs/core": "^2.11.8", "@types/react-modal": "^3.16.3", diff --git a/packages/account/jest.config.js b/packages/account/jest.config.js index 1e3d737cc6df..ee7834a92264 100644 --- a/packages/account/jest.config.js +++ b/packages/account/jest.config.js @@ -4,7 +4,8 @@ module.exports = { ...baseConfigForPackages, preset: 'ts-jest', moduleNameMapper: { - '\\.(s(c|a)ss|css|less)$': '/../../__mocks__/styleMock.js', + '\\.css$': '/../../__mocks__/styleMock.js', + '\\.s(c|a)ss$': '/../../__mocks__/styleMock.js', '^.+\\.svg$': '/../../__mocks__/styleMock.js', '@deriv-com/translations': '/../../__mocks__/translation.mock.js', '^Assets/(.*)$': '/src/Assets/$1', diff --git a/packages/account/package.json b/packages/account/package.json index 815eefb81afa..3106a5b1bee1 100644 --- a/packages/account/package.json +++ b/packages/account/package.json @@ -39,7 +39,7 @@ "@deriv/components": "^1.0.0", "@deriv/hooks": "^1.0.0", "@deriv/integration": "1.0.0", - "@deriv/quill-icons": "^1.23.3", + "@deriv/quill-icons": "1.23.3", "@deriv/shared": "^1.0.0", "@deriv/stores": "^1.0.0", "@deriv/translations": "^1.0.0", diff --git a/packages/account/src/Constants/routes-config.tsx b/packages/account/src/Constants/routes-config.tsx index 8e28874bc461..f73671e9dd84 100644 --- a/packages/account/src/Constants/routes-config.tsx +++ b/packages/account/src/Constants/routes-config.tsx @@ -27,10 +27,6 @@ const Passwords = makeLazyLoader( () => )(); -const PhoneVerificationPage = makeLazyLoader( - () => moduleLoader(() => import('../Sections/Profile/PhoneVerification')), - () => -)(); const AccountLimits = makeLazyLoader( () => moduleLoader(() => import('../Sections/Security/AccountLimits')), () => @@ -109,12 +105,6 @@ const initRoutesConfig = () => [ getTitle: () => localize('Profile'), icon: 'IcUserOutline', subroutes: [ - { - path: routes.phone_verification, - component: PhoneVerificationPage, - getTitle: () => localize('Personal details'), - is_hidden: true, - }, { path: routes.personal_details, component: PersonalDetails, diff --git a/packages/account/src/Containers/__tests__/routes.spec.tsx b/packages/account/src/Containers/__tests__/routes.spec.tsx index 076bd2c3a205..5d2ad2c67afe 100644 --- a/packages/account/src/Containers/__tests__/routes.spec.tsx +++ b/packages/account/src/Containers/__tests__/routes.spec.tsx @@ -16,19 +16,6 @@ jest.mock('@deriv/components', () => ({ })); describe('', () => { - Object.defineProperty(window, 'matchMedia', { - writable: true, - value: jest.fn().mockImplementation(query => ({ - matches: false, - media: query, - onchange: null, - addListener: jest.fn(), // Deprecated - removeListener: jest.fn(), // Deprecated - addEventListener: jest.fn(), - removeEventListener: jest.fn(), - dispatchEvent: jest.fn(), - })), - }); const history = createBrowserHistory(); const mock_root_store = mockStore({ diff --git a/packages/account/src/Containers/routes.tsx b/packages/account/src/Containers/routes.tsx index 3dbb9079f1b2..63566793c9db 100644 --- a/packages/account/src/Containers/routes.tsx +++ b/packages/account/src/Containers/routes.tsx @@ -1,23 +1,18 @@ +import React from 'react'; import { withRouter } from 'react-router'; import { observer, useStore } from '@deriv/stores'; import { BinaryRoutes } from '../Components/Routes'; import ErrorComponent from '../Components/error-component'; -import { ThemeProvider } from '@deriv-com/quill-ui'; const Routes = observer(() => { - const { client, common, ui } = useStore(); + const { client, common } = useStore(); const { is_logged_in, is_logging_in } = client; const { error, has_error } = common; - const { is_dark_mode_on } = ui; if (has_error) { return ; } - return ( - - - - ); + return ; }); // need to wrap withRouter diff --git a/packages/account/src/Helpers/utils.tsx b/packages/account/src/Helpers/utils.tsx index 590a987274ef..70147b7f7faf 100644 --- a/packages/account/src/Helpers/utils.tsx +++ b/packages/account/src/Helpers/utils.tsx @@ -10,7 +10,6 @@ import { getIDVNotApplicableOption, IDV_ERROR_STATUS, AUTH_STATUS_CODES, - VERIFICATION_SERVICES, } from '@deriv/shared'; import { localize } from '@deriv/translations'; import { getIDVDocuments } from '../Configs/idv-document-config'; @@ -278,9 +277,3 @@ export const verifyFields = (status: TIDVErrorStatus) => { export const isSpecialPaymentMethod = (payment_method_icon: string) => ['IcOnlineNaira', 'IcAstroPayLight', 'IcAstroPayDark'].some(icon => icon === payment_method_icon); - -export const convertPhoneTypeDisplay = (phone_verification_type: string) => { - if (phone_verification_type === VERIFICATION_SERVICES.SMS) return phone_verification_type.toUpperCase(); - - return 'WhatsApp'; -}; diff --git a/packages/account/src/Sections/Profile/PersonalDetails/__tests__/personal-details-form.spec.tsx b/packages/account/src/Sections/Profile/PersonalDetails/__tests__/personal-details-form.spec.tsx index ad8208006b22..7f4652e8014c 100644 --- a/packages/account/src/Sections/Profile/PersonalDetails/__tests__/personal-details-form.spec.tsx +++ b/packages/account/src/Sections/Profile/PersonalDetails/__tests__/personal-details-form.spec.tsx @@ -44,9 +44,6 @@ describe('', () => { place_of_birth: 'Thailand', citizen: 'Thailand', email_consent: 1, - phone_number_verification: { - verified: 0, - }, }, }, }); diff --git a/packages/account/src/Sections/Profile/PersonalDetails/__tests__/verify-button.spec.tsx b/packages/account/src/Sections/Profile/PersonalDetails/__tests__/verify-button.spec.tsx deleted file mode 100644 index 2bf8cb9c87e5..000000000000 --- a/packages/account/src/Sections/Profile/PersonalDetails/__tests__/verify-button.spec.tsx +++ /dev/null @@ -1,103 +0,0 @@ -import React from 'react'; -import { screen, render } from '@testing-library/react'; -import userEvent from '@testing-library/user-event'; -import { VerifyButton } from '../verify-button'; -import { StoreProvider, mockStore } from '@deriv/stores'; -import { Router } from 'react-router'; -import { createBrowserHistory } from 'history'; -import { routes } from '@deriv/shared'; -import { usePhoneNumberVerificationSetTimer, useVerifyEmail } from '@deriv/hooks'; - -jest.mock('@deriv/hooks', () => ({ - ...jest.requireActual('@deriv/hooks'), - usePhoneNumberVerificationSetTimer: jest.fn(), - useVerifyEmail: jest.fn(() => ({ - sendPhoneNumberVerifyEmail: jest.fn(), - WS: {}, - })), -})); - -describe('VerifyButton', () => { - beforeEach(() => { - (usePhoneNumberVerificationSetTimer as jest.Mock).mockReturnValue({ next_otp_request: '' }); - }); - const history = createBrowserHistory(); - const mock_store = mockStore({ - client: { - account_settings: { - phone_number_verification: { - verified: 0, - }, - }, - }, - }); - - const renderWithRouter = () => { - return render( - - - - - - ); - }; - - it('should render Verify Button', () => { - renderWithRouter(); - expect(screen.getByText('Verify')).toBeInTheDocument(); - }); - - it('should render Verify Button with countdown timer return from usePhoneNumberSetTimer and should have disabled class', () => { - (usePhoneNumberVerificationSetTimer as jest.Mock).mockReturnValue({ next_otp_request: 'in 60s' }); - renderWithRouter(); - expect(screen.getByText('Verify in 60s')).toBeInTheDocument(); - expect(screen.getByText('Verify in 60s')).toHaveClass('phone-verification-btn--not-verified--disabled'); - }); - - it('should redirect user to phone-verification page when clicked on Verify Button', () => { - (useVerifyEmail as jest.Mock).mockReturnValue({ - sendPhoneNumberVerifyEmail: jest.fn(), - WS: { - isSuccess: true, - }, - }); - renderWithRouter(); - const verifyButton = screen.getByText('Verify'); - userEvent.click(verifyButton); - expect(history.location.pathname).toBe(routes.phone_verification); - }); - - it('should render Verified text', () => { - if (mock_store.client.account_settings.phone_number_verification) - mock_store.client.account_settings.phone_number_verification.verified = 1; - renderWithRouter(); - expect(screen.getByText('Verified')).toBeInTheDocument(); - expect(screen.getByTestId('dt_phone_verification_popover')).toBeInTheDocument(); - }); - - it('should render popover text when popover is clicked', () => { - if (mock_store.client.account_settings.phone_number_verification) - mock_store.client.account_settings.phone_number_verification.verified = 1; - renderWithRouter(); - const popover = screen.getByTestId('dt_phone_verification_popover'); - userEvent.click(popover); - expect(screen.getByText(/To change your verified phone number, contact us via/)).toBeInTheDocument(); - expect(screen.getByText(/live chat/)).toBeInTheDocument(); - }); - - it('should render live chat window when live chat is clicked', () => { - if (mock_store.client.account_settings.phone_number_verification) - mock_store.client.account_settings.phone_number_verification.verified = 1; - window.LC_API = { - open_chat_window: jest.fn(), - on_chat_ended: jest.fn(), - }; - - renderWithRouter(); - const popover = screen.getByTestId('dt_phone_verification_popover'); - userEvent.click(popover); - const livechat = screen.getByText(/live chat/); - userEvent.click(livechat); - expect(window.LC_API.open_chat_window).toHaveBeenCalled(); - }); -}); diff --git a/packages/account/src/Sections/Profile/PersonalDetails/personal-details-form.tsx b/packages/account/src/Sections/Profile/PersonalDetails/personal-details-form.tsx index 5dab42230c46..8ac9321ec2f2 100644 --- a/packages/account/src/Sections/Profile/PersonalDetails/personal-details-form.tsx +++ b/packages/account/src/Sections/Profile/PersonalDetails/personal-details-form.tsx @@ -29,7 +29,6 @@ import { getEmploymentStatusList } from 'Sections/Assessment/FinancialAssessment import InputGroup from './input-group'; import { getPersonalDetailsInitialValues, getPersonalDetailsValidationSchema, makeSettingsRequest } from './validation'; import FormSelectField from 'Components/forms/form-select-field'; -import { VerifyButton } from './verify-button'; import { useInvalidateQuery } from '@deriv/api'; import { useStatesList, useResidenceList } from '@deriv/hooks'; @@ -361,10 +360,6 @@ const PersonalDetailsForm = observer(() => { name='phone' id={'phone'} label={localize('Phone number*')} - className={clsx({ - 'account-form__fieldset--phone': - account_settings?.phone_number_verification?.verified, - })} //@ts-expect-error type of residence should not be null: needs to be updated in GetSettings type value={values.phone} onChange={handleChange} @@ -374,7 +369,6 @@ const PersonalDetailsForm = observer(() => { disabled={isFieldDisabled('phone')} data-testid='dt_phone' /> - )} diff --git a/packages/account/src/Sections/Profile/PersonalDetails/verify-button.scss b/packages/account/src/Sections/Profile/PersonalDetails/verify-button.scss deleted file mode 100644 index 8288fc00f4d7..000000000000 --- a/packages/account/src/Sections/Profile/PersonalDetails/verify-button.scss +++ /dev/null @@ -1,41 +0,0 @@ -.phone-verification-btn { - position: absolute; - inset-inline-end: 0; - top: 0.4rem; - - &--not-verified { - display: flex; - padding-top: 0.6rem; - padding-inline-end: 1.2rem; - cursor: pointer; - - &--disabled { - cursor: not-allowed; - color: rgba(#ff444f, 0.5); - } - } - - &--verified { - display: flex; - padding-top: 0.6rem; - padding-inline-end: 1.2rem; - color: var(--text-profit-success); - - @include mobile { - padding-inline-end: 4rem; - } - - > :first-child { - padding-inline-end: 0.4rem; - } - - .phone-verification__popover { - position: absolute; - inset-inline-end: -3rem; - - @include mobile { - inset-inline-end: 0rem; - } - } - } -} diff --git a/packages/account/src/Sections/Profile/PersonalDetails/verify-button.tsx b/packages/account/src/Sections/Profile/PersonalDetails/verify-button.tsx deleted file mode 100644 index 6106d544d40a..000000000000 --- a/packages/account/src/Sections/Profile/PersonalDetails/verify-button.tsx +++ /dev/null @@ -1,86 +0,0 @@ -import { useEffect, useState } from 'react'; -import clsx from 'clsx'; -import { CaptionText } from '@deriv-com/quill-ui'; -import { observer, useStore } from '@deriv/stores'; -import { LegacyWonIcon } from '@deriv/quill-icons'; -import { useHistory } from 'react-router'; -import { routes } from '@deriv/shared'; -import { OpenLiveChatLink, Popover, Text } from '@deriv/components'; -import { Localize } from '@deriv/translations'; -import { usePhoneNumberVerificationSetTimer, useVerifyEmail } from '@deriv/hooks'; -import { useDevice } from '@deriv-com/ui'; -import './verify-button.scss'; - -export const VerifyButton = observer(() => { - const [open_popover, setOpenPopover] = useState(false); - const { client, ui } = useStore(); - const { setShouldShowPhoneNumberOTP } = ui; - const { account_settings, setVerificationCode } = client; - const { phone_number_verification } = account_settings; - const phone_number_verified = phone_number_verification?.verified; - const history = useHistory(); - //@ts-expect-error remove this comment when types are added in GetSettings api types - const { sendPhoneNumberVerifyEmail, WS } = useVerifyEmail('phone_number_verification'); - const { isMobile } = useDevice(); - const { next_otp_request } = usePhoneNumberVerificationSetTimer(); - - useEffect(() => { - if (WS.isSuccess) { - history.push(routes.phone_verification); - } - }, [WS.isSuccess, history]); - - const redirectToPhoneVerification = () => { - if (next_otp_request) return; - setVerificationCode('', 'phone_number_verification'); - setShouldShowPhoneNumberOTP(false); - sendPhoneNumberVerifyEmail(); - }; - - return ( -
- {phone_number_verified ? ( -
- - - - - setOpenPopover(prev => !prev)} - message={ - - ]} - /> - - } - zIndex='9999' - /> -
- ) : ( - - - - )} -
- ); -}); diff --git a/packages/account/src/Sections/Profile/PhoneVerification/__test__/cancel-phone-verification-modal.spec.tsx b/packages/account/src/Sections/Profile/PhoneVerification/__test__/cancel-phone-verification-modal.spec.tsx deleted file mode 100644 index 403eb09c7a8b..000000000000 --- a/packages/account/src/Sections/Profile/PhoneVerification/__test__/cancel-phone-verification-modal.spec.tsx +++ /dev/null @@ -1,68 +0,0 @@ -import React from 'react'; -import { render, screen } from '@testing-library/react'; -import userEvent from '@testing-library/user-event'; -import CancelPhoneVerificationModal from '../cancel-phone-verification-modal'; -import { StoreProvider, mockStore } from '@deriv/stores'; - -const mock_back_router = jest.fn(); -jest.mock('react-router', () => ({ - ...jest.requireActual('react-router'), - useHistory: () => ({ - goBack: mock_back_router, - }), -})); - -describe('CancelPhoneVerificationModal', () => { - let modal_root_el: HTMLElement; - const mockSetShowCancelModal = jest.fn(); - - beforeAll(() => { - modal_root_el = document.createElement('div'); - modal_root_el.setAttribute('id', 'modal_root'); - document.body.appendChild(modal_root_el); - }); - - afterAll(() => { - document.body.removeChild(modal_root_el); - }); - - const mock_store = mockStore({}); - - const buttons = [/Go back/, /Yes, cancel/]; - - const renderComponent = () => { - render( - - - - ); - }; - - it('it should render CancelPhoneVerificationModal', () => { - renderComponent(); - buttons.forEach(value => { - expect(screen.getByRole('button', { name: value })).toBeInTheDocument(); - }); - expect(screen.getByText(/Cancel phone number verification?/)).toBeInTheDocument(); - expect(screen.getByText(/All details entered will be lost./)).toBeInTheDocument(); - }); - - it('it should render only mockSetShowCancelModal when Go back is clicked', () => { - renderComponent(); - const cancelButton = screen.getByRole('button', { name: buttons[0] }); - userEvent.click(cancelButton); - expect(mockSetShowCancelModal).toBeCalled(); - expect(mock_back_router).not.toBeCalled(); - }); - - it('it should render mockSetShowCancelModal and mock_back_router when Yes, cancel is clicked', () => { - renderComponent(); - const cancelButton = screen.getByRole('button', { name: buttons[1] }); - userEvent.click(cancelButton); - expect(mockSetShowCancelModal).toBeCalled(); - expect(mock_back_router).toBeCalled(); - }); -}); diff --git a/packages/account/src/Sections/Profile/PhoneVerification/__test__/confirm-phone-number.spec.tsx b/packages/account/src/Sections/Profile/PhoneVerification/__test__/confirm-phone-number.spec.tsx deleted file mode 100644 index 720ec9535a32..000000000000 --- a/packages/account/src/Sections/Profile/PhoneVerification/__test__/confirm-phone-number.spec.tsx +++ /dev/null @@ -1,165 +0,0 @@ -import React from 'react'; -import { act, render, screen, waitFor } from '@testing-library/react'; -import userEvent from '@testing-library/user-event'; -import { StoreProvider, mockStore } from '@deriv/stores'; -import { usePhoneNumberVerificationSetTimer, useRequestPhoneNumberOTP, useSettings } from '@deriv/hooks'; -import ConfirmPhoneNumber from '../confirm-phone-number'; - -jest.mock('@deriv/hooks', () => ({ - ...jest.requireActual('@deriv/hooks'), - useRequestPhoneNumberOTP: jest.fn(() => ({ - error_message: '', - requestOnWhatsApp: jest.fn(), - requestOnSMS: jest.fn(), - setErrorMessage: jest.fn(), - setUsersPhoneNumber: jest.fn(), - })), - useSettings: jest.fn(() => ({ - data: {}, - invalidate: jest.fn(), - })), - usePhoneNumberVerificationSetTimer: jest.fn(() => ({ - next_otp_request: undefined, - })), -})); - -describe('ConfirmPhoneNumber', () => { - const store = mockStore({ - ui: { - setShouldShowPhoneNumberOTP: jest.fn(), - }, - }); - - const mockSetOtp = jest.fn(); - const whatsapp_button_text = 'Get code via WhatsApp'; - const sms_button_text = 'Get code via SMS'; - - it('should render ConfirmPhoneNumber', () => { - (useSettings as jest.Mock).mockReturnValue({ - data: { phone: '+0123456789' }, - }); - render( - - - - ); - const phone_number_textfield = screen.getByRole('textbox', { name: 'Phone number' }); - expect(screen.getByText('Confirm your phone number')).toBeInTheDocument(); - expect(phone_number_textfield).toBeInTheDocument(); - expect(phone_number_textfield).toHaveValue('0123456789'); - expect(screen.getByRole('button', { name: sms_button_text })).toBeInTheDocument(); - expect(screen.getByRole('button', { name: whatsapp_button_text })).toBeInTheDocument(); - }); - - it('should call setErrorMessage when the user presses a key', async () => { - const mock_set_error_message = jest.fn(); - (useRequestPhoneNumberOTP as jest.Mock).mockReturnValue({ - setErrorMessage: mock_set_error_message, - }); - render( - - - - ); - const phone_number_textfield = screen.getByRole('textbox', { name: 'Phone number' }); - expect(screen.getByText('Confirm your phone number')).toBeInTheDocument(); - expect(phone_number_textfield).toBeInTheDocument(); - userEvent.clear(phone_number_textfield); - userEvent.type(phone_number_textfield, '+01293291291'); - await waitFor(() => { - expect(mock_set_error_message).toHaveBeenCalled(); - }); - }); - - it('should display given error message', () => { - (useRequestPhoneNumberOTP as jest.Mock).mockReturnValue({ - error_message: 'This is an error message', - }); - render( - - - - ); - expect(screen.getByText(/This is an error message/)).toBeInTheDocument(); - }); - - it('should render handleError function when WS returns error promises', async () => { - const mock_handle_error = jest.fn().mockResolvedValue({ error: null }); - (useRequestPhoneNumberOTP as jest.Mock).mockReturnValue({ - requestOnWhatsApp: jest.fn(), - setUsersPhoneNumber: mock_handle_error, - }); - - render( - - - - ); - const whatsapp_btn = screen.getByRole('button', { name: whatsapp_button_text }); - userEvent.click(whatsapp_btn); - await waitFor(() => { - expect(mock_handle_error).toBeCalledTimes(1); - }); - }); - - it('should call requestOnWhatsApp when Whatsapp button is clicked', async () => { - const mockWhatsappButtonClick = jest.fn(); - - (useRequestPhoneNumberOTP as jest.Mock).mockReturnValue({ - requestOnWhatsApp: mockWhatsappButtonClick, - setUsersPhoneNumber: jest.fn().mockResolvedValue({ error: null }), - }); - render( - - - - ); - const whatsapp_btn = screen.getByRole('button', { name: whatsapp_button_text }); - userEvent.click(whatsapp_btn); - await waitFor(() => { - expect(mockWhatsappButtonClick).toHaveBeenCalled(); - }); - }); - - it('should call requestOnSMS when SMS button is clicked', async () => { - const mockSmsButtonClick = jest.fn(); - - (useRequestPhoneNumberOTP as jest.Mock).mockReturnValue({ - requestOnSMS: mockSmsButtonClick, - setUsersPhoneNumber: jest.fn().mockResolvedValue({ error: null }), - }); - render( - - - - ); - const sms_btn = screen.getByRole('button', { name: sms_button_text }); - userEvent.click(sms_btn); - await waitFor(() => { - expect(mockSmsButtonClick).toHaveBeenCalled(); - }); - }); - - it('should make both buttons disabled if next_otp_request text is provided', async () => { - (usePhoneNumberVerificationSetTimer as jest.Mock).mockReturnValue({ next_otp_request: '60 seconds' }); - render( - - - - ); - const sms_btn = screen.getByRole('button', { name: sms_button_text }); - const whatsapp_btn = screen.getByRole('button', { name: whatsapp_button_text }); - expect(sms_btn).toBeDisabled(); - expect(whatsapp_btn).toBeDisabled(); - }); - - it('should get snackbar text when next_otp_request text is provided', async () => { - (usePhoneNumberVerificationSetTimer as jest.Mock).mockReturnValue({ next_otp_request: '60 seconds' }); - render( - - - - ); - expect(screen.getByText(/An error occurred. Request a new OTP in 60 seconds./)); - }); -}); diff --git a/packages/account/src/Sections/Profile/PhoneVerification/__test__/didnt-get-the-code-modal.spec.tsx b/packages/account/src/Sections/Profile/PhoneVerification/__test__/didnt-get-the-code-modal.spec.tsx deleted file mode 100644 index d75d37fa0953..000000000000 --- a/packages/account/src/Sections/Profile/PhoneVerification/__test__/didnt-get-the-code-modal.spec.tsx +++ /dev/null @@ -1,114 +0,0 @@ -import React from 'react'; -import { render, screen } from '@testing-library/react'; -import DidntGetTheCodeModal from '../didnt-get-the-code-modal'; -import userEvent from '@testing-library/user-event'; -import { VERIFICATION_SERVICES } from '@deriv/shared'; - -describe('DidntGetTheCodeModal', () => { - const mockClearOtpValue = jest.fn(); - const mockSetShouldShowDidntGetTheCodeModal = jest.fn(); - const mockSetOtpVerification = jest.fn(); - const mockReInitializeGetSettings = jest.fn(); - const mockSetIsButtonDisabled = jest.fn(); - const mockRequestOnWhatsApp = jest.fn(); - const mockRequestOnSms = jest.fn(); - const resend_code_text = /Resend code/; - - const renderComponent = (phone_verification_type: string) => { - render( - - ); - }; - - beforeEach(() => { - mockSetShouldShowDidntGetTheCodeModal.mockClear(); - mockSetOtpVerification.mockClear(); - mockRequestOnSms.mockClear(); - mockRequestOnWhatsApp.mockClear(); - }); - - it('should render DidntGetTheCodeModal', () => { - renderComponent(VERIFICATION_SERVICES.SMS); - expect(screen.getByText(/Get a new code/)).toBeInTheDocument(); - expect(screen.getByRole('button', { name: resend_code_text })).toBeInTheDocument(); - expect(screen.getByRole('button', { name: /Send code via WhatsApp/ })).toBeInTheDocument(); - expect(screen.getByText(/or/)).toBeInTheDocument(); - expect(screen.getByRole('button', { name: /Change phone number/ })).toBeInTheDocument(); - }); - - it('should show Send code via SMS if phone_verification_type is whatsapp', () => { - renderComponent(VERIFICATION_SERVICES.WHATSAPP); - expect(screen.getByRole('button', { name: /Send code via SMS/ })).toBeInTheDocument(); - }); - - it('should render setOtpVerification and setShouldShowDidintGetTheCodeModal when Change phone number is clicked, should not render mockSetTimer', () => { - renderComponent(VERIFICATION_SERVICES.SMS); - const change_phone_number_button = screen.getByRole('button', { name: /Change phone number/ }); - userEvent.click(change_phone_number_button); - expect(mockSetShouldShowDidntGetTheCodeModal).toHaveBeenCalledTimes(1); - expect(mockSetOtpVerification).toHaveBeenCalledTimes(1); - }); - - it('should render setShouldShowDidintGetTheCodeModal when Resend code is clicked', () => { - renderComponent(VERIFICATION_SERVICES.SMS); - const resend_code_button = screen.getByRole('button', { name: resend_code_text }); - userEvent.click(resend_code_button); - expect(mockSetShouldShowDidntGetTheCodeModal).toHaveBeenCalledTimes(1); - }); - - it('should render mockRequestOnSMS and setOtpVerification with phone_verification_type: sms when Resend code is clicked, phone_verification_type is sms', () => { - renderComponent(VERIFICATION_SERVICES.SMS); - const resend_code_button = screen.getByRole('button', { name: resend_code_text }); - userEvent.click(resend_code_button); - expect(mockRequestOnSms).toHaveBeenCalledTimes(1); - expect(mockSetOtpVerification).toBeCalledWith({ - show_otp_verification: true, - phone_verification_type: VERIFICATION_SERVICES.SMS, - }); - }); - - it('should render mockRequestOnWhatsapp and setOtpVerification with phone_verification_type: whatsapp when Resend code is clicked, phone_verification_type is whatsapp', () => { - renderComponent(VERIFICATION_SERVICES.WHATSAPP); - const resend_code_button = screen.getByRole('button', { name: resend_code_text }); - userEvent.click(resend_code_button); - expect(mockRequestOnWhatsApp).toHaveBeenCalledTimes(1); - expect(mockSetOtpVerification).toBeCalledWith({ - show_otp_verification: true, - phone_verification_type: VERIFICATION_SERVICES.WHATSAPP, - }); - }); - - it('should render mockRequestOnSMS and setOtpVerification with phone_verification_type: sms when Send code via SMS is clicked, phone_verification_type is whatsapp', () => { - renderComponent(VERIFICATION_SERVICES.WHATSAPP); - const resend_code_button = screen.getByRole('button', { name: /Send code via SMS/ }); - userEvent.click(resend_code_button); - expect(mockRequestOnSms).toHaveBeenCalledTimes(1); - expect(mockSetOtpVerification).toBeCalledWith({ - show_otp_verification: true, - phone_verification_type: VERIFICATION_SERVICES.SMS, - }); - }); - - it('should render mockRequestOnWhatsApp and setOtpVerification with phone_verification_type: whatsapp when Send code via WhatsApp is clicked, phone_verification_type is whatsapp', () => { - renderComponent(VERIFICATION_SERVICES.SMS); - const resend_code_button = screen.getByRole('button', { name: /Send code via WhatsApp/ }); - userEvent.click(resend_code_button); - expect(mockRequestOnWhatsApp).toHaveBeenCalledTimes(1); - expect(mockSetOtpVerification).toBeCalledWith({ - show_otp_verification: true, - phone_verification_type: VERIFICATION_SERVICES.WHATSAPP, - }); - }); -}); diff --git a/packages/account/src/Sections/Profile/PhoneVerification/__test__/otp-verification.spec.tsx b/packages/account/src/Sections/Profile/PhoneVerification/__test__/otp-verification.spec.tsx deleted file mode 100644 index 3ecceb5626c8..000000000000 --- a/packages/account/src/Sections/Profile/PhoneVerification/__test__/otp-verification.spec.tsx +++ /dev/null @@ -1,184 +0,0 @@ -import { render, screen } from '@testing-library/react'; -import React from 'react'; -import { StoreProvider, mockStore } from '@deriv/stores'; -import OTPVerification from '../otp-verification'; -import { useSendOTPVerificationCode, useSettings } from '@deriv/hooks'; -import userEvent from '@testing-library/user-event'; - -jest.mock('@deriv/hooks', () => ({ - ...jest.requireActual('@deriv/hooks'), - useSettings: jest.fn(), - useSendOTPVerificationCode: jest.fn(), -})); - -jest.mock('../phone-number-verified-modal', () => jest.fn(() =>
Phone Number Verified Modal
)); - -describe('OTPVerification', () => { - const store = mockStore({ - client: { - email: 'johndoe@regentmarkets.com', - }, - ui: { - should_show_phone_number_otp: false, - }, - }); - let phone_verification_type = 'sms'; - const mockSetOtpVerification = jest.fn(); - const mockSendPhoneOTPVerification = jest.fn(); - const mockSetPhoneOtpErrorMessage = jest.fn(); - const renderComponent = () => { - render( - - - - ); - }; - - beforeEach(() => { - (useSettings as jest.Mock).mockReturnValue({ - data: { - email: 'johndoe@regentmarkets.com', - }, - invalidate: jest.fn(() => Promise.resolve()), - }); - (useSendOTPVerificationCode as jest.Mock).mockReturnValue({ - sendPhoneOTPVerification: jest.fn(), - }); - }); - - it('should render ConfirmYourEmail in OTP Verification', () => { - renderComponent(); - expect(screen.getByText(/Confirm it's you/)).toBeInTheDocument(); - expect(screen.getByText(/We've sent a verification code to/)).toBeInTheDocument(); - expect(screen.getByText('johndoe@regentmarkets.com')).toBeInTheDocument(); - expect( - screen.getByText(/Enter the code or click the link in the email to verify that the account belongs to you./) - ).toBeInTheDocument(); - expect(screen.getByRole('textbox', { name: /OTP code/ })).toBeInTheDocument(); - expect(screen.getByRole('button', { name: /Resend code/ })).toBeInTheDocument(); - }); - - it('should render Verify your number in OTP Verification', () => { - store.ui.should_show_phone_number_otp = true; - renderComponent(); - expect(screen.getByText(/Verify your number/)).toBeInTheDocument(); - expect(screen.getByText(/Enter the 6-digit code sent to you via SMS at :/)).toBeInTheDocument(); - }); - - it('should render whatsapp when phone_verification_type is whatsapp', () => { - store.ui.should_show_phone_number_otp = true; - phone_verification_type = 'whatsapp'; - renderComponent(); - expect(screen.getByText(/WhatsApp/)).toBeInTheDocument(); - }); - - it('should not enabled Verify button when otp does not have 6 characters', () => { - store.ui.should_show_phone_number_otp = true; - (useSendOTPVerificationCode as jest.Mock).mockReturnValue({ - sendPhoneOTPVerification: jest.fn(), - setPhoneOtpErrorMessage: jest.fn(), - }); - renderComponent(); - const otp_textfield = screen.getByRole('textbox'); - const verify_button = screen.getByRole('button', { name: 'Verify' }); - userEvent.type(otp_textfield, '12345'); - expect(verify_button).toBeDisabled(); - }); - - it('should contain value of 123456 for otp textfield component', () => { - store.ui.should_show_phone_number_otp = true; - (useSendOTPVerificationCode as jest.Mock).mockReturnValue({ - sendPhoneOTPVerification: jest.fn(), - setPhoneOtpErrorMessage: jest.fn(), - }); - renderComponent(); - const otp_textfield = screen.getByRole('textbox'); - userEvent.type(otp_textfield, '123456'); - expect(otp_textfield).toHaveValue('123456'); - }); - - it('should render mockSendPhoneOTPVerification when Verify button is clicked', () => { - store.ui.should_show_phone_number_otp = true; - (useSendOTPVerificationCode as jest.Mock).mockReturnValue({ - sendPhoneOTPVerification: mockSendPhoneOTPVerification, - setPhoneOtpErrorMessage: jest.fn(), - }); - renderComponent(); - const otp_textfield = screen.getByRole('textbox'); - const verify_button = screen.getByRole('button', { name: 'Verify' }); - userEvent.type(otp_textfield, '123456'); - expect(verify_button).toBeEnabled(); - userEvent.click(verify_button); - expect(mockSendPhoneOTPVerification).toBeCalledTimes(1); - }); - - it('should show error message when API returns error', () => { - store.ui.should_show_phone_number_otp = true; - (useSendOTPVerificationCode as jest.Mock).mockReturnValue({ - sendPhoneOTPVerification: mockSendPhoneOTPVerification, - phone_otp_error_message: 'Error Message', - }); - renderComponent(); - expect(screen.getByText(/Error Message/)).toBeInTheDocument(); - }); - - it('should render mockSetPhoneOtpErrorMessage to be empty when users retype inside textfield', () => { - store.ui.should_show_phone_number_otp = true; - (useSendOTPVerificationCode as jest.Mock).mockReturnValue({ - sendPhoneOTPVerification: mockSendPhoneOTPVerification, - phone_otp_error_message: 'Error Message', - setPhoneOtpErrorMessage: mockSetPhoneOtpErrorMessage, - }); - renderComponent(); - expect(screen.getByText(/Error Message/)).toBeInTheDocument(); - const otp_textfield = screen.getByRole('textbox'); - userEvent.type(otp_textfield, '123456'); - expect(mockSetPhoneOtpErrorMessage).toBeCalled(); - }); - - it('should display Phone Number Verified Modal when API returns phone_number_verified is true', () => { - store.ui.should_show_phone_number_otp = true; - (useSendOTPVerificationCode as jest.Mock).mockReturnValue({ - sendPhoneOTPVerification: mockSendPhoneOTPVerification, - is_phone_number_verified: true, - }); - renderComponent(); - expect(screen.getByText(/Phone Number Verified Modal/)).toBeInTheDocument(); - }); - - it('should render sendEmailOTPVerification when should_show_phone_number_otp is false', () => { - const mockSendEmailOTPVerification = jest.fn(); - store.ui.should_show_phone_number_otp = false; - (useSendOTPVerificationCode as jest.Mock).mockReturnValue({ - sendEmailOTPVerification: mockSendEmailOTPVerification, - setPhoneOtpErrorMessage: jest.fn(), - }); - renderComponent(); - const otp_textfield = screen.getByRole('textbox'); - const verify_button = screen.getByRole('button', { name: 'Verify' }); - userEvent.type(otp_textfield, '123456'); - expect(verify_button).toBeEnabled(); - userEvent.click(verify_button); - expect(mockSendEmailOTPVerification).toBeCalledTimes(1); - }); - - it('should render setOtpVerification and setVerificationCode when is_email_verified is true', () => { - store.ui.should_show_phone_number_otp = false; - (useSendOTPVerificationCode as jest.Mock).mockReturnValue({ - is_email_verified: true, - sendEmailOTPVerification: jest.fn(), - setPhoneOtpErrorMessage: jest.fn(), - }); - renderComponent(); - const otp_textfield = screen.getByRole('textbox'); - const verify_button = screen.getByRole('button', { name: 'Verify' }); - userEvent.type(otp_textfield, '123456'); - expect(verify_button).toBeEnabled(); - userEvent.click(verify_button); - expect(store.client.setVerificationCode).toBeCalled(); - expect(mockSetOtpVerification).toBeCalledWith({ phone_verification_type: '', show_otp_verification: false }); - }); -}); diff --git a/packages/account/src/Sections/Profile/PhoneVerification/__test__/phone-number-verified-modal.spec.tsx b/packages/account/src/Sections/Profile/PhoneVerification/__test__/phone-number-verified-modal.spec.tsx deleted file mode 100644 index bf3524e2c5d9..000000000000 --- a/packages/account/src/Sections/Profile/PhoneVerification/__test__/phone-number-verified-modal.spec.tsx +++ /dev/null @@ -1,56 +0,0 @@ -import React from 'react'; -import { MemoryRouter } from 'react-router'; -import { render, screen } from '@testing-library/react'; -import PhoneNumberVerifiedModal from '../phone-number-verified-modal'; -import userEvent from '@testing-library/user-event'; -import { routes } from '@deriv/shared'; - -const mockHistoryPush = jest.fn(); - -jest.mock('react-router', () => ({ - ...jest.requireActual('react-router'), - useHistory: () => ({ - push: mockHistoryPush, - }), -})); - -describe('PhoneNumberVerifiedModal', () => { - let modal_root_el: HTMLElement; - - beforeAll(() => { - modal_root_el = document.createElement('div'); - modal_root_el.setAttribute('id', 'modal_root'); - document.body.appendChild(modal_root_el); - }); - - afterAll(() => { - document.body.removeChild(modal_root_el); - }); - - const mockSetShouldShowPhoneNumberVerifiedModal = jest.fn(); - - const renderModal = () => { - render( - - - - ); - }; - - it('it should render PhoneNumberVerifiedModal', () => { - renderModal(); - expect(screen.getByText(/Verification successful/)).toBeInTheDocument(); - expect(screen.getByText(/That's it! Your number is verified./)).toBeInTheDocument(); - }); - - it('it should close PhoneNumberVerifiedModal and navigate to PersonalDetails section when done is clicked', () => { - renderModal(); - const doneButton = screen.getByRole('button', { name: /Done/ }); - userEvent.click(doneButton); - expect(mockSetShouldShowPhoneNumberVerifiedModal).toHaveBeenCalledTimes(1); - expect(mockHistoryPush).toHaveBeenCalledWith(routes.personal_details); - }); -}); diff --git a/packages/account/src/Sections/Profile/PhoneVerification/__test__/phone-verification-card.spec.tsx b/packages/account/src/Sections/Profile/PhoneVerification/__test__/phone-verification-card.spec.tsx deleted file mode 100644 index f4bf19b3615d..000000000000 --- a/packages/account/src/Sections/Profile/PhoneVerification/__test__/phone-verification-card.spec.tsx +++ /dev/null @@ -1,19 +0,0 @@ -import { render, screen } from '@testing-library/react'; -import React from 'react'; -import PhoneVerificationCard from '../phone-verification-card'; - -describe('ConfirmPhoneNumber', () => { - it('should render ConfirmPhoneNumber', () => { - render(Card Content); - expect(screen.getByText(/Card Content/)).toBeInTheDocument(); - expect(screen.getByText(/Card Content/)).not.toHaveClass( - 'phone-verification__card phone-verification__card--small-card' - ); - }); - - it('should include --small-card className if props is being passed in', () => { - render(Card Content); - const card_content = screen.getByText(/Card Content/); - expect(card_content).toHaveClass('phone-verification__card phone-verification__card--small-card'); - }); -}); diff --git a/packages/account/src/Sections/Profile/PhoneVerification/__test__/phone-verification-page.spec.tsx b/packages/account/src/Sections/Profile/PhoneVerification/__test__/phone-verification-page.spec.tsx deleted file mode 100644 index 428a137fe4b9..000000000000 --- a/packages/account/src/Sections/Profile/PhoneVerification/__test__/phone-verification-page.spec.tsx +++ /dev/null @@ -1,94 +0,0 @@ -import React from 'react'; -import { render, screen } from '@testing-library/react'; -import userEvent from '@testing-library/user-event'; -import PhoneVerificationPage from '../phone-verification-page'; -import { StoreProvider, mockStore } from '@deriv/stores'; -import { useSendOTPVerificationCode } from '@deriv/hooks'; - -jest.mock('../otp-verification.tsx', () => jest.fn(() =>
Confirm Your Email
)); -jest.mock('../confirm-phone-number.tsx', () => jest.fn(() =>
Confirm Phone Number
)); -jest.mock('../cancel-phone-verification-modal', () => jest.fn(() =>
Cancel Phone Verification Modal
)); -jest.mock('../verification-link-expired-modal', () => jest.fn(() =>
Verification Link Expired Modal
)); -jest.mock('@deriv/hooks', () => ({ - ...jest.requireActual('@deriv/hooks'), - useSendOTPVerificationCode: jest.fn(() => ({ - email_otp_error: undefined, - is_email_verified: false, - sendEmailOTPVerification: jest.fn(), - })), -})); -jest.mock('@deriv/components', () => ({ - ...jest.requireActual('@deriv/components'), - Loading: jest.fn(() => 'mockedLoading'), -})); - -describe('ConfirmPhoneNumber', () => { - let mock_store_data = mockStore({}); - const renderComponent = () => { - render( - - - - ); - }; - beforeEach(() => { - mock_store_data = mockStore({ - client: { - verification_code: { - phone_number_verification: '', - }, - }, - ui: { - is_redirected_from_email: false, - }, - }); - }); - - afterEach(() => { - jest.clearAllMocks(); - }); - - it('should render ConfirmPhoneNumber', () => { - renderComponent(); - expect(screen.getByText(/Phone number verification/)).toBeInTheDocument(); - expect(screen.getByText(/Confirm Your Email/)).toBeInTheDocument(); - }); - - it('should display cancel phone verification modal when back button is clicked', () => { - renderComponent(); - const backButton = screen.getByTestId('dt_phone_verification_back_btn'); - userEvent.click(backButton); - expect(screen.getByText(/Cancel Phone Verification Modal/)).toBeInTheDocument(); - }); - - it('should display mockedLoading and render sendEmailOTPVerification when phone_number_verification has value', () => { - const mockSendEmailOTPVerification = jest.fn(); - (useSendOTPVerificationCode as jest.Mock).mockReturnValue({ - sendEmailOTPVerification: mockSendEmailOTPVerification, - }); - mock_store_data.client.verification_code.phone_number_verification = '123456'; - mock_store_data.client.is_authorize = true; - mock_store_data.ui.is_redirected_from_email = true; - renderComponent(); - expect(screen.getByText(/mockedLoading/)).toBeInTheDocument(); - expect(mockSendEmailOTPVerification).toBeCalledTimes(1); - }); - - it('should display Verification Link Expired Modal when hook returns error', async () => { - (useSendOTPVerificationCode as jest.Mock).mockReturnValue({ - email_otp_error: { code: 'InvalidToken', message: '' }, - sendEmailOTPVerification: jest.fn(), - }); - renderComponent(); - expect(screen.getByText(/Verification Link Expired Modal/)).toBeInTheDocument(); - }); - - it('should display Confirm Phone Number when is_email_verified is true', async () => { - (useSendOTPVerificationCode as jest.Mock).mockReturnValue({ - is_email_verified: true, - }); - mock_store_data.ui.is_redirected_from_email = true; - renderComponent(); - expect(screen.getByText(/Confirm Phone Number/)).toBeInTheDocument(); - }); -}); diff --git a/packages/account/src/Sections/Profile/PhoneVerification/__test__/resend-code-timer.spec.tsx b/packages/account/src/Sections/Profile/PhoneVerification/__test__/resend-code-timer.spec.tsx deleted file mode 100644 index 3c6563e074d2..000000000000 --- a/packages/account/src/Sections/Profile/PhoneVerification/__test__/resend-code-timer.spec.tsx +++ /dev/null @@ -1,109 +0,0 @@ -import React from 'react'; -import { render, screen } from '@testing-library/react'; -import userEvent from '@testing-library/user-event'; -import ResendCodeTimer from '../resend-code-timer'; -import { StoreProvider, mockStore } from '@deriv/stores'; -import { usePhoneNumberVerificationSetTimer, useVerifyEmail } from '@deriv/hooks'; - -jest.mock('@deriv/hooks', () => ({ - ...jest.requireActual('@deriv/hooks'), - useVerifyEmail: jest.fn(() => ({ - sendPhoneNumberVerifyEmail: jest.fn(), - WS: { - isSuccess: false, - }, - })), - useSettings: jest.fn(() => ({ - data: { - phone_number_verification: { - next_email_attempt: null, - next_attempt: null, - }, - }, - })), - usePhoneNumberVerificationSetTimer: jest.fn(() => ({ - next_otp_request: '', - })), -})); - -describe('ConfirmPhoneNumber', () => { - beforeEach(() => { - (useVerifyEmail as jest.Mock).mockReturnValue({ - sendPhoneNumberVerifyEmail: jest.fn(), - WS: { isSuccess: false }, - }); - }); - - afterEach(() => { - jest.clearAllMocks(); - (usePhoneNumberVerificationSetTimer as jest.Mock).mockReturnValue({ next_otp_request: '' }); - }); - - const mockSetShouldShowDidntGetTheCodeModal = jest.fn(); - const mockSetIsButtonDisabled = jest.fn(); - const mockReInitializeGetSettings = jest.fn(); - const mockClearOtpValue = jest.fn(); - - const renderComponent = (is_button_disabled = false, should_show_resend_code_button = true) => { - render( - - - - ); - }; - - const mock_store = mockStore({}); - it('should enable button if usePhoneNumberVerificationSetTimer did not return next_otp_request', async () => { - renderComponent(); - - expect(screen.queryByRole('button', { name: 'Resend code' })).toBeEnabled; - }); - - it('should disable button if usePhoneNumberVerificationSetTimer returns next_otp_request', async () => { - (usePhoneNumberVerificationSetTimer as jest.Mock).mockReturnValue({ next_otp_request: 'in 59s' }); - renderComponent(); - - expect(screen.queryByRole('button', { name: 'Resend code in 59s' })).toBeDisabled; - }); - - it('should trigger mockSend when send button is clicked', () => { - const mockSend = jest.fn(); - (useVerifyEmail as jest.Mock).mockReturnValue({ - sendPhoneNumberVerifyEmail: mockSend, - WS: { isSuccess: false }, - }); - renderComponent(); - const resend_button = screen.getByRole('button', { name: 'Resend code' }); - expect(resend_button).toBeEnabled(); - - userEvent.click(resend_button); - expect(mockSend).toBeCalled(); - }); - - it('should display Didn’t get the code? should_show_resend_code_button is false', () => { - renderComponent(false, false); - const resend_button = screen.getByRole('button', { name: "Didn't get the code?" }); - expect(resend_button).toBeInTheDocument(); - }); - - it('should display Didn’t get the code? (60s) when usePhoneNumberSetTimer returns (60s)', () => { - (usePhoneNumberVerificationSetTimer as jest.Mock).mockReturnValue({ next_otp_request: ' (60s)' }); - renderComponent(false, false); - const resend_button = screen.getByRole('button', { name: "Didn't get the code? (60s)" }); - expect(resend_button).toBeInTheDocument(); - }); - - it('should trigger setShouldShowDidntGetTheCodeModal when Didn`t get the code is clicked', () => { - renderComponent(false, false); - const resend_button_after = screen.getByRole('button', { name: "Didn't get the code?" }); - userEvent.click(resend_button_after); - expect(mockSetShouldShowDidntGetTheCodeModal).toHaveBeenCalled(); - }); -}); diff --git a/packages/account/src/Sections/Profile/PhoneVerification/__test__/validation.spec.tsx b/packages/account/src/Sections/Profile/PhoneVerification/__test__/validation.spec.tsx deleted file mode 100644 index bf281f34f855..000000000000 --- a/packages/account/src/Sections/Profile/PhoneVerification/__test__/validation.spec.tsx +++ /dev/null @@ -1,58 +0,0 @@ -import { act } from '@testing-library/react'; -import { validatePhoneNumber } from '../validation'; - -describe('validatePhoneNumber', () => { - let setErrorMessage: jest.Mock; - - beforeEach(() => { - setErrorMessage = jest.fn(); - }); - - it('should set an empty error message for a valid phone number', async () => { - const validPhoneNumber = '+1234567890'; - await act(async () => { - validatePhoneNumber(validPhoneNumber, setErrorMessage); - }); - expect(setErrorMessage).toHaveBeenCalledWith(''); - }); - - it('should set an error message for an invalid phone number', async () => { - const invalidPhoneNumber = 'invalid'; - await act(async () => { - validatePhoneNumber(invalidPhoneNumber, setErrorMessage); - }); - expect(setErrorMessage).toHaveBeenCalledWith(['Please enter a valid phone number.']); - }); - - it('should set an error message for an empty phone number', async () => { - const invalidPhoneNumber = ''; - await act(async () => { - validatePhoneNumber(invalidPhoneNumber, setErrorMessage); - }); - expect(setErrorMessage).toHaveBeenCalledWith(['Please enter a valid phone number.']); - }); - - it('should set an error message for an phone number more than 36 characters', async () => { - const invalidPhoneNumber = '+123123123123123123123123232333333333'; - await act(async () => { - validatePhoneNumber(invalidPhoneNumber, setErrorMessage); - }); - expect(setErrorMessage).toHaveBeenCalledWith(['Please enter a valid phone number.']); - }); - - it('should set an error message for an phone number less than 8 characters', async () => { - const invalidPhoneNumber = '+1234567'; - await act(async () => { - validatePhoneNumber(invalidPhoneNumber, setErrorMessage); - }); - expect(setErrorMessage).toHaveBeenCalledWith(['Please enter a valid phone number.']); - }); - - it('should set an error message for phone number without including + sign', async () => { - const invalidPhoneNumber = '0123456789'; - await act(async () => { - validatePhoneNumber(invalidPhoneNumber, setErrorMessage); - }); - expect(setErrorMessage).toHaveBeenCalledWith(['Please enter a valid phone number.']); - }); -}); diff --git a/packages/account/src/Sections/Profile/PhoneVerification/__test__/verification-link-expired-modal.spec.tsx b/packages/account/src/Sections/Profile/PhoneVerification/__test__/verification-link-expired-modal.spec.tsx deleted file mode 100644 index 5fa5fa00310a..000000000000 --- a/packages/account/src/Sections/Profile/PhoneVerification/__test__/verification-link-expired-modal.spec.tsx +++ /dev/null @@ -1,80 +0,0 @@ -import React from 'react'; -import { render, screen } from '@testing-library/react'; -import userEvent from '@testing-library/user-event'; -import VerificationLinkExpiredModal from '../verification-link-expired-modal'; -import { StoreProvider, mockStore } from '@deriv/stores'; -import { routes } from '@deriv/shared'; -import { usePhoneNumberVerificationSetTimer } from '@deriv/hooks'; - -const mock_push_function = jest.fn(); -jest.mock('react-router', () => ({ - ...jest.requireActual('react-router'), - useHistory: () => ({ - push: mock_push_function, - }), -})); - -jest.mock('@deriv/hooks', () => ({ - ...jest.requireActual('@deriv/hooks'), - usePhoneNumberVerificationSetTimer: jest.fn(() => ({ - next_otp_request: '', - })), -})); - -describe('VerificationLinkExpiredModal', () => { - let modal_root_el: HTMLElement; - const mockSetShowVerificationLinkExpiredModal = jest.fn(); - - beforeEach(() => { - mockSetShowVerificationLinkExpiredModal.mockClear(); - mock_push_function.mockClear(); - }); - - beforeAll(() => { - modal_root_el = document.createElement('div'); - modal_root_el.setAttribute('id', 'modal_root'); - document.body.appendChild(modal_root_el); - }); - - afterAll(() => { - document.body.removeChild(modal_root_el); - }); - - const mock_store = mockStore({}); - - const buttons = [/Send new link/, /Cancel/]; - - const renderComponent = () => { - render( - - - - ); - }; - - it('should render VerificationLinkExpiredModal', () => { - renderComponent(); - buttons.forEach(value => { - expect(screen.getByRole('button', { name: value })).toBeInTheDocument(); - }); - expect(screen.getByText(/Verification link expired/)).toBeInTheDocument(); - expect(screen.getByText(/Get another link to verify your number./)).toBeInTheDocument(); - }); - - it('should render mockSetShowVerificationLinkExpiredModal and mock_back_router when Cancel is clicked', () => { - renderComponent(); - const cancelButton = screen.getByRole('button', { name: buttons[1] }); - userEvent.click(cancelButton); - expect(mockSetShowVerificationLinkExpiredModal).toBeCalledTimes(1); - expect(mock_push_function).toBeCalledWith(routes.personal_details); - }); - - it('should show in 60s which is coming from usePhoneNumberVerificationSetTimer', () => { - (usePhoneNumberVerificationSetTimer as jest.Mock).mockReturnValue({ next_otp_request: ' in 60s' }); - renderComponent(); - expect(screen.getByText(/in 60s/)).toBeInTheDocument(); - }); -}); diff --git a/packages/account/src/Sections/Profile/PhoneVerification/cancel-phone-verification-modal.tsx b/packages/account/src/Sections/Profile/PhoneVerification/cancel-phone-verification-modal.tsx deleted file mode 100644 index 897b26551fcb..000000000000 --- a/packages/account/src/Sections/Profile/PhoneVerification/cancel-phone-verification-modal.tsx +++ /dev/null @@ -1,62 +0,0 @@ -import React from 'react'; -import { Modal, Text } from '@deriv-com/quill-ui'; -import { Localize } from '@deriv/translations'; -import { useHistory } from 'react-router'; -import { observer, useStore } from '@deriv/stores'; -import { LabelPairedCircleXmarkLgRegularIcon } from '@deriv/quill-icons'; -import { useDevice } from '@deriv-com/ui'; - -type TCancelPhoneVerificationModal = { - should_show_cancel_verification_modal: boolean; - setShouldShowCancelVerificationModal: (value: boolean) => void; -}; - -const CancelPhoneVerificationModal = observer( - ({ - should_show_cancel_verification_modal, - setShouldShowCancelVerificationModal, - }: TCancelPhoneVerificationModal) => { - const history = useHistory(); - const handleCancelButton = () => { - setVerificationCode('', 'phone_number_verification'); - setShouldShowPhoneNumberOTP(false); - setShouldShowCancelVerificationModal(false); - history.goBack(); - }; - const { ui, client } = useStore(); - const { setShouldShowPhoneNumberOTP } = ui; - const { isMobile } = useDevice(); - const { setVerificationCode } = client; - - return ( - setShouldShowCancelVerificationModal(false)} - primaryButtonLabel={} - disableCloseOnOverlay - showSecondaryButton - secondaryButtonLabel={} - secondaryButtonCallback={handleCancelButton} - > - } - /> - -
- - - - - - -
-
-
- ); - } -); - -export default CancelPhoneVerificationModal; diff --git a/packages/account/src/Sections/Profile/PhoneVerification/confirm-phone-number.tsx b/packages/account/src/Sections/Profile/PhoneVerification/confirm-phone-number.tsx deleted file mode 100644 index 7379658c694c..000000000000 --- a/packages/account/src/Sections/Profile/PhoneVerification/confirm-phone-number.tsx +++ /dev/null @@ -1,118 +0,0 @@ -import { useState, useEffect, ChangeEvent } from 'react'; -import PhoneVerificationCard from './phone-verification-card'; -import { Button, Snackbar, Text, TextFieldAddon } from '@deriv-com/quill-ui'; -import { Localize, localize } from '@deriv/translations'; -import { observer, useStore } from '@deriv/stores'; -import { usePhoneNumberVerificationSetTimer, useRequestPhoneNumberOTP, useSettings } from '@deriv/hooks'; -import { VERIFICATION_SERVICES } from '@deriv/shared'; -import { validatePhoneNumber } from './validation'; - -type TConfirmPhoneNumber = { - setOtpVerification: (value: { show_otp_verification: boolean; phone_verification_type: string }) => void; -}; - -const ConfirmPhoneNumber = observer(({ setOtpVerification }: TConfirmPhoneNumber) => { - const [phone_number, setPhoneNumber] = useState(''); - const [phone_verification_type, setPhoneVerificationType] = useState(''); - const [is_button_loading, setIsButtonLoading] = useState(false); - const { - requestOnSMS, - requestOnWhatsApp, - error_message, - setErrorMessage, - setUsersPhoneNumber, - is_email_verified, - email_otp_error, - } = useRequestPhoneNumberOTP(); - const { data: account_settings, invalidate } = useSettings(); - const { ui } = useStore(); - const { setShouldShowPhoneNumberOTP } = ui; - const { next_otp_request } = usePhoneNumberVerificationSetTimer(true); - - useEffect(() => { - setPhoneNumber(account_settings?.phone?.replace('+', '') || ''); - }, [account_settings?.phone]); - - useEffect(() => { - if (email_otp_error) { - invalidate('get_settings').then(() => setIsButtonLoading(false)); - } - if (is_email_verified) { - setIsButtonLoading(false); - setOtpVerification({ show_otp_verification: true, phone_verification_type }); - setShouldShowPhoneNumberOTP(true); - } - }, [is_email_verified, email_otp_error, invalidate]); - - const handleOnChangePhoneNumber = (e: ChangeEvent) => { - setPhoneNumber(e.target.value); - validatePhoneNumber(`+${e.target.value}`, setErrorMessage); - }; - - const handleSubmit = async (phone_verification_type: string) => { - setIsButtonLoading(true); - setPhoneVerificationType(phone_verification_type); - const { error } = await setUsersPhoneNumber({ phone: `+${phone_number}` }); - - if (!error) { - phone_verification_type === VERIFICATION_SERVICES.SMS ? requestOnSMS() : requestOnWhatsApp(); - } else { - setIsButtonLoading(false); - } - }; - - return ( - - - - -
- -
-
- - -
- - } - isVisible={!!next_otp_request} - /> -
- ); -}); - -export default ConfirmPhoneNumber; diff --git a/packages/account/src/Sections/Profile/PhoneVerification/didnt-get-the-code-modal.tsx b/packages/account/src/Sections/Profile/PhoneVerification/didnt-get-the-code-modal.tsx deleted file mode 100644 index 24b7b62b7b8c..000000000000 --- a/packages/account/src/Sections/Profile/PhoneVerification/didnt-get-the-code-modal.tsx +++ /dev/null @@ -1,135 +0,0 @@ -import { Button, Modal, Text } from '@deriv-com/quill-ui'; -import { Localize, localize } from '@deriv/translations'; -import { VERIFICATION_SERVICES } from '@deriv/shared'; -import { convertPhoneTypeDisplay } from '../../../Helpers/utils'; -import { TSocketError } from '@deriv/api/types'; -import { useDevice } from '@deriv-com/ui'; -import { useEffect } from 'react'; - -type TDidntGetTheCodeModal = { - phone_verification_type: string; - should_show_didnt_get_the_code_modal: boolean; - setIsButtonDisabled: (value: boolean) => void; - setShouldShowDidntGetTheCodeModal: (value: boolean) => void; - requestOnSMS: () => void; - requestOnWhatsApp: () => void; - clearOtpValue: () => void; - is_email_verified: boolean; - email_otp_error: TSocketError<'phone_number_challenge'> | null; - setOtpVerification: (value: { show_otp_verification: boolean; phone_verification_type: string }) => void; - reInitializeGetSettings: () => void; -}; - -const DidntGetTheCodeModal = ({ - should_show_didnt_get_the_code_modal, - setShouldShowDidntGetTheCodeModal, - setIsButtonDisabled, - reInitializeGetSettings, - requestOnSMS, - requestOnWhatsApp, - clearOtpValue, - phone_verification_type, - is_email_verified, - email_otp_error, - setOtpVerification, -}: TDidntGetTheCodeModal) => { - const { isMobile } = useDevice(); - - useEffect(() => { - if (is_email_verified || email_otp_error) reInitializeGetSettings(); - }, [is_email_verified, email_otp_error, reInitializeGetSettings]); - - const setDidntGetACodeButtonDisabled = () => { - setIsButtonDisabled(true); - }; - - const handleResendCode = () => { - clearOtpValue(); - setDidntGetACodeButtonDisabled(); - phone_verification_type === VERIFICATION_SERVICES.SMS ? requestOnSMS() : requestOnWhatsApp(); - setOtpVerification({ show_otp_verification: true, phone_verification_type }); - setShouldShowDidntGetTheCodeModal(false); - }; - - const handleChangeOTPVerification = () => { - clearOtpValue(); - setDidntGetACodeButtonDisabled(); - const changed_phone_verification_type = - phone_verification_type === VERIFICATION_SERVICES.SMS - ? VERIFICATION_SERVICES.WHATSAPP - : VERIFICATION_SERVICES.SMS; - - phone_verification_type === VERIFICATION_SERVICES.SMS ? requestOnWhatsApp() : requestOnSMS(); - - setOtpVerification({ - show_otp_verification: true, - phone_verification_type: changed_phone_verification_type, - }); - setShouldShowDidntGetTheCodeModal(false); - }; - - const handleChangePhoneNumber = () => { - clearOtpValue(); - setShouldShowDidntGetTheCodeModal(false); - setOtpVerification({ show_otp_verification: false, phone_verification_type }); - }; - - return ( - setShouldShowDidntGetTheCodeModal(false)} - hasFooter={false} - > - -
- - - -
- - - - - - -
-
-
-
- ); -}; - -export default DidntGetTheCodeModal; diff --git a/packages/account/src/Sections/Profile/PhoneVerification/index.ts b/packages/account/src/Sections/Profile/PhoneVerification/index.ts deleted file mode 100644 index 8a1c82b65a3d..000000000000 --- a/packages/account/src/Sections/Profile/PhoneVerification/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -import PhoneVerificationPage from './phone-verification-page'; - -export default PhoneVerificationPage; diff --git a/packages/account/src/Sections/Profile/PhoneVerification/otp-verification.tsx b/packages/account/src/Sections/Profile/PhoneVerification/otp-verification.tsx deleted file mode 100644 index 5ee617a62e9c..000000000000 --- a/packages/account/src/Sections/Profile/PhoneVerification/otp-verification.tsx +++ /dev/null @@ -1,158 +0,0 @@ -import { useEffect, useState, useCallback, Fragment } from 'react'; -import PhoneVerificationCard from './phone-verification-card'; -import { Text, InputGroupButton } from '@deriv-com/quill-ui'; -import { Localize, localize } from '@deriv/translations'; -import { observer, useStore } from '@deriv/stores'; -import { useSendOTPVerificationCode, useSettings } from '@deriv/hooks'; -import { convertPhoneTypeDisplay } from '../../../Helpers/utils'; -import ResendCodeTimer from './resend-code-timer'; -import DidntGetTheCodeModal from './didnt-get-the-code-modal'; -import PhoneNumberVerifiedModal from './phone-number-verified-modal'; - -type TOTPVerification = { - phone_verification_type: string; - setOtpVerification: (value: { show_otp_verification: boolean; phone_verification_type: string }) => void; -}; - -const OTPVerification = observer(({ phone_verification_type, setOtpVerification }: TOTPVerification) => { - const { client, ui } = useStore(); - const { setVerificationCode } = client; - const { data: account_settings, invalidate } = useSettings(); - const [should_show_phone_number_verified_modal, setShouldShowPhoneNumberVerifiedModal] = useState(false); - const [should_show_didnt_get_the_code_modal, setShouldShowDidntGetTheCodeModal] = useState(false); - const [otp, setOtp] = useState(''); - const [is_button_disabled, setIsButtonDisabled] = useState(false); - - const { - sendPhoneOTPVerification, - phone_otp_error_message, - setPhoneOtpErrorMessage, - is_phone_number_verified, - is_email_verified, - sendEmailOTPVerification, - requestOnSMS, - requestOnWhatsApp, - email_otp_error, - } = useSendOTPVerificationCode(); - const { should_show_phone_number_otp } = ui; - - const reInitializeGetSettings = useCallback(() => { - invalidate('get_settings').then(() => { - setIsButtonDisabled(false); - }); - }, [invalidate]); - - useEffect(() => { - setIsButtonDisabled(true); - reInitializeGetSettings(); - }, [reInitializeGetSettings]); - - useEffect(() => { - if (is_phone_number_verified) { - reInitializeGetSettings(); - setShouldShowPhoneNumberVerifiedModal(true); - } else if (is_email_verified && !should_show_phone_number_otp) { - setVerificationCode(otp, 'phone_number_verification'); - setOtpVerification({ show_otp_verification: false, phone_verification_type: '' }); - } - }, [is_phone_number_verified, is_email_verified, setOtpVerification, should_show_phone_number_otp]); - - const clearOtpValue = () => { - setOtp(''); - setPhoneOtpErrorMessage(''); - }; - - const handleGetOtpValue = (e: React.ChangeEvent) => { - setOtp(e.target.value); - setPhoneOtpErrorMessage(''); - }; - - const handleVerifyOTP = () => { - if (should_show_phone_number_otp) { - sendPhoneOTPVerification(otp); - } else { - sendEmailOTPVerification(otp); - } - }; - - return ( - - - {should_show_phone_number_otp && ( - - )} - - {should_show_phone_number_otp ? ( - - ) : ( - - )} - -
- {should_show_phone_number_otp ? ( - - - - ) : ( - - - ]} - /> - - - - - - )} -
-
- - -
-
- ); -}); - -export default OTPVerification; diff --git a/packages/account/src/Sections/Profile/PhoneVerification/phone-number-verified-modal.tsx b/packages/account/src/Sections/Profile/PhoneVerification/phone-number-verified-modal.tsx deleted file mode 100644 index 05f06ca0bfb8..000000000000 --- a/packages/account/src/Sections/Profile/PhoneVerification/phone-number-verified-modal.tsx +++ /dev/null @@ -1,51 +0,0 @@ -import { useHistory } from 'react-router'; -import { Modal, Text } from '@deriv-com/quill-ui'; -import { Localize } from '@deriv/translations'; -import { routes } from '@deriv/shared'; -import { LabelPairedBadgeCheckLgRegularIcon } from '@deriv/quill-icons'; -import { useDevice } from '@deriv-com/ui'; - -type TPhoneNumberVerifiedModal = { - should_show_phone_number_verified_modal: boolean; - setShouldShowPhoneNumberVerifiedModal: (value: boolean) => void; -}; - -const PhoneNumberVerifiedModal = ({ - should_show_phone_number_verified_modal, - setShouldShowPhoneNumberVerifiedModal, -}: TPhoneNumberVerifiedModal) => { - const history = useHistory(); - const handleDoneButton = () => { - setShouldShowPhoneNumberVerifiedModal(false); - history.push(routes.personal_details); - }; - const { isMobile } = useDevice(); - - return ( - } - disableCloseOnOverlay - > - } - /> - -
- - - - - - -
-
-
- ); -}; - -export default PhoneNumberVerifiedModal; diff --git a/packages/account/src/Sections/Profile/PhoneVerification/phone-verification-card.tsx b/packages/account/src/Sections/Profile/PhoneVerification/phone-verification-card.tsx deleted file mode 100644 index d8b162ae3acd..000000000000 --- a/packages/account/src/Sections/Profile/PhoneVerification/phone-verification-card.tsx +++ /dev/null @@ -1,14 +0,0 @@ -import clsx from 'clsx'; -import React from 'react'; - -type TPhoneVerificationCard = { - is_small_card?: boolean; -}; - -const PhoneVerificationCard = ({ children, is_small_card }: React.PropsWithChildren) => ( -
- {children} -
-); - -export default PhoneVerificationCard; diff --git a/packages/account/src/Sections/Profile/PhoneVerification/phone-verification-page.tsx b/packages/account/src/Sections/Profile/PhoneVerification/phone-verification-page.tsx deleted file mode 100644 index d9fd9fbcba89..000000000000 --- a/packages/account/src/Sections/Profile/PhoneVerification/phone-verification-page.tsx +++ /dev/null @@ -1,92 +0,0 @@ -import './phone-verification.scss'; -import { LabelPairedArrowLeftCaptionFillIcon } from '@deriv/quill-icons'; -import { Text } from '@deriv-com/quill-ui'; -import { Localize } from '@deriv/translations'; -import ConfirmPhoneNumber from './confirm-phone-number'; -import OTPVerification from './otp-verification'; -import CancelPhoneVerificationModal from './cancel-phone-verification-modal'; -import VerificationLinkExpiredModal from './verification-link-expired-modal'; -import { observer, useStore } from '@deriv/stores'; -import { useSendOTPVerificationCode } from '@deriv/hooks'; -import { Loading } from '@deriv/components'; -import { useEffect, useState } from 'react'; - -const PhoneVerificationPage = observer(() => { - const [otp_verification, setOtpVerification] = useState({ - show_otp_verification: true, - phone_verification_type: '', - }); - const [is_loading, setIsLoading] = useState(false); - const [should_show_cancel_verification_modal, setShouldShowCancelVerificationModal] = useState(false); - const [should_show_verification_link_expired_modal, setShouldShowVerificationLinkExpiredModal] = useState(false); - const handleBackButton = () => { - setShouldShowCancelVerificationModal(true); - }; - const { sendEmailOTPVerification, email_otp_error, is_email_verified } = useSendOTPVerificationCode(); - - const { client, ui } = useStore(); - const { is_redirected_from_email, setRedirectFromEmail } = ui; - const { - verification_code: { phone_number_verification: phone_number_verification_code }, - is_authorize, - } = client; - - useEffect(() => { - if (is_redirected_from_email) { - if (email_otp_error) { - setIsLoading(false); - setShouldShowVerificationLinkExpiredModal(true); - setRedirectFromEmail(false); - } else if (is_email_verified) { - setIsLoading(false); - setOtpVerification({ - show_otp_verification: false, - phone_verification_type: '', - }); - setRedirectFromEmail(false); - } else if (phone_number_verification_code && is_authorize) { - setIsLoading(true); - sendEmailOTPVerification(phone_number_verification_code); - } - } - }, [email_otp_error, is_email_verified, phone_number_verification_code, is_authorize]); - - if (is_loading) { - return ; - } - - return ( -
- - -
- - - - -
- {otp_verification.show_otp_verification ? ( - - ) : ( - - )} -
- ); -}); - -export default PhoneVerificationPage; diff --git a/packages/account/src/Sections/Profile/PhoneVerification/phone-verification.scss b/packages/account/src/Sections/Profile/PhoneVerification/phone-verification.scss deleted file mode 100644 index 5888d307dac4..000000000000 --- a/packages/account/src/Sections/Profile/PhoneVerification/phone-verification.scss +++ /dev/null @@ -1,133 +0,0 @@ -.phone-verification { - &__get-code-modal, - &__verified-modal, - &__cancel-modal { - &--contents { - display: flex; - flex-direction: column; - gap: 3.2rem; - &__buttons { - display: flex; - flex-direction: column; - align-items: center; - width: 100%; - gap: 0.8rem; - margin-top: 2.4rem; - } - } - } - - &__cancel-modal--header { - background-color: var(--core-color-solid-red-100); - } - &__verified-modal--header { - background-color: var(--core-color-solid-green-100); - } - - &__redirect_button { - display: flex; - align-items: center; - - &--text { - padding-inline-start: 1.6rem; - } - - &--icon { - cursor: pointer; - } - - @include mobile { - margin-top: 1.6rem; - padding-inline-start: 1.6rem; - } - } - - &__card { - width: 60rem; - height: 60rem; - border: 1px solid var(--core-color-solid-slate-100, #ebecef); - border-radius: 2 * $BORDER_RADIUS; - display: flex; - flex-direction: column; - align-items: center; - padding: 1.6rem; - margin-top: 2.4rem; - - &--small-card { - height: 40rem; - } - - &--inputfield { - width: 60%; - margin-top: 2.4rem; - margin-bottom: 4.4rem; - @include mobile { - width: 100%; - margin-top: 3.2rem; - } - - &__livechat { - color: var(--core-color-solid-red-900, $color-red-12); - font-weight: bold; - text-decoration: underline; - &:hover { - cursor: pointer; - } - } - } - - &--buttons_container { - width: 100%; - display: flex; - gap: 1.6rem; - margin-top: 0.8rem; - - @include mobile { - flex-direction: column-reverse; - position: fixed; - padding: 0 1.6rem; - bottom: 1.6rem; - } - } - - &--email-verification { - &-content { - width: 100%; - margin-top: 2.4rem; - display: flex; - flex-direction: column; - text-align: center; - } - - &-otp-container { - display: flex; - flex-direction: column; - gap: 1.6rem; - width: 60%; - margin-top: 1.6rem; - align-items: flex-start; - @include mobile { - width: 100%; - gap: 3.2rem; - } - } - } - - @include mobile { - width: 100vw; - border: none; - margin-top: 0.8rem; - - .dc-input { - width: 100%; - } - } - - @include desktop { - .snackbar { - margin-bottom: 3.2rem; - width: fit-content; - } - } - } -} diff --git a/packages/account/src/Sections/Profile/PhoneVerification/resend-code-timer.tsx b/packages/account/src/Sections/Profile/PhoneVerification/resend-code-timer.tsx deleted file mode 100644 index 3f88d57f627d..000000000000 --- a/packages/account/src/Sections/Profile/PhoneVerification/resend-code-timer.tsx +++ /dev/null @@ -1,61 +0,0 @@ -import React from 'react'; -import { Button, CaptionText } from '@deriv-com/quill-ui'; -import { Localize } from '@deriv/translations'; -import { usePhoneNumberVerificationSetTimer, useVerifyEmail } from '@deriv/hooks'; - -type TResendCodeTimer = { - is_button_disabled: boolean; - should_show_resend_code_button: boolean; - setIsButtonDisabled: (value: boolean) => void; - setShouldShowDidntGetTheCodeModal: (value: boolean) => void; - clearOtpValue: () => void; - reInitializeGetSettings: () => void; -}; -const ResendCodeTimer = ({ - is_button_disabled, - should_show_resend_code_button, - clearOtpValue, - setIsButtonDisabled, - setShouldShowDidntGetTheCodeModal, - reInitializeGetSettings, -}: TResendCodeTimer) => { - // @ts-expect-error this for now - const { sendPhoneNumberVerifyEmail, WS, error } = useVerifyEmail('phone_number_verification'); - const { next_otp_request } = usePhoneNumberVerificationSetTimer(); - - React.useEffect(() => { - if (WS.isSuccess || error) reInitializeGetSettings(); - }, [WS.isSuccess, reInitializeGetSettings, error]); - - const resendCode = () => { - if (should_show_resend_code_button) { - clearOtpValue(); - setIsButtonDisabled(true); - sendPhoneNumberVerifyEmail(); - } else { - setShouldShowDidntGetTheCodeModal(true); - } - }; - - return ( - - ); -}; - -export default ResendCodeTimer; diff --git a/packages/account/src/Sections/Profile/PhoneVerification/validation.ts b/packages/account/src/Sections/Profile/PhoneVerification/validation.ts deleted file mode 100644 index 1b8c305b1bb7..000000000000 --- a/packages/account/src/Sections/Profile/PhoneVerification/validation.ts +++ /dev/null @@ -1,17 +0,0 @@ -import * as Yup from 'yup'; -import { ValidationConstants } from '@deriv-com/utils'; -import { localize } from '@deriv/translations'; - -const phoneNumberSchema = Yup.string().matches( - ValidationConstants.patterns.phoneNumber, - localize('Please enter a valid phone number.') -); - -export const validatePhoneNumber = (phone_number: string, setErrorMessage: (value: string) => void) => { - phoneNumberSchema - .validate(phone_number) - .then(() => setErrorMessage('')) - .catch(({ errors }: any) => { - setErrorMessage(errors); - }); -}; diff --git a/packages/account/src/Sections/Profile/PhoneVerification/verification-link-expired-modal.tsx b/packages/account/src/Sections/Profile/PhoneVerification/verification-link-expired-modal.tsx deleted file mode 100644 index ff8ec8ab5d82..000000000000 --- a/packages/account/src/Sections/Profile/PhoneVerification/verification-link-expired-modal.tsx +++ /dev/null @@ -1,75 +0,0 @@ -import { Modal, Text } from '@deriv-com/quill-ui'; -import { Localize } from '@deriv/translations'; -import { useHistory } from 'react-router'; -import { LabelPairedCircleXmarkLgRegularIcon } from '@deriv/quill-icons'; -import { usePhoneNumberVerificationSetTimer, useSettings, useVerifyEmail } from '@deriv/hooks'; -import { routes } from '@deriv/shared'; -import { useDevice } from '@deriv-com/ui'; -import { useEffect } from 'react'; - -type TVerificationLinkExpiredModal = { - should_show_verification_link_expired_modal: boolean; - setShouldShowVerificationLinkExpiredModal: (value: boolean) => void; -}; - -const VerificationLinkExpiredModal = ({ - should_show_verification_link_expired_modal, - setShouldShowVerificationLinkExpiredModal, -}: TVerificationLinkExpiredModal) => { - const history = useHistory(); - //@ts-expect-error ignore this until we add it in GetSettings api types - const { sendPhoneNumberVerifyEmail, WS } = useVerifyEmail('phone_number_verification'); - const { next_otp_request } = usePhoneNumberVerificationSetTimer(); - const { invalidate } = useSettings(); - const { isMobile } = useDevice(); - - const handleCancelButton = () => { - setShouldShowVerificationLinkExpiredModal(false); - history.push(routes.personal_details); - }; - - const handleSendNewLinkButton = () => { - sendPhoneNumberVerifyEmail(); - }; - - useEffect(() => { - if (WS.isSuccess) invalidate('get_settings').then(() => setShouldShowVerificationLinkExpiredModal(false)); - }, [WS.isSuccess, invalidate]); - - return ( - - } - disableCloseOnOverlay - showSecondaryButton - secondaryButtonLabel={} - secondaryButtonCallback={handleCancelButton} - > - } - /> - -
- - - - - - -
-
-
- ); -}; - -export default VerificationLinkExpiredModal; diff --git a/packages/account/src/Styles/account.scss b/packages/account/src/Styles/account.scss index 6a072040dd34..3e197ef50b2d 100644 --- a/packages/account/src/Styles/account.scss +++ b/packages/account/src/Styles/account.scss @@ -321,13 +321,6 @@ $MIN_HEIGHT_FLOATING: calc( &__fieldset { position: relative; max-width: 400px; - - &--phone { - @include mobile { - padding-inline-end: 2.5rem; - } - } - @include mobile-or-tablet-screen { max-width: 100%; width: 100%; diff --git a/packages/api/types.ts b/packages/api/types.ts index 4de932cad57b..86c0224d0e58 100644 --- a/packages/api/types.ts +++ b/packages/api/types.ts @@ -2300,89 +2300,6 @@ type PasskeysRenameResponse = { [k: string]: unknown; }; -// TODO: remove these mock phone number challenge types after implementing them inside api-types -type PhoneNumberChallengeRequest = { - /** - * Must be `1` - */ - phone_number_challenge: 1; - /** - * The carrier sending the email code. - */ - email_code: string; - /** - * The carrier sending the OTP. - */ - carrier?: 'whatsapp' | 'sms'; - /** - * [Optional] The login id of the user. If left unspecified, it defaults to the initial authorized token's login id. - */ - loginid?: string; - /** - * [Optional] Used to pass data through the websocket, which may be retrieved via the `echo_req` output field. - */ - passthrough?: { - [k: string]: unknown; - }; - /** - * [Optional] Used to map request to response. - */ - req_id?: number; -}; - -type PhoneNumberChallengeResponse = { - phone_number_challenge?: number; - /** - * Echo of the request made. - */ - echo_req: { - [k: string]: unknown; - }; - /** - * Action name of the request made. - */ - msg_type: 'phone_number_challenge'; - /** - * Optional field sent in request to map to response, present only when request contains `req_id`. - */ - req_id?: number; - [k: string]: unknown; -}; - -// TODO: remove these mock phone number challenge types after implementing them inside api-types -type PhoneNumberVerifyRequest = { - /** - * Must be `1` - */ - phone_number_verify: 1; - /** - * The carrier sending the OTP. - */ - otp: string; - /** - * [Optional] Used to map request to response. - */ - req_id?: number; -}; - -type PhoneNumberVerifyResponse = { - /** - * Echo of the request made. - */ - echo_req: { - [k: string]: unknown; - }; - /** - * Action name of the request made. - */ - msg_type: 'phone_number_verify'; - /** - * Optional field sent in request to map to response, present only when request contains `req_id`. - */ - req_id?: number; - [k: string]: unknown; -}; - type ChangeEmailRequest = { change_email: 'verify' | 'update'; new_email: string; @@ -2756,14 +2673,6 @@ type TSocketEndpoints = { request: PayoutCurrenciesRequest; response: PayoutCurrenciesResponse; }; - phone_number_challenge: { - request: PhoneNumberChallengeRequest; - response: PhoneNumberChallengeResponse; - }; - phone_number_verify: { - request: PhoneNumberVerifyRequest; - response: PhoneNumberVerifyResponse; - }; ping: { request: PingRequest; response: PingResponse; diff --git a/packages/cashier-v2/package.json b/packages/cashier-v2/package.json index 595058a572fd..a7ab208703dd 100644 --- a/packages/cashier-v2/package.json +++ b/packages/cashier-v2/package.json @@ -18,7 +18,7 @@ "@deriv-com/utils": "^0.0.25", "@deriv/api-v2": "^1.0.0", "@deriv/integration": "^1.0.0", - "@deriv/quill-icons": "^1.23.3", + "@deriv/quill-icons": "1.23.3", "@deriv/utils": "^1.0.0", "clsx": "^2.1.1", "formik": "^2.1.4", diff --git a/packages/core/package.json b/packages/core/package.json index 01e8df01b076..a0c5b8d07ad5 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -115,7 +115,7 @@ "@deriv/hooks": "^1.0.0", "@deriv/p2p": "^0.7.3", "@deriv/quill-design": "^1.3.2", - "@deriv/quill-icons": "^1.23.3", + "@deriv/quill-icons": "1.23.3", "@deriv/reports": "^1.0.0", "@deriv/shared": "^1.0.0", "@deriv/stores": "^1.0.0", @@ -129,7 +129,6 @@ "canvas-toBlob": "^1.0.0", "classnames": "^2.2.6", "crc-32": "^1.2.0", - "dayjs": "^1.11.11", "dotenv-webpack": "^8.0.1", "extend": "^3.0.2", "formik": "^2.1.4", diff --git a/packages/core/src/App/Containers/NotificationsDialog/notifications-list.tsx b/packages/core/src/App/Containers/NotificationsDialog/notifications-list.tsx index bf8f9b0b6a44..d1a395a4b70c 100644 --- a/packages/core/src/App/Containers/NotificationsDialog/notifications-list.tsx +++ b/packages/core/src/App/Containers/NotificationsDialog/notifications-list.tsx @@ -61,7 +61,7 @@ const NotificationsList = observer(() => { {getButtonSettings(item)?.route ? ( { openRealAccountSignup, setCFDPasswordResetModal, setResetTradingPasswordModalOpen, - setRedirectFromEmail, toggleAccountSignupModal, toggleResetPasswordModal, toggleResetEmailModal, @@ -132,12 +131,6 @@ const Redirect = observer(() => { setResetTradingPasswordModalOpen(true); break; } - case 'phone_number_verification': { - setRedirectFromEmail(true); - history.push(routes.phone_verification); - redirected_to_route = true; - break; - } case 'payment_deposit': { if (has_wallet) { history.push(routes.wallets_deposit); diff --git a/packages/core/src/App/Containers/app-notification-messages.jsx b/packages/core/src/App/Containers/app-notification-messages.jsx index 11fb6b9f6811..4f9603da1693 100644 --- a/packages/core/src/App/Containers/app-notification-messages.jsx +++ b/packages/core/src/App/Containers/app-notification-messages.jsx @@ -103,7 +103,6 @@ const AppNotificationMessages = observer( 'need_fa', 'needs_poinc', 'notify_financial_assessment', - 'phone_number_verification', 'poi_name_mismatch', 'poa_address_mismatch_failure', 'poa_address_mismatch_success', diff --git a/packages/core/src/Services/socket-general.js b/packages/core/src/Services/socket-general.js index c93e4b28d0e8..aa707c06e3e1 100644 --- a/packages/core/src/Services/socket-general.js +++ b/packages/core/src/Services/socket-general.js @@ -224,7 +224,6 @@ const BinarySocketGeneral = (() => { 'portfolio', 'proposal_open_contract', 'change_email', - 'phone_number_challenge', ].includes(msg_type) ) { return; diff --git a/packages/core/src/Stores/client-store.js b/packages/core/src/Stores/client-store.js index 6799392864ea..0b58d5ae2065 100644 --- a/packages/core/src/Stores/client-store.js +++ b/packages/core/src/Stores/client-store.js @@ -117,7 +117,6 @@ export default class ClientStore extends BaseStore { reset_password: '', payment_withdraw: '', payment_agent_withdraw: '', - phone_number_verification: '', trading_platform_mt5_password_reset: '', trading_platform_dxtrade_password_reset: '', request_email: '', @@ -2212,12 +2211,10 @@ export default class ClientStore extends BaseStore { setVerificationCode(code, action) { this.verification_code[action] = code; - if (action !== 'phone_number_verification') { - if (code) { - LocalStore.set(`verification_code.${action}`, code); - } else { - LocalStore.remove(`verification_code.${action}`); - } + if (code) { + LocalStore.set(`verification_code.${action}`, code); + } else { + LocalStore.remove(`verification_code.${action}`); } if (action === 'signup') { // TODO: add await if error handling needs to happen before AccountSignup is initialised diff --git a/packages/core/src/Stores/notification-store.js b/packages/core/src/Stores/notification-store.js index c39160a9aaa7..2001e9b02552 100644 --- a/packages/core/src/Stores/notification-store.js +++ b/packages/core/src/Stores/notification-store.js @@ -12,7 +12,6 @@ import { getMarketName, getPathname, getPlatformSettings, - shouldShowPhoneVerificationNotification, getStaticUrl, getTotalProfit, getTradeTypeName, @@ -42,7 +41,6 @@ import { poi_notifications, } from './Helpers/client-notifications'; import BaseStore from './base-store'; -import dayjs from 'dayjs'; export default class NotificationStore extends BaseStore { is_notifications_visible = false; @@ -304,7 +302,6 @@ export default class NotificationStore extends BaseStore { } async handleClientNotifications() { - const current_time = dayjs(); const { account_settings, account_status, @@ -341,12 +338,7 @@ export default class NotificationStore extends BaseStore { const has_trustpilot = LocalStore.getObject('notification_messages')[loginid]?.includes( this.client_notifications.trustpilot?.key ); - const is_next_email_attempt_timer_running = shouldShowPhoneVerificationNotification( - account_settings?.phone_number_verification?.next_email_attempt, - current_time - ); - const show_phone_number_verification_notification = - !account_settings?.phone_number_verification?.verified && !is_next_email_attempt_timer_running; + let has_missing_required_field; const is_server_down = checkServerMaintenance(website_status); @@ -386,9 +378,6 @@ export default class NotificationStore extends BaseStore { this.removeNotificationByKey({ key: this.client_notifications.two_f_a?.key }); } - if (show_phone_number_verification_notification) { - this.addNotificationMessage(this.client_notifications.phone_number_verification); - } if (malta_account && is_financial_information_incomplete) { this.addNotificationMessage(this.client_notifications.need_fa); } else { @@ -753,7 +742,7 @@ export default class NotificationStore extends BaseStore { setClientNotifications(client_data = {}) { const { ui } = this.root_store; - const { has_enabled_two_fa, setTwoFAChangedStatus, logout, email } = this.root_store.client; + const { has_enabled_two_fa, setTwoFAChangedStatus, logout } = this.root_store.client; const two_fa_status = has_enabled_two_fa ? localize('enabled') : localize('disabled'); const platform_name_trader = getPlatformSettings('trader').name; @@ -1064,19 +1053,6 @@ export default class NotificationStore extends BaseStore { message: , type: 'info', }, - phone_number_verification: { - key: 'phone_number_verification', - header: localize('Verify your phone number'), - message: , - type: 'warning', - action: { - onClick: () => { - WS.verifyEmail(email, 'phone_number_verification'); - }, - route: routes.phone_verification, - text: localize('Get started'), - }, - }, poa_rejected_for_mt5: { action: { route: routes.proof_of_address, diff --git a/packages/core/src/Stores/ui-store.js b/packages/core/src/Stores/ui-store.js index 2f206a88ca43..d6e5fe5d5256 100644 --- a/packages/core/src/Stores/ui-store.js +++ b/packages/core/src/Stores/ui-store.js @@ -129,9 +129,6 @@ export default class UIStore extends BaseStore { prompt_when = false; promptFn = () => {}; - //phone number verification - should_show_phone_number_otp = false; - //warn user if they want to close create real account modal is_closing_create_real_account_modal = false; @@ -170,7 +167,6 @@ export default class UIStore extends BaseStore { should_show_assessment_complete_modal = false; app_contents_scroll_ref = null; is_deriv_account_needed_modal_visible = false; - is_redirected_from_email = false; is_wallet_modal_visible = false; is_ready_to_deposit_modal_visible = false; is_need_real_account_for_cashier_modal_visible = false; @@ -263,7 +259,6 @@ export default class UIStore extends BaseStore { is_dark_mode_on: observable, is_deriv_account_needed_modal_visible: observable, is_from_signup_account: observable, - is_redirected_from_email: observable, is_wallet_modal_visible: observable, is_history_tab_active: observable, @@ -301,7 +296,6 @@ export default class UIStore extends BaseStore { real_account_signup: observable, reports_route_tab_index: observable, settings_extension: observable, - should_show_phone_number_otp: observable, should_show_appropriateness_warning_modal: observable, should_show_assessment_complete_modal: observable, should_show_cancel: observable, @@ -352,7 +346,6 @@ export default class UIStore extends BaseStore { resetPurchaseStates: action.bound, resetRealAccountSignupParams: action.bound, resetRealAccountSignupTarget: action.bound, - setShouldShowPhoneNumberOTP: action.bound, setAccountSwitcherDisabledMessage: action.bound, setAppContentsScrollRef: action.bound, setCFDPasswordResetModal: action.bound, @@ -374,7 +367,6 @@ export default class UIStore extends BaseStore { shouldNavigateAfterChooseCrypto: action.bound, setIsMT5VerificationFailedModal: action.bound, setShouldShowRiskWarningModal: action.bound, - setRedirectFromEmail: action.bound, setIsWalletModalVisible: action.bound, setIsRealTabEnabled: action.bound, setIsTradingAssessmentForExistingUserEnabled: action.bound, @@ -451,10 +443,6 @@ export default class UIStore extends BaseStore { this.is_real_tab_enabled = is_real_tab_enabled; } - setShouldShowPhoneNumberOTP(should_show_phone_number_otp) { - this.should_show_phone_number_otp = should_show_phone_number_otp; - } - setHashedValue(url_hashed_values) { this.url_hashed_values = url_hashed_values; } @@ -873,10 +861,6 @@ export default class UIStore extends BaseStore { this.is_deriv_account_needed_modal_visible = !this.is_deriv_account_needed_modal_visible; } - setRedirectFromEmail(value) { - this.is_redirected_from_email = value; - } - setIsWalletModalVisible(value) { this.is_wallet_modal_visible = value; } diff --git a/packages/hooks/package.json b/packages/hooks/package.json index 892f03213313..a610f7ed47f9 100644 --- a/packages/hooks/package.json +++ b/packages/hooks/package.json @@ -11,12 +11,10 @@ "@deriv/stores": "^1.0.0", "@deriv/utils": "^1.0.0", "@deriv/shared": "^1.0.0", - "@deriv/translations": "^1.0.0", "usehooks-ts": "^2.7.0", "react-i18next": "^11.11.0", "@simplewebauthn/browser": "^8.3.4", "@simplewebauthn/typescript-types": "^8.3.4", - "dayjs": "^1.11.11", "react": "^17.0.2" }, "devDependencies": { diff --git a/packages/hooks/src/__tests__/usePhoneNumberVerificationSetTimer.spec.tsx b/packages/hooks/src/__tests__/usePhoneNumberVerificationSetTimer.spec.tsx deleted file mode 100644 index 434bd019e7fc..000000000000 --- a/packages/hooks/src/__tests__/usePhoneNumberVerificationSetTimer.spec.tsx +++ /dev/null @@ -1,76 +0,0 @@ -import React from 'react'; -import { renderHook, act } from '@testing-library/react-hooks'; -import dayjs from 'dayjs'; -import usePhoneNumberVerificationSetTimer from '../usePhoneNumberVerificationSetTimer'; -import { StoreProvider, mockStore } from '@deriv/stores'; - -const mock_store = mockStore({ - client: { - account_settings: { - phone_number_verification: { - next_email_attempt: undefined, - next_attempt: undefined, - }, - }, - }, - ui: { - should_show_phone_number_otp: false, - }, -}); - -describe('usePhoneNumberVerificationSetTimer', () => { - const wrapper = ({ children }: { children: JSX.Element }) => ( - {children} - ); - beforeEach(() => { - jest.clearAllMocks(); - jest.useFakeTimers(); - }); - - afterEach(() => { - jest.useRealTimers(); - mock_store.ui.should_show_phone_number_otp = false; - }); - - it('should set the correct timer and title when next_attempt is provided and should_show_phone_number_otp is true', () => { - const next_attempt = dayjs().add(65, 'seconds').unix(); - if (mock_store.client.account_settings.phone_number_verification) - mock_store.client.account_settings.phone_number_verification.next_attempt = next_attempt; - mock_store.ui.should_show_phone_number_otp = true; - - const { result } = renderHook(() => usePhoneNumberVerificationSetTimer(), { wrapper }); - - act(() => { - jest.advanceTimersByTime(1000); - }); - - expect(result.current.next_otp_request).toMatch(/\(1m\)/); - }); - - it('should set the correct timer and title when next_email_attempt is provided', () => { - const next_email_attempt = dayjs().add(2, 'minutes').unix(); - if (mock_store.client.account_settings.phone_number_verification) - mock_store.client.account_settings.phone_number_verification.next_email_attempt = next_email_attempt; - - const { result } = renderHook(() => usePhoneNumberVerificationSetTimer(), { wrapper }); - - act(() => { - jest.advanceTimersByTime(1000); - }); - - expect(result.current.next_otp_request).toMatch(/ in 2m/); - }); - - it('should set the correct timer and title when is_from_request_phone_otp is true', async () => { - const next_email_attempt = dayjs().add(1, 'minutes').unix(); - if (mock_store.client.account_settings.phone_number_verification) - mock_store.client.account_settings.phone_number_verification.next_email_attempt = next_email_attempt; - const { result } = renderHook(() => usePhoneNumberVerificationSetTimer(true), { wrapper }); - - act(() => { - jest.advanceTimersByTime(1000); - }); - - expect(result.current.next_otp_request).toMatch(/ 1 minutes/); - }); -}); diff --git a/packages/hooks/src/__tests__/useRequestPhoneNumberOTP.spec.tsx b/packages/hooks/src/__tests__/useRequestPhoneNumberOTP.spec.tsx deleted file mode 100644 index e99607c38ec8..000000000000 --- a/packages/hooks/src/__tests__/useRequestPhoneNumberOTP.spec.tsx +++ /dev/null @@ -1,164 +0,0 @@ -import { act, renderHook } from '@testing-library/react-hooks'; -import { useMutation } from '@deriv/api'; -import useRequestPhoneNumberOTP from '../useRequestPhoneNumberOTP'; -import { VERIFICATION_SERVICES } from '@deriv/shared'; -import React from 'react'; -import useSettings from '../useSettings'; -import { StoreProvider, mockStore } from '@deriv/stores'; - -jest.mock('@deriv/api', () => ({ - ...jest.requireActual('@deriv/api'), - useMutation: jest.fn(), -})); - -jest.mock('../useSettings'); - -const mock_response = { - data: { - phone_number_challenge: 1, - }, - mutate: jest.fn(), - isSuccess: true, -}; - -const mock_set_settings_response = { - data: {}, - mutate: jest.fn(), - isSuccess: true, -}; - -const mock_store_data = mockStore({ - client: { verification_code: { phone_number_verification: '' } }, -}); - -const mock_set_settings = jest.fn().mockResolvedValue(mock_set_settings_response); - -describe('useRequestPhoneNumberOTP', () => { - beforeEach(() => { - (useSettings as jest.Mock).mockReturnValue({ - mutation: { mutateAsync: mock_set_settings }, - }); - }); - const wrapper = ({ children }: { children: JSX.Element }) => ( - {children} - ); - - it('should call mutate with correct payload for SMS request and return correct response', () => { - (useMutation as jest.Mock).mockReturnValueOnce(mock_response); - const { result } = renderHook(() => useRequestPhoneNumberOTP(), { wrapper }); - - result.current.requestOnSMS(); - - expect(useMutation).toHaveBeenCalledWith('phone_number_challenge'); - expect(result.current.mutate).toHaveBeenCalledWith({ - payload: { carrier: VERIFICATION_SERVICES.SMS, email_code: '' }, - }); - expect(result.current.data).toEqual(1); - }); - - it('should call mutate with correct payload for WhatsApp request and return correct response', () => { - (useMutation as jest.Mock).mockReturnValueOnce(mock_response); - const { result } = renderHook(() => useRequestPhoneNumberOTP(), { wrapper }); - - result.current.requestOnWhatsApp(); - - expect(useMutation).toHaveBeenCalledWith('phone_number_challenge'); - expect(result.current.mutate).toHaveBeenCalledWith({ - payload: { carrier: VERIFICATION_SERVICES.WHATSAPP, email_code: '' }, - }); - expect(result.current.data).toEqual(1); - }); - - it('should call mutate with code given in phone_number_verification for SMS request and return correct response', () => { - mock_store_data.client.verification_code.phone_number_verification = '121212'; - (useMutation as jest.Mock).mockReturnValueOnce(mock_response); - const { result } = renderHook(() => useRequestPhoneNumberOTP(), { wrapper }); - - result.current.requestOnSMS(); - - expect(useMutation).toHaveBeenCalledWith('phone_number_challenge'); - expect(result.current.mutate).toHaveBeenCalledWith({ - payload: { carrier: VERIFICATION_SERVICES.SMS, email_code: '121212' }, - }); - expect(result.current.data).toEqual(1); - }); - - it('should call mutate with code given in phone_number_verification for WhatsApp request and return correct response', () => { - mock_store_data.client.verification_code.phone_number_verification = '121212'; - (useMutation as jest.Mock).mockReturnValueOnce(mock_response); - const { result } = renderHook(() => useRequestPhoneNumberOTP(), { wrapper }); - - result.current.requestOnWhatsApp(); - - expect(useMutation).toHaveBeenCalledWith('phone_number_challenge'); - expect(result.current.mutate).toHaveBeenCalledWith({ - payload: { carrier: VERIFICATION_SERVICES.WHATSAPP, email_code: '121212' }, - }); - expect(result.current.data).toEqual(1); - }); - - it('should call mutate with correct payload for sendEmailOTPVerification request and return correct response', () => { - (useMutation as jest.Mock).mockReturnValueOnce(mock_response); - const { result } = renderHook(() => useRequestPhoneNumberOTP(), { wrapper }); - - result.current.sendEmailOTPVerification('123456'); - - expect(useMutation).toHaveBeenCalledWith('phone_number_challenge'); - expect(result.current.mutate).toHaveBeenCalledWith({ - payload: { email_code: '123456' }, - }); - expect(result.current.data).toEqual(1); - }); - - it('should return Localized error message when PhoneNumberTaken error code is passed inside', () => { - (useMutation as jest.Mock).mockReturnValue(mock_response); - const { result } = renderHook(() => useRequestPhoneNumberOTP(), { wrapper }); - - act(() => { - result.current.formatError({ code: 'PhoneNumberTaken', message: '' }); - }); - - if (result.current?.error_message && React.isValidElement(result.current?.error_message)) - expect(result.current?.error_message?.props.i18n_default_text).toBe( - "This number is in use. Enter a new one or contact <0>live chat if you think there's a mistake." - ); - }); - - it('should return given error message when Other error code is passed inside', () => { - const { result } = renderHook(() => useRequestPhoneNumberOTP(), { wrapper }); - - act(() => { - result.current.formatError({ code: 'OtherError', message: 'This is an error message' }); - }); - - if (result.current?.error_message) expect(result.current?.error_message).toBe('This is an error message'); - }); - - it('should call setSettings with correct payload and handle success response', async () => { - const { result } = renderHook(() => useRequestPhoneNumberOTP(), { wrapper }); - - await act(async () => { - const response = await result.current.setUsersPhoneNumber({ phone: '+1234567890' }); - expect(response.error).toBe(undefined); - }); - - expect(mock_set_settings).toHaveBeenCalledWith({ payload: { phone: '+1234567890' } }); - }); - - it('should handle error response from setSettings', async () => { - (useMutation as jest.Mock).mockReturnValue(mock_response); - const mock_set_settings_error_response = { - error: { code: 'SomeError', message: 'An error occurred' }, - }; - (useSettings as jest.Mock).mockReturnValueOnce({ - mutation: { mutateAsync: jest.fn().mockRejectedValue(mock_set_settings_error_response) }, - }); - - const { result } = renderHook(() => useRequestPhoneNumberOTP(), { wrapper }); - - await act(async () => { - const response = await result.current.setUsersPhoneNumber({ phone: '+1234567890' }); - expect(response.error).toEqual(mock_set_settings_error_response); - }); - }); -}); diff --git a/packages/hooks/src/__tests__/useSendOTPVerificationCode.spec.tsx b/packages/hooks/src/__tests__/useSendOTPVerificationCode.spec.tsx deleted file mode 100644 index 0b220efe6cce..000000000000 --- a/packages/hooks/src/__tests__/useSendOTPVerificationCode.spec.tsx +++ /dev/null @@ -1,115 +0,0 @@ -import { renderHook, act } from '@testing-library/react-hooks'; -import { useMutation } from '@deriv/api'; -import useSendOTPVerificationCode from '../useSendOTPVerificationCode'; -import useRequestPhoneNumberOTP from '../useRequestPhoneNumberOTP'; - -jest.mock('@deriv/api', () => ({ - ...jest.requireActual('@deriv/api'), - useMutation: jest.fn(), -})); - -jest.mock('../useRequestPhoneNumberOTP'); - -type TMockResponse = { - data: null; - mutate: () => void; - error?: object; - isSuccess: boolean; -}; - -describe('useSendOTPVerificationCode', () => { - const mockMutate = jest.fn(); - const mock_response: TMockResponse = { - data: null, - mutate: mockMutate, - error: undefined, - isSuccess: false, - }; - - const mock_request_phone_number_otp_response = { - sendEmailOTPVerification: jest.fn(), - email_otp_error: {}, - is_email_verified: false, - }; - - beforeEach(() => { - (useMutation as jest.Mock).mockReturnValue(mock_response); - (useRequestPhoneNumberOTP as jest.Mock).mockReturnValue(mock_request_phone_number_otp_response); - }); - - afterEach(() => { - jest.clearAllMocks(); - mock_response.error = undefined; - }); - - it('should return initial state correctly', () => { - const { result } = renderHook(() => useSendOTPVerificationCode()); - - expect(result.current.data).toBe(null); - expect(result.current.phone_otp_error).toBe(undefined); - expect(result.current.phone_otp_error_message).toBe(undefined); - expect(result.current.is_phone_number_verified).toBe(false); - }); - - it('should handle successful OTP submission', () => { - mock_response.isSuccess = true; - - const { result } = renderHook(() => useSendOTPVerificationCode()); - - act(() => { - result.current.sendPhoneOTPVerification('123456'); - }); - - expect(mockMutate).toHaveBeenCalledWith({ payload: { otp: '123456' } }); - - expect(result.current.is_phone_number_verified).toBe(true); - }); - - it('should handle ExpiredCode for phone_otp_error', () => { - mock_response.error = { code: 'ExpiredCode', message: 'Code expired.' }; - - const { result } = renderHook(() => useSendOTPVerificationCode()); - - expect(result.current.phone_otp_error_message).toBe('Code expired. Please get a new one.'); - }); - - it('should handle InvalidOTP for phone_otp_error', () => { - mock_response.error = { code: 'InvalidOTP', message: 'Invalid code.' }; - - const { result } = renderHook(() => useSendOTPVerificationCode()); - - expect(result.current.phone_otp_error_message).toBe('Invalid code. Please try again.'); - }); - - it('should handle NoAttemptsLeft for phone_otp_error', () => { - mock_response.error = { code: 'NoAttemptsLeft', message: 'OTP limit reached.' }; - - const { result } = renderHook(() => useSendOTPVerificationCode()); - - expect(result.current.phone_otp_error_message).toBe('Invalid code. OTP limit reached.'); - }); - - it('should handle ExpiredCode for email_otp_error', () => { - mock_request_phone_number_otp_response.email_otp_error = { code: 'ExpiredCode', message: 'ExpiredCode' }; - - const { result } = renderHook(() => useSendOTPVerificationCode()); - - expect(result.current.phone_otp_error_message).toBe('Code expired.'); - }); - - it('should handle InvalidOTP for email_top_error', () => { - mock_request_phone_number_otp_response.email_otp_error = { code: 'InvalidToken', message: 'InvalidToken' }; - - const { result } = renderHook(() => useSendOTPVerificationCode()); - - expect(result.current.phone_otp_error_message).toBe('Invalid code. Press the link below to get a new code.'); - }); - - it('should handle NoAttemptsLeft for email_top_error', () => { - mock_request_phone_number_otp_response.email_otp_error = { code: 'NoAttemptsLeft', message: 'NoAttemptsLeft' }; - - const { result } = renderHook(() => useSendOTPVerificationCode()); - - expect(result.current.phone_otp_error_message).toBe('Invalid code. OTP limit reached.'); - }); -}); diff --git a/packages/hooks/src/__tests__/useSettings.spec.tsx b/packages/hooks/src/__tests__/useSettings.spec.tsx deleted file mode 100644 index a69ce0225e1f..000000000000 --- a/packages/hooks/src/__tests__/useSettings.spec.tsx +++ /dev/null @@ -1,94 +0,0 @@ -import React from 'react'; -import { renderHook, act } from '@testing-library/react-hooks'; -import { useQuery, useMutation, useInvalidateQuery } from '@deriv/api'; -import { StoreProvider, mockStore } from '@deriv/stores'; -import useSettings from '../useSettings'; - -jest.mock('@deriv/api', () => ({ - ...jest.requireActual('@deriv/api'), - useQuery: jest.fn(), - useMutation: jest.fn(), - useInvalidateQuery: jest.fn(), -})); - -describe('useSettings', () => { - const mockInvalidateQuery = jest.fn(); - const mockMutate = jest.fn(); - const mockStoreData = mockStore({ - client: { is_authorize: true }, - }); - const wrapper = ({ children }: { children: JSX.Element }) => ( - {children} - ); - - beforeEach(() => { - (useInvalidateQuery as jest.Mock).mockReturnValue(mockInvalidateQuery); - (useMutation as jest.Mock).mockReturnValue({ - mutate: mockMutate, - data: null, - isLoading: false, - error: null, - }); - }); - - afterEach(() => { - jest.clearAllMocks(); - }); - - it('should return initial state correctly', () => { - (useQuery as jest.Mock).mockReturnValue({ - data: null, - isLoading: false, - error: null, - }); - - const { result } = renderHook(() => useSettings(), { wrapper }); - - expect(result.current.data).toBe(undefined); - expect(result.current.mutation.data).toBe(null); - expect(result.current.mutation.isLoading).toBe(false); - expect(result.current.mutation.error).toBe(null); - }); - - it('should return modified settings', () => { - const mockData = { - get_settings: { - citizen: 'country', - account_opening_reason: 'reason', - has_submitted_personal_details: true, - place_of_birth: 'place', - tax_residence: 'residence', - tax_identification_number: 'number', - }, - }; - - (useQuery as jest.Mock).mockReturnValue({ - data: mockData, - isLoading: false, - error: null, - }); - - const { result } = renderHook(() => useSettings(), { wrapper }); - - expect(result.current.data).toEqual({ - ...mockData.get_settings, - has_submitted_personal_details: true, - }); - }); - - it('should call mutate with correct payload', () => { - (useQuery as jest.Mock).mockReturnValue({ - data: null, - isLoading: false, - error: null, - }); - - const { result } = renderHook(() => useSettings(), { wrapper }); - - act(() => { - result.current.update({ phone: '+123456789' }); - }); - - expect(mockMutate).toHaveBeenCalledWith({ payload: { phone: '+123456789' } }); - }); -}); diff --git a/packages/hooks/src/index.ts b/packages/hooks/src/index.ts index 011f704ff13c..d2ea5d6d66d9 100644 --- a/packages/hooks/src/index.ts +++ b/packages/hooks/src/index.ts @@ -23,7 +23,6 @@ export { default as useFiatAccountList } from './useFiatAccountList'; export { default as useFileUploader } from './useFileUploader'; export { default as useGetMFAccountStatus } from './useGetMFAccountStatus'; export { default as useGetPasskeysList } from './useGetPasskeysList'; -export { default as useRequestPhoneNumberOTP } from './useRequestPhoneNumberOTP'; export { default as useHasActiveRealAccount } from './useHasActiveRealAccount'; export { default as useHasCryptoCurrency } from './useHasCryptoCurrency'; export { default as useHasFiatCurrency } from './useHasFiatCurrency'; @@ -68,10 +67,8 @@ export { default as usePlatformDemoAccount } from './usePlatformDemoAccount'; export { default as usePlatformRealAccounts } from './usePlatformRealAccounts'; export { default as useRealSTPAccount } from './useRealSTPAccount'; export { default as useRegisterPasskey } from './useRegisterPasskey'; -export { default as useSendOTPVerificationCode } from './useSendOTPVerificationCode'; export { default as useRenamePasskey } from './useRenamePasskey'; export { default as useServiceToken } from './useServiceToken'; -export { default as useSettings } from './useSettings'; export { default as useStatesList } from './useStatesList'; export { default as useStoreLinkedWalletsAccounts } from './useStoreLinkedWalletsAccounts'; export { default as useStoreWalletAccountsList } from './useStoreWalletAccountsList'; @@ -87,4 +84,3 @@ export { default as useResidenceSelfDeclaration } from './useResidenceSelfDeclar export { default as useTotalAssetCurrency } from './useTotalAssetCurrency'; export { default as useGrowthbookIsOn } from './useGrowthbookIsOn'; export { default as useResidenceList } from './useResidenceList'; -export { default as usePhoneNumberVerificationSetTimer } from './usePhoneNumberVerificationSetTimer'; diff --git a/packages/hooks/src/usePhoneNumberVerificationSetTimer.tsx b/packages/hooks/src/usePhoneNumberVerificationSetTimer.tsx deleted file mode 100644 index 075a6183d8e6..000000000000 --- a/packages/hooks/src/usePhoneNumberVerificationSetTimer.tsx +++ /dev/null @@ -1,89 +0,0 @@ -import { useStore } from '@deriv/stores'; -import dayjs from 'dayjs'; -import React from 'react'; - -const otpRequestCountdown = ( - nextAttemptTimestamp: number, - setTitle: (title: number) => void, - setTimer: (title: number) => void, - current_time: dayjs.Dayjs -) => { - const request_in_milliseconds = dayjs(nextAttemptTimestamp * 1000); - const next_request = Math.round(request_in_milliseconds.diff(current_time) / 1000); - - if (next_request > 0) { - setTitle(next_request); - setTimer(next_request); - } -}; - -/** A hook for calculating email verification otp and phone number otp timer */ -const usePhoneNumberVerificationSetTimer = (is_from_request_phone_number_otp = false) => { - const { client, ui } = useStore(); - const { account_settings } = client; - const { should_show_phone_number_otp } = ui; - const { phone_number_verification } = account_settings; - const [timer, setTimer] = React.useState(); - const [next_otp_request, setNextOtpRequest] = React.useState(''); - const current_time = dayjs(); - - const setTitle = React.useCallback( - (timer: number) => { - let display_time: string; - if (timer > 60) { - display_time = is_from_request_phone_number_otp - ? `${Math.round(timer / 60)} minutes` - : `${Math.round(timer / 60)}m`; - } else { - display_time = is_from_request_phone_number_otp ? `${timer} seconds` : `${timer}s`; - } - if (is_from_request_phone_number_otp) { - setNextOtpRequest(` ${display_time}`); - } else if (should_show_phone_number_otp) { - setNextOtpRequest(` (${display_time})`); - } else { - setNextOtpRequest(` in ${display_time}`); - } - }, - [should_show_phone_number_otp, is_from_request_phone_number_otp] - ); - - React.useEffect(() => { - if ( - !should_show_phone_number_otp && - !is_from_request_phone_number_otp && - phone_number_verification?.next_email_attempt - ) { - otpRequestCountdown(phone_number_verification.next_email_attempt, setTitle, setTimer, current_time); - } else if (phone_number_verification?.next_attempt) { - otpRequestCountdown(phone_number_verification.next_attempt, setTitle, setTimer, current_time); - } - }, [ - current_time, - phone_number_verification?.next_email_attempt, - phone_number_verification?.next_attempt, - is_from_request_phone_number_otp, - setTitle, - should_show_phone_number_otp, - ]); - - React.useEffect(() => { - let countdown: ReturnType; - if (timer && timer > 0) { - countdown = setInterval(() => { - setTimer(timer - 1); - setTitle(timer); - }, 1000); - } else { - setNextOtpRequest(''); - } - - return () => clearInterval(countdown); - }, [timer, setTitle]); - - return { - next_otp_request, - }; -}; - -export default usePhoneNumberVerificationSetTimer; diff --git a/packages/hooks/src/useRequestPhoneNumberOTP.tsx b/packages/hooks/src/useRequestPhoneNumberOTP.tsx deleted file mode 100644 index 47ccce1f52f9..000000000000 --- a/packages/hooks/src/useRequestPhoneNumberOTP.tsx +++ /dev/null @@ -1,111 +0,0 @@ -import React from 'react'; -import { useMutation } from '@deriv/api'; -import { VERIFICATION_SERVICES } from '@deriv/shared'; -import { Localize } from '@deriv/translations'; -import useSettings from './useSettings'; -import { useStore } from '@deriv/stores'; - -type TFormatError = { - code: string; - message: string; -}; - -/** A hook for requesting OTP which is sent on whatsapp or sms platforms */ -const useRequestPhoneNumberOTP = () => { - const { - data, - mutate, - error: email_otp_error, - isSuccess: is_email_verified, - ...rest - } = useMutation('phone_number_challenge'); - const [error_message, setErrorMessage] = React.useState(''); - const { client } = useStore(); - const { verification_code } = client; - const { phone_number_verification: phone_number_verification_code } = verification_code; - const { - mutation: { mutateAsync: updateSettings }, - } = useSettings(); - - React.useEffect(() => { - //@ts-expect-error will fix this later - if (email_otp_error) formatError(email_otp_error); - }, [email_otp_error]); - - const requestOnSMS = () => { - mutate({ - payload: { - carrier: VERIFICATION_SERVICES.SMS, - email_code: phone_number_verification_code || '', - }, - }); - }; - - const requestOnWhatsApp = () => { - mutate({ - payload: { - carrier: VERIFICATION_SERVICES.WHATSAPP, - email_code: phone_number_verification_code || '', - }, - }); - }; - - const sendEmailOTPVerification = (value: string) => { - mutate({ payload: { email_code: value } }); - }; - - const setUsersPhoneNumber = async (value: { [key: string]: unknown }) => { - let error; - try { - await updateSettings({ - payload: value, - }); - } catch (err) { - formatError(err as TFormatError); - error = err; - } - - return { - error, - }; - }; - - const formatError = ({ code, message }: TFormatError) => { - switch (code) { - case 'PhoneNumberTaken': - setErrorMessage( - window.LC_API.open_chat_window()} - />, - ]} - /> - ); - break; - default: - setErrorMessage(message); - break; - } - }; - - return { - data: data?.phone_number_challenge, - error_message, - email_otp_error, - is_email_verified, - requestOnWhatsApp, - requestOnSMS, - formatError, - setErrorMessage, - setUsersPhoneNumber, - sendEmailOTPVerification, - mutate, - ...rest, - }; -}; - -export default useRequestPhoneNumberOTP; diff --git a/packages/hooks/src/useSendOTPVerificationCode.ts b/packages/hooks/src/useSendOTPVerificationCode.ts deleted file mode 100644 index f8bb8db1a943..000000000000 --- a/packages/hooks/src/useSendOTPVerificationCode.ts +++ /dev/null @@ -1,85 +0,0 @@ -import React from 'react'; -import { useMutation } from '@deriv/api'; -import { TSocketError } from '@deriv/api/types'; -import { localize } from '@deriv/translations'; -import useRequestPhoneNumberOTP from './useRequestPhoneNumberOTP'; - -/** A hook for verifying Phone Number OTP and Email OTP */ -const useSendOTPVerificationCode = () => { - const [phone_otp_error_message, setPhoneOtpErrorMessage] = React.useState(''); - const { - data, - mutate, - error: phone_otp_error, - isSuccess: is_phone_number_verified, - ...rest - } = useMutation('phone_number_verify'); - const { sendEmailOTPVerification, email_otp_error, is_email_verified, requestOnSMS, requestOnWhatsApp } = - useRequestPhoneNumberOTP(); - - const formatPhoneOtpError = (error: TSocketError<'phone_number_verify'>['error']) => { - switch (error.code) { - case 'ExpiredCode': - setPhoneOtpErrorMessage(localize('Code expired. Please get a new one.')); - break; - case 'InvalidOTP': - setPhoneOtpErrorMessage(localize('Invalid code. Please try again.')); - break; - case 'NoAttemptsLeft': - setPhoneOtpErrorMessage(localize('Invalid code. OTP limit reached.')); - break; - default: - setPhoneOtpErrorMessage(error.message); - break; - } - }; - - const formatEmailOtpError = (error: TSocketError<'phone_number_challenge'>['error']) => { - switch (error.code) { - case 'ExpiredCode': - setPhoneOtpErrorMessage(localize('Code expired.')); - break; - case 'InvalidToken': - setPhoneOtpErrorMessage(localize('Invalid code. Press the link below to get a new code.')); - break; - case 'NoAttemptsLeft': - setPhoneOtpErrorMessage(localize('Invalid code. OTP limit reached.')); - break; - default: - setPhoneOtpErrorMessage(error.message); - break; - } - }; - - React.useEffect(() => { - if (phone_otp_error) { - // @ts-expect-error will remove once solved - formatPhoneOtpError(phone_otp_error); - } else if (email_otp_error) { - // @ts-expect-error will remove once solved - formatEmailOtpError(email_otp_error); - } - }, [phone_otp_error, email_otp_error]); - - const sendPhoneOTPVerification = (value: string) => { - mutate({ payload: { otp: value } }); - }; - - return { - data, - sendPhoneOTPVerification, - sendEmailOTPVerification, - requestOnSMS, - requestOnWhatsApp, - email_otp_error, - phone_otp_error, - phone_otp_error_message, - setPhoneOtpErrorMessage, - is_phone_number_verified, - is_email_verified, - mutate, - ...rest, - }; -}; - -export default useSendOTPVerificationCode; diff --git a/packages/hooks/src/useSettings.ts b/packages/hooks/src/useSettings.ts deleted file mode 100644 index 89fb07c6c1ad..000000000000 --- a/packages/hooks/src/useSettings.ts +++ /dev/null @@ -1,31 +0,0 @@ -import { useInvalidateQuery, useMutation, useQuery } from '@deriv/api'; -import { useStore } from '@deriv/stores'; - -type TSetSettingsPayload = NonNullable< - NonNullable>['mutate']>>[0]>['payload'] ->; - -/** A custom hook to get and update the user settings. */ -const useSettings = () => { - const { - client: { is_authorize }, - } = useStore(); - const { data, ...rest } = useQuery('get_settings', { options: { enabled: is_authorize } }); - const { mutate, ...mutate_rest } = useMutation('set_settings', { onSuccess: () => invalidate('get_settings') }); - const invalidate = useInvalidateQuery(); - - const update = (payload: TSetSettingsPayload) => mutate({ payload }); - - return { - /** The settings response. */ - data: data?.get_settings, - /** Function to update user settings */ - update, - invalidate, - /** The mutation related information */ - mutation: mutate_rest, - ...rest, - }; -}; - -export default useSettings; diff --git a/packages/hooks/src/useVerifyEmail.ts b/packages/hooks/src/useVerifyEmail.ts index 1f871e1bb7e8..4d9961df3ac1 100644 --- a/packages/hooks/src/useVerifyEmail.ts +++ b/packages/hooks/src/useVerifyEmail.ts @@ -5,6 +5,9 @@ import useCountdown from './useCountdown'; const RESEND_COUNTDOWN = 60; +/** + * @deprecated Please use useVerifyEmail from @deriv/api instead + */ const useVerifyEmail = ( type: Parameters>['mutate']>[0]['payload']['type'] ) => { @@ -29,12 +32,7 @@ const useVerifyEmail = ( [WS, client.email, counter, type] ); - const sendPhoneNumberVerifyEmail = useCallback(() => { - WS.mutate({ payload: { verify_email: client.email, type } }); - }, [WS, client.email, type]); - return { - WS, is_loading: WS.isLoading, error: WS.error, data: WS.data, @@ -43,7 +41,6 @@ const useVerifyEmail = ( sent_count, has_been_sent: sent_count !== 0, send, - sendPhoneNumberVerifyEmail, }; }; diff --git a/packages/integration/src/mocks/auth/getSettings.ts b/packages/integration/src/mocks/auth/getSettings.ts index 7a1e423ec69f..298db5c173c2 100644 --- a/packages/integration/src/mocks/auth/getSettings.ts +++ b/packages/integration/src/mocks/auth/getSettings.ts @@ -33,10 +33,6 @@ export default function mockGetSettings(context: Context) { last_name: 'Smith', non_pep_declaration: 1, phone: '+66111111111', - phone_number_verification: { - next_attempt: 0, - verified: 0, - }, place_of_birth: 'Thailand', preferred_language: 'EN', request_professional_status: 0, diff --git a/packages/shared/package.json b/packages/shared/package.json index 55cb50673734..de57b290ee11 100644 --- a/packages/shared/package.json +++ b/packages/shared/package.json @@ -47,14 +47,13 @@ }, "dependencies": { "@deriv-com/analytics": "1.5.9", - "@deriv/quill-icons": "^1.23.3", + "@deriv/quill-icons": "1.23.3", "@deriv/api-types": "1.0.172", "@deriv/translations": "^1.0.0", "@types/js-cookie": "^3.0.1", "@types/react-loadable": "^5.5.6", "canvas-toBlob": "^1.0.0", "extend": "^3.0.2", - "dayjs": "^1.11.11", "i18next": "^22.4.6", "js-cookie": "^2.2.1", "mobx": "^6.6.1", diff --git a/packages/shared/src/styles/constants.scss b/packages/shared/src/styles/constants.scss index 3b71fd30eeff..4ce468e9fb62 100644 --- a/packages/shared/src/styles/constants.scss +++ b/packages/shared/src/styles/constants.scss @@ -74,7 +74,6 @@ $color-red-8: #661b20; $color-red-9: #b33037; $color-red-10: #ff444f; $color-red-11: #fce3e3; -$color-red-12: #c40000; $color-violet: #4a3871; $color-white: #ffffff; $color-yellow: #ffad3a; diff --git a/packages/shared/src/utils/constants/index.ts b/packages/shared/src/utils/constants/index.ts index 6573050d96f7..e8fc73627855 100644 --- a/packages/shared/src/utils/constants/index.ts +++ b/packages/shared/src/utils/constants/index.ts @@ -8,5 +8,4 @@ export * from './error'; export * from './poi-failure-codes'; export * from './mt5-login-list-status'; export * from './auth-status-codes'; -export * from './phone-number-verification'; export * from './translation-flag'; diff --git a/packages/shared/src/utils/constants/phone-number-verification.ts b/packages/shared/src/utils/constants/phone-number-verification.ts deleted file mode 100644 index ba711cb270eb..000000000000 --- a/packages/shared/src/utils/constants/phone-number-verification.ts +++ /dev/null @@ -1,13 +0,0 @@ -import dayjs from 'dayjs'; - -export const VERIFICATION_SERVICES = { - SMS: 'sms', - WHATSAPP: 'whatsapp', -} as const; - -export const shouldShowPhoneVerificationNotification = (nextAttemptTimestamp: number, current_time: dayjs.Dayjs) => { - const request_in_milliseconds = dayjs(nextAttemptTimestamp * 1000); - const seconds_until_next_attempt = Math.round(request_in_milliseconds.diff(current_time) / 1000); - - return seconds_until_next_attempt > 0; -}; diff --git a/packages/shared/src/utils/routes/routes.ts b/packages/shared/src/utils/routes/routes.ts index 6fb9bc6c19b8..d6392293d203 100644 --- a/packages/shared/src/utils/routes/routes.ts +++ b/packages/shared/src/utils/routes/routes.ts @@ -32,7 +32,6 @@ export const routes = { proof_of_income: '/account/proof-of-income', passwords: '/account/passwords', passkeys: '/account/passkeys', - phone_verification: '/account/personal-details/phone-verification', closing_account: '/account/closing-account', deactivate_account: '/account/deactivate-account', // TODO: Remove once mobile team has changed this link account_closed: '/account-closed', diff --git a/packages/stores/src/mockStore.ts b/packages/stores/src/mockStore.ts index cd1f6c164721..69460eec2d1d 100644 --- a/packages/stores/src/mockStore.ts +++ b/packages/stores/src/mockStore.ts @@ -187,7 +187,6 @@ const mock = (): TStores & { is_mock: boolean } => { verification_code: { payment_agent_withdraw: '', payment_withdraw: '', - phone_number_verification: '', request_email: '', reset_password: '', signup: '', @@ -345,7 +344,6 @@ const mock = (): TStores & { is_mock: boolean } => { is_history_tab_active: false, is_loading: false, is_cashier_visible: false, - is_redirected_from_email: false, is_wallet_modal_visible: false, is_chart_layout_default: false, is_chart_countdown_visible: false, @@ -369,10 +367,7 @@ const mock = (): TStores & { is_mock: boolean } => { is_reset_password_modal_visible: false, is_route_modal_on: false, is_services_error_visible: false, - should_show_phone_number_otp: false, is_trading_assessment_for_existing_user_enabled: false, - setRedirectFromEmail: jest.fn(), - setShouldShowPhoneNumberOTP: jest.fn(), disableApp: jest.fn(), enableApp: jest.fn(), setCurrentFocus: jest.fn(), diff --git a/packages/stores/types.ts b/packages/stores/types.ts index d762ab07cf3a..d909b29e8f7f 100644 --- a/packages/stores/types.ts +++ b/packages/stores/types.ts @@ -516,7 +516,6 @@ type TClientStore = { verification_code: { payment_agent_withdraw: string; payment_withdraw: string; - phone_number_verification: string; request_email: string; reset_password: string; signup: string; @@ -540,12 +539,6 @@ type TClientStore = { account_settings: GetSettings & { upload_file?: string; poi_state?: string; - phone_number_verification?: { - verified?: 0 | 1; - next_attempt?: number; - next_email_attempt?: number; - next_verify_attempt?: number; - }; }; residence_list: ResidenceList; should_restrict_bvi_account_creation: boolean; @@ -686,7 +679,6 @@ type TUiStore = { is_advanced_duration: boolean; is_cashier_visible: boolean; is_history_tab_active: boolean; - is_redirected_from_email: boolean; is_wallet_modal_visible: boolean; is_chart_asset_info_visible?: boolean; is_chart_layout_default: boolean; @@ -742,7 +734,6 @@ type TUiStore = { setCurrentFocus: (value: string | null) => void; setDarkMode: (is_dark_mode_on: boolean) => boolean; setIsWalletModalVisible: (value: boolean) => void; - setRedirectFromEmail: (value: boolean) => void; setHasOnlyForwardingContracts: (has_only_forward_starting_contracts?: boolean) => void; setMobileLanguageMenuOpen: (is_mobile_language_menu_open: boolean) => void; setReportsTabIndex: (value: number) => void; @@ -755,8 +746,6 @@ type TUiStore = { setRealAccountSignupEnd: (status: boolean) => void; setPurchaseState: (index: number) => void; simple_duration_unit: string; - should_show_phone_number_otp: boolean; - setShouldShowPhoneNumberOTP: (value: boolean) => void; sub_section_index: number; setPromptHandler: ( condition: boolean, diff --git a/packages/trader/package.json b/packages/trader/package.json index 23e1f1918e57..082768fde0bb 100644 --- a/packages/trader/package.json +++ b/packages/trader/package.json @@ -101,7 +101,7 @@ "@deriv/shared": "^1.0.0", "@deriv/stores": "^1.0.0", "@deriv/translations": "^1.0.0", - "@deriv/quill-icons": "^1.23.3", + "@deriv/quill-icons": "1.23.3", "@lottiefiles/dotlottie-react": "0.7.2", "@types/react-loadable": "^5.5.6", "classnames": "^2.2.6", diff --git a/packages/wallets/package.json b/packages/wallets/package.json index fec753b18d8c..e6e38ebab357 100644 --- a/packages/wallets/package.json +++ b/packages/wallets/package.json @@ -20,7 +20,7 @@ "@deriv-com/utils": "^0.0.25", "@deriv/api-v2": "^1.0.0", "@deriv/integration": "^1.0.0", - "@deriv/quill-icons": "^1.23.3", + "@deriv/quill-icons": "1.23.3", "react-joyride": "^2.5.3", "@deriv/utils": "^1.0.0", "@tanstack/react-table": "^8.10.3",