Skip to content

Commit

Permalink
Amina/coj 737/duplicate document error fix (deriv-com#15635)
Browse files Browse the repository at this point in the history
* feat: poa_account_settings

* feat: duplicate document in mt5 poa

* fix: component naming

* fix: poi duplicate document

* fix: cfd-poa

* fix: test case

* fix: test case fix

* fix: constant value

* fix: linting:

* fix: typing

* fix: removed step-idex undefined

* fix: test case description

* fix: remove back button in manual upload if resunbmission
  • Loading branch information
amina-deriv authored Jun 21, 2024
1 parent f58ca5f commit b35b2c5
Show file tree
Hide file tree
Showing 19 changed files with 212 additions and 94 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ type TIconMessageContent = {
icon: React.ReactElement;
is_disabled_for_mobile?: boolean;
message: React.ReactNode;
text?: string | React.ReactElement;
text?: React.ReactNode;
};

const IconMessageContent = ({
Expand Down
Original file line number Diff line number Diff line change
@@ -1,22 +1,25 @@
import React from 'react';
import React, { ReactNode } from 'react';
import { Button, Icon, Text } from '@deriv/components';
import { localize } from '@deriv/translations';
import IconMessageContent from '../../../icon-message-content';

type TUnverified = {
title?: ReactNode;
description?: ReactNode;
onClick: () => void;
button_text?: ReactNode;
};

export const Unverified = ({ onClick }: TUnverified) => {
export const Unverified = ({ title, description, button_text, onClick }: TUnverified) => {
return (
<IconMessageContent
message={localize('We could not verify your proof of address')}
text={localize('Please check your email for details.')}
message={title ?? localize('We could not verify your proof of address')}
text={description ?? localize('Please check your email for details.')}
icon={<Icon icon='IcPoaError' size={128} />}
>
<Button onClick={onClick} has_effect primary>
<Text className='dc-btn__text' size='xs' weight='bold' as='p'>
{localize('Resubmit')}
{button_text ?? localize('Resubmit')}
</Text>
</Button>
</IconMessageContent>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import React from 'react';
import { screen, render } from '@testing-library/react';
import POIManualUploadFailed from '../poi-manual-upload-failed';

jest.mock('@deriv/components', () => {
const original_module = jest.requireActual('@deriv/components');
return {
...original_module,
Icon: jest.fn(() => <div>Mocked Icon</div>),
};
});

describe('<POIManualUploadFailed />', () => {
const error = 'MockAPIError';
it('should render <POIManualUploadFailed /> component with its default content', () => {
render(<POIManualUploadFailed error={error} />);
expect(screen.getByText('Proof of identity documents upload failed')).toBeInTheDocument();
expect(screen.getByText('MockAPIError')).toBeInTheDocument();
expect(screen.getByText('Mocked Icon')).toBeInTheDocument();
});

it('should render <POIManualUploadFailed /> component with content from props', () => {
render(<POIManualUploadFailed message='message' error={error} />);
expect(screen.getByText('message')).toBeInTheDocument();
expect(screen.getByText('Mocked Icon')).toBeInTheDocument();
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import POIManualUploadFailed from './poi-manual-upload-failed';

export default POIManualUploadFailed;
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import React, { ReactNode } from 'react';
import { Icon } from '@deriv/components';
import { Localize } from '@deriv/translations';
import IconMessageContent from '../icon-message-content';

type TPOIManualUploadFailed = {
error: string;
message?: ReactNode;
};
const POIManualUploadFailed = ({ children, message, error }: React.PropsWithChildren<TPOIManualUploadFailed>) => (
<IconMessageContent
message={message ?? <Localize i18n_default_text={'Proof of identity documents upload failed'} />}
text={error}
icon={<Icon icon='IcPoiFailed' size={128} />}
className='account-management-dashboard'
>
{children}
</IconMessageContent>
);

export default POIManualUploadFailed;

This file was deleted.

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
/* eslint-disable @typescript-eslint/ban-ts-comment */
//@ts-nocheck [TODO] - Need to fix typescript errors in OnfidoUpload component
import React from 'react';
import { Loading, Icon, Text } from '@deriv/components';
import { localize } from '@deriv/translations';
import { Loading, Icon, Text, Button } from '@deriv/components';
import { localize, Localize } from '@deriv/translations';
import { WS } from '@deriv/shared';
import { UploadComplete } from '../upload-complete/upload-complete';
import PoiUnsupportedFailed from '../../../poi-unsupported-failed';
import POIManualUploadFailed from '../../../poi-manual-upload-failed';
import { API_ERROR_CODES } from '../../../../Constants/api-error-codes';
import uploadFile from '../../../file-uploader-container/upload-file';
import OnfidoUpload from '../../../../Sections/Verification/ProofOfIdentity/onfido-sdk-view-container';

Expand Down Expand Up @@ -74,7 +75,9 @@ const DetailComponent = ({
})
.then(response => {
file_to_upload_index += 1;
if (response.warning || response.error) {
if (response?.warning === API_ERROR_CODES.DUPLICATE_DOCUMENT) {
setStatus(STATUS.IS_DUPLICATE_UPLOAD);
} else if (response?.warning || response.error) {
is_any_failed = true;
setStatus(STATUS.IS_FAILED);
setError(
Expand Down Expand Up @@ -122,7 +125,20 @@ const DetailComponent = ({
case STATUS.IS_COMPLETED:
return <UploadComplete is_from_external={true} needs_poa={false} is_manual_upload />;
case STATUS.IS_FAILED:
return <PoiUnsupportedFailed error={response_error} />;
return <POIManualUploadFailed error={response_error} />;
case STATUS.IS_DUPLICATE_UPLOAD:
return (
<POIManualUploadFailed
error={
<Localize i18n_default_text='It seems you’ve submitted this document before. Upload a new document.' />
}
>
<Button onClick={onClickBack} large primary className='upload_error_btn'>
<Localize i18n_default_text='Try Again' />
</Button>
</POIManualUploadFailed>
);

default:
return (
<React.Fragment>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ type TUnsupported = {
submissions_left: number;
};
is_for_mt5?: boolean;
is_resubmission?: boolean;
};

const Unsupported = ({
Expand All @@ -52,6 +53,7 @@ const Unsupported = ({
handleViewComplete,
onfido,
is_for_mt5,
is_resubmission,
...props
}: TUnsupported) => {
const [detail, setDetail] = React.useState<number | null>(null);
Expand Down Expand Up @@ -102,7 +104,7 @@ const Unsupported = ({
<Localize i18n_default_text='Please upload one of the following documents:' />
</Text>
<Documents documents={documents} toggleDetail={toggleDetail} />
{!is_for_mt5 && (
{!is_for_mt5 && !is_resubmission && (
<FormFooter className='proof-of-identity__footer'>
<Button className='back-btn' onClick={handleBack} type='button' has_effect large secondary>
<Localize i18n_default_text='Back' />
Expand Down
1 change: 1 addition & 0 deletions packages/account/src/Constants/api-error-codes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,5 @@
export const API_ERROR_CODES = Object.freeze({
DUPLICATE_ACCOUNT: 'DuplicateAccount',
CLAIMED_DOCUMENT: 'ClaimedDocument',
DUPLICATE_DOCUMENT: 'DuplicateUpload',
});
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,8 @@ type TAuthenticationStatus = Record<
| 'needs_poi'
| 'poa_address_mismatch'
| 'resubmit_poa'
| 'poa_expiring_soon',
| 'poa_expiring_soon'
| 'has_submitted_duplicate_poa',
boolean
> & { document_status?: DeepRequired<GetAccountStatus>['authentication']['document']['status'] };

Expand All @@ -47,6 +48,7 @@ const ProofOfAddressContainer = observer(({ onSubmit }: TProofOfAddressContainer
is_age_verified: false,
poa_address_mismatch: false,
poa_expiring_soon: false,
has_submitted_duplicate_poa: false,
});

const { client, notifications, common, ui } = useStore();
Expand Down Expand Up @@ -92,13 +94,28 @@ const ProofOfAddressContainer = observer(({ onSubmit }: TProofOfAddressContainer
}, [is_switching, refreshNotifications]);

const handleResubmit = () => {
setAuthenticationStatus(authentication_status => ({ ...authentication_status, ...{ resubmit_poa: true } }));
setAuthenticationStatus(authentication_status => ({
...authentication_status,
...{ resubmit_poa: true },
}));
};

const onSubmitDocument = (needs_poi: boolean) => {
const handleDuplicatePOASubmission = () => {
setAuthenticationStatus(authentication_status => ({
...authentication_status,
...{ has_submitted_poa: true, needs_poi, poa_expiring_soon: false },
...{ resubmit_poa: true, has_submitted_duplicate_poa: false, has_submitted_poa: false },
}));
};

const onSubmitDocument = (needs_poi: boolean, has_submitted_duplicate_poa?: boolean) => {
setAuthenticationStatus(authentication_status => ({
...authentication_status,
...{
has_submitted_poa: true,
needs_poi,
poa_expiring_soon: false,
has_submitted_duplicate_poa: has_submitted_duplicate_poa ?? false,
},
}));
if (is_verification_modal_visible) {
onSubmit?.();
Expand All @@ -114,6 +131,7 @@ const ProofOfAddressContainer = observer(({ onSubmit }: TProofOfAddressContainer
has_submitted_poa,
poa_address_mismatch,
poa_expiring_soon,
has_submitted_duplicate_poa,
} = authentication_status;

const from_platform = getPlatformRedirect(app_routing_history);
Expand Down Expand Up @@ -147,6 +165,17 @@ const ProofOfAddressContainer = observer(({ onSubmit }: TProofOfAddressContainer

if (is_loading) return <Loading is_fullscreen={false} className='account__initial-loader' />;
if (!allow_document_upload) return <NotRequired />;
if (has_submitted_duplicate_poa)
return (
<Unverified
title={<Localize i18n_default_text='Proof of address documents upload failed' />}
description={
<Localize i18n_default_text='It seems you’ve submitted this document before. Upload a new document.' />
}
button_text={<Localize i18n_default_text='Try again' />}
onClick={handleDuplicatePOASubmission}
/>
);
if (has_submitted_poa && !poa_address_mismatch)
return <Submitted needs_poi={needs_poi} redirect_button={redirect_button} />;
if (should_allow_resubmit) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,15 @@ import CommonMistakeExamples from '../../../Components/poa/common-mistakes/commo
import PersonalDetailsForm from '../../../Components/forms/personal-details-form.jsx';
import { isServerError, validate } from '../../../Helpers/utils';
import { getFileUploaderDescriptions } from '../../../Constants/file-uploader';
import { API_ERROR_CODES } from '../../../Constants/api-error-codes';

type TProofOfAddressForm = {
className?: string;
className: string;
is_resubmit: boolean;
is_for_cfd_modal?: boolean;
onCancel?: () => void;
onSubmit: (needs_poi: boolean) => void;
onSubmitForCFDModal: (index: number, values: FormikValues) => void;
step_index: number;
is_for_cfd_modal: boolean;
onCancel: () => void;
onSubmit: (needs_poi: boolean, has_submitted_duplicate_poa?: boolean) => void;
onSubmitForCFDModal: (values: FormikValues, has_submitted_duplicate_poa?: boolean) => void;
};

type TFormInitialValues = Record<
Expand All @@ -36,14 +36,7 @@ type TFormInitialValues = Record<
type TFormState = Record<'is_btn_loading' | 'is_submit_success' | 'should_allow_submit' | 'should_show_form', boolean>;

const ProofOfAddressForm = observer(
({
is_resubmit,
is_for_cfd_modal,
onSubmit,
onSubmitForCFDModal,
step_index,
className,
}: Partial<TProofOfAddressForm>) => {
({ is_resubmit, is_for_cfd_modal, onSubmit, onSubmitForCFDModal, className }: Partial<TProofOfAddressForm>) => {
const { client, notifications, ui } = useStore();
const { account_settings, fetchResidenceList, fetchStatesList, getChangeableFields, states_list, is_eu } =
client;
Expand Down Expand Up @@ -201,10 +194,20 @@ const ProofOfAddressForm = observer(
// upload files
try {
const api_response = await upload(document_files);

if (api_response?.warning) {
setStatus({ msg: api_response?.message });
setFormState({ ...form_state, ...{ is_btn_loading: false } });
setShouldScrollToTop(true);

if (api_response.warning === API_ERROR_CODES.DUPLICATE_DOCUMENT) {
if (is_for_cfd_modal) {
onSubmitForCFDModal?.(values, true);
} else {
onSubmit?.(false, true);
}
} else {
setStatus({ msg: api_response?.message });
setShouldScrollToTop(true);
}
return;
}

Expand Down Expand Up @@ -237,15 +240,13 @@ const ProofOfAddressForm = observer(
} catch (error) {
if (isServerError(error)) {
setStatus({ msg: error.message });
setSubmitting(false);
setFormState({ ...form_state, ...{ is_btn_loading: false } });
setShouldScrollToTop(true);
}
} finally {
setSubmitting(false);
setFormState({ ...form_state, ...{ is_btn_loading: false } });
}
if (is_for_cfd_modal && typeof step_index !== 'undefined') {
onSubmitForCFDModal?.(step_index, values);
if (is_for_cfd_modal) {
onSubmitForCFDModal?.(values);
}
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,7 @@ const POISubmission = observer(
handleViewComplete={handleViewComplete}
onfido={onfido}
handleBack={handleBack}
is_resubmission={needs_resubmission}
/>
);
default:
Expand Down
Loading

0 comments on commit b35b2c5

Please sign in to comment.