Skip to content

Commit

Permalink
Likhith/trah 3856/add poa document type (#16611)
Browse files Browse the repository at this point in the history
* feat: incorporated POA dropdown field

* chore: fixed the POA dropdown

* fix: type issues in TS

* fix: testcase for File upload

* chore: incorporated Mobile layout

* chore: incorporated POA for mobile

* fix: failing testcases

* fix: failing testcase in cfd-poa

* fix: failing testcase in cfd-poa

* chore: added POAForm testcase

* chore: added POAForm testcase

* fix: incorporated review comments

* fix: incorporated new layout changes

* fix: incorporated validation for Document type field

* fix: incorporated validation for Document type field

* likhith/trah-4188/incorporate POA enhancement for wallet (#75)

* chore: incorporated POA enhancement in Desktop for wallet

* chore: incorporated POA changes in mobile

* fix: incorporated review comments

* fix: remove comment

* Merge remote-tracking branch 'origin/likhith/TRAH-3856/add-poa-document-type' into likhith/TRAH-4188/handle-poa-enhancement-in-wallets

* fix: failing testcase

* fix: overirde CSS

* fix: incorporated review comments

* fix: incoprorated review comments

* chore: added POA others
  • Loading branch information
likhith-deriv authored Oct 3, 2024
1 parent 3b30cb8 commit 8bb21d4
Show file tree
Hide file tree
Showing 27 changed files with 1,097 additions and 197 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ import React from 'react';
import { render, screen } from '@testing-library/react';
import FileUploaderContainer from '../file-uploader-container';
import { useDevice } from '@deriv-com/ui';
import { mockStore, StoreProvider } from '@deriv/stores';
import { Formik } from 'formik';

jest.mock('@deriv/components', () => {
const original_module = jest.requireActual('@deriv/components');
Expand All @@ -10,20 +12,36 @@ jest.mock('@deriv/components', () => {
Icon: jest.fn(() => 'mockedIcon'),
};
});

jest.mock('@deriv-com/ui', () => ({
...jest.requireActual('@deriv-com/ui'),
useDevice: jest.fn(),
}));

const mock_kyc_auth_status_response = {
kyc_auth_status: {
address: {
supported_documents: ['utility_bill', 'affidavit', 'poa_others'],
},
},
isLoading: false,
isSuccess: false,
};

jest.mock('../../../hooks', () => ({
useKycAuthStatus: jest.fn(() => mock_kyc_auth_status_response),
}));

describe('<FileUploaderContainer />', () => {
let mock_props: React.ComponentProps<typeof FileUploaderContainer>;
const mock_props: React.ComponentProps<typeof FileUploaderContainer> = {
examples: '',
files_description: '',
onFileDrop: jest.fn(),
country_of_residence: 'in',
};
const store = mockStore({});

beforeEach(() => {
mock_props = {
examples: '',
files_description: '',
onFileDrop: jest.fn(),
};
(useDevice as jest.Mock).mockReturnValue({ isDesktop: true });
jest.clearAllMocks();
});
Expand All @@ -41,35 +59,44 @@ describe('<FileUploaderContainer />', () => {
expect(screen.getByText(file_warning_msg)).toBeInTheDocument();
};

it('should render FileUploaderContainer component and show descriptions', () => {
render(<FileUploaderContainer {...mock_props} />);
runCommonTests();
});
const renderComponent = (props = mock_props) =>
render(
<StoreProvider store={store}>
<Formik
initialValues={{
document_type: { text: '', value: '' },
}}
onSubmit={jest.fn()}
>
<FileUploaderContainer {...props} />
</Formik>
</StoreProvider>
);

it('should render FileUploaderContainer component if getSocket is not passed as prop', () => {
render(<FileUploaderContainer {...mock_props} />);
it('should render FileUploaderContainer component and show descriptions', () => {
renderComponent();
runCommonTests();
});

it('files description and examples should be shown when passed', () => {
mock_props.files_description = <div>Files description</div>;
mock_props.examples = <div>Files failure examples</div>;

render(<FileUploaderContainer {...mock_props} />);
renderComponent(mock_props);
expect(screen.getByText('Files description')).toBeInTheDocument();
expect(screen.getByText('Files failure examples')).toBeInTheDocument();
});

it('should show hint message for desktop', () => {
render(<FileUploaderContainer {...mock_props} />);
renderComponent();
expect(screen.getByText(hint_msg_desktop)).toBeInTheDocument();
expect(screen.queryByText(hint_msg_mobile)).not.toBeInTheDocument();
});

it('should show hint message for mobile', () => {
(useDevice as jest.Mock).mockReturnValue({ isMobile: true });

render(<FileUploaderContainer {...mock_props} />);
renderComponent();
expect(screen.getByText(hint_msg_mobile)).toBeInTheDocument();
expect(screen.queryByText(hint_msg_desktop)).not.toBeInTheDocument();
});
Expand Down
Original file line number Diff line number Diff line change
@@ -1,23 +1,81 @@
/* eslint-disable @typescript-eslint/ban-ts-comment */
//@ts-nocheck [TODO] - Need to fix typescript errors in this file
import React from 'react';
import { Text } from '@deriv/components';
import { Localize } from '@deriv/translations';
import { Autocomplete, Loading, Text } from '@deriv/components';
import { Localize, useTranslations } from '@deriv-com/translations';
import FileUploader from './file-uploader';
import { useDevice } from '@deriv-com/ui';
import { useKycAuthStatus } from '../../hooks';
import { getSupportedProofOfAddressDocuments } from '../../Constants/file-uploader';
import { TListItem } from 'Types';
import { Field, FieldProps } from 'formik';

type TFileUploaderContainer = {
onFileDrop: (files: File[]) => void;
country_of_residence?: string;
files_description?: React.ReactNode;
examples?: React.ReactNode;
onError?: (error_message: string) => void;
placeholder?: string;
};

const FileUploaderContainer = ({ examples, files_description, onFileDrop, onError }: TFileUploaderContainer) => {
const FileUploaderContainer = ({
examples,
files_description,
country_of_residence,
onFileDrop,
onError,
placeholder,
}: TFileUploaderContainer) => {
const { isMobile } = useDevice();
const { localize } = useTranslations();
const { kyc_auth_status, isLoading } = useKycAuthStatus({ country: country_of_residence });
const [document_list, setDocumentList] = React.useState<Required<TListItem>[]>([]);

React.useEffect(() => {
if (kyc_auth_status) {
const { address } = kyc_auth_status;
const { supported_documents } = address;
const doc_list = getSupportedProofOfAddressDocuments().filter(doc =>
supported_documents?.includes(doc.value)
);
setDocumentList(doc_list);
}
}, [kyc_auth_status]);

if (isLoading) {
return <Loading is_fullscreen={false} />;
}

return (
<div className='file-uploader__container' data-testid='dt_file_uploader_container'>
{files_description}
{examples}
{country_of_residence && (
<React.Fragment>
<Text size={isMobile ? 'xxs' : 'xs'} as='div' className='file-uploader__file-title' weight='bold'>
<Localize i18n_default_text='Select the type of document:' />
</Text>
<Field name='document_type'>
{({ field, form: { setFieldValue } }: FieldProps<string>) => (
<Autocomplete
{...field}
data-lpignore='true'
autoComplete='off'
list_items={document_list}
type='text'
value={field.value}
label={placeholder}
placeholder={placeholder ?? localize('Select a document')}
onItemSelection={(item: TListItem) => {
setFieldValue('document_type', item.text, true);
}}
required
/>
)}
</Field>
</React.Fragment>
)}
<Text size={isMobile ? 'xxs' : 'xs'} as='div' className='file-uploader__file-title' weight='bold'>
<Localize i18n_default_text='Upload file' />
</Text>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ const PersonalDetailsForm = props => {
};

const poa_clarification_message = (
<Localize i18n_default_text='For faster verification, input the same address here as in your proof of address document (see section below)' />
<Localize i18n_default_text='Use the same address that appears on your proof of address (utility bill, bank statement, etc.).' />
);

// need to disable the checkbox if the user has not filled in the name and dob fields initially
Expand Down
60 changes: 53 additions & 7 deletions packages/account/src/Constants/file-uploader.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Localize } from '@deriv/translations';
import React from 'react';
import { TFilesDescription } from '../Types';
import { TFilesDescription, TListItem } from '../Types';
import { localize, Localize } from '@deriv-com/translations';

export const getFileUploaderDescriptions = (page: string, is_eu?: boolean): TFilesDescription => {
const proof_of_income_descriptions = {
Expand All @@ -25,24 +25,37 @@ export const getFileUploaderDescriptions = (page: string, is_eu?: boolean): TFil
const proof_of_address_descriptions = {
title: (
<Localize
i18n_default_text='We accept only these types of documents as proof of your address. The document must be recent (issued within last {{expiry_in_months}} months) and include your name and address:'
i18n_default_text='We accept only the following documents as proof of address. The document must be issued within the last {{expiry_in_months}} months and include your full name and address:'
values={{ expiry_in_months: is_eu ? 6 : 12 }}
/>
),
descriptions: [
{
id: 'utility_bill',
value: <Localize i18n_default_text='Utility bill: electricity, water, gas, or landline phone bill.' />,
value: (
<Localize
i18n_default_text='<0>Utility bill:</0> Electricity, water, gas, or landline phone bill.'
components={[<strong key={0} />]}
/>
),
},
{
id: 'financial_legal_government_document',
value: (
<Localize i18n_default_text='Financial, legal, or government document: recent bank statement, affidavit, or government-issued letter.' />
<Localize
i18n_default_text='<0>Financial, legal, or government document:</0> Recent bank statement, affidavit, or government-issued letter.'
components={[<strong key={0} />]}
/>
),
},
{
id: 'home_rental_agreement',
value: <Localize i18n_default_text='Home rental agreement: valid and current agreement.' />,
id: 'tenancy_agreement',
value: (
<Localize
i18n_default_text='<0>Tenancy agreement:</0> Valid and current agreement.'
components={[<strong key={0} />]}
/>
),
},
],
};
Expand All @@ -51,3 +64,36 @@ export const getFileUploaderDescriptions = (page: string, is_eu?: boolean): TFil
if (page === 'poa') return proof_of_address_descriptions;
return { title: '', descriptions: [] };
};

export const getSupportedProofOfAddressDocuments = (): Required<TListItem>[] => {
return [
{
value: 'utility_bill',
text: localize('Utility bill (electricity, water, gas)'),
},
{
value: 'phone_bill',
text: localize('Landline phone bill'),
},
{
value: 'bank_statement',
text: localize('Bank statement'),
},
{
value: 'affidavit',
text: localize('Official residence declaration or affidavit'),
},
{
value: 'official_letter',
text: localize('Official letter issued by the government or solicitor'),
},
{
value: 'rental_agreement',
text: localize('Rental/tenancy agreement'),
},
{
text: localize('Others'),
value: 'poa_others',
},
];
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
import React from 'react';
import { render, screen, waitFor } from '@testing-library/react';
import ProofOfAddressForm from '../proof-of-address-form';
import { useDevice } from '@deriv-com/ui';
import { mockStore, StoreProvider } from '@deriv/stores';
import { BrowserRouter } from 'react-router-dom';

jest.mock('@deriv-com/ui', () => ({
...jest.requireActual('@deriv-com/ui'),
useDevice: jest.fn(),
}));

jest.mock('@deriv/hooks', () => ({
...jest.requireActual('@deriv/hooks'),
useFileUploader: jest.fn(() => ({
upload: jest.fn(),
})),
}));

jest.mock('../poa-desktop-layout.tsx', () => jest.fn(() => 'mockedPOADesktopForm'));

jest.mock('../poa-mobile-layout.tsx', () => jest.fn(() => 'mockedPOAMobileForm'));

jest.mock('@deriv/shared', () => ({
...jest.requireActual('@deriv/shared'),
WS: {
authorized: {
storage: {
getSettings: jest.fn().mockResolvedValue({
get_settings: {
address_line_1: 'test address_line_1',
address_line_2: 'test address_line_2',
address_city: 'test address_city',
address_state: 'test address_state',
address_postcode: 'test address_postcode',
},
}),
getAccountStatus: jest.fn().mockResolvedValue({
get_account_status: {
authentication: {
document: {
status: 'none',
},
identity: {
status: 'none',
},
},
},
}),
},
},
setSettings: jest.fn(() => Promise.resolve({ error: '' })),
wait: jest.fn(() => Promise.resolve([])),
getSocket: jest.fn().mockReturnValue({}),
},
}));

describe('ProofOfAddressForm', () => {
const mock_props: React.ComponentProps<typeof ProofOfAddressForm> = {};

const mock_store = mockStore({
client: {
account_settings: {
address_line_1: 'test address_line_1',
address_line_2: 'test address_line_2',
address_city: 'test address_city',
address_state: 'test address_state',
address_postcode: 'test address_postcode',
},
fetchResidenceList: jest.fn(() => Promise.resolve('')),
fetchStatesList: jest.fn(() => Promise.resolve('')),
getChangeableFields: jest.fn(() => []),
},
});

const renderComponent = ({ props = mock_props, store = mock_store }) => {
return render(
<BrowserRouter>
<StoreProvider store={store}>
<ProofOfAddressForm {...props} />
</StoreProvider>
</BrowserRouter>
);
};

it('should render Desktop layout of the form', async () => {
(useDevice as jest.Mock).mockReturnValue({ isMobile: false, isDesktop: true });

renderComponent({});

expect(await screen.findByText('mockedPOADesktopForm')).toBeInTheDocument();
});

it('should render Mobile layout of the form', async () => {
(useDevice as jest.Mock).mockReturnValue({ isMobile: true, isDesktop: false });

renderComponent({});

expect(await screen.findByText('mockedPOAMobileForm')).toBeInTheDocument();
});
});
Loading

0 comments on commit 8bb21d4

Please sign in to comment.