diff --git a/packages/account/build/webpack.config.js b/packages/account/build/webpack.config.js index 726c135a9344..7d257fea61b3 100644 --- a/packages/account/build/webpack.config.js +++ b/packages/account/build/webpack.config.js @@ -92,7 +92,6 @@ module.exports = function (env) { '@deriv/utils': '@deriv/utils', '@deriv/quill-icons': `@deriv/quill-icons`, '@deriv-com/utils': '@deriv-com/utils', - '@deriv-com/translations': '@deriv-com/translations', }, /^@deriv\/shared\/.+$/, /^@deriv\/components\/.+$/, diff --git a/packages/account/src/App.tsx b/packages/account/src/App.tsx index a914d212006a..8a3e72c4ebaf 100644 --- a/packages/account/src/App.tsx +++ b/packages/account/src/App.tsx @@ -1,4 +1,3 @@ -import React from 'react'; import Routes from './Containers/routes'; import ResetTradingPassword from './Containers/reset-trading-password'; import { NetworkStatusToastErrorPopup } from './Containers/toast-popup'; diff --git a/packages/account/src/Components/form-body/form-body.tsx b/packages/account/src/Components/form-body/form-body.tsx index 39ed0c94e29b..9431966abef9 100644 --- a/packages/account/src/Components/form-body/form-body.tsx +++ b/packages/account/src/Components/form-body/form-body.tsx @@ -1,4 +1,5 @@ -import React from 'react'; +// [TODO] - To be removed once CFD is configured to use the new form-body component +import React, { PropsWithChildren, Fragment } from 'react'; import { ScrollbarsContainer } from '../scrollbars-container/scrollbars-container'; import { Div100vhContainer, DesktopWrapper, MobileWrapper } from '@deriv/components'; import clsx from 'clsx'; @@ -8,8 +9,8 @@ type TFormBody = { className?: string; }; -export const FormBody = ({ children, scroll_offset, className }: React.PropsWithChildren) => ( - +export const FormBody = ({ children, scroll_offset, className }: PropsWithChildren) => ( + - + ); diff --git a/packages/account/src/Components/form-sub-header/form-sub-header.tsx b/packages/account/src/Components/form-sub-header/form-sub-header.tsx index d0fa05325c64..453b6b4a9450 100644 --- a/packages/account/src/Components/form-sub-header/form-sub-header.tsx +++ b/packages/account/src/Components/form-sub-header/form-sub-header.tsx @@ -1,5 +1,6 @@ +// [TODO] - To be removed once CFD is configured to use the new form-body component +import React, { Fragment } from 'react'; import clsx from 'clsx'; -import React from 'react'; import { Text } from '@deriv/components'; export type TFormSubHeader = { @@ -13,7 +14,7 @@ export const FormSubHeader = ({ description, subtitle, title, title_text_size = const title_as_class = title.replace(/\s+/g, '-').toLowerCase(); return ( - +
)} - + ); }; diff --git a/packages/account/src/Components/forms/form-fields/date-of-birth-field.tsx b/packages/account/src/Components/forms/form-fields/date-of-birth-field.tsx index 5e79e847aabb..e5f00fbebc91 100644 --- a/packages/account/src/Components/forms/form-fields/date-of-birth-field.tsx +++ b/packages/account/src/Components/forms/form-fields/date-of-birth-field.tsx @@ -1,6 +1,6 @@ /* eslint-disable @typescript-eslint/ban-ts-comment */ //@ts-nocheck [TODO] - Need to fix typescript errors - +// [TODO] - Remove React after CFD is configured with new JSX transformer import React from 'react'; import { Field, FieldProps } from 'formik'; import { DateOfBirthPicker } from '@deriv/components'; @@ -17,7 +17,7 @@ type TDateOfBirthFieldProps = { * @param name - Name of the field * @param portal_id - Portal ID * @param [props] - Other props to pass to DateOfBirthPicker - * @returns {React.ReactNode} + * @returns {ReactNode} */ const DateOfBirthField = ({ name, portal_id, ...rest }: TDateOfBirthFieldProps) => ( diff --git a/packages/account/src/Components/forms/form-select-field.tsx b/packages/account/src/Components/forms/form-select-field.tsx index 1bcfeeaf9118..08a3cbb0766c 100644 --- a/packages/account/src/Components/forms/form-select-field.tsx +++ b/packages/account/src/Components/forms/form-select-field.tsx @@ -1,7 +1,7 @@ +import { FC, Fragment } from 'react'; import { Autocomplete, SelectNative } from '@deriv/components'; import { useStore } from '@deriv/stores'; import { Field, FieldProps, FormikErrors } from 'formik'; -import React from 'react'; import { TGetField } from '../additional-kyc-info-modal/form-config'; import { TListItem } from 'Types'; @@ -16,7 +16,7 @@ type TSetFieldValue = ( shouldValidate?: boolean ) => Promise>>; -const FormSelectField: React.FC = ({ +const FormSelectField: FC = ({ label, name, required = false, @@ -38,7 +38,7 @@ const FormSelectField: React.FC = ({ return ( {({ field, meta: { touched, error }, form: { setFieldValue } }: FieldProps) => ( - + {is_mobile ? ( = ({ list_height={list_height} /> )} - + )} ); diff --git a/packages/account/src/Components/language-settings/__tests__/language-radio-button.spec.tsx b/packages/account/src/Components/language-settings/__tests__/language-radio-button.spec.tsx index 334ae5bc2d47..a6c0e3cd18c5 100644 --- a/packages/account/src/Components/language-settings/__tests__/language-radio-button.spec.tsx +++ b/packages/account/src/Components/language-settings/__tests__/language-radio-button.spec.tsx @@ -23,7 +23,7 @@ describe('LanguageRadioButton', () => { const mock_props: TLanguageRadioButton = { is_current_language: true, id: 'test id', - language_code: 'lang_1', + language_text: 'Lang 1', name: 'Test Language', onChange: jest.fn(), }; @@ -32,7 +32,7 @@ describe('LanguageRadioButton', () => { render(); expect(screen.getByText('Flag Icon')).toBeInTheDocument(); - expect(screen.getByText('Test Lang 1')).toBeInTheDocument(); + expect(screen.getByText('Lang 1')).toBeInTheDocument(); expect(screen.getByTestId('dt_language_settings_button')).toHaveClass( 'settings-language__language-link--active' ); @@ -44,7 +44,7 @@ describe('LanguageRadioButton', () => { render(); expect(screen.getByText('Flag Icon')).toBeInTheDocument(); - expect(screen.getByText('Test Lang 1')).toBeInTheDocument(); + expect(screen.getByText('Lang 1')).toBeInTheDocument(); expect(screen.getByTestId('dt_language_settings_button')).not.toHaveClass( 'settings-language__language-link--active' ); diff --git a/packages/account/src/Components/language-settings/language-radio-button.tsx b/packages/account/src/Components/language-settings/language-radio-button.tsx index 6f877a28b37c..b81975ea6ec3 100644 --- a/packages/account/src/Components/language-settings/language-radio-button.tsx +++ b/packages/account/src/Components/language-settings/language-radio-button.tsx @@ -1,24 +1,22 @@ -import React from 'react'; +import { ChangeEventHandler } from 'react'; import { Text, Icon } from '@deriv/components'; import clsx from 'clsx'; -import { getAllowedLanguages } from '@deriv/translations'; export type TLanguageRadioButton = { is_current_language: boolean; id: string; - language_code: string; + language_text: string; name: string; - onChange: React.ChangeEventHandler; + onChange: ChangeEventHandler; }; -const LanguageRadioButton = ({ is_current_language, id, language_code, name, onChange }: TLanguageRadioButton) => { - const allowed_languages: Record = getAllowedLanguages(); +const LanguageRadioButton = ({ is_current_language, id, language_text, name, onChange }: TLanguageRadioButton) => { return (
diff --git a/packages/account/src/Components/load-error-message/load-error-message.tsx b/packages/account/src/Components/load-error-message/load-error-message.tsx index 537232847a5e..a6e01f50acaa 100644 --- a/packages/account/src/Components/load-error-message/load-error-message.tsx +++ b/packages/account/src/Components/load-error-message/load-error-message.tsx @@ -1,9 +1,9 @@ -import React from 'react'; +import { ReactNode } from 'react'; import { Icon } from '@deriv/components'; import IconMessageContent from '../icon-message-content'; type TLoadErrorMessage = { - error_message: React.ReactNode; + error_message: ReactNode; }; const LoadErrorMessage = ({ error_message }: TLoadErrorMessage) => ( diff --git a/packages/account/src/Components/personal-details/__tests__/personal-details.spec.jsx b/packages/account/src/Components/personal-details/__tests__/personal-details.spec.tsx similarity index 83% rename from packages/account/src/Components/personal-details/__tests__/personal-details.spec.jsx rename to packages/account/src/Components/personal-details/__tests__/personal-details.spec.tsx index bcac06ea9e94..13fb5b372664 100644 --- a/packages/account/src/Components/personal-details/__tests__/personal-details.spec.jsx +++ b/packages/account/src/Components/personal-details/__tests__/personal-details.spec.tsx @@ -1,15 +1,14 @@ -// [TODO] - Convert this to TypeScript -import React from 'react'; -import ReactDOM from 'react-dom'; +import React, { ComponentProps, ReactNode } from 'react'; import { BrowserRouter } from 'react-router-dom'; import { fireEvent, render, screen, waitFor, within } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import { isDesktop, isMobile } from '@deriv/shared'; import { splitValidationResultTypes } from '../../real-account-signup/helpers/utils'; import PersonalDetails from '../personal-details'; -import { shouldShowIdentityInformation, isDocumentTypeValid, isAdditionalDocumentValid } from 'Helpers/utils'; +import { shouldShowIdentityInformation, isDocumentTypeValid, isAdditionalDocumentValid } from '../../../Helpers/utils'; import { StoreProvider, mockStore } from '@deriv/stores'; import { Analytics } from '@deriv-com/analytics'; +import { FormikErrors } from 'formik'; jest.mock('Assets/ic-poi-name-dob-example.svg', () => jest.fn(() => 'PoiNameDobExampleImage')); @@ -18,6 +17,7 @@ jest.mock('@deriv/components', () => ({ Popover: jest.fn(props => props.is_open && {props.message}), })); +// [TODO] - To be removed when PersonalDetailsForm is migrated to TSX jest.mock('@deriv/shared', () => ({ ...jest.requireActual('@deriv/shared'), isMobile: jest.fn(() => false), @@ -31,6 +31,11 @@ jest.mock('../../real-account-signup/helpers/utils.ts', () => ({ })), })); +jest.mock('react-dom', () => ({ + ...jest.requireActual('react-dom'), + createPortal: (node: ReactNode) => node, +})); + jest.mock('Helpers/utils', () => ({ ...jest.requireActual('Helpers/utils'), isDocumentTypeValid: jest.fn(), @@ -38,8 +43,10 @@ jest.mock('Helpers/utils', () => ({ isAdditionalDocumentValid: jest.fn(), })); +type TPersonalDetailsSectionForm = ComponentProps['value']; + const mock_warnings = {}; -const mock_errors = { +const mock_errors: FormikErrors = { account_opening_reason: 'Account opening reason is required.', salutation: 'Salutation is required.', first_name: 'First name is required.', @@ -57,7 +64,7 @@ const tax_residence_pop_over_text = /the country in which you meet the criteria for paying taxes\. usually the country in which you physically reside\./i; const tin_pop_over_text = /don't know your tax identification number\?/i; -const runCommonFormfieldsTests = is_svg => { +const runCommonFormfieldsTests = (is_svg: boolean) => { expect(screen.getByRole('radio', { name: /mr/i })).toBeInTheDocument(); expect(screen.getByRole('radio', { name: /ms/i })).toBeInTheDocument(); expect(screen.getByTestId('first_name')).toBeInTheDocument(); @@ -92,9 +99,9 @@ const runCommonFormfieldsTests = is_svg => { } const tax_residence_pop_over = screen.queryByTestId('tax_residence_pop_over'); - expect(tax_residence_pop_over).toBeInTheDocument(); - - fireEvent.click(tax_residence_pop_over); + if (tax_residence_pop_over) { + fireEvent.click(tax_residence_pop_over); + } expect(screen.getByText(tax_residence_pop_over_text)).toBeInTheDocument(); @@ -102,7 +109,9 @@ const runCommonFormfieldsTests = is_svg => { const tax_identification_number_pop_over = screen.queryByTestId('tax_identification_number_pop_over'); expect(tax_identification_number_pop_over).toBeInTheDocument(); - fireEvent.click(tax_identification_number_pop_over); + if (tax_identification_number_pop_over) { + fireEvent.click(tax_identification_number_pop_over); + } expect(screen.getByText(tin_pop_over_text)).toBeInTheDocument(); expect(screen.getByRole('link', { name: 'here' })).toBeInTheDocument(); @@ -124,6 +133,7 @@ describe('', () => { document_type: { value: 'national_id', text: 'National ID', + id: '0', }, document_number: '1234567890123', }; @@ -150,16 +160,15 @@ describe('', () => { format: 'A54321', }, }, - has_visual_sample: true, + has_visual_sample: 1 as any, }, }, }, }, ]; - const props = { + const mock_props: ComponentProps = { is_svg: true, - is_high_risk: false, account_opening_reason_list: [ { text: 'Hedging', @@ -190,7 +199,7 @@ describe('', () => { { identity: { services: { - idv: default_IDV_config, + idv: default_IDV_config as any, onfido: { documents_supported: { passport: { @@ -208,7 +217,7 @@ describe('', () => { { identity: { services: { - idv: default_IDV_config, + idv: default_IDV_config as any, onfido: { documents_supported: {}, is_country_supported: 0, @@ -264,46 +273,47 @@ describe('', () => { tax_identification_number: '', tax_identification_confirm: false, }, - index: 1, - has_currency: true, - form_error: '', - bypass_to_personal: false, onSubmit: jest.fn(), getCurrentStep: jest.fn(() => 1), onSave: jest.fn(), onCancel: jest.fn(), account_settings: {}, + goToPreviousStep: jest.fn(), + goToNextStep: jest.fn(), + is_virtual: false, + is_fully_authenticated: false, + has_real_account: false, + account_status: undefined, + residence: '', + real_account_signup_target: '', }; - beforeAll(() => { - ReactDOM.createPortal = jest.fn(component => component); - }); - - afterAll(() => ReactDOM.createPortal.mockClear()); - afterEach(() => { jest.clearAllMocks(); }); - const renderwithRouter = (component, store) => { - const mock_store = mockStore({}); + const mock_store = mockStore({}); + + const renderwithRouter = ({ props = mock_props, store = mock_store }) => { render( - {component} + + + ); }; it('should have called trackEvent on mount', () => { - renderwithRouter(); + renderwithRouter({}); expect(Analytics.trackEvent).toHaveBeenCalledTimes(1); }); it('should have validation errors on form fields', async () => { - isMobile.mockReturnValue(false); - isDesktop.mockReturnValue(true); + const new_props = { ...mock_props, is_svg: false }; + const store_config = mockStore({ ui: { is_desktop: true } }); - renderwithRouter(); + renderwithRouter({ props: new_props, store: store_config }); const first_name = screen.getByTestId('first_name'); const last_name = screen.getByTestId('last_name'); @@ -331,10 +341,10 @@ describe('', () => { expect(await screen.findByText(/phone is required\./i)).toBeInTheDocument(); expect(await screen.findByText(/tax residence is required\./i)).toBeInTheDocument(); expect(await screen.findByText(/tax identification number is required\./i)).toBeInTheDocument(); - splitValidationResultTypes.mockReturnValue({ + (splitValidationResultTypes as jest.Mock).mockReturnValue({ ...mock_warnings, errors: { - ...mock_errors.errors, + ...mock_errors, first_name: 'letters, spaces, periods, hyphens, apostrophes only', last_name: 'Enter no more than 50 characters.', date_of_birth: 'You must be 18 years old and above.', @@ -358,7 +368,7 @@ describe('', () => { it('submit button should be enabled if TIN or tax_residence is optional in case of CR accounts', () => { const new_props = { - ...props, + ...mock_props, is_svg: true, value: { first_name: '', @@ -368,10 +378,9 @@ describe('', () => { phone: '+34', tax_residence: '', tax_identification_number: '', - document_type: 'none', }, }; - renderwithRouter(); + renderwithRouter({ props: new_props }); const first_name = screen.getByTestId('first_name'); const last_name = screen.getByTestId('last_name'); @@ -386,9 +395,9 @@ describe('', () => { }); it('should not display confirmation checkbox if opt-out of IDV', async () => { - splitValidationResultTypes.mockReturnValue({ warnings: {}, errors: {} }); + (splitValidationResultTypes as jest.Mock).mockReturnValue({ warnings: {}, errors: {} }); const new_props = { - ...props, + ...mock_props, value: { first_name: '', last_name: '', @@ -396,11 +405,10 @@ describe('', () => { phone: '+93', account_opening_reason: '', place_of_birth: '', - document_type: 'none', }, }; - renderwithRouter(); + renderwithRouter({ props: new_props }); const first_name = screen.getByTestId('first_name'); const last_name = screen.getByTestId('last_name'); @@ -431,14 +439,14 @@ describe('', () => { it('should autopopulate tax_residence for MF clients', () => { const new_props = { - ...props, + ...mock_props, is_svg: false, value: { - ...props.value, + ...mock_props.value, tax_residence: 'Malta', }, }; - renderwithRouter(); + renderwithRouter({ props: new_props }); expect( screen.getByRole('textbox', { name: /tax residence\*/i, @@ -447,12 +455,13 @@ describe('', () => { }); it('should render PersonalDetails component', () => { - renderwithRouter(); + renderwithRouter({}); expect(screen.getByTestId('personal_details_form')).toBeInTheDocument(); }); it('should show proper salutation message when is_virtual is true', () => { - renderwithRouter(); + const new_props = { ...mock_props, is_virtual: true }; + renderwithRouter({ props: new_props }); expect( screen.getByText( @@ -462,7 +471,7 @@ describe('', () => { }); it('should show proper salutation message when is_virtual is false', () => { - renderwithRouter(); + renderwithRouter({}); expect( screen.getByText( @@ -473,7 +482,23 @@ describe('', () => { fireEvent.click(screen.getByText('account settings')); - expect(props.closeRealAccountSignup).toHaveBeenCalledTimes(1); + expect(mock_props.closeRealAccountSignup).toHaveBeenCalledTimes(1); + }); + + it('should disable tax_residence field if it is immutable from BE', () => { + const new_store = mockStore({ ui: { is_mobile: false, is_desktop: true } }); + + const new_props = { + ...mock_props, + value: { + ...mock_props.value, + ...idv_document_data, + tax_residence: 'France', + }, + disabled_items: ['salutation', 'first_name', 'last_name', 'date_of_birth', 'tax_residence'], + }; + renderwithRouter({ props: new_props, store: new_store }); + expect(screen.getByTestId('tax_residence')).toBeDisabled(); }); it('should show title and Name label when salutation is passed', () => { @@ -482,7 +507,7 @@ describe('', () => { is_eu_user: true, }, }); - renderwithRouter(, mock_store); + renderwithRouter({ store: mock_store }); expect( screen.getByRole('heading', { @@ -492,18 +517,18 @@ describe('', () => { }); it('should show Name label when salutation is not passed', () => { - const newprops = { ...props, value: {} }; - renderwithRouter(); + const newprops = { ...mock_props, value: {} }; + renderwithRouter({ props: newprops }); expect(screen.getByRole('heading', { name: /details/i })).toBeInTheDocument(); expect(screen.queryByRole('heading', { name: /title and name/i })).not.toBeInTheDocument(); }); it('should show salutation options', () => { - renderwithRouter(); + renderwithRouter({}); - const mr_radio_btn = screen.getByRole('radio', { name: /mr/i }); - const mrs_radio_btn = screen.getByRole('radio', { name: /ms/i }); + const mr_radio_btn: HTMLInputElement = screen.getByRole('radio', { name: /mr/i }) as HTMLInputElement; + const mrs_radio_btn: HTMLInputElement = screen.getByRole('radio', { name: /ms/i }) as HTMLInputElement; expect(mr_radio_btn).toBeInTheDocument(); expect(mrs_radio_btn).toBeInTheDocument(); expect(mr_radio_btn.checked).toEqual(false); @@ -515,18 +540,18 @@ describe('', () => { }); it('should display the correct field details ', () => { - renderwithRouter(); + renderwithRouter({}); expect(screen.getByText(/first name\*/i)).toBeInTheDocument(); expect(screen.getByText(/date of birth\*/i)).toBeInTheDocument(); expect(screen.getByText(/phone number\*/i)).toBeInTheDocument(); expect(screen.getByLabelText(/phone number\*/i)).toBeInTheDocument(); - runCommonFormfieldsTests(props.is_svg); + runCommonFormfieldsTests(mock_props.is_svg); }); it('should display the correct field details when is_svg is true ', () => { - renderwithRouter(); + renderwithRouter({}); expect(screen.queryByRole('heading', { name: 'Details' })).toBeInTheDocument(); expect(screen.getByText(/first name\*/i)).toBeInTheDocument(); @@ -534,7 +559,7 @@ describe('', () => { expect(screen.getByText(/date of birth\*/i)).toBeInTheDocument(); expect(screen.getByText(/phone number\*/i)).toBeInTheDocument(); - runCommonFormfieldsTests(props.is_svg); + runCommonFormfieldsTests(mock_props.is_svg); }); it('should display the correct field details when is_svg is false ', () => { @@ -543,7 +568,7 @@ describe('', () => { is_eu_user: true, }, }); - renderwithRouter(, mock_store); + renderwithRouter({ store: mock_store }); expect(screen.getByRole('heading', { name: 'Title and name' })).toBeInTheDocument(); expect(screen.queryByRole('heading', { name: 'name' })).not.toBeInTheDocument(); @@ -558,12 +583,11 @@ describe('', () => { }); it('should not enable fields which are disabled and empty', () => { - renderwithRouter( - - ); + const new_props = { + ...mock_props, + disabled_items: ['salutation', 'first_name', 'last_name', 'date_of_birth', 'account_opening_reason'], + }; + renderwithRouter({ props: new_props }); expect(screen.getByRole('radio', { name: /mr/i })).toBeEnabled(); expect(screen.getByRole('radio', { name: /ms/i })).toBeEnabled(); expect(screen.getByTestId('first_name')).toBeDisabled(); @@ -575,21 +599,26 @@ describe('', () => { it('should disable citizen field if the client is_fully_authenticated', () => { const new_props = { - ...props, + ...mock_props, + is_fully_authenticated: true, value: { - ...props.value, + ...mock_props.value, citizen: 'france', }, }; - renderwithRouter(); + renderwithRouter({ props: new_props }); expect(screen.getByTestId('citizenship')).toBeDisabled(); }); it('should display proper data in mobile mode', () => { - isMobile.mockReturnValue(true); - isDesktop.mockReturnValue(false); - renderwithRouter(); + // [TODO] - Remove this when PersonalDetailsForm is migrated to TSX + (isMobile as jest.Mock).mockReturnValue(true); + (isDesktop as jest.Mock).mockReturnValue(false); + const mock_store = mockStore({ ui: { is_mobile: true, is_desktop: false } }); + const new_props = { ...mock_props, is_svg: false }; + + renderwithRouter({ props: new_props, store: mock_store }); expect(screen.getByRole('radio', { name: /mr/i })).toBeInTheDocument(); expect(screen.getByRole('radio', { name: /ms/i })).toBeInTheDocument(); @@ -613,15 +642,19 @@ describe('', () => { }); it('should select correct dropdown options in mobile mode', () => { - isMobile.mockReturnValue(true); - isDesktop.mockReturnValue(false); + (isMobile as jest.Mock).mockReturnValue(true); + (isDesktop as jest.Mock).mockReturnValue(false); + const mock_store = mockStore({ ui: { is_mobile: true, is_desktop: false } }); + const new_props = { ...mock_props, is_svg: false }; - renderwithRouter(); + renderwithRouter({ props: new_props, store: mock_store }); const place_of_birth_mobile = screen.queryByTestId('place_of_birth_mobile'); expect(place_of_birth_mobile).toBeInTheDocument(); - fireEvent.change(place_of_birth_mobile, { target: { value: 'Afghanistan' } }); + if (place_of_birth_mobile) { + fireEvent.change(place_of_birth_mobile, { target: { value: 'Afghanistan' } }); + } const { getByText } = within(screen.getAllByTestId('selected_value')[0]); expect(getByText('Afghanistan')).toBeInTheDocument(); @@ -634,8 +667,8 @@ describe('', () => { tax_identification_number: 'Tax Identification Number is not properly formatted.', }, }; - splitValidationResultTypes.mockReturnValue(newvalidate); - renderwithRouter(); + (splitValidationResultTypes as jest.Mock).mockReturnValue(newvalidate); + renderwithRouter({}); const tax_identification_number = screen.getByTestId('tax_identification_number'); fireEvent.blur(tax_identification_number); @@ -645,9 +678,9 @@ describe('', () => { }); it('should submit the form if there is no validation error on desktop', async () => { - splitValidationResultTypes.mockReturnValue({ warnings: {}, errors: {} }); + (splitValidationResultTypes as jest.Mock).mockReturnValue({ warnings: {}, errors: {} }); const new_props = { - ...props, + ...mock_props, value: { first_name: '', last_name: '', @@ -656,7 +689,7 @@ describe('', () => { }, }; - renderwithRouter(); + renderwithRouter({ props: new_props }); const first_name = screen.getByTestId('first_name'); const last_name = screen.getByTestId('last_name'); @@ -686,11 +719,13 @@ describe('', () => { }); it('should submit the form if there is no validation error on mobile', async () => { - isMobile.mockReturnValue(true); - isDesktop.mockReturnValue(false); - splitValidationResultTypes.mockReturnValue({ warnings: {}, errors: {} }); + // [TODO] - Remove this when PersonalDetailsForm is migrated to TSX + (isMobile as jest.Mock).mockReturnValue(true); + (isDesktop as jest.Mock).mockReturnValue(false); + + (splitValidationResultTypes as jest.Mock).mockReturnValue({ warnings: {}, errors: {} }); const new_props = { - ...props, + ...mock_props, is_svg: false, value: { account_opening_reason: '', @@ -707,9 +742,9 @@ describe('', () => { }, }; - renderwithRouter(); + renderwithRouter({ props: new_props }); - const mr_radio_btn = screen.getByRole('radio', { name: /mr/i }); + const mr_radio_btn = screen.getByRole('radio', { name: /mr/i }) as HTMLInputElement; const first_name = screen.getByTestId('first_name'); const last_name = screen.getByTestId('last_name'); const date_of_birth = screen.getByTestId('date_of_birth'); @@ -750,16 +785,16 @@ describe('', () => { }); it('should save filled date when cancel button is clicked ', async () => { - splitValidationResultTypes.mockReturnValue({ warnings: {}, errors: {} }); + (splitValidationResultTypes as jest.Mock).mockReturnValue({ warnings: {}, errors: {} }); const new_props = { - ...props, + ...mock_props, value: { first_name: '', last_name: '', }, }; - renderwithRouter(); + renderwithRouter({ props: new_props }); const first_name = screen.getByTestId('first_name'); const last_name = screen.getByTestId('last_name'); @@ -772,12 +807,13 @@ describe('', () => { fireEvent.click(previous_btn); await waitFor(() => { - expect(props.onSave).toBeCalledWith(0, { first_name: 'test firstname', last_name: 'test lastname' }); + expect(mock_props.onSave).toBeCalledWith(0, { first_name: 'test firstname', last_name: 'test lastname' }); }); }); it('should close tax_residence pop-over when clicked outside', () => { - renderwithRouter(); + const new_props = { ...mock_props, is_svg: false }; + renderwithRouter({ props: new_props }); const tax_residence_pop_over = screen.getByTestId('tax_residence_pop_over'); expect(tax_residence_pop_over).toBeInTheDocument(); @@ -791,7 +827,8 @@ describe('', () => { }); it('should close tax_identification_number_pop_over when clicked outside', () => { - renderwithRouter(); + const new_props = { ...mock_props, is_svg: false }; + renderwithRouter({ props: new_props }); const tin_pop_over = screen.getByTestId('tax_identification_number_pop_over'); expect(tin_pop_over).toBeInTheDocument(); @@ -807,7 +844,7 @@ describe('', () => { }); it('should close tax_residence pop-over when scrolled', () => { - renderwithRouter(); + renderwithRouter({}); const tax_residence_pop_over = screen.getByTestId('tax_residence_pop_over'); expect(tax_residence_pop_over).toBeInTheDocument(); @@ -823,7 +860,7 @@ describe('', () => { }); it('should close tax_identification_number_pop_over when scrolled', () => { - renderwithRouter(); + renderwithRouter({}); const tax_identification_number_pop_over = screen.getByTestId('tax_identification_number_pop_over'); expect(tax_identification_number_pop_over).toBeInTheDocument(); @@ -840,16 +877,16 @@ describe('', () => { }); it('should validate idv values when a document type is selected', async () => { - shouldShowIdentityInformation.mockReturnValue(true); + (shouldShowIdentityInformation as jest.Mock).mockReturnValue(true); const new_props = { - ...props, + ...mock_props, value: { - ...props.value, + ...mock_props.value, ...idv_document_data, }, - residence_list: default_residence_details, + residence_list: default_residence_details as any, }; - renderwithRouter(); + renderwithRouter({ props: new_props }); await waitFor(() => { expect(isDocumentTypeValid).toHaveBeenCalled(); @@ -858,41 +895,30 @@ describe('', () => { }); it('should validate idv values along with additional document number when a document type is selected', async () => { - shouldShowIdentityInformation.mockReturnValue(true); + (shouldShowIdentityInformation as jest.Mock).mockReturnValue(true); const new_document_data = { ...idv_document_data, - document_type: { ...idv_document_data.document_type, additional: '12345' }, + document_type: { + ...idv_document_data.document_type, + additional: { + display_name: '12345', + }, + }, }; const new_props = { - ...props, + ...mock_props, value: { - ...props.value, + ...mock_props.value, ...new_document_data, }, residence_list: default_residence_details, }; - renderwithRouter(); + renderwithRouter({ props: new_props }); await waitFor(() => { expect(isAdditionalDocumentValid).toHaveBeenCalled(); }); }); - - it('should disable tax_residence field if it is immutable from BE', () => { - isMobile.mockReturnValue(false); - isDesktop.mockReturnValue(true); - const new_props = { - ...props, - value: { - ...props.value, - tax_residence: 'France', - document_type: idv_document_data, - }, - disabled_items: ['salutation', 'first_name', 'last_name', 'date_of_birth', 'tax_residence'], - }; - renderwithRouter(); - expect(screen.getByTestId('tax_residence')).toBeDisabled(); - }); }); diff --git a/packages/account/src/Components/personal-details/index.ts b/packages/account/src/Components/personal-details/index.ts index 35f9409b788f..04fb7e635663 100644 --- a/packages/account/src/Components/personal-details/index.ts +++ b/packages/account/src/Components/personal-details/index.ts @@ -1,3 +1,3 @@ -import PersonalDetails from './personal-details.jsx'; +import PersonalDetails from './personal-details'; export default PersonalDetails; diff --git a/packages/account/src/Components/personal-details/personal-details.jsx b/packages/account/src/Components/personal-details/personal-details.tsx similarity index 74% rename from packages/account/src/Components/personal-details/personal-details.jsx rename to packages/account/src/Components/personal-details/personal-details.tsx index 7f2f266f59d7..4d578a6271c2 100644 --- a/packages/account/src/Components/personal-details/personal-details.jsx +++ b/packages/account/src/Components/personal-details/personal-details.tsx @@ -1,11 +1,9 @@ -// [TODO] - Convert this to TypeScript - -import React, { useState, Fragment, useCallback, useMemo, useEffect } from 'react'; +import { useState, Fragment, useCallback, useMemo, useEffect } from 'react'; import clsx from 'clsx'; -import { Form, Formik } from 'formik'; -import { Analytics } from '@deriv-com/analytics'; +import { Form, Formik, FormikErrors } from 'formik'; +import { Analytics, TEvents } from '@deriv-com/analytics'; import { AutoHeightWrapper, Div100vhContainer, FormSubmitButton, Modal, ThemedScrollbars } from '@deriv/components'; -import { getIDVNotApplicableOption, isDesktop, isMobile, removeEmptyPropertiesFromObject } from '@deriv/shared'; +import { getIDVNotApplicableOption, removeEmptyPropertiesFromObject } from '@deriv/shared'; import { Localize, localize } from '@deriv/translations'; import { useStore, observer } from '@deriv/stores'; import { @@ -14,12 +12,49 @@ import { isDocumentTypeValid, shouldShowIdentityInformation, } from '../../Helpers/utils'; -import PoiNameDobExample from '../../Assets/ic-poi-name-dob-example.svg'; +import { DerivLightNameDobPoiIcon } from '@deriv/quill-icons'; import FormSubHeader from '../form-sub-header'; import IDVForm from '../forms/idv-form'; import PersonalDetailsForm from '../forms/personal-details-form'; import { splitValidationResultTypes } from '../real-account-signup/helpers/utils'; import ScrollToFieldWithError from '../forms/scroll-to-field-with-error'; +import { TIDVFormValues, TListItem, TPersonalDetailsBaseForm } from '../../Types'; +import { GetAccountStatus, GetSettings, ResidenceList } from '@deriv/api-types'; + +type TPersonalDetailsSectionForm = Partial & { + confirmation_checkbox?: boolean; +}; + +type TPersonalDetailProps = { + getCurrentStep: () => number; + onSave: (current_step: number, values: TPersonalDetailsSectionForm) => void; + onCancel: (current_step: number, goToPreviousStep: () => void) => void; + onSubmit: ( + current_step: number, + values: TPersonalDetailsSectionForm, + setSubmitting: (is_submitting: boolean) => void, + goToNextStep: () => void + ) => void; + goToPreviousStep: () => void; + goToNextStep: () => void; + validate: (values: TPersonalDetailsSectionForm) => TPersonalDetailsSectionForm; + salutation_list: { label: string; value: string }[]; + disabled_items: string[]; + is_svg: boolean; + residence_list: ResidenceList; + is_virtual: boolean; + is_fully_authenticated: boolean; + account_opening_reason_list: TListItem[]; + closeRealAccountSignup: () => void; + has_real_account: boolean; + account_status?: GetAccountStatus; + account_settings: GetSettings; + residence: string; + real_account_signup_target: string; + value: TPersonalDetailsSectionForm; +}; + +type TrackEvent = TEvents['ce_real_account_signup_identity_form']; const PersonalDetails = observer( ({ @@ -39,18 +74,18 @@ const PersonalDetails = observer( account_opening_reason_list, closeRealAccountSignup, has_real_account, + value, ...props - }) => { + }: TPersonalDetailProps) => { const { traders_hub: { is_eu_user }, + ui: { is_mobile, is_desktop }, } = useStore(); const { account_status, account_settings, residence, real_account_signup_target } = props; const [should_close_tooltip, setShouldCloseTooltip] = useState(false); const [no_confirmation_needed, setNoConfirmationNeeded] = useState(false); - const PoiNameDobExampleIcon = PoiNameDobExample; - - const handleCancel = values => { + const handleCancel = (values: TPersonalDetailsSectionForm) => { const current_step = getCurrentStep() - 1; onSave(current_step, values); onCancel(current_step, goToPreviousStep); @@ -58,7 +93,7 @@ const PersonalDetails = observer( const citizen = residence || account_settings?.citizen; const trackEvent = useCallback( - payload => { + (payload: TrackEvent) => { if (is_eu_user) return; Analytics.trackEvent('ce_real_account_signup_identity_form', { ...payload, @@ -83,22 +118,23 @@ const PersonalDetails = observer( //is_rendered_for_idv is used for configuring the components when they are used in idv page const is_rendered_for_idv = shouldShowIdentityInformation({ - account_status, - citizen, + account_status: account_status as GetAccountStatus, + citizen: citizen as string, residence_list, real_account_signup_target, }); const IDV_NOT_APPLICABLE_OPTION = useMemo(() => getIDVNotApplicableOption(), []); - const validateIDV = values => { - const errors = {}; + const validateIDV = (values: TPersonalDetailsSectionForm) => { + const errors: FormikErrors = {}; const { document_type, document_number, document_additional } = values; - if (document_type.id === IDV_NOT_APPLICABLE_OPTION.id) return errors; - + if (document_type?.id === IDV_NOT_APPLICABLE_OPTION.id) return errors; + /* eslint-disable @typescript-eslint/ban-ts-comment */ + // @ts-expect-error Error is tring but Formik value was an object errors.document_type = isDocumentTypeValid(document_type); - const needs_additional_document = !!document_type.additional; + const needs_additional_document = !!document_type?.additional; if (needs_additional_document) { errors.document_additional = isAdditionalDocumentValid(document_type, document_additional); @@ -106,13 +142,13 @@ const PersonalDetails = observer( errors.document_number = isDocumentNumberValid(document_number, document_type); - if (document_type.id !== IDV_NOT_APPLICABLE_OPTION.id && !values.confirmation_checkbox) { + if (document_type?.id !== IDV_NOT_APPLICABLE_OPTION.id && !values?.confirmation_checkbox) { errors.confirmation_checkbox = 'error'; } return removeEmptyPropertiesFromObject(errors); }; - const handleValidate = values => { + const handleValidate = (values: TPersonalDetailsSectionForm) => { const current_step = getCurrentStep() - 1; onSave(current_step, values); @@ -136,8 +172,8 @@ const PersonalDetails = observer( const selected_country = residence_list.find(residence_data => residence_data.value === citizen) || {}; - const getEditableFields = (is_confirmed, selected_document_type_id) => { - const editable_fields = Object.keys(props.value).filter(field => !disabled_items.includes(field)) || []; + const getEditableFields = (is_confirmed = false, selected_document_type_id?: string) => { + const editable_fields = Object.keys(value).filter(field => !disabled_items.includes(field)) || []; if (IDV_NOT_APPLICABLE_OPTION.id === selected_document_type_id) return editable_fields; @@ -150,7 +186,7 @@ const PersonalDetails = observer( return ( { @@ -162,7 +198,7 @@ const PersonalDetails = observer( }} > {({ handleSubmit, isSubmitting, values }) => ( - + {({ setRef, height }) => (
-
+
{is_rendered_for_idv && ( @@ -212,10 +245,10 @@ const PersonalDetails = observer( is_virtual={is_virtual} is_svg={is_svg} is_eu_user={is_eu_user} - side_note={} + side_note={} is_rendered_for_idv={is_rendered_for_idv} editable_fields={getEditableFields( - values.confirmation_checkbox, + values?.confirmation_checkbox, values?.document_type?.id )} residence_list={residence_list} @@ -237,12 +270,12 @@ const PersonalDetails = observer(
- + handleCancel(values)} /> diff --git a/packages/account/src/Components/poa-address-mismatch-hint-box/poa-address-mismatch-hint-box.scss b/packages/account/src/Components/poa-address-mismatch-hint-box/poa-address-mismatch-hint-box.scss index 78e06f14d253..08cc253a19b5 100644 --- a/packages/account/src/Components/poa-address-mismatch-hint-box/poa-address-mismatch-hint-box.scss +++ b/packages/account/src/Components/poa-address-mismatch-hint-box/poa-address-mismatch-hint-box.scss @@ -1,13 +1,5 @@ .poa-address-mismatch-hint-box { &--wrapper { - .dc-hint-box { - align-items: start; - max-width: 40rem; - - &__icon { - min-width: 1.6rem; - min-height: 1.6rem; - } - } + max-width: 40rem; } } diff --git a/packages/account/src/Components/poa-address-mismatch-hint-box/poa-address-mismatch-hint-box.tsx b/packages/account/src/Components/poa-address-mismatch-hint-box/poa-address-mismatch-hint-box.tsx index fc9e6e17918d..ca203e61dda2 100644 --- a/packages/account/src/Components/poa-address-mismatch-hint-box/poa-address-mismatch-hint-box.tsx +++ b/packages/account/src/Components/poa-address-mismatch-hint-box/poa-address-mismatch-hint-box.tsx @@ -1,30 +1,24 @@ -import React from 'react'; -import { Text, HintBox } from '@deriv/components'; +import { useRef, useEffect } from 'react'; +import { InlineMessage } from '@deriv/components'; import { Localize } from '@deriv/translations'; import './poa-address-mismatch-hint-box.scss'; const POAAddressMismatchHintBox = () => { - const ref = React.useRef(null); + const ref = useRef(null); - React.useEffect(() => { + useEffect(() => { // To make scrolling work on mobile we need to add a delay. setTimeout(() => ref?.current?.scrollIntoView(), 0); }, []); return (
- - - + } - is_warn />
); diff --git a/packages/account/src/Components/poi/idv-document-submit/idv-document-submit.tsx b/packages/account/src/Components/poi/idv-document-submit/idv-document-submit.tsx index a0bbc2f32559..a790a42c35c0 100644 --- a/packages/account/src/Components/poi/idv-document-submit/idv-document-submit.tsx +++ b/packages/account/src/Components/poi/idv-document-submit/idv-document-submit.tsx @@ -33,7 +33,7 @@ import { DUPLICATE_ACCOUNT_ERROR_MESSAGE, GENERIC_ERROR_MESSAGE, } from '../../../Configs/poi-error-config'; -import { TIDVFormValues, TPersonalDetailsForm } from 'Types'; +import { TIDVFormValues, TConfirmPersonalDetailsForm } from 'Types'; import { API_ERROR_CODES } from '../../../Constants/api-error-codes'; type TIDVDocumentSubmitProps = { @@ -44,7 +44,7 @@ type TIDVDocumentSubmitProps = { handleSelectionNext?: (should_show_manual: boolean) => void; }; -export type TIdvDocumentSubmitForm = TIDVFormValues & TPersonalDetailsForm & { confirmation_checkbox: boolean }; +export type TIdvDocumentSubmitForm = TIDVFormValues & TConfirmPersonalDetailsForm; const IdvDocumentSubmit = observer( ({ handleBack, handleViewComplete, handleSelectionNext, selected_country }: TIDVDocumentSubmitProps) => { @@ -58,7 +58,7 @@ const IdvDocumentSubmit = observer( const side_note_image = ; const form_initial_values = filterObjProperties(account_settings, visible_settings) as { - [Property in keyof TPersonalDetailsForm]: string; + [Property in keyof TConfirmPersonalDetailsForm]: string; }; if (form_initial_values.date_of_birth) { diff --git a/packages/account/src/Components/poi/idv-status/idv-failed/idv-failed.tsx b/packages/account/src/Components/poi/idv-status/idv-failed/idv-failed.tsx index 9e0f10417c50..d7a6a79d602e 100644 --- a/packages/account/src/Components/poi/idv-status/idv-failed/idv-failed.tsx +++ b/packages/account/src/Components/poi/idv-status/idv-failed/idv-failed.tsx @@ -37,7 +37,7 @@ import { generateIDVError, } from '../../../../Configs/poi-error-config'; import { API_ERROR_CODES } from '../../../../Constants/api-error-codes'; -import { TIDVFormValues, TPersonalDetailsForm } from '../../../../Types'; +import { TIDVFormValues, TConfirmPersonalDetailsForm } from '../../../../Types'; import LoadErrorMessage from '../../../load-error-message'; import { TIdvDocumentSubmitForm } from '../../idv-document-submit/idv-document-submit'; @@ -67,7 +67,7 @@ type TIDVFailureConfig = { inline_note_text: React.ReactNode; }; -type TIdvFailedForm = Partial & Partial; +type TIdvFailedForm = Partial & Partial; const IdvFailed = ({ getChangeableFields, diff --git a/packages/account/src/Components/poi/poi-form-on-signup/idv-doc-submit-on-signup/idv-doc-submit-on-signup.tsx b/packages/account/src/Components/poi/poi-form-on-signup/idv-doc-submit-on-signup/idv-doc-submit-on-signup.tsx index bd7a62c84fb4..3825fc721eb5 100644 --- a/packages/account/src/Components/poi/poi-form-on-signup/idv-doc-submit-on-signup/idv-doc-submit-on-signup.tsx +++ b/packages/account/src/Components/poi/poi-form-on-signup/idv-doc-submit-on-signup/idv-doc-submit-on-signup.tsx @@ -22,7 +22,7 @@ import { validate, validateName, } from '../../../../Helpers/utils'; -import { TIDVFormValues, TPersonalDetailsForm } from '../../../../Types'; +import { TIDVFormValues, TConfirmPersonalDetailsForm } from '../../../../Types'; type TIdvDocSubmitOnSignup = { citizen_data: FormikValues; @@ -34,7 +34,7 @@ type TIdvDocSubmitOnSignup = { residence_list: ResidenceList; }; -type TIDVDocFormType = TIDVFormValues & TPersonalDetailsForm; +type TIDVDocFormType = TIDVFormValues & TConfirmPersonalDetailsForm; export const IdvDocSubmitOnSignup = ({ citizen_data, diff --git a/packages/account/src/Helpers/utils.tsx b/packages/account/src/Helpers/utils.tsx index 659febd6db60..70147b7f7faf 100644 --- a/packages/account/src/Helpers/utils.tsx +++ b/packages/account/src/Helpers/utils.tsx @@ -162,9 +162,9 @@ export const isAdditionalDocumentValid = (document_type: FormikValues, additiona return undefined; }; -export const isDocumentNumberValid = (document_number: string, document_type: FormikValues) => { - const is_document_number_invalid = document_number === document_type.example_format; - if (!document_number && document_type.text) { +export const isDocumentNumberValid = (document_number?: string, document_type?: FormikValues) => { + const is_document_number_invalid = document_number === document_type?.example_format; + if (!document_number && document_type?.text) { let document_name = ''; const example_format = getExampleFormat(document_type.example_format); switch (document_type.id) { @@ -185,9 +185,9 @@ export const isDocumentNumberValid = (document_number: string, document_type: Fo } else if (is_document_number_invalid) { return localize('Please enter a valid ID number.'); } - const format_regex = getRegex(document_type.value); - if (!format_regex.test(document_number)) { - return localize('Please enter the correct format. ') + getExampleFormat(document_type.example_format); + const format_regex = getRegex(document_type?.value); + if (document_number && !format_regex.test(document_number)) { + return localize('Please enter the correct format. ') + getExampleFormat(document_type?.example_format); } return undefined; }; diff --git a/packages/account/src/Sections/Profile/LanguageSettings/__tests__/language-settings.spec.tsx b/packages/account/src/Sections/Profile/LanguageSettings/__tests__/language-settings.spec.tsx index f5c0decdf646..2a936cbe9b04 100644 --- a/packages/account/src/Sections/Profile/LanguageSettings/__tests__/language-settings.spec.tsx +++ b/packages/account/src/Sections/Profile/LanguageSettings/__tests__/language-settings.spec.tsx @@ -1,3 +1,4 @@ +import React from 'react'; import { screen, render } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import { routes } from '@deriv/shared'; diff --git a/packages/account/src/Sections/Profile/LanguageSettings/language-settings.tsx b/packages/account/src/Sections/Profile/LanguageSettings/language-settings.tsx index 7259eeea8263..2fcf9d1ca569 100644 --- a/packages/account/src/Sections/Profile/LanguageSettings/language-settings.tsx +++ b/packages/account/src/Sections/Profile/LanguageSettings/language-settings.tsx @@ -15,17 +15,17 @@ const LanguageSettings = observer(() => { return ; } - const allowed_language_keys: string[] = Object.keys(getAllowedLanguages()); + const allowed_languages: Record = getAllowedLanguages(); return (
- {allowed_language_keys.map(language_key => { + {Object.entries(allowed_languages).map(([language_key, value]) => { return ( { 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 69f035afdedc..5785300dafe2 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 @@ -1,3 +1,4 @@ +import React from 'react'; import { cleanup, render, waitFor, screen } from '@testing-library/react'; import { createBrowserHistory } from 'history'; import { Router } from 'react-router'; diff --git a/packages/account/src/Sections/Profile/PersonalDetails/input-group.tsx b/packages/account/src/Sections/Profile/PersonalDetails/input-group.tsx index 4399aa48e7c5..71b65bdad568 100644 --- a/packages/account/src/Sections/Profile/PersonalDetails/input-group.tsx +++ b/packages/account/src/Sections/Profile/PersonalDetails/input-group.tsx @@ -1,10 +1,10 @@ -import React from 'react'; +import { PropsWithChildren } from 'react'; type TInputGroup = { className?: string; }; -const InputGroup = ({ children, className }: React.PropsWithChildren) => ( +const InputGroup = ({ children, className }: PropsWithChildren) => (
{children}
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 5bf889cd72f1..5a791480740a 100644 --- a/packages/account/src/Sections/Profile/PersonalDetails/personal-details-form.tsx +++ b/packages/account/src/Sections/Profile/PersonalDetails/personal-details-form.tsx @@ -1,8 +1,7 @@ import { useState, useRef, useEffect, Fragment } from 'react'; import clsx from 'clsx'; import { Formik, Form, FormikHelpers } from 'formik'; -import { BrowserHistory } from 'history'; -import { withRouter } from 'react-router'; +import { RouteComponentProps, withRouter } from 'react-router'; import { Button, Checkbox, @@ -34,13 +33,10 @@ import FormSelectField from 'Components/forms/form-select-field'; type TRestState = { show_form: boolean; - errors?: boolean; api_error?: string; - changeable_fields?: string[]; - form_initial_values?: Record; }; -export const PersonalDetailsForm = observer(({ history }: { history: BrowserHistory }) => { +export const PersonalDetailsForm = observer(({ history }: Partial) => { const [is_loading, setIsLoading] = useState(true); const [is_state_loading, setIsStateLoading] = useState(false); const [is_btn_loading, setIsBtnLoading] = useState(false); @@ -78,7 +74,6 @@ export const PersonalDetailsForm = observer(({ history }: { history: BrowserHist const has_poa_address_mismatch = account_status?.status?.includes('poa_address_mismatch'); const [rest_state, setRestState] = useState({ show_form: true, - form_initial_values: {}, }); const notification_timeout = useRef(); @@ -138,12 +133,11 @@ export const PersonalDetailsForm = observer(({ history }: { history: BrowserHist // force request to update settings cache since settings have been updated const response = await WS.authorized.storage.getSettings(); if (response.error) { - setRestState({ ...rest_state, api_error: response.error.message }); + setRestState(prev_state => ({ ...prev_state, api_error: response.error.message })); return; } // Fetches the status of the account after update updateAccountStatus(); - setRestState({ ...rest_state, ...response.get_settings }); setIsLoading(false); refreshNotifications(); setIsBtnLoading(false); @@ -202,7 +196,7 @@ export const PersonalDetailsForm = observer(({ history }: { history: BrowserHist const is_account_verified = is_poa_verified && is_poi_verified; - //Generate Redirection Link to user based on verifiction status + //Generate Redirection Link to user based on verification status const getRedirectionLink = () => { if (!is_poi_verified) { return '/account/proof-of-identity'; diff --git a/packages/account/src/Types/common.type.ts b/packages/account/src/Types/common.type.ts index f783df55b213..c0969879c612 100644 --- a/packages/account/src/Types/common.type.ts +++ b/packages/account/src/Types/common.type.ts @@ -111,11 +111,25 @@ export type TPOIStatus = { is_manual_upload?: boolean; }; -export type TPersonalDetailsForm = { +export type TConfirmPersonalDetailsForm = Pick< + TPersonalDetailsBaseForm, + 'first_name' | 'last_name' | 'date_of_birth' +> & { + confirmation_checkbox?: boolean; +}; + +export type TPersonalDetailsBaseForm = { first_name: string; last_name: string; date_of_birth: string; - confirmation_checkbox?: boolean; + account_opening_reason: string; + salutation: string; + phone: string; + tax_residence: string; + tax_identification_number: string; + tax_identification_confirm: boolean; + place_of_birth: string; + citizen: string; }; export type TInputFieldValues = Record; diff --git a/packages/core/src/sass/account-wizard.scss b/packages/core/src/sass/account-wizard.scss index c5bfc2c6e652..d8582307dc2a 100644 --- a/packages/core/src/sass/account-wizard.scss +++ b/packages/core/src/sass/account-wizard.scss @@ -805,6 +805,9 @@ width: 0; height: 0; } + @include desktop { + padding-bottom: unset; + } } .wizard__main-step {