Skip to content

Commit

Permalink
Likhith/kyc 274/add missing example formats for idv countries (deriv-…
Browse files Browse the repository at this point in the history
…com#9349)

* fix: 🐛 translation of IDV documents dropdown option

* fix: 🐛 translation of default config

* fix: 🐛 translation of default config

* fix: 🐛 removed unused-import

* fix: 🐛 refactored code

* fix: ♻️ incorporated review comments

* feat: ✨ added example formats for IDV docs

* feat: ✨ added new text as requested by compliance

* fix: ♻️ incorporated review comments

* fix: country selector change language and fetch residence list (#46)

* fix: country selector change language and fetch residence list

* fix: residence list call for mt5

* fix: autocomplete not_found issue, loading poi page directly issue

* refactor: avoid double call for fetching residence

* refactor: current_language removed from deps

* refactor: remove undefinied prop

* fix: failing tests

* fix: failing tests

---------

Co-authored-by: “yauheni-kryzhyk-deriv” <“yauheni@deriv.me”>

* refactor: remove commented code

* fix: wrong import

* refactor: ♻️ incorporated review comments

* fix: failing testcase

* fix: ts any rreplace

* fix: resolved path issues

* fix: translation issue with No results found text in dropdowns

* fix: translation issue with No results found text in dropdowns

* fix: Country selecror in mobile

* fix: Country selecror in mobile

* fix: wrong file import name

---------

Co-authored-by: yauheni-deriv <103182683+yauheni-deriv@users.noreply.github.com>
Co-authored-by: “yauheni-kryzhyk-deriv” <“yauheni@deriv.me”>
  • Loading branch information
3 people authored Sep 15, 2023
1 parent d99ad25 commit a86a1b3
Show file tree
Hide file tree
Showing 42 changed files with 736 additions and 717 deletions.
21 changes: 13 additions & 8 deletions packages/account/src/Components/forms/idv-form.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,13 @@ import { Field, FieldProps } from 'formik';
import { localize } from '@deriv/translations';
import { formatInput, getIDVNotApplicableOption } from '@deriv/shared';
import { Autocomplete, DesktopWrapper, Input, MobileWrapper, SelectNative, Text } from '@deriv/components';
import { getDocumentData, preventEmptyClipboardPaste, generatePlaceholderText, getExampleFormat } from 'Helpers/utils';
import { TDocumentList, TIDVForm } from 'Types';
import {
getDocumentData,
preventEmptyClipboardPaste,
generatePlaceholderText,
getExampleFormat,
} from '../../Helpers/utils';
import { TDocument, TIDVForm } from 'Types';

const IDVForm = ({
errors,
Expand All @@ -19,7 +24,7 @@ const IDVForm = ({
hide_hint,
can_skip_document_verification = false,
}: TIDVForm) => {
const [document_list, setDocumentList] = React.useState<TDocumentList[]>([]);
const [document_list, setDocumentList] = React.useState<TDocument[]>([]);
const [document_image, setDocumentImage] = React.useState<string | null>(null);
const [selected_doc, setSelectedDoc] = React.useState('');

Expand All @@ -45,10 +50,8 @@ const IDVForm = ({

const new_document_list = filtered_documents.map(key => {
const { display_name, format } = document_data[key];
const { new_display_name, example_format, sample_image } = getDocumentData(
selected_country.value ?? '',
key
);
const { new_display_name, example_format, sample_image, additional_document_example_format } =
getDocumentData(selected_country.value ?? '', key);
const needs_additional_document = !!document_data[key].additional;

if (needs_additional_document) {
Expand All @@ -58,6 +61,7 @@ const IDVForm = ({
additional: {
display_name: document_data[key].additional?.display_name,
format: document_data[key].additional?.format,
example_format: additional_document_example_format,
},
value: format,
sample_image,
Expand Down Expand Up @@ -98,7 +102,7 @@ const IDVForm = ({
setFieldValue(document_name, current_input, true);
};

const bindDocumentData = (item: TDocumentList) => {
const bindDocumentData = (item: TDocument) => {
setFieldValue('document_type', item, true);
setSelectedDoc(item?.id);
if (item?.id === IDV_NOT_APPLICABLE_OPTION.id) {
Expand Down Expand Up @@ -221,6 +225,7 @@ const IDVForm = ({
onKeyUp={(e: { target: HTMLInputElement }) =>
onKeyUp(e, 'document_number')
}
className='additional-field'
required
label={generatePlaceholderText(selected_doc)}
/>
Expand Down
10 changes: 5 additions & 5 deletions packages/account/src/Components/forms/personal-details-form.jsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React from 'react';
import { Link } from 'react-router-dom';
import classNames from 'classnames';
import { Field, useFormikContext } from 'formik';
import { Link } from 'react-router-dom';
import {
Autocomplete,
Checkbox,
Expand All @@ -15,13 +15,13 @@ import {
} from '@deriv/components';
import { getLegalEntityName, isDesktop, isMobile, routes, validPhone } from '@deriv/shared';
import { Localize, localize } from '@deriv/translations';
import InlineNoteWithIcon from '../inline-note-with-icon';
import { DateOfBirthField, FormInputField } from './form-fields.jsx';
import FormBodySection from '../form-body-section';
import FormSubHeader from '../form-sub-header';
import PoiNameDobExample from '../../Assets/ic-poi-name-dob-example.svg';
import { isFieldImmutable } from '../../Helpers/utils';
import InlineNoteWithIcon from '../inline-note-with-icon';
import FormBodySection from '../form-body-section';
import { DateOfBirthField, FormInputField } from './form-fields.jsx';
import { getEmploymentStatusList } from '../../Sections/Assessment/FinancialAssessment/financial-information-list';
import { isFieldImmutable } from '../../Helpers/utils';

const PersonalDetailsForm = props => {
const {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { createBrowserHistory } from 'history';
import { Router } from 'react-router';
import { fireEvent, render, screen } from '@testing-library/react';
import { routes } from '@deriv/shared';
import { PoaButton } from '../poa-button';
import PoaButton from '../poa-button';

describe('<PoaButton/>', () => {
const history = createBrowserHistory();
Expand Down
2 changes: 1 addition & 1 deletion packages/account/src/Components/poa/poa-button/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
import { PoaButton } from './poa-button';
import PoaButton from './poa-button';

export default PoaButton;
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,12 @@ type TPoaButton = {
custom_text?: string;
};

export const PoaButton = ({ custom_text = localize('Submit proof of address') }: TPoaButton) => (
const PoaButton = ({ custom_text = localize('Submit proof of address') }: TPoaButton) => (
<ButtonLink className='account-management__button' to={routes.proof_of_address}>
<Text className='dc-btn__text' as='p' weight='bold' data-testid='poa_button_text'>
{custom_text}
</Text>
</ButtonLink>
);

export default PoaButton;
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React from 'react';
import { Icon } from '@deriv/components';
import { localize } from '@deriv/translations';
import IconMessageContent from 'Components/icon-message-content';
import IconMessageContent from '../icon-message-content';

type TUnsupportedFailed = {
error?: string;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,21 @@ import {
removeEmptyPropertiesFromObject,
formatIDVFormValues,
} from '@deriv/shared';
import { documentAdditionalError, getRegex, validate, makeSettingsRequest, validateName } from 'Helpers/utils';
import {
documentAdditionalError,
getRegex,
validate,
makeSettingsRequest,
validateName,
getExampleFormat,
} from 'Helpers/utils';
import FormFooter from 'Components/form-footer';
import BackButtonIcon from 'Assets/ic-poi-back-btn.svg';
import IDVForm from 'Components/forms/idv-form';
import PersonalDetailsForm from 'Components/forms/personal-details-form';
import FormSubHeader from 'Components/form-sub-header';
import { GetSettings, IdentityVerificationAddDocumentResponse, ResidenceList } from '@deriv/api-types';
import { TIDVFormValues, TInputFieldValues, TDocumentList } from 'Types';
import { GetSettings, ResidenceList, IdentityVerificationAddDocumentResponse } from '@deriv/api-types';
import { TDocument, TInputFieldValues, TIDVFormValues } from 'Types';

type TIDVDocumentSubmitProps = {
account_settings: GetSettings;
Expand Down Expand Up @@ -58,29 +65,26 @@ const IdvDocumentSubmit = ({
...form_initial_values,
};

const getExampleFormat = (example_format: string) => {
return example_format ? localize('Example: ') + example_format : '';
};
const IDV_NOT_APPLICABLE_OPTION = React.useMemo(() => getIDVNotApplicableOption(), []);

const shouldHideHelperImage = (document_id: string) => document_id === IDV_NOT_APPLICABLE_OPTION.id;

const isDocumentTypeValid = (document_type: TDocumentList) => {
const isDocumentTypeValid = (document_type: TDocument) => {
if (!document_type?.text) {
return localize('Please select a document type.');
}
return undefined;
};

const isAdditionalDocumentValid = (document_type: TDocumentList, document_additional: string) => {
const isAdditionalDocumentValid = (document_type: TDocument, document_additional: string) => {
const error_message = documentAdditionalError(document_additional, document_type.additional?.format);
if (error_message) {
return localize(error_message) + getExampleFormat(document_type.additional?.example_format);
}
return undefined;
};

const isDocumentNumberValid = (document_number: string, document_type: Required<TDocumentList>) => {
const isDocumentNumberValid = (document_number: string, document_type: Required<TDocument>) => {
const is_document_number_invalid = document_number === document_type.example_format;
if (!document_number) {
return localize('Please enter your document number. ') + getExampleFormat(document_type.example_format);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { BrowserRouter } from 'react-router-dom';
import { render, screen } from '@testing-library/react';
import IdvSubmitComplete from '../idv-submit-complete';

jest.mock('Assets/ic-idv-document-pending.svg', () => jest.fn(() => 'IdvDocumentPending'));
jest.mock('../../../../../Assets/ic-idv-document-pending.svg', () => jest.fn(() => 'IdvDocumentPending'));

describe('<IdvSubmitComplete/>', () => {
const mock_props = {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import IdvDocumentPending from 'Assets/ic-idv-document-pending.svg';
import PoaButton from 'Components/poa/poa-button';
import IdvDocumentPending from '../../../../Assets/ic-idv-document-pending.svg';
import PoaButton from '../../../poa/poa-button/poa-button';
import React from 'react';
import { Text } from '@deriv/components';
import { localize } from '@deriv/translations';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ jest.mock('@deriv/shared', () => ({
isMobile: jest.fn(() => false),
}));

jest.mock('Assets/ic-idv-verified.svg', () => jest.fn(() => 'mockedSVGIcon'));
jest.mock('../../../../../Assets/ic-idv-verified.svg', () => jest.fn(() => 'mockedSVGIcon'));

describe('<IdvVerified />', () => {
const needs_poa_header = /your id is verified\. you will also need to submit proof of your address\./i;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import IdvDocumentVerified from 'Assets/ic-idv-verified.svg';
import PoaButton from 'Components/poa/poa-button';
import IdvDocumentVerified from '../../../../Assets/ic-idv-verified.svg';
import PoaButton from '../../../poa/poa-button/poa-button';
import React from 'react';
import { Text } from '@deriv/components';
import { isMobile } from '@deriv/shared';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import React from 'react';
import { PlatformContext } from '@deriv/shared';
import { ButtonLink, Icon, Text } from '@deriv/components';
import { localize } from '@deriv/translations';
import IconMessageContent from 'Components/icon-message-content';
import IconMessageContent from '../../icon-message-content';

type TGoToPersonalDetailsButton = {
has_invalid_postal_code?: boolean;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,10 @@ import {
toMoment,
WS,
} from '@deriv/shared';
import FormBody from 'Components/form-body';
import LoadErrorMessage from 'Components/load-error-message';
import PersonalDetailsForm from 'Components/forms/personal-details-form';
import { makeSettingsRequest, validate, validateName } from 'Helpers/utils';
import FormBody from '../../form-body';
import LoadErrorMessage from '../../load-error-message';
import PersonalDetailsForm from '../../forms/personal-details-form.jsx';
import { makeSettingsRequest, validate, validateName } from '../../../Helpers/utils';
import { TInputFieldValues } from 'Types';

type TRestState = {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
import React from 'react';
import { fireEvent, render, screen, waitFor } from '@testing-library/react';
import { isDesktop, isMobile } from '@deriv/shared';
import CountrySelector from '../poi-country-selector';
import PoiCountrySelector from '../poi-country-selector';

jest.mock('@deriv/shared', () => ({
...jest.requireActual('@deriv/shared'),
isDesktop: jest.fn(() => true),
isMobile: jest.fn(() => false),
}));

describe('<CountrySelector/>', () => {
describe('<PoiCountrySelector/>', () => {
let mock_props = {
handleSelectionNext: jest.fn(),
is_from_external: false,
Expand All @@ -32,10 +32,10 @@ describe('<CountrySelector/>', () => {
};
});

it('should render CountrySelector component external', () => {
it('should render PoiCountrySelector component external', () => {
mock_props.is_from_external = true;

render(<CountrySelector {...mock_props} />);
render(<PoiCountrySelector {...mock_props} />);

expect(screen.getByText('Proof of identity')).toBeInTheDocument();
expect(screen.getByText('In which country was your document issued?')).toBeInTheDocument();
Expand All @@ -45,7 +45,7 @@ describe('<CountrySelector/>', () => {
});

it('should show error message after clicking the input without choosing the country', async () => {
render(<CountrySelector {...mock_props} />);
render(<PoiCountrySelector {...mock_props} />);

const field = screen.getByLabelText('Country');
const next_btn = screen.getByRole('button');
Expand All @@ -68,7 +68,7 @@ describe('<CountrySelector/>', () => {
(isMobile as jest.Mock).mockReturnValue(true);
mock_props.selected_country = 'Country 2';

render(<CountrySelector {...mock_props} />);
render(<PoiCountrySelector {...mock_props} />);

const field = screen.getByRole('combobox');

Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
import CountrySelector from './poi-country-selector';
import PoiCountrySelector from './poi-country-selector';

export default CountrySelector;
export default PoiCountrySelector;
Original file line number Diff line number Diff line change
Expand Up @@ -7,23 +7,21 @@ import FormFooter from 'Components/form-footer';

type TCountry = Record<string, string>;

type TCountrySelector = {
type TPoiCountrySelector = {
handleSelectionNext: () => void;
is_from_external: boolean;
residence_list: TCountry[];
residence_list: Array<TCountry>;
selected_country: string;
setSelectedCountry: (value: TCountry) => void;
};

const CountrySelector = ({
const PoiCountrySelector = ({
handleSelectionNext,
is_from_external,
residence_list,
selected_country,
setSelectedCountry,
}: TCountrySelector) => {
const [country_list, setCountryList] = React.useState<TCountry[]>([]);

}: TPoiCountrySelector) => {
const initial_form_values: FormikValues = {
country_input: '',
};
Expand All @@ -34,15 +32,17 @@ const CountrySelector = ({

if (!country_input) {
errors.country_input = localize('Please select the country of document issuance.');
} else if (!country_list.find((c: FormikValues) => c.text === country_input)) {
} else if (!residence_list.find((c: FormikValues) => c.text === country_input)) {
errors.country_input = localize('Please select a valid country of document issuance.');
}

return errors;
};

const updateSelectedCountry = (country_name: string) => {
const matching_country: TCountry | undefined = country_list.find((c: FormikValues) => c.text === country_name);
const matching_country: TCountry | undefined = residence_list.find(
(c: FormikValues) => c.text === country_name
);
if (matching_country) {
setSelectedCountry?.(matching_country);
}
Expand All @@ -54,10 +54,6 @@ const CountrySelector = ({
handleSelectionNext?.();
};

React.useEffect(() => {
setCountryList(residence_list);
}, [residence_list]);

return (
<Formik initialValues={initial_form_values} validate={validateFields} onSubmit={submitHandler}>
{({
Expand Down Expand Up @@ -99,13 +95,13 @@ const CountrySelector = ({
autoComplete='off'
type='text'
label={localize('Country')}
list_items={country_list}
list_items={residence_list}
value={values.country_input}
onBlur={(e: FormikValues) => {
handleBlur(e);
const current_input = e.target.value;
if (
!country_list.find(
!residence_list.find(
(c: FormikValues) => c.text === current_input
)
) {
Expand All @@ -131,7 +127,7 @@ const CountrySelector = ({
error={touched.country_input && errors.country_input}
label={localize('Country')}
placeholder={localize('Please select')}
list_items={country_list}
list_items={residence_list}
value={values.country_input}
onChange={(e: React.ChangeEvent<HTMLSelectElement>) => {
handleChange(e);
Expand Down Expand Up @@ -168,4 +164,4 @@ const CountrySelector = ({
);
};

export default CountrySelector;
export default PoiCountrySelector;
Loading

0 comments on commit a86a1b3

Please sign in to comment.