Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Maryia/80948/fix: avoid rate limit error by storing counter after sending verification email in Withdrawal #7218

Merged
merged 25 commits into from
Mar 21, 2023
Merged
Show file tree
Hide file tree
Changes from 20 commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
17576db
fix: instantiating useVerifyEmail object once for each email verifica…
maryia-deriv Dec 21, 2022
08e153e
chore: store verify_email_sent_count in store instead of locally
maryia-deriv Dec 22, 2022
e0eedee
Merge branch develop of github.com:binary-com/deriv-app into maryia/8…
maryia-deriv Jan 2, 2023
ec13eba
test: fix test for email-verification-empty-state.tsx
maryia-deriv Jan 2, 2023
f9055e6
Merge branch develop of github.com:binary-com/deriv-app into maryia/8…
maryia-deriv Jan 5, 2023
88a8eaa
Merge branch 'develop' of github.com:binary-com/deriv-app into maryia…
maryia-deriv Jan 8, 2023
d7f5d83
fix: avoid counter reset by storing and using the time an email was l…
maryia-deriv Jan 8, 2023
75d637c
chore: a workaround for VerifyEmailRequest type declared with an extr…
maryia-deriv Jan 8, 2023
d33d5b3
Merge branch 'develop' of github.com:binary-com/deriv-app into maryia…
maryia-deriv Jan 19, 2023
ec80cbc
chore: remove api-types workaround
maryia-deriv Jan 19, 2023
8152059
Merge branch develop of github.com:binary-com/deriv-app into maryia/8…
maryia-deriv Feb 5, 2023
c87dbde
Merge branch develop of github.com:binary-com/deriv-app into maryia/8…
maryia-deriv Feb 22, 2023
6929b98
build: update @deriv/api-types to 1.0.85
maryia-deriv Feb 22, 2023
9a08440
Merge branch 'develop' of github.com:binary-com/deriv-app into maryia…
maryia-deriv Feb 22, 2023
e3332e3
Merge branch develop of github.com:binary-com/deriv-app into maryia/8…
maryia-deriv Feb 23, 2023
8a37398
revert: api-types version upgrade
maryia-deriv Feb 23, 2023
2751b1c
Merge branch 'develop' of github.com:binary-com/deriv-app into maryia…
maryia-deriv Feb 23, 2023
6274f01
revert: package-lock
maryia-deriv Feb 23, 2023
a41725f
revert: modal-manager.jsx
maryia-deriv Feb 23, 2023
0a3f1a9
revert: modal-manager.jsx
maryia-deriv Feb 23, 2023
2dadbbc
Merge branch 'master' into maryia/80948/rate_limit
maryia-deriv Mar 9, 2023
afb6e6e
Merge branch 'master' into maryia/80948/rate_limit
maryia-deriv Mar 12, 2023
95d952c
Merge branch master of github.com:binary-com/deriv-app into maryia/80…
maryia-deriv Mar 15, 2023
99d0520
Merge branch 'master' into maryia/80948/rate_limit
maryia-deriv Mar 16, 2023
4f31154
Merge branch 'master' into maryia/80948/rate_limit
maryia-deriv Mar 17, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 EmailVerificationEmptyState from '../email-verification-empty-state';
import { TRootStore } from 'Types';
import { useVerifyEmail } from '@deriv/hooks';
import { VerifyEmail } from '@deriv/api-types';
import CashierProviders from '../../../cashier-providers';

const mock_store: DeepPartial<TRootStore> = {
Expand All @@ -11,8 +13,18 @@ const mock_store: DeepPartial<TRootStore> = {
};

describe('EmailVerificationEmptyState', () => {
const verify: ReturnType<typeof useVerifyEmail> = {
is_loading: false,
error: '',
data: {} as VerifyEmail,
counter: 58,
is_counter_running: true,
sent_count: 2,
has_been_sent: true,
send: jest.fn(),
};
test('should disable resend button after sending the request', () => {
render(<EmailVerificationEmptyState type='reset_password' />, {
render(<EmailVerificationEmptyState verify={verify} />, {
wrapper: ({ children }) => <CashierProviders store={mock_store as TRootStore}>{children}</CashierProviders>,
});

Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,15 @@
import React from 'react';
import { useVerifyEmail, TEmailVerificationType } from '@deriv/hooks';
import { useVerifyEmail } from '@deriv/hooks';
import { localize } from '@deriv/translations';
import EmptyState from 'Components/empty-state';
import EmailVerificationResendEmptyState from './email-verification-resend-empty-state';
import './email-verification-empty-state.scss';

type TEmailVerificationEmptyStateProps = {
type: TEmailVerificationType;
verify: ReturnType<typeof useVerifyEmail>;
};

const EmailVerificationEmptyState = ({ type }: TEmailVerificationEmptyStateProps) => {
const verify = useVerifyEmail(type);

const EmailVerificationEmptyState = ({ verify }: TEmailVerificationEmptyStateProps) => {
const action = {
label: localize("Didn't receive the email?"),
onClick: verify.send,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,7 @@ const WithdrawalTab = observer(() => {
// match the behavior of the `Withdrawal` page and first inform the user.

if (verify.error && 'code' in verify.error) return <PaymentAgentWithdrawalLocked error={verify.error} />;
if (!verify.is_loading && verify.has_been_sent)
return <EmailVerificationEmptyState type={'paymentagent_withdraw'} />;
if (!verify.is_loading && verify.has_been_sent) return <EmailVerificationEmptyState verify={verify} />;
if (verification_code || payment_agent.is_withdraw)
return <PaymentAgentContainer verification_code={verification_code} />;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ const WithdrawalVerificationEmail = observer(() => {

if (verify.error) return <Error error={verify.error} />;

if (verify.has_been_sent) return <EmailVerificationEmptyState type={'payment_withdraw'} />;
if (verify.has_been_sent) return <EmailVerificationEmptyState verify={verify} />;

return (
<>
Expand Down
9 changes: 9 additions & 0 deletions packages/core/src/Stores/client-store.js
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,7 @@ export default class ClientStore extends BaseStore {

account_limits = {};
self_exclusion = {};
sent_verify_emails_data = {};

local_currency_config = {
currency: '',
Expand Down Expand Up @@ -203,6 +204,7 @@ export default class ClientStore extends BaseStore {
new_email: observable,
account_limits: observable,
self_exclusion: observable,
sent_verify_emails_data: observable,
local_currency_config: observable,
has_cookie_account: observable,
financial_assessment: observable,
Expand Down Expand Up @@ -304,6 +306,7 @@ export default class ClientStore extends BaseStore {
setPreferredLanguage: action.bound,
setCookieAccount: action.bound,
setCFDScore: action.bound,
setSentVerifyEmailsData: action.bound,
updateSelfExclusion: action.bound,
responsePayoutCurrencies: action.bound,
responseAuthorize: action.bound,
Expand Down Expand Up @@ -1169,6 +1172,11 @@ export default class ClientStore extends BaseStore {
LocalStore.setObject(LANGUAGE_KEY, lang);
};

setSentVerifyEmailsData(sent_verify_emails_data) {
this.sent_verify_emails_data = sent_verify_emails_data;
LocalStore.setObject('sent_verify_emails_data', sent_verify_emails_data);
}

setCookieAccount() {
const domain = /deriv\.(com|me)/.test(window.location.hostname) ? deriv_urls.DERIV_HOST_NAME : 'binary.sx';
// eslint-disable-next-line max-len
Expand Down Expand Up @@ -1572,6 +1580,7 @@ export default class ClientStore extends BaseStore {

this.setLoginId(LocalStore.get('active_loginid'));
this.setAccounts(LocalStore.getObject(storage_key));
this.setSentVerifyEmailsData(LocalStore.getObject('sent_verify_emails_data'));
this.setSwitched('');
const client = this.accounts[this.loginid];
// If there is an authorize_response, it means it was the first login
Expand Down
22 changes: 17 additions & 5 deletions packages/hooks/src/useVerifyEmail.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { useState } from 'react';
import { useWS } from '@deriv/api';
import { useStore } from '@deriv/stores';
import type { TSocketEndpoints } from '@deriv/api/types';
Expand All @@ -10,18 +9,31 @@ export type TEmailVerificationType = TSocketEndpoints['verify_email']['request']

const useVerifyEmail = (type: TEmailVerificationType) => {
const WS = useWS('verify_email');
const counter = useCountdown({ from: RESEND_COUNTDOWN });
const { client } = useStore();
const [sent_count, setSentCount] = useState(0);
const { setSentVerifyEmailsData, sent_verify_emails_data } = client;
const { last_time_sent_seconds = 0, sent_count = 0 } = sent_verify_emails_data[type] || {};
const time_now_seconds = Math.floor(Date.now() / 1000);
const seconds_left = last_time_sent_seconds + RESEND_COUNTDOWN - time_now_seconds;
const should_not_allow_resend =
last_time_sent_seconds && time_now_seconds < last_time_sent_seconds + RESEND_COUNTDOWN;
const countdown = should_not_allow_resend ? seconds_left : RESEND_COUNTDOWN;
const counter = useCountdown({ from: countdown });

if (!counter.is_running && should_not_allow_resend) {
counter.start();
}

const send = () => {
if (!client.email) return;
if (counter.is_running) return;

counter.reset();
counter.start();

setSentCount(old => old + 1);
const sent_emails_data = {
...sent_verify_emails_data,
[type]: { last_time_sent_seconds: time_now_seconds, sent_count: sent_count + 1 },
};
setSentVerifyEmailsData(sent_emails_data);

WS.send({ verify_email: client.email, type });
};
Expand Down
2 changes: 2 additions & 0 deletions packages/stores/src/mockStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,8 @@ const mock = (): TRootStore => {
residence: '',
responseMt5LoginList: jest.fn(),
responseTradingPlatformAccountsList: jest.fn(),
sent_verify_emails_data: {},
setSentVerifyEmailsData: jest.fn(),
standpoint: {
iom: '',
},
Expand Down
13 changes: 13 additions & 0 deletions packages/stores/types.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import type { GetAccountStatus, Authorize, DetailsOfEachMT5Loginid, LogOutResponse, GetLimits } from '@deriv/api-types';
import type { TEmailVerificationType } from '@deriv/hooks';
import type { RouteComponentProps } from 'react-router';

type TAccount = NonNullable<Authorize['account_list']>[0];
Expand Down Expand Up @@ -160,7 +161,9 @@ type TClientStore = {
trading_platform_dxtrade_password_reset: string;
trading_platform_mt5_password_reset: string;
};
sent_verify_emails_data: TSentVerifyEmailsData;
email: string;
setSentVerifyEmailsData: (sent_verify_emails_data: TSentVerifyEmailsData) => void;
setVerificationCode: (code: string, action: string) => void;
updateAccountStatus: () => Promise<void>;
is_authentication_needed: boolean;
Expand All @@ -172,6 +175,16 @@ type TClientStore = {
is_crypto: boolean;
};

type TSentVerifyEmailsData = Partial<
Record<
TEmailVerificationType,
{
last_time_sent_seconds: number;
sent_count: number;
}
>
>;

type TCommonStoreError = {
header: string | JSX.Element;
message: string | JSX.Element;
Expand Down