Skip to content

Commit db9de01

Browse files
[FEQ] / Ameerul / FEQ-1716 Create the email verification modal (deriv-com#14132)
* feat: added email verification modal * chore: added comment to use epoch value from BE when implementing Modal * chore: added TODO
1 parent 1a4a897 commit db9de01

File tree

5 files changed

+181
-0
lines changed

5 files changed

+181
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
.p2p-v2-email-verification-modal {
2+
height: auto;
3+
width: 44rem;
4+
border-radius: 8px;
5+
6+
@include mobile {
7+
max-width: calc(100vw - 3.2rem);
8+
}
9+
10+
// TODO: Remove this when Button allows to pass prop to prevent hover styles
11+
&__button {
12+
&:hover {
13+
// stylelint-disable-next-line declaration-no-important
14+
background-color: transparent !important;
15+
16+
& > span {
17+
// stylelint-disable-next-line declaration-no-important
18+
color: #ff444f !important;
19+
}
20+
}
21+
}
22+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
import React, { useState } from 'react';
2+
import {
3+
DerivLightIcEmailSentIcon,
4+
DerivLightIcFirewallEmailPasskeyIcon,
5+
DerivLightIcSpamEmailPasskeyIcon,
6+
DerivLightIcTypoEmailPasskeyIcon,
7+
DerivLightIcWrongEmailPasskeyIcon,
8+
} from '@deriv/quill-icons';
9+
import { Button, Modal, Text, useDevice } from '@deriv-com/ui';
10+
import './EmailVerificationModal.scss';
11+
12+
const reasons = [
13+
{
14+
icon: DerivLightIcSpamEmailPasskeyIcon,
15+
text: 'The email is in your spam folder (sometimes things get lost there).',
16+
},
17+
{
18+
icon: DerivLightIcWrongEmailPasskeyIcon,
19+
text: 'You accidentally gave us another email address (usually a work or a personal one instead of the one you meant).',
20+
},
21+
{
22+
icon: DerivLightIcTypoEmailPasskeyIcon,
23+
text: 'The email address you entered had a mistake or typo (happens to the best of us).',
24+
},
25+
{
26+
icon: DerivLightIcFirewallEmailPasskeyIcon,
27+
text: 'We can’t deliver the email to this address (usually because of firewalls or filtering).',
28+
},
29+
];
30+
31+
type TEmailVerificationModalProps = {
32+
isModalOpen: boolean;
33+
onRequestClose: () => void;
34+
};
35+
36+
const EmailVerificationModal = ({ isModalOpen, onRequestClose }: TEmailVerificationModalProps) => {
37+
const [shouldShowReasons, setShouldShowReasons] = useState<boolean>(false);
38+
const { isMobile } = useDevice();
39+
const emailIconSize = isMobile ? 100 : 128;
40+
const reasonIconSize = isMobile ? 32 : 36;
41+
42+
return (
43+
<Modal
44+
ariaHideApp={false}
45+
className='p2p-v2-email-verification-modal'
46+
isOpen={isModalOpen}
47+
onRequestClose={onRequestClose}
48+
>
49+
<Modal.Header className='mt-2' hideBorder onRequestClose={onRequestClose} />
50+
<Modal.Body className='flex flex-col items-center justify-center lg:gap-[2.4rem] gap-8 lg:px-10 lg:pb-10 p-8 pt-0'>
51+
<DerivLightIcEmailSentIcon height={emailIconSize} width={emailIconSize} />
52+
<Text align='center' weight='bold'>
53+
Has the buyer paid you?
54+
</Text>
55+
<Text align='center' size={isMobile ? 'sm' : 'md'}>
56+
Releasing funds before receiving payment may result in losses. Check your email and follow the
57+
instructions <strong>within 10 minutes</strong> to release the funds.
58+
</Text>
59+
<Button
60+
className='p2p-v2-email-verification-modal__button'
61+
onClick={() => setShouldShowReasons(true)}
62+
variant='ghost'
63+
>
64+
I didn’t receive the email
65+
</Button>
66+
{shouldShowReasons && (
67+
<div className='flex flex-col w-full gap-8'>
68+
{reasons.map(reason => (
69+
<div className='grid grid-cols-[11%_89%] gap-4 items-center' key={reason.text}>
70+
<reason.icon height={reasonIconSize} width={reasonIconSize} />
71+
<Text size='xs'>{reason.text}</Text>
72+
</div>
73+
))}
74+
<div className='flex justify-center'>
75+
{/* TODO: Replace 59s with epoch value (verification_next_request) from BE response
76+
* and disable the button if the epoch value is not reached yet
77+
*/}
78+
<Button size='md'>Resend email 59s</Button>
79+
</div>
80+
</div>
81+
)}
82+
</Modal.Body>
83+
</Modal>
84+
);
85+
};
86+
87+
export default EmailVerificationModal;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
import React from 'react';
2+
import { render, screen } from '@testing-library/react';
3+
import userEvent from '@testing-library/user-event';
4+
import EmailVerificationModal from '../EmailVerificationModal';
5+
6+
jest.mock('@deriv-com/ui', () => ({
7+
...jest.requireActual('@deriv-com/ui'),
8+
useDevice: () => ({ isMobile: false }),
9+
}));
10+
11+
const mockProps = {
12+
isModalOpen: true,
13+
onRequestClose: jest.fn(),
14+
};
15+
16+
describe('<EmailVerificationModal />', () => {
17+
it('should render the EmailVerificationModal', () => {
18+
render(<EmailVerificationModal {...mockProps} />);
19+
20+
expect(screen.getByText('Has the buyer paid you?')).toBeInTheDocument();
21+
expect(
22+
screen.queryByText(
23+
/Releasing funds before receiving payment may result in losses. Check your email and follow the instructions/
24+
)
25+
).toBeInTheDocument();
26+
expect(screen.queryByText('within 10 minutes', { selector: 'strong' })).toBeInTheDocument();
27+
expect(screen.queryByText(/to release the funds./)).toBeInTheDocument();
28+
expect(screen.getByRole('button', { name: 'I didn’t receive the email' })).toBeInTheDocument();
29+
});
30+
31+
it('should show reasons if I didn’t receive the email button is clicked', () => {
32+
render(<EmailVerificationModal {...mockProps} />);
33+
34+
const didntReceiveEmailButton = screen.getByRole('button', { name: 'I didn’t receive the email' });
35+
36+
expect(
37+
screen.queryByText('The email is in your spam folder (sometimes things get lost there).')
38+
).not.toBeInTheDocument();
39+
expect(
40+
screen.queryByText(
41+
'You accidentally gave us another email address (usually a work or a personal one instead of the one you meant).'
42+
)
43+
).not.toBeInTheDocument();
44+
expect(
45+
screen.queryByText('The email address you entered had a mistake or typo (happens to the best of us).')
46+
).not.toBeInTheDocument();
47+
expect(
48+
screen.queryByText(
49+
'We can’t deliver the email to this address (usually because of firewalls or filtering).'
50+
)
51+
).not.toBeInTheDocument();
52+
53+
userEvent.click(didntReceiveEmailButton);
54+
55+
expect(
56+
screen.getByText('The email is in your spam folder (sometimes things get lost there).')
57+
).toBeInTheDocument();
58+
expect(
59+
screen.getByText(
60+
'You accidentally gave us another email address (usually a work or a personal one instead of the one you meant).'
61+
)
62+
).toBeInTheDocument();
63+
expect(
64+
screen.getByText('The email address you entered had a mistake or typo (happens to the best of us).')
65+
).toBeInTheDocument();
66+
expect(
67+
screen.getByText('We can’t deliver the email to this address (usually because of firewalls or filtering).')
68+
).toBeInTheDocument();
69+
});
70+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export { default as EmailVerificationModal } from './EmailVerificationModal';

packages/p2p-v2/src/components/Modals/index.ts

+1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ export * from './AdErrorTooltipModal';
22
export * from './AvailableP2PBalanceModal';
33
export * from './BlockUnblockUserModal';
44
export * from './DailyLimitModal';
5+
export * from './EmailVerificationModal';
56
export * from './FilterModal';
67
export * from './MyAdsDeleteModal';
78
export * from './NicknameModal';

0 commit comments

Comments
 (0)