Skip to content

Commit

Permalink
likhith/trah-4188/incorporate POA enhancement for wallet (#75)
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
likhith-deriv authored Sep 23, 2024
1 parent 8708832 commit 3ff1bdc
Show file tree
Hide file tree
Showing 16 changed files with 372 additions and 62 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -64,10 +64,11 @@ const FileUploaderContainer = ({
autoComplete='off'
list_items={document_list}
type='text'
value={field.value?.text}
value={field.value}
label={placeholder}
placeholder={placeholder ?? localize('Select a document')}
onItemSelection={(item: TListItem) => {
setFieldValue('document_type', item, true);
setFieldValue('document_type', item.text, true);
}}
required
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import POADesktopLayout from './poa-desktop-layout';
import { TPOAFormState } from '../../../Types';
import { useTranslations } from '@deriv-com/translations';
import POAMobileLayout from './poa-mobile-layout';
import { getSupportedProofOfAddressDocuments } from '../../../Constants/file-uploader';

type TProofOfAddressForm = {
className: string;
Expand All @@ -28,7 +29,7 @@ type TFormInitialValues = Record<
'address_line_1' | 'address_line_2' | 'address_city' | 'address_state' | 'address_postcode',
string
> & {
document_type?: Record<'text' | 'value', string>;
document_type?: string;
};

const ProofOfAddressForm = observer(
Expand Down Expand Up @@ -136,7 +137,7 @@ const ProofOfAddressForm = observer(
}
}

if (!values.document_type?.value) {
if (!values.document_type) {
errors.document_type = localize('Document type is required.');
}

Expand Down Expand Up @@ -189,8 +190,12 @@ const ProofOfAddressForm = observer(

// upload files
try {
// This is required as AutoComplate displays only the selected value
const selected_doc_type = getSupportedProofOfAddressDocuments().find(
doc => doc.text === values.document_type
);
const api_response = await upload(document_files, {
document_type: values.document_type?.value as DocumentUploadRequest['document_type'],
document_type: selected_doc_type?.value as DocumentUploadRequest['document_type'],
});

if (api_response?.warning) {
Expand Down Expand Up @@ -256,7 +261,7 @@ const ProofOfAddressForm = observer(
address_city,
address_state,
address_postcode,
document_type: { text: '', value: '' },
document_type: '',
};

if (api_initial_load_error) return <LoadErrorMessage error_message={api_initial_load_error} />;
Expand Down
4 changes: 4 additions & 0 deletions packages/api-v2/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,10 @@ type KycAuthStatus = {
* Current POA status.
*/
status?: 'none' | 'pending' | 'rejected' | 'verified' | 'expired';
/**
* Supported documents per document_type.
*/
supported_documents?: string[];
};
/**
* POI authentication status details.
Expand Down
6 changes: 4 additions & 2 deletions packages/cfd/src/Components/__tests__/cfd-poa.spec.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React from 'react';
import { BrowserRouter } from 'react-router-dom';
import { render, screen, waitFor } from '@testing-library/react';
import { fireEvent, render, screen, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { mockStore } from '@deriv/stores';
import CFDPOA from '../cfd-poa';
Expand Down Expand Up @@ -89,6 +89,7 @@ describe('<CFDPOA />', () => {
address_city: 'test address_city',
address_state: 'test address_state',
address_postcode: 'test address_postcode',
country_code: 'in',
},
fetchResidenceList: jest.fn(() => Promise.resolve('')),
getChangeableFields: jest.fn(() => []),
Expand All @@ -112,7 +113,8 @@ describe('<CFDPOA />', () => {

const uploader = screen.getByTestId('dt_file_upload_input');
const file = new File(['test file'], 'test_file.png', { type: 'image/png' });

const dt_document_type = screen.getByRole('textbox', { name: /Type of document/ });
fireEvent.change(dt_document_type, { target: { value: 'utility_bill' } });
await waitFor(() => {
userEvent.upload(uploader, file);
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,6 @@
@include mobile-or-tablet-screen {
width: 100%;
height: 100%;
padding: 1.6rem;
padding: unset;
}
}
40 changes: 23 additions & 17 deletions packages/wallets/src/features/accounts/modules/Poa/Poa.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import React, { useEffect, useState } from 'react';
import { Formik, FormikValues } from 'formik';
import { useTranslations } from '@deriv-com/translations';
import { InlineMessage, Loader, Text } from '@deriv-com/ui';
import { InlineMessage, Loader, Text, useDevice } from '@deriv-com/ui';
import { ModalStepWrapper } from '../../../../components';
import { THooks } from '../../../../types';
import { Footer } from '../components';
import POAMobile from './components/POAMobile/POAMobile';
import { AddressSection, DocumentSubmission, PoaUploadErrorMessage } from './components';
import { usePoa } from './hooks';
import { getPoaValidationSchema } from './utils';
Expand All @@ -16,7 +17,9 @@ type TPoaProps = {

const Poa: React.FC<TPoaProps> = ({ onCompletion }) => {
const { localize } = useTranslations();
const { isDesktop } = useDevice();
const {
countryCode,
errorSettings,
initialStatus,
initialValues,
Expand Down Expand Up @@ -63,22 +66,25 @@ const Poa: React.FC<TPoaProps> = ({ onCompletion }) => {
return <PoaUploadErrorMessage errorCode={errorDocumentUpload.code} onRetry={onErrorRetry} />;
}

return (
<ModalStepWrapper
renderFooter={() => <Footer disableNext={!isValid} onClickNext={handleSubmit} />}
title={localize('Add a real MT5 account')}
>
<div className='wallets-poa'>
{errorSettings?.message && (
<InlineMessage variant='error'>
<Text>{localize(errorSettings.message)}</Text>
</InlineMessage>
)}
<AddressSection />
<DocumentSubmission />
</div>
</ModalStepWrapper>
);
if (isDesktop) {
return (
<ModalStepWrapper
renderFooter={() => <Footer disableNext={!isValid} onClickNext={handleSubmit} />}
title={localize('Add a real MT5 account')}
>
<div className='wallets-poa'>
{errorSettings?.message && (
<InlineMessage variant='error'>
<Text>{localize(errorSettings.message)}</Text>
</InlineMessage>
)}
<AddressSection hasError={Boolean(errorSettings?.message)} />
<DocumentSubmission countryCode={countryCode as string} />
</div>
</ModalStepWrapper>
);
}
return <POAMobile countryCode={countryCode as string} onCompletion={handleSubmit} />;
}}
</Formik>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
align-items: flex-start;
gap: 0.8rem;
margin-bottom: 1rem;
line-height: 14px;

&-message {
width: 80rem;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,30 +1,35 @@
import React from 'react';
import { useFormikContext } from 'formik';
import { Localize, useTranslations } from '@deriv-com/translations';
import { InlineMessage, Text } from '@deriv-com/ui';
import { InlineMessage, Text, useDevice } from '@deriv-com/ui';
import { FormDropdown, FormField } from '../../../../../../components';
import { TAddressDetails } from '../../types';
import { TAddressDetails, TAddressSectionProps } from '../../types';
import './AddressSection.scss';

const AddressSection: React.FC = () => {
const AddressSection: React.FC<TAddressSectionProps> = ({ hasError }) => {
const { localize } = useTranslations();
const { status } = useFormikContext<TAddressDetails>();
const { isDesktop } = useDevice();

return (
<div className='wallets-address-section'>
<div className='wallets-address-section__title'>
<Text weight='bold'>
<Localize i18n_default_text='Address' />
</Text>
<div className='wallets-address-section__title__divider' />
</div>
<div className='wallets-address-section__inline'>
<InlineMessage variant='warning'>
<div className='wallets-address-section__inline-message'>
<Localize i18n_default_text='For faster verification, input the same address here as in your proof of address document (see section below)' />
</div>
</InlineMessage>
</div>
{isDesktop && (
<div className='wallets-address-section__title'>
<Text weight='bold'>
<Localize i18n_default_text='Address' />
</Text>
<div className='wallets-address-section__title__divider' />
</div>
)}
{!hasError && (
<div className='wallets-address-section__inline'>
<InlineMessage variant='warning'>
<div className='wallets-address-section__inline-message'>
<Localize i18n_default_text='Use the same address that appears on your proof of address (utility bill, bank statement, etc.).' />
</div>
</InlineMessage>
</div>
)}
<div className='wallets-address-section__input'>
<FormField label={localize('First line of address*')} name='firstLine' />
<FormField label={localize('Second line of address (optional)')} name='secondLine' />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -115,4 +115,15 @@
width: 100%;
}
}

&__type-selection {
display: flex;
flex-direction: column;
gap: 1.6rem;
align-self: stretch;

label {
text-transform: none !important;
}
}
}
Original file line number Diff line number Diff line change
@@ -1,27 +1,62 @@
import React, { useEffect } from 'react';
import React, { useEffect, useState } from 'react';
import { useFormikContext } from 'formik';
import { useIsEuRegion } from '@deriv/api-v2';
import { useIsEuRegion, useKycAuthStatus } from '@deriv/api-v2';
import { LabelPairedArrowUpFromBracketXlFillIcon } from '@deriv/quill-icons';
import { Localize, useTranslations } from '@deriv-com/translations';
import { Text, useDevice } from '@deriv-com/ui';
import { Dropzone } from '../../../../../../components';
import { TDocumentSubmission } from '../../types';
import { getExampleImagesConfig } from '../../utils';
import { Dropzone, FormDropdown } from '../../../../../../components';
import { TDocumentSubmission, TDocumentSubmissionProps, TListItem } from '../../types';
import { getExampleImagesConfig, getSupportedProofOfAddressDocuments } from '../../utils';
import { CommonMistakesExamples } from '../CommonMistakesExamples';
import './DocumentSubmission.scss';

const DocumentSubmission: React.FC = () => {
const DocumentSubmission: React.FC<TDocumentSubmissionProps> = ({ countryCode }) => {
const { localize } = useTranslations();
const { isDesktop } = useDevice();
const { data: isEuRegion } = useIsEuRegion();
const { isLoading, kyc_auth_status: kycAuthStatus } = useKycAuthStatus({ country: countryCode });
const [documentList, setDocumentList] = useState<Required<TListItem>[]>([]);
const { setFieldValue, values } = useFormikContext<TDocumentSubmission>();

useEffect(() => {
if (!isLoading && kycAuthStatus) {
const { address } = kycAuthStatus;
const { supported_documents: supportedDocuments } = address;
const docList = getSupportedProofOfAddressDocuments().filter(doc =>
supportedDocuments?.includes(doc.value)
);
setDocumentList(docList);
}
}, [isLoading, kycAuthStatus]);

const listItems = [
localize('Utility bill: electricity, water, gas, or landline phone bill.'),
localize(
'Financial, legal, or government document: recent bank statement, affidavit, or government-issued letter.'
),
localize('Home rental agreement: valid and current agreement.'),
{
id: 'utility_bill',
value: (
<Localize
components={[<strong key={0} />]}
i18n_default_text='<0>Utility bill:</0> Electricity, water, gas, or landline phone bill.'
/>
),
},
{
id: 'financial_legal_government_document',
value: (
<Localize
components={[<strong key={0} />]}
i18n_default_text='<0>Financial, legal, or government document:</0> Recent bank statement, affidavit, or government-issued letter.'
/>
),
},
{
id: 'tenancy_agreement',
value: (
<Localize
components={[<strong key={0} />]}
i18n_default_text='<0>Tenancy agreement:</0> Valid and current agreement.'
/>
),
},
];

useEffect(() => {
Expand All @@ -34,23 +69,23 @@ const DocumentSubmission: React.FC = () => {
<div className='wallets-poa__document'>
<div className='wallets-poa__document__title'>
<Text weight='bold'>
<Localize i18n_default_text='Document submission' />
<Localize i18n_default_text='Submit your document' />
</Text>
<div className='wallets-poa__document__title__divider' />
</div>
<div className='wallets-poa__document__container'>
<div className='wallets-poa__document__container__disclaimer'>
<Text size='sm' weight='bold'>
{localize(
'We accept only these types of documents as proof of address. The document must be recent (issued within last {{timePeriod}} months) and include your name and address:',
'We accept only the following documents as proof of address. The document must be issued within last {{timePeriod}} months and include your name and address:',
{ timePeriod: isEuRegion ? '6' : '12' }
)}
</Text>

<ul className='wallets-poa__document__container__disclaimer__list'>
{listItems.map(item => (
<li key={`list-item-${item}`}>
<Text size='sm'>{item}</Text>
<li key={`list-item-${item.id}`}>
<Text size='sm'>{item.value}</Text>
</li>
))}
</ul>
Expand All @@ -70,6 +105,20 @@ const DocumentSubmission: React.FC = () => {
))}
</div>
</div>

<div className='wallets-poa__document__type-selection'>
<Text size='sm' weight='bold'>
<Localize i18n_default_text='Select the type of document:' />
</Text>
<FormDropdown
isFullWidth
label={localize('Type of document')}
list={documentList}
listHeight='sm'
name='documentType'
/>
</div>

<div className='wallets-poa__document__container__upload'>
<Text size='sm' weight='bold'>
<Localize i18n_default_text='Upload file' />
Expand Down
Loading

0 comments on commit 3ff1bdc

Please sign in to comment.