From d4125b1733650cf53819b9ca210e89b2575e1924 Mon Sep 17 00:00:00 2001 From: amina-deriv Date: Sat, 19 Aug 2023 08:56:27 +0400 Subject: [PATCH 01/13] chore: initial_draft --- ...jsx => account-has-pending-conditions.tsx} | 179 ++++++++++++------ ...rm.jsx => closing-account-reason-form.tsx} | 84 +++++--- ...-reason.jsx => closing-account-reason.tsx} | 91 +++++---- ...nt-steps.jsx => closing-account-steps.tsx} | 6 +- ...losing-account.jsx => closing-account.tsx} | 4 +- .../Sections/Security/ClosingAccount/index.js | 2 +- packages/account/tsconfig.json | 1 + packages/stores/types.ts | 2 +- 8 files changed, 238 insertions(+), 131 deletions(-) rename packages/account/src/Sections/Security/ClosingAccount/{account-has-balance.jsx => account-has-pending-conditions.tsx} (66%) rename packages/account/src/Sections/Security/ClosingAccount/{closing-account-reason-form.jsx => closing-account-reason-form.tsx} (81%) rename packages/account/src/Sections/Security/ClosingAccount/{closing-account-reason.jsx => closing-account-reason.tsx} (79%) rename packages/account/src/Sections/Security/ClosingAccount/{closing-account-steps.jsx => closing-account-steps.tsx} (95%) rename packages/account/src/Sections/Security/ClosingAccount/{closing-account.jsx => closing-account.tsx} (84%) diff --git a/packages/account/src/Sections/Security/ClosingAccount/account-has-balance.jsx b/packages/account/src/Sections/Security/ClosingAccount/account-has-pending-conditions.tsx similarity index 66% rename from packages/account/src/Sections/Security/ClosingAccount/account-has-balance.jsx rename to packages/account/src/Sections/Security/ClosingAccount/account-has-pending-conditions.tsx index a4707e01e561..4af995d350df 100644 --- a/packages/account/src/Sections/Security/ClosingAccount/account-has-balance.jsx +++ b/packages/account/src/Sections/Security/ClosingAccount/account-has-pending-conditions.tsx @@ -1,18 +1,58 @@ import React from 'react'; import { Button, Icon, Money, ThemedScrollbars, Text } from '@deriv/components'; import { formatMoney, getCFDAccount, getCFDAccountDisplay, CFD_PLATFORMS } from '@deriv/shared'; +import { DetailsOfEachMT5Loginid } from '@deriv/api-types'; import { localize, Localize } from '@deriv/translations'; +import { observer, useStore } from '@deriv/stores'; -const getDerivAccount = (client_accounts, login_id) => +const getDerivAccount = (client_accounts: TAccounts[], login_id: string) => client_accounts.find(client_account => client_account.loginid === login_id); -const getCurrMT5Account = (mt5_login_list, login_id) => +const getCurrMT5Account = (mt5_login_list: DetailsOfEachMT5Loginid[], login_id: string) => mt5_login_list.find(account_obj => account_obj.login === login_id); -const getCurrDxtradeAccount = (dxtrade_accounts_list, login_id) => +const getCurrDxtradeAccount = (dxtrade_accounts_list: TDxtradeAccount[], login_id: string) => dxtrade_accounts_list.find(account_obj => account_obj.account_id === login_id); -const Wrapper = ({ children, title, desc }) => ( +type TWrapperProps = { + children: React.ReactNode; + title: string; + desc?: React.ReactNode; +}; + +type TDxtradeAccount = DetailsOfEachMT5Loginid & { account_id?: string }; + +type TPendingProps = TAccounts & { positions?: number }; +type TAccounts = { + account?: { + balance?: string | number; + currency?: string; + disabled?: boolean; + error?: JSX.Element | string; + is_crypto?: boolean; + is_dxtrade?: boolean; + is_mt?: boolean; + market_type?: string; + nativepicker_text?: string; + platform_icon?: { + Derived: React.SVGAttributes; + Financial: React.SVGAttributes; + Options: React.SVGAttributes; + CFDs: React.SVGAttributes; + }; + text?: JSX.Element | string; + value?: string; + }; + icon?: string; + idx?: string | number; + is_dark_mode_on?: boolean; + is_virtual?: boolean | number; + loginid?: string; + mt5_login_list?: DetailsOfEachMT5Loginid[]; + title?: string; +}; + +const Wrapper = ({ children, title, desc }: TWrapperProps) => (
{title} @@ -25,8 +65,14 @@ const Wrapper = ({ children, title, desc }) => (
{children}
); +type TContentProps = { + currency_icon: string; + loginid?: string; + title?: string; + value: React.ReactNode; +}; -const Content = ({ currency_icon, loginid, title, value }) => ( +const Content = ({ currency_icon, loginid, title, value }: TContentProps) => (
@@ -45,39 +91,45 @@ const Content = ({ currency_icon, loginid, title, value }) => (
); -const AccountHasPendingConditions = ({ - details, - mt5_login_list, - dxtrade_accounts_list, - client_accounts, - onBackClick, - is_eu, -}) => { - const deriv_open_positions = []; - const deriv_balance = []; - const mt5_open_positions = []; - const mt5_balance = []; - const account_pending_withdrawals = []; - const dxtrade_open_positions = []; - const dxtrade_balance = []; +type TBalance = { balance?: number; currency?: string }; + +type TAccountHasPendingConditionsProps = { + details?: { + pending_withdrawals?: Record; + open_positions?: Record; + balance?: Record; + }; + onBackClick: () => void; +}; + +const AccountHasPendingConditions = observer(({ details, onBackClick }: TAccountHasPendingConditionsProps) => { + const { client } = useStore(); + const { dxtrade_accounts_list, mt5_login_list, account_list, is_eu } = client; + const deriv_open_positions: TPendingProps[] = []; + const deriv_balance: (TAccounts & TBalance)[] = []; + const mt5_open_positions: (DetailsOfEachMT5Loginid & { display_login?: string } & { positions?: number })[] = []; + const mt5_balance: (DetailsOfEachMT5Loginid & TBalance & { display_login?: string })[] = []; + const account_pending_withdrawals: (TAccounts & { withdrawals?: number })[] = []; + const dxtrade_open_positions: (TDxtradeAccount & { display_login?: string } & { positions?: number })[] = []; + const dxtrade_balance: (TDxtradeAccount & TBalance & { display_login?: string })[] = []; - if (details.pending_withdrawals) { + if (details?.pending_withdrawals) { Object.keys(details.pending_withdrawals).forEach(login_id => { const info = { - withdrawals: details.pending_withdrawals[login_id], + withdrawals: details.pending_withdrawals?.[login_id], }; - const deriv_account = getDerivAccount(client_accounts, login_id); + const deriv_account = getDerivAccount(account_list, login_id); if (deriv_account) { account_pending_withdrawals.push({ ...deriv_account, ...info }); } }); } - if (details.open_positions) { - Object.keys(details.open_positions).forEach(login_id => { + if (details?.open_positions) { + Object.keys(details?.open_positions).forEach(login_id => { const info = { - positions: details.open_positions[login_id], + positions: details.open_positions?.[login_id], }; - const deriv_account = getDerivAccount(client_accounts, login_id); + const deriv_account = getDerivAccount(account_list, login_id); if (deriv_account) { deriv_open_positions.push({ ...deriv_account, ...info }); } else { @@ -93,13 +145,13 @@ const AccountHasPendingConditions = ({ } }); } - if (details.balance) { + if (details?.balance) { Object.keys(details.balance).forEach(login_id => { const info = { - balance: details.balance[login_id].balance, - currency: details.balance[login_id].currency, + balance: details.balance?.[login_id].balance, + currency: details.balance?.[login_id].currency, }; - const deriv_account = getDerivAccount(client_accounts, login_id); + const deriv_account = getDerivAccount(account_list, login_id); if (deriv_account) { deriv_balance.push({ ...deriv_account, ...info }); } else { @@ -115,7 +167,6 @@ const AccountHasPendingConditions = ({ } }); } - return ( @@ -148,7 +199,7 @@ const AccountHasPendingConditions = ({ value={ } @@ -168,12 +219,14 @@ const AccountHasPendingConditions = ({ is_eu, })}`} loginid={account.display_login} - title={getCFDAccountDisplay({ - market_type: account.market_type, - sub_account_type: account.sub_account_type, - platform: CFD_PLATFORMS.MT5, - is_eu, - })} + title={ + getCFDAccountDisplay({ + market_type: account.market_type, + sub_account_type: account.sub_account_type, + platform: CFD_PLATFORMS.MT5, + is_eu, + }) ?? '' + } value={ } @@ -225,12 +280,14 @@ const AccountHasPendingConditions = ({ is_eu, })}`} loginid={account.display_login} - title={getCFDAccountDisplay({ - market_type: account.market_type, - sub_account_type: account.sub_account_type, - platform: CFD_PLATFORMS.DXTRADE, - is_eu, - })} + title={ + getCFDAccountDisplay({ + market_type: account.market_type, + sub_account_type: account.sub_account_type, + platform: CFD_PLATFORMS.DXTRADE, + is_eu, + }) ?? '' + } value={ } @@ -304,6 +363,6 @@ const AccountHasPendingConditions = ({
); -}; +}); export default AccountHasPendingConditions; diff --git a/packages/account/src/Sections/Security/ClosingAccount/closing-account-reason-form.jsx b/packages/account/src/Sections/Security/ClosingAccount/closing-account-reason-form.tsx similarity index 81% rename from packages/account/src/Sections/Security/ClosingAccount/closing-account-reason-form.jsx rename to packages/account/src/Sections/Security/ClosingAccount/closing-account-reason-form.tsx index 98ea771c511f..fa6b6c17d7f0 100644 --- a/packages/account/src/Sections/Security/ClosingAccount/closing-account-reason-form.jsx +++ b/packages/account/src/Sections/Security/ClosingAccount/closing-account-reason-form.tsx @@ -1,10 +1,24 @@ import React from 'react'; -import { Formik, Field } from 'formik'; +import { Formik, Field, FormikValues, FormikErrors } from 'formik'; import { Checkbox, Input, FormSubmitButton, Text } from '@deriv/components'; import { localize } from '@deriv/translations'; import { PlatformContext } from '@deriv/shared'; -const initial_form = { +type TFormValues = { + // Define the checkbox values + 'financial-priorities': boolean; + 'stop-trading': boolean; + 'not-interested': boolean; + 'another-website': boolean; + 'not-user-friendly': boolean; + 'difficult-transactions': boolean; + 'lack-of-features': boolean; + 'unsatisfactory-service': boolean; + 'other-reasons': boolean; + other_trading_platforms: string; + do_to_improve: string; +}; +const initial_form: TFormValues = { 'financial-priorities': false, 'stop-trading': false, 'not-interested': false, @@ -17,8 +31,26 @@ const initial_form = { other_trading_platforms: '', do_to_improve: '', }; - -const ClosingAccountReasonFrom = ({ +type TClosingAccountReasonFormProps = { + validateFields: (values: FormikValues) => FormikErrors; + onSubmit: (values: FormikValues) => void; + is_checkbox_disabled: boolean; + onChangeCheckbox: ( + values: FormikValues, + field_name: keyof TFormValues, + setFieldValue: (name: string, values: string | boolean) => void + ) => void; + character_limit_no: number; + onInputChange: ( + e: React.ChangeEvent, + old_value: string, + onChange: (e: React.ChangeEvent) => void + ) => void; + onInputPaste: (e: React.ClipboardEvent) => void; + remaining_characters: number; + onBackClick: () => void; +}; +const ClosingAccountReasonForm = ({ validateFields, onSubmit, is_checkbox_disabled, @@ -28,7 +60,7 @@ const ClosingAccountReasonFrom = ({ onInputPaste, remaining_characters, onBackClick, -}) => { +}: TClosingAccountReasonFormProps) => { const { is_appstore } = React.useContext(PlatformContext); return ( @@ -36,9 +68,9 @@ const ClosingAccountReasonFrom = ({ {({ values, setFieldValue, errors, handleChange, handleSubmit, dirty }) => (
- {({ field }) => ( + {({ field }: FormikValues) => ( - {({ field }) => ( + {({ field }: FormikValues) => ( - {({ field }) => ( + {({ field }: FormikValues) => ( - {({ field }) => ( + {({ field }: FormikValues) => ( - {({ field }) => ( + {({ field }: FormikValues) => ( - {({ field }) => ( + {({ field }: FormikValues) => ( - {({ field }) => ( + {({ field }: FormikValues) => ( - {({ field }) => ( + {({ field }: FormikValues) => ( - {({ field }) => ( + {({ field }: FormikValues) => ( - {({ field }) => ( + {({ field }: FormikValues) => ( - {({ field }) => ( + {({ field }: FormikValues) => ( { +type TClosingAccountReasonProps = { + onBackClick: () => void; +}; + +const preparingReason = (values: FormikValues) => { let selected_reasons = selectedReasons(values) .map(val => val[0]) .toString(); @@ -24,13 +27,17 @@ const preparingReason = values => { return selected_reasons.replace(/(\r\n|\n|\r)/gm, ' '); }; -const selectedReasons = values => { +const selectedReasons = (values: FormikValues) => { return Object.entries(values).filter( ([key, value]) => !['other_trading_platforms', 'do_to_improve'].includes(key) && value ); }; -const WarningModal = props => { +type TWarningModalProps = { + closeModal: () => void; + startDeactivating: () => void; +}; +const WarningModal = ({ closeModal, startDeactivating }: TWarningModalProps) => { return (
@@ -50,15 +57,19 @@ const WarningModal = props => { className='account-closure-warning-modal__close-account-button' has_cancel cancel_label={localize('Go Back')} - onClick={() => props.startDeactivating()} - onCancel={() => props.closeModal()} + onClick={() => startDeactivating()} + onCancel={() => closeModal()} />
); }; +type TGeneralErrorContentProps = { + message: string; + onClick: () => void; +}; -const GeneralErrorContent = ({ message, onClick }) => ( - <> +const GeneralErrorContent = ({ message, onClick }: TGeneralErrorContentProps) => ( +
{message}
@@ -67,21 +78,18 @@ const GeneralErrorContent = ({ message, onClick }) => ( {localize('OK')} - +
); const character_limit_no = 110; const max_allowed_reasons = 3; -const ClosingAccountReason = observer(({ onBackClick }) => { - const { client } = useStore(); - const { dxtrade_accounts_list, mt5_login_list, account_list } = client; - const { is_appstore } = React.useContext(PlatformContext); +const ClosingAccountReason = ({ onBackClick }: TClosingAccountReasonProps) => { const [is_account_closed, setIsAccountClosed] = React.useState(false); const [is_loading, setIsLoading] = React.useState(false); const [is_modal_open, setIsModalOpen] = React.useState(false); - const [which_modal_should_render, setWhichModalShouldRender] = React.useState(); - const [reason, setReason] = React.useState(null); + const [which_modal_should_render, setWhichModalShouldRender] = React.useState(''); + const [reason, setReason] = React.useState(''); const [is_checkbox_disabled, setIsCheckboxDisabled] = React.useState(false); const [total_checkbox_checked, setTotalCheckboxChecked] = React.useState(0); const [remaining_characters, setRemainingCharacters] = React.useState(character_limit_no); @@ -89,8 +97,13 @@ const ClosingAccountReason = observer(({ onBackClick }) => { const [api_error_message, setApiErrorMessage] = React.useState(''); const [details, setDetails] = React.useState(); - const validateFields = values => { - const error = {}; + type Error = { + characters_limits?: string; + empty_reason?: string; + // Add other potential error properties + }; + const validateFields = (values: FormikValues) => { + const error: Error = {}; const selected_reason_count = selectedReasons(values).length; const text_inputs_length = (values.other_trading_platforms + values.do_to_improve).length; let remaining_chars = character_limit_no - text_inputs_length; @@ -112,7 +125,7 @@ const ClosingAccountReason = observer(({ onBackClick }) => { return error; }; - const handleSubmitForm = values => { + const handleSubmitForm = (values: FormikValues) => { const final_reason = preparingReason(values); setIsModalOpen(true); @@ -126,7 +139,11 @@ const ClosingAccountReason = observer(({ onBackClick }) => { // eslint-disable-next-line react-hooks/exhaustive-deps }, [total_checkbox_checked]); - const handleChangeCheckbox = (values, name, setFieldValue) => { + const handleChangeCheckbox = ( + values: FormikValues, + name: string, + setFieldValue: (name: string, values: string | boolean) => void + ) => { if (!values[name]) { setTotalCheckboxChecked(total_checkbox_checked + 1); setFieldValue(name, !values[name]); @@ -136,7 +153,11 @@ const ClosingAccountReason = observer(({ onBackClick }) => { } }; - const handleInputChange = (e, old_value, onChange) => { + const handleInputChange = ( + e: React.ChangeEvent, + old_value: string, + onChange: (e: React.ChangeEvent) => void + ) => { const value = e.target.value; const is_delete_action = old_value.length > value.length; @@ -147,8 +168,8 @@ const ClosingAccountReason = observer(({ onBackClick }) => { } }; - const handleInputPaste = e => { - const clipboardData = (e.clipboardData || window.clipboardData).getData('text'); + const handleInputPaste = async (e: React.ClipboardEvent): Promise => { + const clipboardData = e.clipboardData.getData('text') || (await navigator.clipboard.readText()); if (remaining_characters <= 0 || clipboardData.length > remaining_characters) { e.preventDefault(); @@ -196,17 +217,13 @@ const ClosingAccountReason = observer(({ onBackClick }) => { if (is_loading) return ; return ( -
+
{localize('Please tell us why you’re leaving. (Select up to {{ allowed_reasons }} reasons.)', { allowed_reasons: max_allowed_reasons, })} - { setIsModalOpen(false)} startDeactivating={startDeactivating} /> )} {which_modal_should_render === 'AccountHasPendingConditions' && ( - + )} {which_modal_should_render === 'inaccessible_modal' && ( setIsModalOpen(false)} /> @@ -241,6 +252,6 @@ const ClosingAccountReason = observer(({ onBackClick }) => {
); -}); +}; export default ClosingAccountReason; diff --git a/packages/account/src/Sections/Security/ClosingAccount/closing-account-steps.jsx b/packages/account/src/Sections/Security/ClosingAccount/closing-account-steps.tsx similarity index 95% rename from packages/account/src/Sections/Security/ClosingAccount/closing-account-steps.jsx rename to packages/account/src/Sections/Security/ClosingAccount/closing-account-steps.tsx index 51a7215a66bc..358e1283f41f 100644 --- a/packages/account/src/Sections/Security/ClosingAccount/closing-account-steps.jsx +++ b/packages/account/src/Sections/Security/ClosingAccount/closing-account-steps.tsx @@ -6,7 +6,11 @@ import { Link } from 'react-router-dom'; import { Button, Text, StaticUrl } from '@deriv/components'; import { PlatformContext } from '@deriv/shared'; -const ClosingAccountSteps = observer(({ redirectToReasons }) => { +type TClosingAccountStepsProps = { + redirectToReasons: () => void; +}; + +const ClosingAccountSteps = observer(({ redirectToReasons }: TClosingAccountStepsProps) => { const { common } = useStore(); const { is_from_derivgo } = common; const { is_appstore } = React.useContext(PlatformContext); diff --git a/packages/account/src/Sections/Security/ClosingAccount/closing-account.jsx b/packages/account/src/Sections/Security/ClosingAccount/closing-account.tsx similarity index 84% rename from packages/account/src/Sections/Security/ClosingAccount/closing-account.jsx rename to packages/account/src/Sections/Security/ClosingAccount/closing-account.tsx index c04c6ae2cf41..094a9f5dd48e 100644 --- a/packages/account/src/Sections/Security/ClosingAccount/closing-account.jsx +++ b/packages/account/src/Sections/Security/ClosingAccount/closing-account.tsx @@ -1,6 +1,6 @@ import React, { useState } from 'react'; -import ClosingAccountSteps from './closing-account-steps.jsx'; -import ClosingAccountReason from './closing-account-reason.jsx'; +import ClosingAccountSteps from './closing-account-steps'; +import ClosingAccountReason from './closing-account-reason'; const ClosingAccount = () => { const [render_close_account_reason, setRenderCloseAccountReason] = useState(false); diff --git a/packages/account/src/Sections/Security/ClosingAccount/index.js b/packages/account/src/Sections/Security/ClosingAccount/index.js index 43096d758601..b5c822784e89 100644 --- a/packages/account/src/Sections/Security/ClosingAccount/index.js +++ b/packages/account/src/Sections/Security/ClosingAccount/index.js @@ -1,3 +1,3 @@ -import ClosingAccount from './closing-account.jsx'; +import ClosingAccount from './closing-account'; export default ClosingAccount; diff --git a/packages/account/tsconfig.json b/packages/account/tsconfig.json index aec2281f5147..543c501d9c31 100644 --- a/packages/account/tsconfig.json +++ b/packages/account/tsconfig.json @@ -1,6 +1,7 @@ { "extends": "../../tsconfig.json", "compilerOptions": { + "lib": [ "dom"], "outDir": "./dist", "baseUrl": "./", "paths": { diff --git a/packages/stores/types.ts b/packages/stores/types.ts index 20687872a115..b387f039f002 100644 --- a/packages/stores/types.ts +++ b/packages/stores/types.ts @@ -378,7 +378,7 @@ type TClientStore = { states_list: StatesList; /** @deprecated Use `useCurrencyConfig` or `useCurrentCurrencyConfig` from `@deriv/hooks` package instead. */ is_crypto: (currency?: string) => boolean; - dxtrade_accounts_list: DetailsOfEachMT5Loginid[]; + dxtrade_accounts_list: DetailsOfEachMT5Loginid & { account_id?: string }[]; derivez_accounts_list: DetailsOfEachMT5Loginid[]; default_currency: string; resetVirtualBalance: () => Promise; From 281585295f1e3a7b1068847ed8b4902a69f2d7e2 Mon Sep 17 00:00:00 2001 From: amina-deriv Date: Sat, 19 Aug 2023 10:11:47 +0400 Subject: [PATCH 02/13] chore: initial_draft --- .../account-has-pending-conditions.tsx | 137 ++++++++---------- .../account/src/Types/common-prop.type.ts | 36 ++++- 2 files changed, 98 insertions(+), 75 deletions(-) diff --git a/packages/account/src/Sections/Security/ClosingAccount/account-has-pending-conditions.tsx b/packages/account/src/Sections/Security/ClosingAccount/account-has-pending-conditions.tsx index 4af995d350df..48bb4936d0d6 100644 --- a/packages/account/src/Sections/Security/ClosingAccount/account-has-pending-conditions.tsx +++ b/packages/account/src/Sections/Security/ClosingAccount/account-has-pending-conditions.tsx @@ -4,15 +4,19 @@ import { formatMoney, getCFDAccount, getCFDAccountDisplay, CFD_PLATFORMS } from import { DetailsOfEachMT5Loginid } from '@deriv/api-types'; import { localize, Localize } from '@deriv/translations'; import { observer, useStore } from '@deriv/stores'; +import { TAccounts } from 'Types'; -const getDerivAccount = (client_accounts: TAccounts[], login_id: string) => - client_accounts.find(client_account => client_account.loginid === login_id); - -const getCurrMT5Account = (mt5_login_list: DetailsOfEachMT5Loginid[], login_id: string) => - mt5_login_list.find(account_obj => account_obj.login === login_id); +type TPendingAccountDetails = { + balance?: number; + currency?: string; + display_login?: string; + positions?: number; + withdrawals?: number; +}; -const getCurrDxtradeAccount = (dxtrade_accounts_list: TDxtradeAccount[], login_id: string) => - dxtrade_accounts_list.find(account_obj => account_obj.account_id === login_id); +type TDetailsOfDerivAccount = TAccounts & TPendingAccountDetails; +type TDetailsOfMT5Account = DetailsOfEachMT5Loginid & TPendingAccountDetails; +type TDetailsOfDerivXAccount = TDetailsOfMT5Account & { account_id?: string }; type TWrapperProps = { children: React.ReactNode; @@ -20,38 +24,31 @@ type TWrapperProps = { desc?: React.ReactNode; }; -type TDxtradeAccount = DetailsOfEachMT5Loginid & { account_id?: string }; - -type TPendingProps = TAccounts & { positions?: number }; -type TAccounts = { - account?: { - balance?: string | number; - currency?: string; - disabled?: boolean; - error?: JSX.Element | string; - is_crypto?: boolean; - is_dxtrade?: boolean; - is_mt?: boolean; - market_type?: string; - nativepicker_text?: string; - platform_icon?: { - Derived: React.SVGAttributes; - Financial: React.SVGAttributes; - Options: React.SVGAttributes; - CFDs: React.SVGAttributes; - }; - text?: JSX.Element | string; - value?: string; - }; - icon?: string; - idx?: string | number; - is_dark_mode_on?: boolean; - is_virtual?: boolean | number; +type TContentProps = { + currency_icon: string; loginid?: string; - mt5_login_list?: DetailsOfEachMT5Loginid[]; title?: string; + value: React.ReactNode; +}; + +type TAccountHasPendingConditionsProps = { + details?: { + pending_withdrawals?: Record; + open_positions?: Record; + balance?: Record; + }; + onBackClick: () => void; }; +const getDerivAccount = (client_accounts: TAccounts[], login_id: string) => + client_accounts.find(client_account => client_account.loginid === login_id); + +const getCurrMT5Account = (mt5_login_list: DetailsOfEachMT5Loginid[], login_id: string) => + mt5_login_list.find(account_obj => account_obj.login === login_id); + +const getCurrDxtradeAccount = (dxtrade_accounts_list: TDetailsOfDerivXAccount[], login_id: string) => + dxtrade_accounts_list.find(account_obj => account_obj.account_id === login_id); + const Wrapper = ({ children, title, desc }: TWrapperProps) => (
@@ -65,12 +62,6 @@ const Wrapper = ({ children, title, desc }: TWrapperProps) => (
{children}
); -type TContentProps = { - currency_icon: string; - loginid?: string; - title?: string; - value: React.ReactNode; -}; const Content = ({ currency_icon, loginid, title, value }: TContentProps) => (
@@ -91,27 +82,19 @@ const Content = ({ currency_icon, loginid, title, value }: TContentProps) => (
); -type TBalance = { balance?: number; currency?: string }; - -type TAccountHasPendingConditionsProps = { - details?: { - pending_withdrawals?: Record; - open_positions?: Record; - balance?: Record; - }; - onBackClick: () => void; -}; - const AccountHasPendingConditions = observer(({ details, onBackClick }: TAccountHasPendingConditionsProps) => { const { client } = useStore(); const { dxtrade_accounts_list, mt5_login_list, account_list, is_eu } = client; - const deriv_open_positions: TPendingProps[] = []; - const deriv_balance: (TAccounts & TBalance)[] = []; - const mt5_open_positions: (DetailsOfEachMT5Loginid & { display_login?: string } & { positions?: number })[] = []; - const mt5_balance: (DetailsOfEachMT5Loginid & TBalance & { display_login?: string })[] = []; - const account_pending_withdrawals: (TAccounts & { withdrawals?: number })[] = []; - const dxtrade_open_positions: (TDxtradeAccount & { display_login?: string } & { positions?: number })[] = []; - const dxtrade_balance: (TDxtradeAccount & TBalance & { display_login?: string })[] = []; + + const deriv_open_positions: TDetailsOfDerivAccount[] = []; + const deriv_balance: TDetailsOfDerivAccount[] = []; + const account_pending_withdrawals: TDetailsOfDerivAccount[] = []; + + const mt5_open_positions: TDetailsOfMT5Account[] = []; + const mt5_balance: TDetailsOfMT5Account[] = []; + + const dxtrade_open_positions: TDetailsOfDerivXAccount[] = []; + const dxtrade_balance: TDetailsOfDerivXAccount[] = []; if (details?.pending_withdrawals) { Object.keys(details.pending_withdrawals).forEach(login_id => { @@ -197,11 +180,13 @@ const AccountHasPendingConditions = observer(({ details, onBackClick }: TAccount loginid={account.loginid} title={account.title} value={ - + account.currency && ( + + ) } /> ))} @@ -258,11 +243,13 @@ const AccountHasPendingConditions = observer(({ details, onBackClick }: TAccount }) ?? '' } value={ - + account.currency && ( + + ) } /> ))} @@ -319,11 +306,13 @@ const AccountHasPendingConditions = observer(({ details, onBackClick }: TAccount }) ?? '' } value={ - + account.currency && ( + + ) } /> ))} diff --git a/packages/account/src/Types/common-prop.type.ts b/packages/account/src/Types/common-prop.type.ts index 5298105baa8b..3e6facb69b62 100644 --- a/packages/account/src/Types/common-prop.type.ts +++ b/packages/account/src/Types/common-prop.type.ts @@ -1,6 +1,11 @@ /** Add types that are shared between components */ import { FormikHandlers, FormikProps, FormikValues } from 'formik'; -import { Authorize, IdentityVerificationAddDocumentResponse, ResidenceList } from '@deriv/api-types'; +import { + Authorize, + IdentityVerificationAddDocumentResponse, + ResidenceList, + DetailsOfEachMT5Loginid, +} from '@deriv/api-types'; import { Redirect } from 'react-router-dom'; export type TToken = { @@ -201,3 +206,32 @@ export type TIDVFormValues = { document_additional?: string; error_message?: string; }; + +export type TAccounts = { + account?: { + balance?: string | number; + currency?: string; + disabled?: boolean; + error?: JSX.Element | string; + is_crypto?: boolean; + is_dxtrade?: boolean; + is_mt?: boolean; + market_type?: string; + nativepicker_text?: string; + platform_icon?: { + Derived: React.SVGAttributes; + Financial: React.SVGAttributes; + Options: React.SVGAttributes; + CFDs: React.SVGAttributes; + }; + text?: JSX.Element | string; + value?: string; + }; + icon?: string; + idx?: string | number; + is_dark_mode_on?: boolean; + is_virtual?: boolean | number; + loginid?: string; + mt5_login_list?: DetailsOfEachMT5Loginid[]; + title?: string; +}; From 89e7442772a804192953b1cde1a4bafa520af6a2 Mon Sep 17 00:00:00 2001 From: amina-deriv Date: Wed, 23 Aug 2023 08:53:04 +0400 Subject: [PATCH 03/13] feat: ts migration for closing account --- ...ing-account-general-error-content.spec.tsx | 24 ++ ...ng-account-has-pending-conditions.spec.tsx | 253 ++++++++++++ .../closing-account-reason-form.spec.js | 49 --- .../closing-account-reason-form.spec.tsx | 62 +++ ...pec.js => closing-account-reason.spec.tsx} | 60 ++- .../__tests__/closing-account-steps.spec.tsx | 76 ++++ .../closing-account-warning-modal.spec.tsx | 34 ++ .../__tests__/closing-account.spec.tsx | 48 +++ .../account-has-pending-conditions.tsx | 357 ---------------- .../closing-account-general-error-content.tsx | 23 ++ ...closing-account-has-pending-conditions.tsx | 361 ++++++++++++++++ .../closing-account-reason-form.tsx | 389 +++++++++--------- .../ClosingAccount/closing-account-reason.tsx | 99 ++--- .../ClosingAccount/closing-account-steps.tsx | 26 +- .../closing-account-warning-modal.tsx | 36 ++ .../ClosingAccount/closing-account.tsx | 6 +- packages/account/src/Styles/account.scss | 4 - packages/stores/types.ts | 2 +- 18 files changed, 1189 insertions(+), 720 deletions(-) create mode 100644 packages/account/src/Sections/Security/ClosingAccount/__tests__/closing-account-general-error-content.spec.tsx create mode 100644 packages/account/src/Sections/Security/ClosingAccount/__tests__/closing-account-has-pending-conditions.spec.tsx delete mode 100644 packages/account/src/Sections/Security/ClosingAccount/__tests__/closing-account-reason-form.spec.js create mode 100644 packages/account/src/Sections/Security/ClosingAccount/__tests__/closing-account-reason-form.spec.tsx rename packages/account/src/Sections/Security/ClosingAccount/__tests__/{closing-account-reason.spec.js => closing-account-reason.spec.tsx} (50%) create mode 100644 packages/account/src/Sections/Security/ClosingAccount/__tests__/closing-account-steps.spec.tsx create mode 100644 packages/account/src/Sections/Security/ClosingAccount/__tests__/closing-account-warning-modal.spec.tsx create mode 100644 packages/account/src/Sections/Security/ClosingAccount/__tests__/closing-account.spec.tsx delete mode 100644 packages/account/src/Sections/Security/ClosingAccount/account-has-pending-conditions.tsx create mode 100644 packages/account/src/Sections/Security/ClosingAccount/closing-account-general-error-content.tsx create mode 100644 packages/account/src/Sections/Security/ClosingAccount/closing-account-has-pending-conditions.tsx create mode 100644 packages/account/src/Sections/Security/ClosingAccount/closing-account-warning-modal.tsx diff --git a/packages/account/src/Sections/Security/ClosingAccount/__tests__/closing-account-general-error-content.spec.tsx b/packages/account/src/Sections/Security/ClosingAccount/__tests__/closing-account-general-error-content.spec.tsx new file mode 100644 index 000000000000..91c0f65ad00b --- /dev/null +++ b/packages/account/src/Sections/Security/ClosingAccount/__tests__/closing-account-general-error-content.spec.tsx @@ -0,0 +1,24 @@ +import React from 'react'; +import { render, screen } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; +import ClosingAccountGeneralErrorContent from '../closing-account-general-error-content'; + +describe('', () => { + const mock_props = { + message: 'mock message', + onClick: jest.fn(), + }; + it('should render the ClosingAccountGeneralErrorContent component', () => { + render(); + expect(screen.getByText('mock message')).toBeInTheDocument(); + }); + + it('should call onClick when button is clicked', () => { + render(); + + const ok_button = screen.getByRole('button', { name: /OK/i }); + userEvent.click(ok_button); + + expect(mock_props.onClick).toHaveBeenCalledTimes(1); + }); +}); diff --git a/packages/account/src/Sections/Security/ClosingAccount/__tests__/closing-account-has-pending-conditions.spec.tsx b/packages/account/src/Sections/Security/ClosingAccount/__tests__/closing-account-has-pending-conditions.spec.tsx new file mode 100644 index 000000000000..dd793edcbde0 --- /dev/null +++ b/packages/account/src/Sections/Security/ClosingAccount/__tests__/closing-account-has-pending-conditions.spec.tsx @@ -0,0 +1,253 @@ +import React from 'react'; +import { render, screen } from '@testing-library/react'; +import { StoreProvider, mockStore } from '@deriv/stores'; +import ClosingAccountHasPendingConditions from '../closing-account-has-pending-conditions'; + +jest.mock('@deriv/shared', () => ({ + ...jest.requireActual('@deriv/shared'), + getCFDAccountDisplay: jest.fn(() => 'Financial Demo'), +})); + +describe('', () => { + let store = mockStore({}); + const mock_props = { + details: { + balance: { + CR123: { + balance: 5000.0, + currency: 'USD', + }, + CR234: { + balance: 0.18833116, + currency: 'BTC', + }, + }, + }, + onBackClick: jest.fn(), + }; + store = mockStore({ + client: { + mt5_login_list: [ + { + account_type: 'real', + balance: 2, + country: 'id', + currency: 'USD', + display_balance: '2.00', + email: 'user@deriv.com', + group: 'real\\p01_ts01\\financial\\svg_std-hr_usd', + landing_company_short: 'svg', + leverage: 1000, + login: 'MTR456', + market_type: 'financial', + name: 'QA script userizbta', + server: 'p01_ts01', + server_info: { + environment: 'Deriv-Server', + geolocation: { + group: 'all', + location: 'Ireland', + region: 'Europe', + sequence: 1, + }, + id: 'p01_ts01', + }, + status: null, + sub_account_category: '', + sub_account_type: 'financial', + }, + ], + dxtrade_accounts_list: [ + { + account_id: 'DXR345', + account_type: 'real', + balance: 2221, + currency: 'USD', + display_balance: '2221.00', + landing_company_short: 'svg', + login: '345', + market_type: 'all', + }, + ], + account_list: [ + { + loginid: 'CR123', + is_virtual: 0, + icon: 'usd', + title: 'USD', + }, + { + loginid: 'CR234', + is_virtual: 0, + icon: 'btc', + title: 'BTC', + }, + { + loginid: 'VRTC90000148', + is_virtual: 1, + icon: 'real', + title: 'Real', + }, + ], + + is_eu: false, + }, + }); + + it('should render the ClosingAccountHasPendingConditions component', () => { + const { container } = render( + + + + ); + expect(container).toBeInTheDocument(); + }); + + it('should show the accounts with deriv_balance', () => { + const details = { + balance: { + CR123: { + balance: 2744.0, + currency: 'USD', + }, + CR234: { + balance: 0.18833116, + currency: 'BTC', + }, + }, + }; + + render( + + + + ); + expect( + screen.getByText(/please withdraw your funds from the following deriv account\(s\):/i) + ).toBeInTheDocument(); + expect(screen.getByText(/2,744\.00/i)).toBeInTheDocument(); + expect(screen.getByText(/USD/i)).toBeInTheDocument(); + + expect(screen.getByText(/0\.18833116/i)).toBeInTheDocument(); + expect(screen.getByText(/BTC/i)).toBeInTheDocument(); + }); + + it('should show the accounts with open_positions', () => { + const details = { + open_positions: { + CR123: 1, + }, + }; + + render( + + + + ); + expect( + screen.getByText(/please close your positions in the following deriv account\(s\):/i) + ).toBeInTheDocument(); + expect(screen.getByText(/1 position/i)).toBeInTheDocument(); + }); + + it('should show the accounts with pending withdrawals', () => { + const details = { + pending_withdrawals: { + CR123: 1, + }, + }; + + render( + + + + ); + expect(screen.getByText(/Pending withdrawal request:/i)).toBeInTheDocument(); + expect(screen.getByText(/We are still processing your withdrawal request/i)).toBeInTheDocument(); + expect( + screen.getByText(/Please wait for the transaction to be completed before deactivating your account/i) + ).toBeInTheDocument(); + }); + + it('should show the dxtrade accounts with balance', () => { + const details = { + balance: { + DXR345: { + balance: 2221.0, + currency: 'USD', + }, + }, + }; + + render( + + + + ); + expect( + screen.getByText(/please withdraw your funds from the following deriv x account\(s\):/i) + ).toBeInTheDocument(); + expect(screen.getByText(/2,221\.00/i)).toBeInTheDocument(); + }); + + it('should show the mt5 accounts with balance', () => { + const details = { + balance: { + MTR456: { + balance: 2.0, + currency: 'USD', + }, + MTR567: { + balance: 23.0, + currency: 'USD', + }, + }, + }; + + render( + + + + ); + expect( + screen.getByText(/please withdraw your funds from the following deriv mt5 account\(s\):/i) + ).toBeInTheDocument(); + expect(screen.getByText(/2.0/i)).toBeInTheDocument(); + }); + + it('should show the mt5 accounts with open_positions', () => { + const details = { + open_positions: { + MTR456: 3, + }, + }; + + render( + + + + ); + expect( + screen.getByText(/please close your positions in the following deriv mt5 account\(s\):/i) + ).toBeInTheDocument(); + expect(screen.getByText(/3 position\(s\)/i)).toBeInTheDocument(); + }); + + it('should show the derivx accounts with open_positions', () => { + const details = { + open_positions: { + DXR345: 6, + }, + }; + + render( + + + + ); + expect( + screen.getByText(/please close your positions in the following deriv x account\(s\):/i) + ).toBeInTheDocument(); + expect(screen.getByText(/6 position\(s\)/i)).toBeInTheDocument(); + }); +}); diff --git a/packages/account/src/Sections/Security/ClosingAccount/__tests__/closing-account-reason-form.spec.js b/packages/account/src/Sections/Security/ClosingAccount/__tests__/closing-account-reason-form.spec.js deleted file mode 100644 index ade871f98194..000000000000 --- a/packages/account/src/Sections/Security/ClosingAccount/__tests__/closing-account-reason-form.spec.js +++ /dev/null @@ -1,49 +0,0 @@ -import React from 'react'; -import { render, screen, fireEvent, act, waitFor } from '@testing-library/react'; -import ClosingAccountReasonFrom from '../closing-account-reason-form'; - -describe('', () => { - test('rendering and submitting a basic form', async () => { - const handleSubmit = jest.fn(); - const validateFields = jest.fn(); - const handleChangeCheckbox = (values, name, setFieldValue) => { - setFieldValue(name, !values[name]); - }; - const handleInputChange = (e, _, onChange) => { - onChange(e); - }; - - render( - - ); - - act(() => { - fireEvent.change(screen.getByPlaceholderText(/What could we do to improve/i), { - target: { value: 'do_to_improve' }, - }); - fireEvent.change( - screen.getByPlaceholderText(/If you don’t mind sharing, which other trading platforms do you use/i), - { target: { value: 'other_trading_platforms' } } - ); - }); - - act(() => { - fireEvent.click(screen.getByRole('button', { name: /Continue/i })); - }); - - await waitFor(() => { - expect(handleSubmit).toHaveBeenCalledWith( - expect.objectContaining({ - do_to_improve: 'do_to_improve', - other_trading_platforms: 'other_trading_platforms', - }), - expect.anything() - ); - }); - }); -}); diff --git a/packages/account/src/Sections/Security/ClosingAccount/__tests__/closing-account-reason-form.spec.tsx b/packages/account/src/Sections/Security/ClosingAccount/__tests__/closing-account-reason-form.spec.tsx new file mode 100644 index 000000000000..c1deda49295f --- /dev/null +++ b/packages/account/src/Sections/Security/ClosingAccount/__tests__/closing-account-reason-form.spec.tsx @@ -0,0 +1,62 @@ +import React from 'react'; +import { render, screen, fireEvent, act } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; +import ClosingAccountReasonForm from '../closing-account-reason-form'; + +describe('', () => { + const mock_props = { + validateFields: jest.fn(), + onSubmit: jest.fn(), + is_checkbox_disabled: false, + onChangeCheckbox: jest.fn(), + character_limit_no: 20, + onInputChange: jest.fn(), + onInputPaste: jest.fn(), + remaining_characters: 5, + onBackClick: jest.fn(), + }; + it('Should render ClosingAccountReasonForm component', () => { + render(); + expect(screen.getByLabelText(/I want to stop myself from trading./i)).toBeInTheDocument(); + expect( + screen.getByPlaceholderText(/If you don’t mind sharing, which other trading platforms do you use?/i) + ).toBeInTheDocument(); + + expect(screen.getByRole('button', { name: /Continue/i })).toBeDisabled(); + }); + + it('should call the onBackClick function when cancel button is clicked', () => { + render(); + + userEvent.click(screen.getByRole('button', { name: /Back/i })); + + expect(mock_props.onBackClick).toHaveBeenCalledTimes(1); + }); + + it('should call onChangeCheckbox when checkbox is clicked', () => { + render(); + + const el_checkbox = screen.getByRole('checkbox', { + name: /i’m closing my account for other reasons\./i, + }); + act(() => { + userEvent.click(el_checkbox); + }); + expect(mock_props.onChangeCheckbox).toHaveBeenCalled(); + }); + + it('should call the onInputChange and onInputPaste functions for textarea inputs', () => { + render(); + + const otherPlatformsInput = screen.getByPlaceholderText( + /If you don’t mind sharing, which other trading platforms do you use?/i + ); + const improveInput = screen.getByPlaceholderText(/What could we do to improve?/i); + + fireEvent.change(otherPlatformsInput, { target: { value: 'Other Platforms Input' } }); + fireEvent.paste(improveInput, { clipboardData: { getData: () => 'Pasted Text' } }); + + expect(mock_props.onInputChange).toHaveBeenCalledTimes(1); + expect(mock_props.onInputPaste).toHaveBeenCalledTimes(1); + }); +}); diff --git a/packages/account/src/Sections/Security/ClosingAccount/__tests__/closing-account-reason.spec.js b/packages/account/src/Sections/Security/ClosingAccount/__tests__/closing-account-reason.spec.tsx similarity index 50% rename from packages/account/src/Sections/Security/ClosingAccount/__tests__/closing-account-reason.spec.js rename to packages/account/src/Sections/Security/ClosingAccount/__tests__/closing-account-reason.spec.tsx index ca7527b3c459..bf203bab55ac 100644 --- a/packages/account/src/Sections/Security/ClosingAccount/__tests__/closing-account-reason.spec.js +++ b/packages/account/src/Sections/Security/ClosingAccount/__tests__/closing-account-reason.spec.tsx @@ -1,55 +1,58 @@ import React from 'react'; -import { act, render, screen, waitFor, fireEvent, userEvent } from '@testing-library/react'; -import ClosingAccountReason from '../closing-account-reason'; +import { act, render, screen, waitFor, fireEvent } from '@testing-library/react'; import { mockStore, StoreProvider } from '@deriv/stores'; +import ClosingAccountReason from '../closing-account-reason'; describe('', () => { - let store = mockStore(); + const mockRootStore: ReturnType = mockStore({}); + const mock_props = { + onBackClick: jest.fn(), + }; + let modal_root_el: HTMLDivElement; beforeAll(() => { - const modal_root_el = document.createElement('div'); + modal_root_el = document.createElement('div'); modal_root_el.setAttribute('id', 'modal_root'); document.body.appendChild(modal_root_el); }); afterAll(() => { - let modal_root_el = document.getElementById('modal_root'); document.body.removeChild(modal_root_el); }); - test('Should render properly', async () => { + jest.mock('../closing-account-reason-form', () =>
ClosingAccountReasonForm
); + + it('Should render ClosingAccountReason component', async () => { render( - - + + ); await waitFor(() => { - screen.getAllByText(/Please tell us why you’re leaving/i); + expect(screen.getByText(/Please tell us why you’re leaving/i)).toBeInTheDocument(); }); }); - test('Should be disabled when no reason has been selected', async () => { + it('Should be disabled when no reason has been selected', async () => { render( - - + + ); - // clicking the checkbox twice to select and unselect fireEvent.click(screen.getByRole('checkbox', { name: /I have other financial priorities./i })); fireEvent.click(screen.getByRole('checkbox', { name: /I have other financial priorities./i })); - // when no reason is selected it should show error and the button should be disabled await waitFor(() => { expect(screen.getByText(/Please select at least one reason/i)).toBeInTheDocument(); const continueButton = screen.getAllByRole('button')[1]; - expect(continueButton).toHaveAttribute('disabled'); + expect(continueButton).toBeDisabled(); }); }); - test('should reduce remaining chars', async () => { + it('should reduce remaining chars', () => { render( - - + + ); @@ -70,7 +73,26 @@ describe('', () => { }); expect(screen.getByText(/Remaining characters: 97/i)).toBeInTheDocument(); + }); + + it('should call onBackClick when back button is clicked', () => { + render( + + + + ); + + const el_checkbox = screen.getByRole('checkbox', { + name: /i’m closing my account for other reasons\./i, + }); + act(() => { + fireEvent.click(el_checkbox); + }); + + act(() => { + fireEvent.click(screen.getByRole('button', { name: /Back/i })); + }); - screen.debug(); + expect(mock_props.onBackClick).toHaveBeenCalledTimes(1); }); }); diff --git a/packages/account/src/Sections/Security/ClosingAccount/__tests__/closing-account-steps.spec.tsx b/packages/account/src/Sections/Security/ClosingAccount/__tests__/closing-account-steps.spec.tsx new file mode 100644 index 000000000000..3a4c276c4ef0 --- /dev/null +++ b/packages/account/src/Sections/Security/ClosingAccount/__tests__/closing-account-steps.spec.tsx @@ -0,0 +1,76 @@ +import React from 'react'; +import { render, screen } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; +import { BrowserRouter } from 'react-router-dom'; +import { createBrowserHistory } from 'history'; +import { StoreProvider, mockStore } from '@deriv/stores'; +import ClosingAccountSteps from '../closing-account-steps'; + +describe('', () => { + const mockRootStore: ReturnType = mockStore({}); + const history = createBrowserHistory(); + const mock_props = { + redirectToReasons: jest.fn(), + }; + + const renderComponent = () => { + const wrapper = ({ children }: { children: JSX.Element }) => ( + + {children} + + ); + render(, { + wrapper, + }); + }; + + it('should render the ClosingAccountSteps component', () => { + renderComponent(); + expect(screen.getByText('Are you sure?')).toBeInTheDocument(); + expect(screen.getByText('If you close your account:')).toBeInTheDocument(); + expect(screen.getByText("You can't trade on Deriv.")).toBeInTheDocument(); + expect(screen.getByText("You can't make transactions.")).toBeInTheDocument(); + expect(screen.getByText('Before closing your account:')).toBeInTheDocument(); + expect(screen.getByText('Close all your positions.')).toBeInTheDocument(); + expect(screen.getByText('Withdraw your funds.')).toBeInTheDocument(); + expect( + screen.getByText( + 'We shall delete your personal information as soon as our legal obligations are met, as mentioned in the section on Data Retention in our' + ) + ).toBeInTheDocument(); + }); + + it('should have link to security and privacy policy pdf', () => { + renderComponent(); + expect(screen.getByRole('link', { name: /Security and privacy policy/i })).toHaveAttribute( + 'href', + 'https://deriv.com/tnc/security-and-privacy.pdf' + ); + }); + + it('should call redirectToReasons when close_account_button is clicked ', () => { + renderComponent(); + const close_account_button = screen.getByRole('button', { name: /Close my account/i }); + expect(close_account_button).toBeInTheDocument(); + userEvent.click(close_account_button); + expect(mock_props.redirectToReasons).toHaveBeenCalled(); + }); + + it('should navigate to root page on clicking the cancel button', () => { + renderComponent(); + const cancel_button = screen.getByRole('button', { name: /Cancel/i }); + expect(cancel_button).toBeInTheDocument(); + userEvent.click(cancel_button); + expect(history.location.pathname).toBe('/'); + }); + + it('should render proper button if is_from_derivgo is true', () => { + mockRootStore.common.is_from_derivgo = true; + renderComponent(); + expect(screen.queryByRole('button', { name: /Cancel/i })).not.toBeInTheDocument(); + const close_account_button = screen.getByRole('button', { name: /Close my account/i }); + expect(close_account_button).toBeInTheDocument(); + userEvent.click(close_account_button); + expect(mock_props.redirectToReasons).toHaveBeenCalled(); + }); +}); diff --git a/packages/account/src/Sections/Security/ClosingAccount/__tests__/closing-account-warning-modal.spec.tsx b/packages/account/src/Sections/Security/ClosingAccount/__tests__/closing-account-warning-modal.spec.tsx new file mode 100644 index 000000000000..6485c3a3e148 --- /dev/null +++ b/packages/account/src/Sections/Security/ClosingAccount/__tests__/closing-account-warning-modal.spec.tsx @@ -0,0 +1,34 @@ +import React from 'react'; +import { render, screen } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; +import ClosingAccountWarningModal from '../closing-account-warning-modal'; + +describe('', () => { + const mock_props = { + startDeactivating: jest.fn(), + closeModal: jest.fn(), + }; + it('should render the ClosingAccountWarningModal component', async () => { + render(); + expect(screen.getByText('Close your account?')).toBeInTheDocument(); + expect(screen.getByText(/Closing your account will automatically log you out./i)).toBeInTheDocument(); + }); + + it('calls startDeactivating when "Close account" button is clicked', () => { + render(); + + const closeButton = screen.getByRole('button', { name: /Close account/i }); + userEvent.click(closeButton); + + expect(mock_props.startDeactivating).toHaveBeenCalledTimes(1); + }); + + it('calls closeModal when "Go Back" button is clicked', () => { + render(); + + const goBackButton = screen.getByRole('button', { name: /Go Back/i }); + userEvent.click(goBackButton); + + expect(mock_props.closeModal).toHaveBeenCalledTimes(1); + }); +}); diff --git a/packages/account/src/Sections/Security/ClosingAccount/__tests__/closing-account.spec.tsx b/packages/account/src/Sections/Security/ClosingAccount/__tests__/closing-account.spec.tsx new file mode 100644 index 000000000000..b06c93a564e1 --- /dev/null +++ b/packages/account/src/Sections/Security/ClosingAccount/__tests__/closing-account.spec.tsx @@ -0,0 +1,48 @@ +import React from 'react'; +import { render, screen } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; +import ClosingAccount from '../closing-account'; + +jest.mock('../closing-account-steps', () => ({ + __esModule: true, + default: ({ redirectToReasons }: { redirectToReasons: () => void }) => ( +
ClosingAccountSteps
+ ), +})); + +jest.mock('../closing-account-reason', () => ({ + __esModule: true, + default: ({ onBackClick }: { onBackClick: () => void }) =>
ClosingAccountReason
, +})); + +describe('', () => { + it('should render the ClosingAccountReason component', async () => { + render(); + expect(screen.getByTestId('dt_closing_account')).toBeInTheDocument(); + }); + + it('should render the ClosingAccountSteps component if render_close_account_reason is false', async () => { + render(); + expect(screen.getByText('ClosingAccountSteps')).toBeInTheDocument(); + }); + + it('should render the ClosingAccountReason component if render_close_account_reason is true', async () => { + const spy = jest.spyOn(React, 'useState').mockImplementation(() => [true, jest.fn()]); + render(); + expect(screen.getByText('ClosingAccountReason')).toBeInTheDocument(); + spy.mockRestore(); + }); + + it('should switch from ClosingAccountReason to ClosingAccountSteps on clicking back button in ClosingAccountReason ', () => { + render(); + const closingAccountSteps = screen.getByText('ClosingAccountSteps'); + + userEvent.click(closingAccountSteps); + + const backBtn = screen.getByText('ClosingAccountReason'); + userEvent.click(backBtn); + + const closingAccountStepsAfterBack = screen.getByText('ClosingAccountSteps'); + expect(closingAccountStepsAfterBack).toBeInTheDocument(); + }); +}); diff --git a/packages/account/src/Sections/Security/ClosingAccount/account-has-pending-conditions.tsx b/packages/account/src/Sections/Security/ClosingAccount/account-has-pending-conditions.tsx deleted file mode 100644 index 48bb4936d0d6..000000000000 --- a/packages/account/src/Sections/Security/ClosingAccount/account-has-pending-conditions.tsx +++ /dev/null @@ -1,357 +0,0 @@ -import React from 'react'; -import { Button, Icon, Money, ThemedScrollbars, Text } from '@deriv/components'; -import { formatMoney, getCFDAccount, getCFDAccountDisplay, CFD_PLATFORMS } from '@deriv/shared'; -import { DetailsOfEachMT5Loginid } from '@deriv/api-types'; -import { localize, Localize } from '@deriv/translations'; -import { observer, useStore } from '@deriv/stores'; -import { TAccounts } from 'Types'; - -type TPendingAccountDetails = { - balance?: number; - currency?: string; - display_login?: string; - positions?: number; - withdrawals?: number; -}; - -type TDetailsOfDerivAccount = TAccounts & TPendingAccountDetails; -type TDetailsOfMT5Account = DetailsOfEachMT5Loginid & TPendingAccountDetails; -type TDetailsOfDerivXAccount = TDetailsOfMT5Account & { account_id?: string }; - -type TWrapperProps = { - children: React.ReactNode; - title: string; - desc?: React.ReactNode; -}; - -type TContentProps = { - currency_icon: string; - loginid?: string; - title?: string; - value: React.ReactNode; -}; - -type TAccountHasPendingConditionsProps = { - details?: { - pending_withdrawals?: Record; - open_positions?: Record; - balance?: Record; - }; - onBackClick: () => void; -}; - -const getDerivAccount = (client_accounts: TAccounts[], login_id: string) => - client_accounts.find(client_account => client_account.loginid === login_id); - -const getCurrMT5Account = (mt5_login_list: DetailsOfEachMT5Loginid[], login_id: string) => - mt5_login_list.find(account_obj => account_obj.login === login_id); - -const getCurrDxtradeAccount = (dxtrade_accounts_list: TDetailsOfDerivXAccount[], login_id: string) => - dxtrade_accounts_list.find(account_obj => account_obj.account_id === login_id); - -const Wrapper = ({ children, title, desc }: TWrapperProps) => ( -
- - {title} - - {desc && ( - - {desc} - - )} -
{children}
-
-); - -const Content = ({ currency_icon, loginid, title, value }: TContentProps) => ( -
-
- -
- - {title} - - - {loginid} - -
-
- - {value} - -
-); - -const AccountHasPendingConditions = observer(({ details, onBackClick }: TAccountHasPendingConditionsProps) => { - const { client } = useStore(); - const { dxtrade_accounts_list, mt5_login_list, account_list, is_eu } = client; - - const deriv_open_positions: TDetailsOfDerivAccount[] = []; - const deriv_balance: TDetailsOfDerivAccount[] = []; - const account_pending_withdrawals: TDetailsOfDerivAccount[] = []; - - const mt5_open_positions: TDetailsOfMT5Account[] = []; - const mt5_balance: TDetailsOfMT5Account[] = []; - - const dxtrade_open_positions: TDetailsOfDerivXAccount[] = []; - const dxtrade_balance: TDetailsOfDerivXAccount[] = []; - - if (details?.pending_withdrawals) { - Object.keys(details.pending_withdrawals).forEach(login_id => { - const info = { - withdrawals: details.pending_withdrawals?.[login_id], - }; - const deriv_account = getDerivAccount(account_list, login_id); - if (deriv_account) { - account_pending_withdrawals.push({ ...deriv_account, ...info }); - } - }); - } - if (details?.open_positions) { - Object.keys(details?.open_positions).forEach(login_id => { - const info = { - positions: details.open_positions?.[login_id], - }; - const deriv_account = getDerivAccount(account_list, login_id); - if (deriv_account) { - deriv_open_positions.push({ ...deriv_account, ...info }); - } else { - const mt5_account = getCurrMT5Account(mt5_login_list, login_id); - if (mt5_account) { - mt5_open_positions.push({ ...mt5_account, ...info }); - } - - const dxtrade_account = getCurrDxtradeAccount(dxtrade_accounts_list, login_id); - if (dxtrade_account) { - dxtrade_open_positions.push({ ...dxtrade_account, ...info }); - } - } - }); - } - if (details?.balance) { - Object.keys(details.balance).forEach(login_id => { - const info = { - balance: details.balance?.[login_id].balance, - currency: details.balance?.[login_id].currency, - }; - const deriv_account = getDerivAccount(account_list, login_id); - if (deriv_account) { - deriv_balance.push({ ...deriv_account, ...info }); - } else { - const mt5_account = getCurrMT5Account(mt5_login_list, login_id); - if (mt5_account) { - mt5_balance.push({ ...mt5_account, ...info }); - } - - const dxtrade_account = getCurrDxtradeAccount(dxtrade_accounts_list, login_id); - if (dxtrade_account) { - dxtrade_balance.push({ ...dxtrade_account, ...info }); - } - } - }); - } - return ( - - - {!!deriv_open_positions.length && ( - - {deriv_open_positions.map(account => ( - - } - /> - ))} - - )} - {!!deriv_balance.length && ( - - {deriv_balance.map(account => ( - - ) - } - /> - ))} - - )} - {!!mt5_open_positions.length && ( - - {mt5_open_positions.map(account => ( - - } - /> - ))} - - )} - {!!mt5_balance.length && ( - - {mt5_balance.map(account => ( - - ) - } - /> - ))} - - )} - {!!dxtrade_open_positions.length && ( - - {dxtrade_open_positions.map(account => ( - - } - /> - ))} - - )} - {!!dxtrade_balance.length && ( - - {dxtrade_balance.map(account => ( - - ) - } - /> - ))} - - )} - {!!account_pending_withdrawals.length && ( - ]} - /> - } - > - {account_pending_withdrawals.map(account => ( - - } - /> - ))} - - )} - -
- -
-
- ); -}); - -export default AccountHasPendingConditions; diff --git a/packages/account/src/Sections/Security/ClosingAccount/closing-account-general-error-content.tsx b/packages/account/src/Sections/Security/ClosingAccount/closing-account-general-error-content.tsx new file mode 100644 index 000000000000..905582420324 --- /dev/null +++ b/packages/account/src/Sections/Security/ClosingAccount/closing-account-general-error-content.tsx @@ -0,0 +1,23 @@ +import React from 'react'; +import { localize } from '@deriv/translations'; +import { Button } from '@deriv/components'; + +type TClosingAccountGeneralErrorContentProps = { + message: string; + onClick: () => void; +}; + +const ClosingAccountGeneralErrorContent = ({ message, onClick }: TClosingAccountGeneralErrorContentProps) => ( + +
+
{message}
+
+
+ +
+
+); + +export default ClosingAccountGeneralErrorContent; diff --git a/packages/account/src/Sections/Security/ClosingAccount/closing-account-has-pending-conditions.tsx b/packages/account/src/Sections/Security/ClosingAccount/closing-account-has-pending-conditions.tsx new file mode 100644 index 000000000000..7da6f7227ced --- /dev/null +++ b/packages/account/src/Sections/Security/ClosingAccount/closing-account-has-pending-conditions.tsx @@ -0,0 +1,361 @@ +import React from 'react'; +import { Button, Icon, Money, Text, ThemedScrollbars } from '@deriv/components'; +import { CFD_PLATFORMS, formatMoney, getCFDAccount, getCFDAccountDisplay } from '@deriv/shared'; +import { DetailsOfEachMT5Loginid } from '@deriv/api-types'; +import { localize, Localize } from '@deriv/translations'; +import { observer, useStore } from '@deriv/stores'; +import { TAccounts } from 'Types'; + +type TPendingAccountDetails = { + balance?: number; + currency?: string; + display_login?: string; + positions?: number; + withdrawals?: number; +}; + +type TDetailsOfDerivAccount = TAccounts & TPendingAccountDetails; +type TDetailsOfMT5Account = DetailsOfEachMT5Loginid & TPendingAccountDetails; +type TDetailsOfDerivXAccount = TDetailsOfMT5Account & { account_id?: string }; + +type TWrapperProps = { + children: React.ReactNode; + title: string; + desc?: React.ReactNode; +}; + +type TContentProps = { + currency_icon: string; + loginid?: string; + title?: string; + value: React.ReactNode; +}; + +type TClosingAccountHasPendingConditionsProps = { + details?: { + pending_withdrawals?: Record; + open_positions?: Record; + balance?: Record; + }; + onBackClick: () => void; +}; + +const Wrapper = ({ children, title, desc }: TWrapperProps) => ( +
+ + {title} + + {desc && ( + + {desc} + + )} +
{children}
+
+); + +const Content = ({ currency_icon, loginid, title, value }: TContentProps) => ( +
+
+ +
+ + {title} + + + {loginid} + +
+
+ + {value} + +
+); + +const getDerivAccount = (client_accounts: TAccounts[], login_id: string) => + client_accounts.find(client_account => client_account.loginid === login_id); + +const getCurrMT5Account = (mt5_login_list: DetailsOfEachMT5Loginid[], login_id: string) => + mt5_login_list.find(account_obj => account_obj.login === login_id); + +const getCurrDxtradeAccount = (dxtrade_accounts_list: TDetailsOfDerivXAccount[], login_id: string) => + dxtrade_accounts_list.find(account_obj => account_obj.account_id === login_id); + +const ClosingAccountHasPendingConditions = observer( + ({ details, onBackClick }: TClosingAccountHasPendingConditionsProps) => { + const { client } = useStore(); + const { dxtrade_accounts_list, mt5_login_list, account_list, is_eu } = client; + + const deriv_open_positions: TDetailsOfDerivAccount[] = []; + const deriv_balance: TDetailsOfDerivAccount[] = []; + const account_pending_withdrawals: TDetailsOfDerivAccount[] = []; + + const mt5_open_positions: TDetailsOfMT5Account[] = []; + const mt5_balance: TDetailsOfMT5Account[] = []; + + const dxtrade_open_positions: TDetailsOfDerivXAccount[] = []; + const dxtrade_balance: TDetailsOfDerivXAccount[] = []; + + if (details?.pending_withdrawals) { + Object.keys(details.pending_withdrawals).forEach(login_id => { + const info = { + withdrawals: details.pending_withdrawals?.[login_id], + }; + const deriv_account = getDerivAccount(account_list, login_id); + if (deriv_account) { + account_pending_withdrawals.push({ ...deriv_account, ...info }); + } + }); + } + if (details?.open_positions) { + Object.keys(details?.open_positions).forEach(login_id => { + const info = { + positions: details.open_positions?.[login_id], + }; + const deriv_account = getDerivAccount(account_list, login_id); + if (deriv_account) { + deriv_open_positions.push({ ...deriv_account, ...info }); + } else { + const mt5_account = getCurrMT5Account(mt5_login_list, login_id); + if (mt5_account) { + mt5_open_positions.push({ ...mt5_account, ...info }); + } + + const dxtrade_account = getCurrDxtradeAccount(dxtrade_accounts_list, login_id); + if (dxtrade_account) { + dxtrade_open_positions.push({ ...dxtrade_account, ...info }); + } + } + }); + } + if (details?.balance) { + Object.keys(details.balance).forEach(login_id => { + const info = { + balance: details.balance?.[login_id].balance, + currency: details.balance?.[login_id].currency, + }; + const deriv_account = getDerivAccount(account_list, login_id); + if (deriv_account) { + deriv_balance.push({ ...deriv_account, ...info }); + } else { + const mt5_account = getCurrMT5Account(mt5_login_list, login_id); + if (mt5_account) { + mt5_balance.push({ ...mt5_account, ...info }); + } + + const dxtrade_account = getCurrDxtradeAccount(dxtrade_accounts_list, login_id); + if (dxtrade_account) { + dxtrade_balance.push({ ...dxtrade_account, ...info }); + } + } + }); + } + return ( + + + {!!deriv_open_positions.length && ( + + {deriv_open_positions.map(account => ( + + } + /> + ))} + + )} + {!!deriv_balance.length && ( + + {deriv_balance.map(account => ( + + ) + } + /> + ))} + + )} + {!!mt5_open_positions.length && ( + + {mt5_open_positions.map(account => ( + + } + /> + ))} + + )} + {!!mt5_balance.length && ( + + {mt5_balance.map(account => ( + + ) + } + /> + ))} + + )} + {!!dxtrade_open_positions.length && ( + + {dxtrade_open_positions.map(account => ( + + } + /> + ))} + + )} + {!!dxtrade_balance.length && ( + + {dxtrade_balance.map(account => ( + + ) + } + /> + ))} + + )} + {!!account_pending_withdrawals.length && ( + ]} + /> + } + > + {account_pending_withdrawals.map(account => ( + + } + /> + ))} + + )} + +
+ +
+
+ ); + } +); + +export default ClosingAccountHasPendingConditions; diff --git a/packages/account/src/Sections/Security/ClosingAccount/closing-account-reason-form.tsx b/packages/account/src/Sections/Security/ClosingAccount/closing-account-reason-form.tsx index fa6b6c17d7f0..b92783fc40f7 100644 --- a/packages/account/src/Sections/Security/ClosingAccount/closing-account-reason-form.tsx +++ b/packages/account/src/Sections/Security/ClosingAccount/closing-account-reason-form.tsx @@ -1,11 +1,9 @@ import React from 'react'; -import { Formik, Field, FormikValues, FormikErrors } from 'formik'; -import { Checkbox, Input, FormSubmitButton, Text } from '@deriv/components'; +import { Field, Formik, FormikErrors, FormikValues } from 'formik'; +import { Checkbox, FormSubmitButton, Input, Text } from '@deriv/components'; import { localize } from '@deriv/translations'; -import { PlatformContext } from '@deriv/shared'; type TFormValues = { - // Define the checkbox values 'financial-priorities': boolean; 'stop-trading': boolean; 'not-interested': boolean; @@ -60,202 +58,195 @@ const ClosingAccountReasonForm = ({ onInputPaste, remaining_characters, onBackClick, -}: TClosingAccountReasonFormProps) => { - const { is_appstore } = React.useContext(PlatformContext); - - return ( - - {({ values, setFieldValue, errors, handleChange, handleSubmit, dirty }) => ( - - - {({ field }: FormikValues) => ( - { - onChangeCheckbox(values, field.name, setFieldValue); - }} - /> - )} - - - {({ field }: FormikValues) => ( - { - onChangeCheckbox(values, field.name, setFieldValue); - }} - /> - )} - - - {({ field }: FormikValues) => ( - { - onChangeCheckbox(values, field.name, setFieldValue); - }} - /> - )} - - - {({ field }: FormikValues) => ( - { - onChangeCheckbox(values, field.name, setFieldValue); - }} - /> - )} - - - {({ field }: FormikValues) => ( - { - onChangeCheckbox(values, field.name, setFieldValue); - }} - /> - )} - - - {({ field }: FormikValues) => ( - { - onChangeCheckbox(values, field.name, setFieldValue); - }} - /> - )} - - - {({ field }: FormikValues) => ( - { - onChangeCheckbox(values, field.name, setFieldValue); - }} - /> - )} - - - {({ field }: FormikValues) => ( - { - onChangeCheckbox(values, field.name, setFieldValue); - }} - /> - )} - - - {({ field }: FormikValues) => ( - { - onChangeCheckbox(values, field.name, setFieldValue); - }} - /> - )} - - - {({ field }: FormikValues) => ( - onInputChange(e, values.other_trading_platforms, handleChange)} - onPaste={onInputPaste} - /> - )} - - - {({ field }: FormikValues) => ( - onInputChange(e, values.do_to_improve, handleChange)} - onPaste={onInputPaste} - /> - )} - -
-
- - {localize('Remaining characters: {{remaining_characters}}', { - remaining_characters, - })} - - {Object.keys(errors).length > 0 && - Object.entries(errors).map(([key, value]) => ( - - {value} - - ))} -
- 0 - } - label={localize('Continue')} - has_cancel - cancel_label={localize('Back')} - onCancel={onBackClick} +}: TClosingAccountReasonFormProps) => ( + + {({ values, setFieldValue, errors, handleChange, handleSubmit, dirty }) => ( + + + {({ field }: FormikValues) => ( + { + onChangeCheckbox(values, field.name, setFieldValue); + }} + /> + )} + + + {({ field }: FormikValues) => ( + { + onChangeCheckbox(values, field.name, setFieldValue); + }} + /> + )} + + + {({ field }: FormikValues) => ( + { + onChangeCheckbox(values, field.name, setFieldValue); + }} + /> + )} + + + {({ field }: FormikValues) => ( + { + onChangeCheckbox(values, field.name, setFieldValue); + }} + /> + )} + + + {({ field }: FormikValues) => ( + { + onChangeCheckbox(values, field.name, setFieldValue); + }} + /> + )} + + + {({ field }: FormikValues) => ( + { + onChangeCheckbox(values, field.name, setFieldValue); + }} /> + )} + + + {({ field }: FormikValues) => ( + { + onChangeCheckbox(values, field.name, setFieldValue); + }} + /> + )} + + + {({ field }: FormikValues) => ( + { + onChangeCheckbox(values, field.name, setFieldValue); + }} + /> + )} + + + {({ field }: FormikValues) => ( + { + onChangeCheckbox(values, field.name, setFieldValue); + }} + /> + )} + + + {({ field }: FormikValues) => ( + onInputChange(e, values.other_trading_platforms, handleChange)} + onPaste={onInputPaste} + /> + )} + + + {({ field }: FormikValues) => ( + onInputChange(e, values.do_to_improve, handleChange)} + onPaste={onInputPaste} + /> + )} + +
+
+ + {localize('Remaining characters: {{remaining_characters}}', { + remaining_characters, + })} + + {Object.keys(errors).length > 0 && + Object.entries(errors).map(([key, value]) => ( + + {value} + + ))}
- - )} - - ); -}; + 0} + label={localize('Continue')} + has_cancel + cancel_label={localize('Back')} + onCancel={onBackClick} + /> +
+ + )} +
+); export default ClosingAccountReasonForm; diff --git a/packages/account/src/Sections/Security/ClosingAccount/closing-account-reason.tsx b/packages/account/src/Sections/Security/ClosingAccount/closing-account-reason.tsx index ea9c5a69dd0b..dda275f8fa13 100644 --- a/packages/account/src/Sections/Security/ClosingAccount/closing-account-reason.tsx +++ b/packages/account/src/Sections/Security/ClosingAccount/closing-account-reason.tsx @@ -3,14 +3,24 @@ import { Redirect } from 'react-router-dom'; import { routes, WS } from '@deriv/shared'; import { FormikValues } from 'formik'; import { localize } from '@deriv/translations'; -import { FormSubmitButton, Modal, Icon, Loading, Text, Button } from '@deriv/components'; -import AccountHasPendingConditions from './account-has-pending-conditions'; +import { Loading, Modal, Text } from '@deriv/components'; +import ClosingAccountHasPendingConditions from './closing-account-has-pending-conditions'; import ClosingAccountReasonForm from './closing-account-reason-form'; +import ClosingAccountWarningModal from './closing-account-warning-modal'; +import ClosingAccountGeneralErrorContent from './closing-account-general-error-content'; type TClosingAccountReasonProps = { onBackClick: () => void; }; +type Error = { + characters_limits?: string; + empty_reason?: string; +}; + +const character_limit_no = 110; +const max_allowed_reasons = 3; + const preparingReason = (values: FormikValues) => { let selected_reasons = selectedReasons(values) .map(val => val[0]) @@ -33,57 +43,6 @@ const selectedReasons = (values: FormikValues) => { ); }; -type TWarningModalProps = { - closeModal: () => void; - startDeactivating: () => void; -}; -const WarningModal = ({ closeModal, startDeactivating }: TWarningModalProps) => { - return ( -
- - - {localize('Close your account?')} - -
- - {localize( - 'Closing your account will automatically log you out. We shall delete your personal information as soon as our legal obligations are met.' - )} - -
- startDeactivating()} - onCancel={() => closeModal()} - /> -
- ); -}; -type TGeneralErrorContentProps = { - message: string; - onClick: () => void; -}; - -const GeneralErrorContent = ({ message, onClick }: TGeneralErrorContentProps) => ( - -
-
{message}
-
-
- -
-
-); - -const character_limit_no = 110; -const max_allowed_reasons = 3; - const ClosingAccountReason = ({ onBackClick }: TClosingAccountReasonProps) => { const [is_account_closed, setIsAccountClosed] = React.useState(false); const [is_loading, setIsLoading] = React.useState(false); @@ -97,11 +56,12 @@ const ClosingAccountReason = ({ onBackClick }: TClosingAccountReasonProps) => { const [api_error_message, setApiErrorMessage] = React.useState(''); const [details, setDetails] = React.useState(); - type Error = { - characters_limits?: string; - empty_reason?: string; - // Add other potential error properties - }; + React.useEffect(() => { + if (total_checkbox_checked === max_allowed_reasons) setIsCheckboxDisabled(true); + else if (is_checkbox_disabled) setIsCheckboxDisabled(false); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [total_checkbox_checked]); + const validateFields = (values: FormikValues) => { const error: Error = {}; const selected_reason_count = selectedReasons(values).length; @@ -133,12 +93,6 @@ const ClosingAccountReason = ({ onBackClick }: TClosingAccountReasonProps) => { setReason(final_reason); }; - React.useEffect(() => { - if (total_checkbox_checked === max_allowed_reasons) setIsCheckboxDisabled(true); - else if (is_checkbox_disabled) setIsCheckboxDisabled(false); - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [total_checkbox_checked]); - const handleChangeCheckbox = ( values: FormikValues, name: string, @@ -178,8 +132,9 @@ const ClosingAccountReason = ({ onBackClick }: TClosingAccountReasonProps) => { const getModalTitle = () => { if (which_modal_should_render === 'error_modal') return localize('An error occurred'); - if (which_modal_should_render === 'inaccessible_modal') return localize('Inaccessible MT5 account(s)'); - return which_modal_should_render !== 'warning_modal' ? localize('Action required') : undefined; + else if (which_modal_should_render === 'inaccessible_modal') return localize('Inaccessible MT5 account(s)'); + else if (which_modal_should_render !== 'warning_modal') return localize('Action required'); + return ''; }; const startDeactivating = async () => { @@ -241,13 +196,19 @@ const ClosingAccountReason = ({ onBackClick }: TClosingAccountReasonProps) => { title={getModalTitle()} > {which_modal_should_render === 'warning_modal' && ( - setIsModalOpen(false)} startDeactivating={startDeactivating} /> + setIsModalOpen(false)} + startDeactivating={startDeactivating} + /> )} {which_modal_should_render === 'AccountHasPendingConditions' && ( - + )} {which_modal_should_render === 'inaccessible_modal' && ( - setIsModalOpen(false)} /> + setIsModalOpen(false)} + /> )}
diff --git a/packages/account/src/Sections/Security/ClosingAccount/closing-account-steps.tsx b/packages/account/src/Sections/Security/ClosingAccount/closing-account-steps.tsx index 358e1283f41f..aa5d63f269d3 100644 --- a/packages/account/src/Sections/Security/ClosingAccount/closing-account-steps.tsx +++ b/packages/account/src/Sections/Security/ClosingAccount/closing-account-steps.tsx @@ -1,19 +1,17 @@ import React from 'react'; -import classNames from 'classnames'; import { observer, useStore } from '@deriv/stores'; import { localize, Localize } from '@deriv/translations'; import { Link } from 'react-router-dom'; -import { Button, Text, StaticUrl } from '@deriv/components'; -import { PlatformContext } from '@deriv/shared'; +import { Button, StaticUrl, Text } from '@deriv/components'; type TClosingAccountStepsProps = { redirectToReasons: () => void; }; const ClosingAccountSteps = observer(({ redirectToReasons }: TClosingAccountStepsProps) => { - const { common } = useStore(); - const { is_from_derivgo } = common; - const { is_appstore } = React.useContext(PlatformContext); + const { + common: { is_from_derivgo }, + } = useStore(); return (
@@ -53,9 +51,7 @@ const ClosingAccountSteps = observer(({ redirectToReasons }: TClosingAccountStep {is_from_derivgo ? (
diff --git a/packages/account/src/Sections/Security/ClosingAccount/closing-account-has-pending-conditions.tsx b/packages/account/src/Sections/Security/ClosingAccount/closing-account-has-pending-conditions.tsx index 63761d636f62..cc654756a8b5 100644 --- a/packages/account/src/Sections/Security/ClosingAccount/closing-account-has-pending-conditions.tsx +++ b/packages/account/src/Sections/Security/ClosingAccount/closing-account-has-pending-conditions.tsx @@ -2,7 +2,7 @@ import React from 'react'; import { Button, Icon, Money, Text, ThemedScrollbars } from '@deriv/components'; import { CFD_PLATFORMS, formatMoney, getCFDAccount, getCFDAccountDisplay } from '@deriv/shared'; import { DetailsOfEachMT5Loginid } from '@deriv/api-types'; -import { localize, Localize } from '@deriv/translations'; +import { Localize } from '@deriv/translations'; import { observer, useStore } from '@deriv/stores'; import { TAccounts } from 'Types'; @@ -20,14 +20,14 @@ type TDetailsOfDerivXAccount = TDetailsOfMT5Account & { account_id?: string }; type TWrapperProps = { children: React.ReactNode; - title: string; + title: React.ReactNode; description?: React.ReactNode; }; type TContentProps = { currency_icon: string; loginid?: string; - title?: string; + title?: React.ReactNode; value: React.ReactNode; }; @@ -51,6 +51,21 @@ type TClosingAccountHasPendingConditionsProps = { onBackClick: () => void; }; +const getPlatformName = (platform: 'mt5' | 'dxtrade') => { + if (platform === 'mt5') { + return ; + } + return ; +}; +const getDerivAccount = (client_accounts: TAccounts[], login_id: string) => + client_accounts.find(client_account => client_account.loginid === login_id); + +const getCurrMT5Account = (mt5_login_list: DetailsOfEachMT5Loginid[], login_id: string) => + mt5_login_list.find(account_obj => account_obj.login === login_id); + +const getCurrDxtradeAccount = (dxtrade_accounts_list: TDetailsOfDerivXAccount[], login_id: string) => + dxtrade_accounts_list.find(account_obj => account_obj.account_id === login_id); + const Wrapper = ({ children, title, description }: TWrapperProps) => (
@@ -87,9 +102,10 @@ const Content = ({ currency_icon, loginid, title, value }: TContentProps) => ( const ShowOpenPostions = ({ platform, open_positions, is_eu }: TShowOpenPostionsProps) => ( } > {open_positions.map(account => ( @@ -124,9 +140,10 @@ const ShowOpenPostions = ({ platform, open_positions, is_eu }: TShowOpenPostions const ShowAccountBalance = ({ platform, account_balance, is_eu }: TShowAccountBalanceProps) => ( } > {account_balance.map(account => ( @@ -161,15 +178,6 @@ const ShowAccountBalance = ({ platform, account_balance, is_eu }: TShowAccountBa ); -const getDerivAccount = (client_accounts: TAccounts[], login_id: string) => - client_accounts.find(client_account => client_account.loginid === login_id); - -const getCurrMT5Account = (mt5_login_list: DetailsOfEachMT5Loginid[], login_id: string) => - mt5_login_list.find(account_obj => account_obj.login === login_id); - -const getCurrDxtradeAccount = (dxtrade_accounts_list: TDetailsOfDerivXAccount[], login_id: string) => - dxtrade_accounts_list.find(account_obj => account_obj.account_id === login_id); - const ClosingAccountHasPendingConditions = observer( ({ details, onBackClick }: TClosingAccountHasPendingConditionsProps) => { const { client } = useStore(); @@ -243,7 +251,11 @@ const ClosingAccountHasPendingConditions = observer( {!!deriv_open_positions.length && ( - + + } + > {deriv_open_positions.map(account => ( )} {!!deriv_balance.length && ( - + + } + > {deriv_balance.map(account => ( } description={
From e3d401c3fc649e4443850576306a654890905fe2 Mon Sep 17 00:00:00 2001 From: amina-deriv Date: Wed, 23 Aug 2023 22:44:19 +0400 Subject: [PATCH 10/13] fix: localize --- .../closing-account-general-error-content.tsx | 2 +- ...closing-account-has-pending-conditions.tsx | 8 ++++---- .../closing-account-reason-form.tsx | 9 +++++---- .../ClosingAccount/closing-account-reason.tsx | 18 +++++++++-------- .../ClosingAccount/closing-account-steps.tsx | 20 +++++++++++++------ .../closing-account-warning-modal.tsx | 8 +++----- 6 files changed, 37 insertions(+), 28 deletions(-) diff --git a/packages/account/src/Sections/Security/ClosingAccount/closing-account-general-error-content.tsx b/packages/account/src/Sections/Security/ClosingAccount/closing-account-general-error-content.tsx index bc9d9b4dfed9..8a277b3aec26 100644 --- a/packages/account/src/Sections/Security/ClosingAccount/closing-account-general-error-content.tsx +++ b/packages/account/src/Sections/Security/ClosingAccount/closing-account-general-error-content.tsx @@ -1,6 +1,6 @@ import React from 'react'; -import { Localize } from '@deriv/translations'; import { Button } from '@deriv/components'; +import { Localize } from '@deriv/translations'; type TClosingAccountGeneralErrorContentProps = { message: string; diff --git a/packages/account/src/Sections/Security/ClosingAccount/closing-account-has-pending-conditions.tsx b/packages/account/src/Sections/Security/ClosingAccount/closing-account-has-pending-conditions.tsx index cc654756a8b5..8e68f771974c 100644 --- a/packages/account/src/Sections/Security/ClosingAccount/closing-account-has-pending-conditions.tsx +++ b/packages/account/src/Sections/Security/ClosingAccount/closing-account-has-pending-conditions.tsx @@ -1,9 +1,9 @@ import React from 'react'; +import { DetailsOfEachMT5Loginid } from '@deriv/api-types'; import { Button, Icon, Money, Text, ThemedScrollbars } from '@deriv/components'; import { CFD_PLATFORMS, formatMoney, getCFDAccount, getCFDAccountDisplay } from '@deriv/shared'; -import { DetailsOfEachMT5Loginid } from '@deriv/api-types'; -import { Localize } from '@deriv/translations'; import { observer, useStore } from '@deriv/stores'; +import { Localize } from '@deriv/translations'; import { TAccounts } from 'Types'; type TPendingAccountDetails = { @@ -53,9 +53,9 @@ type TClosingAccountHasPendingConditionsProps = { const getPlatformName = (platform: 'mt5' | 'dxtrade') => { if (platform === 'mt5') { - return ; + return 'Deriv MT5'; } - return ; + return 'Deriv X'; }; const getDerivAccount = (client_accounts: TAccounts[], login_id: string) => client_accounts.find(client_account => client_account.loginid === login_id); diff --git a/packages/account/src/Sections/Security/ClosingAccount/closing-account-reason-form.tsx b/packages/account/src/Sections/Security/ClosingAccount/closing-account-reason-form.tsx index b92783fc40f7..1be47bc7aaa3 100644 --- a/packages/account/src/Sections/Security/ClosingAccount/closing-account-reason-form.tsx +++ b/packages/account/src/Sections/Security/ClosingAccount/closing-account-reason-form.tsx @@ -1,7 +1,7 @@ import React from 'react'; import { Field, Formik, FormikErrors, FormikValues } from 'formik'; import { Checkbox, FormSubmitButton, Input, Text } from '@deriv/components'; -import { localize } from '@deriv/translations'; +import { localize, Localize } from '@deriv/translations'; type TFormValues = { 'financial-priorities': boolean; @@ -218,9 +218,10 @@ const ClosingAccountReasonForm = ({
- {localize('Remaining characters: {{remaining_characters}}', { - remaining_characters, - })} + {Object.keys(errors).length > 0 && Object.entries(errors).map(([key, value]) => ( diff --git a/packages/account/src/Sections/Security/ClosingAccount/closing-account-reason.tsx b/packages/account/src/Sections/Security/ClosingAccount/closing-account-reason.tsx index 91f59c32b4e1..e00dc180ca49 100644 --- a/packages/account/src/Sections/Security/ClosingAccount/closing-account-reason.tsx +++ b/packages/account/src/Sections/Security/ClosingAccount/closing-account-reason.tsx @@ -1,9 +1,9 @@ import React from 'react'; import { Redirect } from 'react-router-dom'; -import { routes, WS } from '@deriv/shared'; import { FormikValues } from 'formik'; -import { localize } from '@deriv/translations'; import { Loading, Modal, Text } from '@deriv/components'; +import { routes, WS } from '@deriv/shared'; +import { localize, Localize } from '@deriv/translations'; import ClosingAccountHasPendingConditions from './closing-account-has-pending-conditions'; import ClosingAccountReasonForm from './closing-account-reason-form'; import ClosingAccountWarningModal from './closing-account-warning-modal'; @@ -131,9 +131,10 @@ const ClosingAccountReason = ({ onBackClick }: TClosingAccountReasonProps) => { }; const getModalTitle = () => { - if (which_modal_should_render === 'error_modal') return localize('An error occurred'); - else if (which_modal_should_render === 'inaccessible_modal') return localize('Inaccessible MT5 account(s)'); - else if (which_modal_should_render !== 'warning_modal') return localize('Action required'); + if (which_modal_should_render === 'error_modal') return ; + else if (which_modal_should_render === 'inaccessible_modal') + return ; + else if (which_modal_should_render !== 'warning_modal') return ; return ''; }; @@ -174,9 +175,10 @@ const ClosingAccountReason = ({ onBackClick }: TClosingAccountReasonProps) => { return (
- {localize('Please tell us why you’re leaving. (Select up to {{ allowed_reasons }} reasons.)', { - allowed_reasons: max_allowed_reasons, - })} +
    -
  • {localize("You can't trade on Deriv.")}
  • -
  • {localize("You can't make transactions.")}
  • +
  • + +
  • +
  • + +
@@ -34,8 +38,12 @@ const ClosingAccountSteps = observer(({ redirectToReasons }: TClosingAccountStep
    -
  • {localize('Close all your positions.')}
  • -
  • {localize('Withdraw your funds.')}
  • +
  • + +
  • +
  • + +
diff --git a/packages/account/src/Sections/Security/ClosingAccount/closing-account-warning-modal.tsx b/packages/account/src/Sections/Security/ClosingAccount/closing-account-warning-modal.tsx index e35b1fc87612..88430fe12050 100644 --- a/packages/account/src/Sections/Security/ClosingAccount/closing-account-warning-modal.tsx +++ b/packages/account/src/Sections/Security/ClosingAccount/closing-account-warning-modal.tsx @@ -1,5 +1,5 @@ import React from 'react'; -import { localize } from '@deriv/translations'; +import { localize, Localize } from '@deriv/translations'; import { FormSubmitButton, Icon, Text } from '@deriv/components'; type TClosingAccountWarningModalProps = { @@ -12,13 +12,11 @@ const ClosingAccountWarningModal = ({ closeModal, startDeactivating }: TClosingA
- {localize('Close your account?')} +
- {localize( - 'Closing your account will automatically log you out. We shall delete your personal information as soon as our legal obligations are met.' - )} +
Date: Wed, 23 Aug 2023 22:48:48 +0400 Subject: [PATCH 11/13] fix: localize --- packages/account/tsconfig.json | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/account/tsconfig.json b/packages/account/tsconfig.json index 543c501d9c31..aec2281f5147 100644 --- a/packages/account/tsconfig.json +++ b/packages/account/tsconfig.json @@ -1,7 +1,6 @@ { "extends": "../../tsconfig.json", "compilerOptions": { - "lib": [ "dom"], "outDir": "./dist", "baseUrl": "./", "paths": { From 6339a0b8b1d6d6fc62ecccdff9747c043f6b9d80 Mon Sep 17 00:00:00 2001 From: amina-deriv Date: Sun, 27 Aug 2023 23:56:33 +0400 Subject: [PATCH 12/13] fix: resolve review comments --- ...ing-account-general-error-content.spec.tsx | 4 +- ...ng-account-has-pending-conditions.spec.tsx | 253 ------------ .../closing-account-reason-form.spec.tsx | 2 +- .../__tests__/closing-account-reason.spec.tsx | 57 +-- .../__tests__/closing-account-steps.spec.tsx | 4 +- .../closing-account-warning-modal.spec.tsx | 4 +- .../__tests__/closing-account.spec.tsx | 6 +- ...closing-account-has-pending-conditions.tsx | 362 ----------------- ...ng-account-has-pending-conditions.spec.tsx | 177 +++++++++ .../closing-account-pending-balance.spec.tsx | 150 +++++++ .../closing-account-pending-content.spec.tsx | 34 ++ ...closing-account-pending-positions.spec.tsx | 120 ++++++ .../closing-account-pending-wrapper.spec.tsx | 27 ++ ...closing-account-has-pending-conditions.tsx | 209 ++++++++++ .../closing-account-pending-balance.tsx | 60 +++ .../closing-account-pending-content.tsx | 29 ++ .../closing-account-pending-positions.tsx | 58 +++ .../closing-account-pending-wrapper.tsx | 27 ++ .../closing-account-reason-form.tsx | 368 +++++++----------- .../ClosingAccount/closing-account-reason.tsx | 72 ++-- .../ClosingAccount/closing-account-steps.tsx | 5 +- .../closing-account-warning-modal.tsx | 5 +- .../ClosingAccount/closing-account.tsx | 6 +- .../ClosingAccount/{index.js => index.ts} | 0 .../account/src/Types/common-prop.type.ts | 30 +- 25 files changed, 1140 insertions(+), 929 deletions(-) delete mode 100644 packages/account/src/Sections/Security/ClosingAccount/__tests__/closing-account-has-pending-conditions.spec.tsx delete mode 100644 packages/account/src/Sections/Security/ClosingAccount/closing-account-has-pending-conditions.tsx create mode 100644 packages/account/src/Sections/Security/ClosingAccount/closing-account-pending-conditions/__tests__/closing-account-has-pending-conditions.spec.tsx create mode 100644 packages/account/src/Sections/Security/ClosingAccount/closing-account-pending-conditions/__tests__/closing-account-pending-balance.spec.tsx create mode 100644 packages/account/src/Sections/Security/ClosingAccount/closing-account-pending-conditions/__tests__/closing-account-pending-content.spec.tsx create mode 100644 packages/account/src/Sections/Security/ClosingAccount/closing-account-pending-conditions/__tests__/closing-account-pending-positions.spec.tsx create mode 100644 packages/account/src/Sections/Security/ClosingAccount/closing-account-pending-conditions/__tests__/closing-account-pending-wrapper.spec.tsx create mode 100644 packages/account/src/Sections/Security/ClosingAccount/closing-account-pending-conditions/closing-account-has-pending-conditions.tsx create mode 100644 packages/account/src/Sections/Security/ClosingAccount/closing-account-pending-conditions/closing-account-pending-balance.tsx create mode 100644 packages/account/src/Sections/Security/ClosingAccount/closing-account-pending-conditions/closing-account-pending-content.tsx create mode 100644 packages/account/src/Sections/Security/ClosingAccount/closing-account-pending-conditions/closing-account-pending-positions.tsx create mode 100644 packages/account/src/Sections/Security/ClosingAccount/closing-account-pending-conditions/closing-account-pending-wrapper.tsx rename packages/account/src/Sections/Security/ClosingAccount/{index.js => index.ts} (100%) diff --git a/packages/account/src/Sections/Security/ClosingAccount/__tests__/closing-account-general-error-content.spec.tsx b/packages/account/src/Sections/Security/ClosingAccount/__tests__/closing-account-general-error-content.spec.tsx index 91c0f65ad00b..dd9934e97093 100644 --- a/packages/account/src/Sections/Security/ClosingAccount/__tests__/closing-account-general-error-content.spec.tsx +++ b/packages/account/src/Sections/Security/ClosingAccount/__tests__/closing-account-general-error-content.spec.tsx @@ -4,7 +4,7 @@ import userEvent from '@testing-library/user-event'; import ClosingAccountGeneralErrorContent from '../closing-account-general-error-content'; describe('', () => { - const mock_props = { + const mock_props: React.ComponentProps = { message: 'mock message', onClick: jest.fn(), }; @@ -16,7 +16,7 @@ describe('', () => { it('should call onClick when button is clicked', () => { render(); - const ok_button = screen.getByRole('button', { name: /OK/i }); + const ok_button = screen.getByRole('button', { name: /ok/i }); userEvent.click(ok_button); expect(mock_props.onClick).toHaveBeenCalledTimes(1); diff --git a/packages/account/src/Sections/Security/ClosingAccount/__tests__/closing-account-has-pending-conditions.spec.tsx b/packages/account/src/Sections/Security/ClosingAccount/__tests__/closing-account-has-pending-conditions.spec.tsx deleted file mode 100644 index dd793edcbde0..000000000000 --- a/packages/account/src/Sections/Security/ClosingAccount/__tests__/closing-account-has-pending-conditions.spec.tsx +++ /dev/null @@ -1,253 +0,0 @@ -import React from 'react'; -import { render, screen } from '@testing-library/react'; -import { StoreProvider, mockStore } from '@deriv/stores'; -import ClosingAccountHasPendingConditions from '../closing-account-has-pending-conditions'; - -jest.mock('@deriv/shared', () => ({ - ...jest.requireActual('@deriv/shared'), - getCFDAccountDisplay: jest.fn(() => 'Financial Demo'), -})); - -describe('', () => { - let store = mockStore({}); - const mock_props = { - details: { - balance: { - CR123: { - balance: 5000.0, - currency: 'USD', - }, - CR234: { - balance: 0.18833116, - currency: 'BTC', - }, - }, - }, - onBackClick: jest.fn(), - }; - store = mockStore({ - client: { - mt5_login_list: [ - { - account_type: 'real', - balance: 2, - country: 'id', - currency: 'USD', - display_balance: '2.00', - email: 'user@deriv.com', - group: 'real\\p01_ts01\\financial\\svg_std-hr_usd', - landing_company_short: 'svg', - leverage: 1000, - login: 'MTR456', - market_type: 'financial', - name: 'QA script userizbta', - server: 'p01_ts01', - server_info: { - environment: 'Deriv-Server', - geolocation: { - group: 'all', - location: 'Ireland', - region: 'Europe', - sequence: 1, - }, - id: 'p01_ts01', - }, - status: null, - sub_account_category: '', - sub_account_type: 'financial', - }, - ], - dxtrade_accounts_list: [ - { - account_id: 'DXR345', - account_type: 'real', - balance: 2221, - currency: 'USD', - display_balance: '2221.00', - landing_company_short: 'svg', - login: '345', - market_type: 'all', - }, - ], - account_list: [ - { - loginid: 'CR123', - is_virtual: 0, - icon: 'usd', - title: 'USD', - }, - { - loginid: 'CR234', - is_virtual: 0, - icon: 'btc', - title: 'BTC', - }, - { - loginid: 'VRTC90000148', - is_virtual: 1, - icon: 'real', - title: 'Real', - }, - ], - - is_eu: false, - }, - }); - - it('should render the ClosingAccountHasPendingConditions component', () => { - const { container } = render( - - - - ); - expect(container).toBeInTheDocument(); - }); - - it('should show the accounts with deriv_balance', () => { - const details = { - balance: { - CR123: { - balance: 2744.0, - currency: 'USD', - }, - CR234: { - balance: 0.18833116, - currency: 'BTC', - }, - }, - }; - - render( - - - - ); - expect( - screen.getByText(/please withdraw your funds from the following deriv account\(s\):/i) - ).toBeInTheDocument(); - expect(screen.getByText(/2,744\.00/i)).toBeInTheDocument(); - expect(screen.getByText(/USD/i)).toBeInTheDocument(); - - expect(screen.getByText(/0\.18833116/i)).toBeInTheDocument(); - expect(screen.getByText(/BTC/i)).toBeInTheDocument(); - }); - - it('should show the accounts with open_positions', () => { - const details = { - open_positions: { - CR123: 1, - }, - }; - - render( - - - - ); - expect( - screen.getByText(/please close your positions in the following deriv account\(s\):/i) - ).toBeInTheDocument(); - expect(screen.getByText(/1 position/i)).toBeInTheDocument(); - }); - - it('should show the accounts with pending withdrawals', () => { - const details = { - pending_withdrawals: { - CR123: 1, - }, - }; - - render( - - - - ); - expect(screen.getByText(/Pending withdrawal request:/i)).toBeInTheDocument(); - expect(screen.getByText(/We are still processing your withdrawal request/i)).toBeInTheDocument(); - expect( - screen.getByText(/Please wait for the transaction to be completed before deactivating your account/i) - ).toBeInTheDocument(); - }); - - it('should show the dxtrade accounts with balance', () => { - const details = { - balance: { - DXR345: { - balance: 2221.0, - currency: 'USD', - }, - }, - }; - - render( - - - - ); - expect( - screen.getByText(/please withdraw your funds from the following deriv x account\(s\):/i) - ).toBeInTheDocument(); - expect(screen.getByText(/2,221\.00/i)).toBeInTheDocument(); - }); - - it('should show the mt5 accounts with balance', () => { - const details = { - balance: { - MTR456: { - balance: 2.0, - currency: 'USD', - }, - MTR567: { - balance: 23.0, - currency: 'USD', - }, - }, - }; - - render( - - - - ); - expect( - screen.getByText(/please withdraw your funds from the following deriv mt5 account\(s\):/i) - ).toBeInTheDocument(); - expect(screen.getByText(/2.0/i)).toBeInTheDocument(); - }); - - it('should show the mt5 accounts with open_positions', () => { - const details = { - open_positions: { - MTR456: 3, - }, - }; - - render( - - - - ); - expect( - screen.getByText(/please close your positions in the following deriv mt5 account\(s\):/i) - ).toBeInTheDocument(); - expect(screen.getByText(/3 position\(s\)/i)).toBeInTheDocument(); - }); - - it('should show the derivx accounts with open_positions', () => { - const details = { - open_positions: { - DXR345: 6, - }, - }; - - render( - - - - ); - expect( - screen.getByText(/please close your positions in the following deriv x account\(s\):/i) - ).toBeInTheDocument(); - expect(screen.getByText(/6 position\(s\)/i)).toBeInTheDocument(); - }); -}); diff --git a/packages/account/src/Sections/Security/ClosingAccount/__tests__/closing-account-reason-form.spec.tsx b/packages/account/src/Sections/Security/ClosingAccount/__tests__/closing-account-reason-form.spec.tsx index c1deda49295f..387b21c3b4ea 100644 --- a/packages/account/src/Sections/Security/ClosingAccount/__tests__/closing-account-reason-form.spec.tsx +++ b/packages/account/src/Sections/Security/ClosingAccount/__tests__/closing-account-reason-form.spec.tsx @@ -4,7 +4,7 @@ import userEvent from '@testing-library/user-event'; import ClosingAccountReasonForm from '../closing-account-reason-form'; describe('', () => { - const mock_props = { + const mock_props: React.ComponentProps = { validateFields: jest.fn(), onSubmit: jest.fn(), is_checkbox_disabled: false, diff --git a/packages/account/src/Sections/Security/ClosingAccount/__tests__/closing-account-reason.spec.tsx b/packages/account/src/Sections/Security/ClosingAccount/__tests__/closing-account-reason.spec.tsx index bf203bab55ac..c43e3a15ad78 100644 --- a/packages/account/src/Sections/Security/ClosingAccount/__tests__/closing-account-reason.spec.tsx +++ b/packages/account/src/Sections/Security/ClosingAccount/__tests__/closing-account-reason.spec.tsx @@ -21,24 +21,22 @@ describe('', () => { jest.mock('../closing-account-reason-form', () =>
ClosingAccountReasonForm
); - it('Should render ClosingAccountReason component', async () => { + const renderComponent = () => render( ); + + it('Should render ClosingAccountReason component', async () => { + renderComponent(); await waitFor(() => { expect(screen.getByText(/Please tell us why you’re leaving/i)).toBeInTheDocument(); }); }); it('Should be disabled when no reason has been selected', async () => { - render( - - - - ); - + renderComponent(); fireEvent.click(screen.getByRole('checkbox', { name: /I have other financial priorities./i })); fireEvent.click(screen.getByRole('checkbox', { name: /I have other financial priorities./i })); @@ -49,50 +47,37 @@ describe('', () => { }); }); - it('should reduce remaining chars', () => { - render( - - - - ); - + it('should reduce remaining chars', async () => { + renderComponent(); expect(screen.getByText(/Remaining characters: 110/i)).toBeInTheDocument(); - act(() => { - fireEvent.change(screen.getByLabelText(/I want to stop myself from trading/i), { - target: { value: 'true' }, - }); + fireEvent.change(screen.getByLabelText(/I want to stop myself from trading/i), { + target: { value: 'true' }, }); - expect(screen.getByText(/Remaining characters: 110/i)).toBeInTheDocument(); + await waitFor(() => { + expect(screen.getByText(/Remaining characters: 110/i)).toBeInTheDocument(); + }); - act(() => { - fireEvent.change(screen.getByPlaceholderText(/What could we do to improve/i), { - target: { value: 'do_to_improve' }, - }); + fireEvent.change(screen.getByPlaceholderText(/What could we do to improve/i), { + target: { value: 'do_to_improve' }, }); expect(screen.getByText(/Remaining characters: 97/i)).toBeInTheDocument(); }); - it('should call onBackClick when back button is clicked', () => { - render( - - - - ); + it('should call onBackClick when back button is clicked', async () => { + renderComponent(); const el_checkbox = screen.getByRole('checkbox', { name: /i’m closing my account for other reasons\./i, }); - act(() => { - fireEvent.click(el_checkbox); - }); + fireEvent.click(el_checkbox); - act(() => { - fireEvent.click(screen.getByRole('button', { name: /Back/i })); - }); + fireEvent.click(screen.getByRole('button', { name: /Back/i })); - expect(mock_props.onBackClick).toHaveBeenCalledTimes(1); + await waitFor(() => { + expect(mock_props.onBackClick).toHaveBeenCalledTimes(1); + }); }); }); diff --git a/packages/account/src/Sections/Security/ClosingAccount/__tests__/closing-account-steps.spec.tsx b/packages/account/src/Sections/Security/ClosingAccount/__tests__/closing-account-steps.spec.tsx index 3a4c276c4ef0..e4be94a27249 100644 --- a/packages/account/src/Sections/Security/ClosingAccount/__tests__/closing-account-steps.spec.tsx +++ b/packages/account/src/Sections/Security/ClosingAccount/__tests__/closing-account-steps.spec.tsx @@ -7,9 +7,9 @@ import { StoreProvider, mockStore } from '@deriv/stores'; import ClosingAccountSteps from '../closing-account-steps'; describe('', () => { - const mockRootStore: ReturnType = mockStore({}); + const mockRootStore = mockStore({}); const history = createBrowserHistory(); - const mock_props = { + const mock_props: React.ComponentProps = { redirectToReasons: jest.fn(), }; diff --git a/packages/account/src/Sections/Security/ClosingAccount/__tests__/closing-account-warning-modal.spec.tsx b/packages/account/src/Sections/Security/ClosingAccount/__tests__/closing-account-warning-modal.spec.tsx index 6485c3a3e148..ff05d9e79f7b 100644 --- a/packages/account/src/Sections/Security/ClosingAccount/__tests__/closing-account-warning-modal.spec.tsx +++ b/packages/account/src/Sections/Security/ClosingAccount/__tests__/closing-account-warning-modal.spec.tsx @@ -4,11 +4,11 @@ import userEvent from '@testing-library/user-event'; import ClosingAccountWarningModal from '../closing-account-warning-modal'; describe('', () => { - const mock_props = { + const mock_props: React.ComponentProps = { startDeactivating: jest.fn(), closeModal: jest.fn(), }; - it('should render the ClosingAccountWarningModal component', async () => { + it('should render the ClosingAccountWarningModal component', () => { render(); expect(screen.getByText('Close your account?')).toBeInTheDocument(); expect(screen.getByText(/Closing your account will automatically log you out./i)).toBeInTheDocument(); diff --git a/packages/account/src/Sections/Security/ClosingAccount/__tests__/closing-account.spec.tsx b/packages/account/src/Sections/Security/ClosingAccount/__tests__/closing-account.spec.tsx index b06c93a564e1..d4cdcedac2d9 100644 --- a/packages/account/src/Sections/Security/ClosingAccount/__tests__/closing-account.spec.tsx +++ b/packages/account/src/Sections/Security/ClosingAccount/__tests__/closing-account.spec.tsx @@ -16,17 +16,17 @@ jest.mock('../closing-account-reason', () => ({ })); describe('', () => { - it('should render the ClosingAccountReason component', async () => { + it('should render the ClosingAccountReason component', () => { render(); expect(screen.getByTestId('dt_closing_account')).toBeInTheDocument(); }); - it('should render the ClosingAccountSteps component if render_close_account_reason is false', async () => { + it('should render the ClosingAccountSteps component if render_close_account_reason is false', () => { render(); expect(screen.getByText('ClosingAccountSteps')).toBeInTheDocument(); }); - it('should render the ClosingAccountReason component if render_close_account_reason is true', async () => { + it('should render the ClosingAccountReason component if render_close_account_reason is true', () => { const spy = jest.spyOn(React, 'useState').mockImplementation(() => [true, jest.fn()]); render(); expect(screen.getByText('ClosingAccountReason')).toBeInTheDocument(); diff --git a/packages/account/src/Sections/Security/ClosingAccount/closing-account-has-pending-conditions.tsx b/packages/account/src/Sections/Security/ClosingAccount/closing-account-has-pending-conditions.tsx deleted file mode 100644 index 8e68f771974c..000000000000 --- a/packages/account/src/Sections/Security/ClosingAccount/closing-account-has-pending-conditions.tsx +++ /dev/null @@ -1,362 +0,0 @@ -import React from 'react'; -import { DetailsOfEachMT5Loginid } from '@deriv/api-types'; -import { Button, Icon, Money, Text, ThemedScrollbars } from '@deriv/components'; -import { CFD_PLATFORMS, formatMoney, getCFDAccount, getCFDAccountDisplay } from '@deriv/shared'; -import { observer, useStore } from '@deriv/stores'; -import { Localize } from '@deriv/translations'; -import { TAccounts } from 'Types'; - -type TPendingAccountDetails = { - balance?: number; - currency?: string; - display_login?: string; - positions?: number; - withdrawals?: number; -}; - -type TDetailsOfDerivAccount = TAccounts & TPendingAccountDetails; -type TDetailsOfMT5Account = DetailsOfEachMT5Loginid & TPendingAccountDetails; -type TDetailsOfDerivXAccount = TDetailsOfMT5Account & { account_id?: string }; - -type TWrapperProps = { - children: React.ReactNode; - title: React.ReactNode; - description?: React.ReactNode; -}; - -type TContentProps = { - currency_icon: string; - loginid?: string; - title?: React.ReactNode; - value: React.ReactNode; -}; - -type TShowOpenPostionsProps = { - platform: 'dxtrade' | 'mt5'; - open_positions: TDetailsOfMT5Account[] | TDetailsOfDerivXAccount[]; - is_eu: boolean; -}; -type TShowAccountBalanceProps = { - platform: 'dxtrade' | 'mt5'; - account_balance: TDetailsOfMT5Account[] | TDetailsOfDerivXAccount[]; - is_eu: boolean; -}; - -type TClosingAccountHasPendingConditionsProps = { - details?: { - pending_withdrawals?: Record; - open_positions?: Record; - balance?: Record; - }; - onBackClick: () => void; -}; - -const getPlatformName = (platform: 'mt5' | 'dxtrade') => { - if (platform === 'mt5') { - return 'Deriv MT5'; - } - return 'Deriv X'; -}; -const getDerivAccount = (client_accounts: TAccounts[], login_id: string) => - client_accounts.find(client_account => client_account.loginid === login_id); - -const getCurrMT5Account = (mt5_login_list: DetailsOfEachMT5Loginid[], login_id: string) => - mt5_login_list.find(account_obj => account_obj.login === login_id); - -const getCurrDxtradeAccount = (dxtrade_accounts_list: TDetailsOfDerivXAccount[], login_id: string) => - dxtrade_accounts_list.find(account_obj => account_obj.account_id === login_id); - -const Wrapper = ({ children, title, description }: TWrapperProps) => ( -
- - {title} - - {description && ( - - {description} - - )} -
{children}
-
-); - -const Content = ({ currency_icon, loginid, title, value }: TContentProps) => ( -
-
- -
- - {title} - - - {loginid} - -
-
- - {value} - -
-); - -const ShowOpenPostions = ({ platform, open_positions, is_eu }: TShowOpenPostionsProps) => ( - - } - > - {open_positions.map(account => ( - - } - /> - ))} - -); - -const ShowAccountBalance = ({ platform, account_balance, is_eu }: TShowAccountBalanceProps) => ( - - } - > - {account_balance.map(account => ( - - ) - } - /> - ))} - -); - -const ClosingAccountHasPendingConditions = observer( - ({ details, onBackClick }: TClosingAccountHasPendingConditionsProps) => { - const { client } = useStore(); - const { dxtrade_accounts_list, mt5_login_list, account_list, is_eu } = client; - - const deriv_open_positions: TDetailsOfDerivAccount[] = []; - const deriv_balance: TDetailsOfDerivAccount[] = []; - const account_pending_withdrawals: TDetailsOfDerivAccount[] = []; - - const mt5_open_positions: TDetailsOfMT5Account[] = []; - const mt5_balance: TDetailsOfMT5Account[] = []; - - const dxtrade_open_positions: TDetailsOfDerivXAccount[] = []; - const dxtrade_balance: TDetailsOfDerivXAccount[] = []; - - if (details?.pending_withdrawals) { - Object.keys(details.pending_withdrawals).forEach(login_id => { - const info = { - withdrawals: details.pending_withdrawals?.[login_id], - }; - const deriv_account = getDerivAccount(account_list, login_id); - if (deriv_account) { - account_pending_withdrawals.push({ ...deriv_account, ...info }); - } - }); - } - if (details?.open_positions) { - Object.keys(details?.open_positions).forEach(login_id => { - const info = { - positions: details.open_positions?.[login_id], - }; - const deriv_account = getDerivAccount(account_list, login_id); - if (deriv_account) { - deriv_open_positions.push({ ...deriv_account, ...info }); - } else { - const mt5_account = getCurrMT5Account(mt5_login_list, login_id); - if (mt5_account) { - mt5_open_positions.push({ ...mt5_account, ...info }); - } - - const dxtrade_account = getCurrDxtradeAccount(dxtrade_accounts_list, login_id); - if (dxtrade_account) { - dxtrade_open_positions.push({ ...dxtrade_account, ...info }); - } - } - }); - } - if (details?.balance) { - Object.keys(details.balance).forEach(login_id => { - const info = { - balance: details.balance?.[login_id].balance, - currency: details.balance?.[login_id].currency, - }; - const deriv_account = getDerivAccount(account_list, login_id); - if (deriv_account) { - deriv_balance.push({ ...deriv_account, ...info }); - } else { - const mt5_account = getCurrMT5Account(mt5_login_list, login_id); - if (mt5_account) { - mt5_balance.push({ ...mt5_account, ...info }); - } - - const dxtrade_account = getCurrDxtradeAccount(dxtrade_accounts_list, login_id); - if (dxtrade_account) { - dxtrade_balance.push({ ...dxtrade_account, ...info }); - } - } - }); - } - return ( - - - {!!deriv_open_positions.length && ( - - } - > - {deriv_open_positions.map(account => ( - - } - /> - ))} - - )} - {!!deriv_balance.length && ( - - } - > - {deriv_balance.map(account => ( - - ) - } - /> - ))} - - )} - {!!mt5_open_positions.length && ( - - )} - - {!!mt5_balance.length && ( - - )} - {!!dxtrade_open_positions.length && ( - - )} - {!!dxtrade_balance.length && ( - - )} - {!!account_pending_withdrawals.length && ( - } - description={ - ]} - /> - } - > - {account_pending_withdrawals.map(account => ( - - } - /> - ))} - - )} - -
- -
-
- ); - } -); - -export default ClosingAccountHasPendingConditions; diff --git a/packages/account/src/Sections/Security/ClosingAccount/closing-account-pending-conditions/__tests__/closing-account-has-pending-conditions.spec.tsx b/packages/account/src/Sections/Security/ClosingAccount/closing-account-pending-conditions/__tests__/closing-account-has-pending-conditions.spec.tsx new file mode 100644 index 000000000000..5341d36e7f3e --- /dev/null +++ b/packages/account/src/Sections/Security/ClosingAccount/closing-account-pending-conditions/__tests__/closing-account-has-pending-conditions.spec.tsx @@ -0,0 +1,177 @@ +import React from 'react'; +import { render, screen } from '@testing-library/react'; +import { StoreProvider, mockStore } from '@deriv/stores'; +import ClosingAccountHasPendingConditions from '../closing-account-has-pending-conditions'; + +jest.mock('@deriv/shared', () => ({ + ...jest.requireActual('@deriv/shared'), + getCFDAccountDisplay: jest.fn(() => 'Financial Demo'), +})); + +describe('', () => { + let store = mockStore({}); + const mock_props: React.ComponentProps = { + details: { + balance: { + CR123: { + balance: 5000.0, + currency: 'USD', + }, + CR234: { + balance: 0.18833116, + currency: 'BTC', + }, + }, + }, + onBackClick: jest.fn(), + }; + store = mockStore({ + client: { + mt5_login_list: [ + { + account_type: 'real', + balance: 2, + country: 'id', + currency: 'USD', + display_balance: '2.00', + email: 'user@deriv.com', + group: 'real\\p01_ts01\\financial\\svg_std-hr_usd', + landing_company_short: 'svg', + leverage: 1000, + login: 'MTR456', + market_type: 'financial', + name: 'QA script userizbta', + server: 'p01_ts01', + server_info: { + environment: 'Deriv-Server', + geolocation: { + group: 'all', + location: 'Ireland', + region: 'Europe', + sequence: 1, + }, + id: 'p01_ts01', + }, + status: null, + sub_account_category: '', + sub_account_type: 'financial', + }, + ], + dxtrade_accounts_list: [ + { + account_id: 'DXR345', + account_type: 'real', + balance: 2221, + currency: 'USD', + display_balance: '2221.00', + landing_company_short: 'svg', + login: '345', + market_type: 'all', + }, + ], + account_list: [ + { + loginid: 'CR123', + is_virtual: 0, + icon: 'usd', + title: 'USD', + }, + { + loginid: 'CR234', + is_virtual: 0, + icon: 'btc', + title: 'BTC', + }, + { + loginid: 'VRTC90000148', + is_virtual: 1, + icon: 'real', + title: 'Real', + }, + ], + + is_eu: false, + }, + }); + + const renderComponent = (props = { ...mock_props }) => { + const wrapper = ({ children }: { children: JSX.Element }) => ( + {children} + ); + + return render(, { + wrapper, + }); + }; + + it('should render the ClosingAccountHasPendingConditions component', () => { + renderComponent(); + expect( + screen.getByText(/please withdraw your funds from the following deriv account\(s\):/i) + ).toBeInTheDocument(); + expect(screen.getByRole('button', { name: /ok/i })).toBeInTheDocument(); + }); + + it('should show deriv accounts with balance', () => { + const new_props = { + ...mock_props, + details: { + balance: { + CR123: { + balance: 2744.0, + currency: 'USD', + }, + CR234: { + balance: 0.18833116, + currency: 'BTC', + }, + }, + }, + }; + renderComponent(new_props); + + expect( + screen.getByText(/please withdraw your funds from the following deriv account\(s\):/i) + ).toBeInTheDocument(); + expect(screen.getByText(/2,744\.00/i)).toBeInTheDocument(); + expect(screen.getByText(/usd/i)).toBeInTheDocument(); + + expect(screen.getByText(/0\.18833116/i)).toBeInTheDocument(); + expect(screen.getByText(/btc/i)).toBeInTheDocument(); + }); + + it('should show deriv accounts with open_positions', () => { + const new_props = { + ...mock_props, + details: { + open_positions: { + CR123: 1, + }, + }, + }; + renderComponent(new_props); + expect( + screen.getByText(/please close your positions in the following deriv account\(s\):/i) + ).toBeInTheDocument(); + expect(screen.getByText(/1 position/i)).toBeInTheDocument(); + }); + + it('should show deriv accounts with pending withdrawals', () => { + const processing_text = /we are still processing your withdrawal request/i; + const transaction_warning = /please wait for the transaction to be completed before deactivating your account/i; + + const new_props = { + ...mock_props, + details: { + pending_withdrawals: { + CR123: 1, + }, + }, + }; + + renderComponent(new_props); + expect(screen.getByText(/pending withdrawal request:/i)).toBeInTheDocument(); + expect(screen.getByText(processing_text)).toBeInTheDocument(); + expect(screen.getByText(transaction_warning)).toBeInTheDocument(); + }); +}); diff --git a/packages/account/src/Sections/Security/ClosingAccount/closing-account-pending-conditions/__tests__/closing-account-pending-balance.spec.tsx b/packages/account/src/Sections/Security/ClosingAccount/closing-account-pending-conditions/__tests__/closing-account-pending-balance.spec.tsx new file mode 100644 index 000000000000..22a40ac497c1 --- /dev/null +++ b/packages/account/src/Sections/Security/ClosingAccount/closing-account-pending-conditions/__tests__/closing-account-pending-balance.spec.tsx @@ -0,0 +1,150 @@ +import React from 'react'; +import { render, screen } from '@testing-library/react'; +import { StoreProvider, mockStore } from '@deriv/stores'; +import ClosingAccountHasPendingConditions from '../closing-account-has-pending-conditions'; + +jest.mock('@deriv/shared', () => ({ + ...jest.requireActual('@deriv/shared'), + getCFDAccountDisplay: jest.fn(() => 'Financial Demo'), +})); + +describe('', () => { + let store = mockStore({}); + const mock_props: React.ComponentProps = { + details: { + balance: { + CR123: { + balance: 5000.0, + currency: 'USD', + }, + CR234: { + balance: 0.18833116, + currency: 'BTC', + }, + }, + }, + onBackClick: jest.fn(), + }; + store = mockStore({ + client: { + mt5_login_list: [ + { + account_type: 'real', + balance: 2, + country: 'id', + currency: 'USD', + display_balance: '2.00', + email: 'user@deriv.com', + group: 'real\\p01_ts01\\financial\\svg_std-hr_usd', + landing_company_short: 'svg', + leverage: 1000, + login: 'MTR456', + market_type: 'financial', + name: 'QA script userizbta', + server: 'p01_ts01', + server_info: { + environment: 'Deriv-Server', + geolocation: { + group: 'all', + location: 'Ireland', + region: 'Europe', + sequence: 1, + }, + id: 'p01_ts01', + }, + status: null, + sub_account_category: '', + sub_account_type: 'financial', + }, + ], + dxtrade_accounts_list: [ + { + account_id: 'DXR345', + account_type: 'real', + balance: 2221, + currency: 'USD', + display_balance: '2221.00', + landing_company_short: 'svg', + login: '345', + market_type: 'all', + }, + ], + account_list: [ + { + loginid: 'CR123', + is_virtual: 0, + icon: 'usd', + title: 'USD', + }, + { + loginid: 'CR234', + is_virtual: 0, + icon: 'btc', + title: 'BTC', + }, + { + loginid: 'VRTC90000148', + is_virtual: 1, + icon: 'real', + title: 'Real', + }, + ], + + is_eu: false, + }, + }); + + const renderComponent = (props = { ...mock_props }) => { + const wrapper = ({ children }: { children: JSX.Element }) => ( + {children} + ); + + return render(, { + wrapper, + }); + }; + + it('should show the dxtrade accounts with balance', () => { + const new_props = { + ...mock_props, + details: { + balance: { + DXR345: { + balance: 2221.0, + currency: 'USD', + }, + }, + }, + }; + + renderComponent(new_props); + expect( + screen.getByText(/please withdraw your funds from the following deriv x account\(s\):/i) + ).toBeInTheDocument(); + expect(screen.getByText(/2,221\.00/i)).toBeInTheDocument(); + }); + + it('should show the mt5 accounts with balance', () => { + const new_props = { + ...mock_props, + details: { + balance: { + MTR456: { + balance: 2.0, + currency: 'USD', + }, + MTR567: { + balance: 23.0, + currency: 'USD', + }, + }, + }, + }; + + renderComponent(new_props); + expect( + screen.getByText(/please withdraw your funds from the following deriv mt5 account\(s\):/i) + ).toBeInTheDocument(); + expect(screen.getByText(/2.0/i)).toBeInTheDocument(); + }); +}); diff --git a/packages/account/src/Sections/Security/ClosingAccount/closing-account-pending-conditions/__tests__/closing-account-pending-content.spec.tsx b/packages/account/src/Sections/Security/ClosingAccount/closing-account-pending-conditions/__tests__/closing-account-pending-content.spec.tsx new file mode 100644 index 000000000000..4538a6489466 --- /dev/null +++ b/packages/account/src/Sections/Security/ClosingAccount/closing-account-pending-conditions/__tests__/closing-account-pending-content.spec.tsx @@ -0,0 +1,34 @@ +import React from 'react'; +import { render, screen } from '@testing-library/react'; +import ClosingAccountPendingContent from '../closing-account-pending-content'; + +jest.mock('@deriv/components', () => { + const original_module = jest.requireActual('@deriv/components'); + return { + ...original_module, + Icon: jest.fn(() =>
mockedIcon
), + }; +}); + +describe('ClosingAccountPendingContent', () => { + const mock_props: React.ComponentProps = { + currency_icon: 'USD', + value: 100, + }; + it('should render the ClosingAccountPendingContent component', () => { + render(); + expect(screen.getByText('mockedIcon')).toBeInTheDocument(); + expect(screen.getByText('100')).toBeInTheDocument(); + }); + + it('should render title and loginid', () => { + const new_props = { + ...mock_props, + title: 'mock_title', + loginid: 'CR123', + }; + render(); + expect(screen.getByText('mock_title')).toBeInTheDocument(); + expect(screen.getByText('CR123')).toBeInTheDocument(); + }); +}); diff --git a/packages/account/src/Sections/Security/ClosingAccount/closing-account-pending-conditions/__tests__/closing-account-pending-positions.spec.tsx b/packages/account/src/Sections/Security/ClosingAccount/closing-account-pending-conditions/__tests__/closing-account-pending-positions.spec.tsx new file mode 100644 index 000000000000..39f6a67bd612 --- /dev/null +++ b/packages/account/src/Sections/Security/ClosingAccount/closing-account-pending-conditions/__tests__/closing-account-pending-positions.spec.tsx @@ -0,0 +1,120 @@ +import React from 'react'; +import { render, screen } from '@testing-library/react'; +import { StoreProvider, mockStore } from '@deriv/stores'; +import ClosingAccountHasPendingConditions from '../closing-account-has-pending-conditions'; + +jest.mock('@deriv/shared', () => ({ + ...jest.requireActual('@deriv/shared'), + getCFDAccountDisplay: jest.fn(() => 'Financial Demo'), +})); + +describe('', () => { + let store = mockStore({}); + const mock_props: React.ComponentProps = { + details: { + balance: { + CR123: { + balance: 5000.0, + currency: 'USD', + }, + CR234: { + balance: 0.18833116, + currency: 'BTC', + }, + }, + }, + onBackClick: jest.fn(), + }; + store = mockStore({ + client: { + mt5_login_list: [ + { + account_type: 'real', + balance: 2, + country: 'id', + currency: 'USD', + display_balance: '2.00', + email: 'user@deriv.com', + group: 'real\\p01_ts01\\financial\\svg_std-hr_usd', + landing_company_short: 'svg', + leverage: 1000, + login: 'MTR456', + market_type: 'financial', + name: 'QA script userizbta', + server: 'p01_ts01', + server_info: { + environment: 'Deriv-Server', + geolocation: { + group: 'all', + location: 'Ireland', + region: 'Europe', + sequence: 1, + }, + id: 'p01_ts01', + }, + status: null, + sub_account_category: '', + sub_account_type: 'financial', + }, + ], + dxtrade_accounts_list: [ + { + account_id: 'DXR345', + account_type: 'real', + balance: 2221, + currency: 'USD', + display_balance: '2221.00', + landing_company_short: 'svg', + login: '345', + market_type: 'all', + }, + ], + + is_eu: false, + }, + }); + + const renderComponent = (props = { ...mock_props }) => { + const wrapper = ({ children }: { children: JSX.Element }) => ( + {children} + ); + + return render(, { + wrapper, + }); + }; + + it('should show the mt5 accounts with open_positions', () => { + const new_props = { + ...mock_props, + details: { + open_positions: { + MTR456: 3, + }, + }, + }; + + renderComponent(new_props); + expect( + screen.getByText(/please close your positions in the following deriv mt5 account\(s\):/i) + ).toBeInTheDocument(); + expect(screen.getByText(/3 position\(s\)/i)).toBeInTheDocument(); + }); + + it('should show the derivx accounts with open_positions', () => { + const new_props = { + ...mock_props, + details: { + open_positions: { + DXR345: 6, + }, + }, + }; + + renderComponent(new_props); + expect( + screen.getByText(/please close your positions in the following deriv x account\(s\):/i) + ).toBeInTheDocument(); + expect(screen.getByText(/6 position\(s\)/i)).toBeInTheDocument(); + }); +}); diff --git a/packages/account/src/Sections/Security/ClosingAccount/closing-account-pending-conditions/__tests__/closing-account-pending-wrapper.spec.tsx b/packages/account/src/Sections/Security/ClosingAccount/closing-account-pending-conditions/__tests__/closing-account-pending-wrapper.spec.tsx new file mode 100644 index 000000000000..3944ca2fa11a --- /dev/null +++ b/packages/account/src/Sections/Security/ClosingAccount/closing-account-pending-conditions/__tests__/closing-account-pending-wrapper.spec.tsx @@ -0,0 +1,27 @@ +import React from 'react'; +import { render, screen } from '@testing-library/react'; +import ClosingAccountPendingWrapper from '../closing-account-pending-wrapper'; + +describe('ClosingAccountPendingWrapper', () => { + const mock_props: React.ComponentProps = { + title:
mock_title
, + }; + it('should render the ClosingAccountPendingWrapper component', () => { + render(); + expect(screen.getByText('mock_title')).toBeInTheDocument(); + }); + + it('should render the ClosingAccountPendingWrapper component with description', () => { + render(mock_description
} />); + expect(screen.getByText('mock_description')).toBeInTheDocument(); + }); + + it('should render the children', () => { + render( + +
mock_children
+
+ ); + expect(screen.getByText('mock_children')).toBeInTheDocument(); + }); +}); diff --git a/packages/account/src/Sections/Security/ClosingAccount/closing-account-pending-conditions/closing-account-has-pending-conditions.tsx b/packages/account/src/Sections/Security/ClosingAccount/closing-account-pending-conditions/closing-account-has-pending-conditions.tsx new file mode 100644 index 000000000000..d5999018104b --- /dev/null +++ b/packages/account/src/Sections/Security/ClosingAccount/closing-account-pending-conditions/closing-account-has-pending-conditions.tsx @@ -0,0 +1,209 @@ +import React from 'react'; +import { DetailsOfEachMT5Loginid } from '@deriv/api-types'; +import { Button, Money, ThemedScrollbars } from '@deriv/components'; +import { CFD_PLATFORMS, formatMoney } from '@deriv/shared'; +import { observer, useStore } from '@deriv/stores'; +import { Localize } from '@deriv/translations'; +import { TAccounts, TDetailsOfDerivAccount, TDetailsOfDerivXAccount, TDetailsOfMT5Account } from 'Types'; +import ClosingAccountPendingContent from './closing-account-pending-content'; +import ClosingAccountPendingWrapper from './closing-account-pending-wrapper'; +import ClosingAccountPendingBalance from './closing-account-pending-balance'; +import ClosingAccountPendingPositions from './closing-account-pending-positions'; + +type TClosingAccountHasPendingConditionsProps = { + details?: { + pending_withdrawals?: Record; + open_positions?: Record; + balance?: Record; + }; + onBackClick: () => void; +}; + +const getDerivAccount = (client_accounts: TAccounts[], login_id: string) => + client_accounts.find(client_account => client_account.loginid === login_id); + +const getCurrentMT5Account = (mt5_login_list: DetailsOfEachMT5Loginid[], login_id: string) => + mt5_login_list.find(account_obj => account_obj.login === login_id); + +const getCurrentDxtradeAccount = (dxtrade_accounts_list: TDetailsOfDerivXAccount[], login_id: string) => + dxtrade_accounts_list.find(account_obj => account_obj.account_id === login_id); + +const ClosingAccountHasPendingConditions = observer( + ({ details, onBackClick }: TClosingAccountHasPendingConditionsProps) => { + const { client } = useStore(); + const { dxtrade_accounts_list, mt5_login_list, account_list } = client; + + let deriv_open_positions: TDetailsOfDerivAccount[] = []; + let deriv_balance: TDetailsOfDerivAccount[] = []; + const account_pending_withdrawals: TDetailsOfDerivAccount[] = []; + + let mt5_open_positions: TDetailsOfMT5Account[] = []; + let mt5_balance: TDetailsOfMT5Account[] = []; + + let dxtrade_open_positions: TDetailsOfDerivXAccount[] = []; + let dxtrade_balance: TDetailsOfDerivXAccount[] = []; + + if (details?.pending_withdrawals) { + Object.keys(details.pending_withdrawals).forEach(login_id => { + const info = { + withdrawals: details.pending_withdrawals?.[login_id], + }; + const deriv_account = getDerivAccount(account_list, login_id); + if (deriv_account) { + account_pending_withdrawals.push({ ...deriv_account, ...info }); + } + }); + } + if (details?.open_positions) { + Object.keys(details?.open_positions).forEach(login_id => { + const info = { + positions: details.open_positions?.[login_id], + }; + const deriv_account = getDerivAccount(account_list, login_id); + if (deriv_account) { + deriv_open_positions = [...deriv_open_positions, { ...deriv_account, ...info }]; + } else { + const mt5_account = getCurrentMT5Account(mt5_login_list, login_id); + if (mt5_account) { + mt5_open_positions = [...mt5_open_positions, { ...mt5_account, ...info }]; + } + + const dxtrade_account = getCurrentDxtradeAccount(dxtrade_accounts_list, login_id); + if (dxtrade_account) { + dxtrade_open_positions = [...dxtrade_open_positions, { ...dxtrade_account, ...info }]; + } + } + }); + } + if (details?.balance) { + Object.keys(details.balance).forEach(login_id => { + const info = { + balance: details.balance?.[login_id].balance, + currency: details.balance?.[login_id].currency, + }; + const deriv_account = getDerivAccount(account_list, login_id); + if (deriv_account) { + deriv_balance = [...deriv_balance, { ...deriv_account, ...info }]; + } else { + const mt5_account = getCurrentMT5Account(mt5_login_list, login_id); + if (mt5_account) { + mt5_balance = [...mt5_balance, { ...mt5_account, ...info }]; + } + + const dxtrade_account = getCurrentDxtradeAccount(dxtrade_accounts_list, login_id); + if (dxtrade_account) { + dxtrade_balance = [...dxtrade_balance, { ...dxtrade_account, ...info }]; + } + } + }); + } + return ( + + + {!!deriv_open_positions.length && ( + + } + > + {deriv_open_positions.map(account => ( + + } + /> + ))} + + )} + {!!deriv_balance.length && ( + + } + > + {deriv_balance.map(account => ( + + ) + } + /> + ))} + + )} + {!!mt5_open_positions.length && ( + + )} + + {!!mt5_balance.length && ( + + )} + {!!dxtrade_open_positions.length && ( + + )} + {!!dxtrade_balance.length && ( + + )} + {!!account_pending_withdrawals.length && ( + } + description={ + ]} + /> + } + > + {account_pending_withdrawals.map(account => ( + + } + /> + ))} + + )} + +
+ +
+
+ ); + } +); + +export default ClosingAccountHasPendingConditions; diff --git a/packages/account/src/Sections/Security/ClosingAccount/closing-account-pending-conditions/closing-account-pending-balance.tsx b/packages/account/src/Sections/Security/ClosingAccount/closing-account-pending-conditions/closing-account-pending-balance.tsx new file mode 100644 index 000000000000..2ed4d21d7793 --- /dev/null +++ b/packages/account/src/Sections/Security/ClosingAccount/closing-account-pending-conditions/closing-account-pending-balance.tsx @@ -0,0 +1,60 @@ +import React from 'react'; +import { Money } from '@deriv/components'; +import { CFD_PLATFORMS, formatMoney, getCFDAccount, getCFDAccountDisplay, getCFDPlatformLabel } from '@deriv/shared'; +import { observer, useStore } from '@deriv/stores'; +import { Localize } from '@deriv/translations'; +import { TCFDPlatform, TDetailsOfDerivXAccount, TDetailsOfMT5Account } from 'Types'; +import ClosingAccountPendingWrapper from './closing-account-pending-wrapper'; +import ClosingAccountPendingContent from './closing-account-pending-content'; + +type TClosingAccountPendingBalanceProps = { + platform: TCFDPlatform; + account_balance: TDetailsOfMT5Account[] | TDetailsOfDerivXAccount[]; +}; +const ClosingAccountPendingBalance = observer(({ platform, account_balance }: TClosingAccountPendingBalanceProps) => { + const { client } = useStore(); + const { is_eu } = client; + + return ( + + } + > + {account_balance.map(account => ( + + ) + } + /> + ))} + + ); +}); + +export default ClosingAccountPendingBalance; diff --git a/packages/account/src/Sections/Security/ClosingAccount/closing-account-pending-conditions/closing-account-pending-content.tsx b/packages/account/src/Sections/Security/ClosingAccount/closing-account-pending-conditions/closing-account-pending-content.tsx new file mode 100644 index 000000000000..866b9b5d49e1 --- /dev/null +++ b/packages/account/src/Sections/Security/ClosingAccount/closing-account-pending-conditions/closing-account-pending-content.tsx @@ -0,0 +1,29 @@ +import React from 'react'; +import { Icon, Text } from '@deriv/components'; + +type TClosingAccountPendingContentProps = { + currency_icon: string; + loginid?: string; + title?: React.ReactNode; + value: React.ReactNode; +}; + +const ClosingAccountPendingContent = ({ currency_icon, loginid, title, value }: TClosingAccountPendingContentProps) => ( +
+
+ +
+ + {title} + + + {loginid} + +
+
+ + {value} + +
+); +export default ClosingAccountPendingContent; diff --git a/packages/account/src/Sections/Security/ClosingAccount/closing-account-pending-conditions/closing-account-pending-positions.tsx b/packages/account/src/Sections/Security/ClosingAccount/closing-account-pending-conditions/closing-account-pending-positions.tsx new file mode 100644 index 000000000000..c84dde130b43 --- /dev/null +++ b/packages/account/src/Sections/Security/ClosingAccount/closing-account-pending-conditions/closing-account-pending-positions.tsx @@ -0,0 +1,58 @@ +import React from 'react'; +import { CFD_PLATFORMS, getCFDAccount, getCFDAccountDisplay, getCFDPlatformLabel } from '@deriv/shared'; +import { observer, useStore } from '@deriv/stores'; +import { Localize } from '@deriv/translations'; +import { TCFDPlatform, TDetailsOfDerivXAccount, TDetailsOfMT5Account } from 'Types'; +import ClosingAccountPendingWrapper from './closing-account-pending-wrapper'; +import ClosingAccountPendingContent from './closing-account-pending-content'; + +type TClosingAccountPendingPositionsProps = { + platform: TCFDPlatform; + open_positions: TDetailsOfMT5Account[] | TDetailsOfDerivXAccount[]; +}; + +const ClosingAccountPendingPositions = observer( + ({ platform, open_positions }: TClosingAccountPendingPositionsProps) => { + const { client } = useStore(); + const { is_eu } = client; + return ( + + } + > + {open_positions.map(account => ( + + } + /> + ))} + + ); + } +); + +export default ClosingAccountPendingPositions; diff --git a/packages/account/src/Sections/Security/ClosingAccount/closing-account-pending-conditions/closing-account-pending-wrapper.tsx b/packages/account/src/Sections/Security/ClosingAccount/closing-account-pending-conditions/closing-account-pending-wrapper.tsx new file mode 100644 index 000000000000..3b9e5a45d638 --- /dev/null +++ b/packages/account/src/Sections/Security/ClosingAccount/closing-account-pending-conditions/closing-account-pending-wrapper.tsx @@ -0,0 +1,27 @@ +import React from 'react'; +import { Text } from '@deriv/components'; + +type TClosingAccountPendingWrapperProps = { + title: JSX.Element; + description?: React.ReactNode; +}; + +const ClosingAccountPendingWrapper = ({ + children, + title, + description, +}: React.PropsWithChildren) => ( +
+ + {title} + + {description && ( + + {description} + + )} +
{children}
+
+); + +export default ClosingAccountPendingWrapper; diff --git a/packages/account/src/Sections/Security/ClosingAccount/closing-account-reason-form.tsx b/packages/account/src/Sections/Security/ClosingAccount/closing-account-reason-form.tsx index 1be47bc7aaa3..40479e608466 100644 --- a/packages/account/src/Sections/Security/ClosingAccount/closing-account-reason-form.tsx +++ b/packages/account/src/Sections/Security/ClosingAccount/closing-account-reason-form.tsx @@ -1,41 +1,16 @@ import React from 'react'; -import { Field, Formik, FormikErrors, FormikValues } from 'formik'; +import { Field, Form, Formik, FormikErrors, FieldProps } from 'formik'; import { Checkbox, FormSubmitButton, Input, Text } from '@deriv/components'; import { localize, Localize } from '@deriv/translations'; +import { TClosingAccountFormValues } from 'Types'; -type TFormValues = { - 'financial-priorities': boolean; - 'stop-trading': boolean; - 'not-interested': boolean; - 'another-website': boolean; - 'not-user-friendly': boolean; - 'difficult-transactions': boolean; - 'lack-of-features': boolean; - 'unsatisfactory-service': boolean; - 'other-reasons': boolean; - other_trading_platforms: string; - do_to_improve: string; -}; -const initial_form: TFormValues = { - 'financial-priorities': false, - 'stop-trading': false, - 'not-interested': false, - 'another-website': false, - 'not-user-friendly': false, - 'difficult-transactions': false, - 'lack-of-features': false, - 'unsatisfactory-service': false, - 'other-reasons': false, - other_trading_platforms: '', - do_to_improve: '', -}; type TClosingAccountReasonFormProps = { - validateFields: (values: FormikValues) => FormikErrors; - onSubmit: (values: FormikValues) => void; + validateFields: (values: TClosingAccountFormValues) => FormikErrors; + onSubmit: (values: TClosingAccountFormValues) => void; is_checkbox_disabled: boolean; onChangeCheckbox: ( - values: FormikValues, - field_name: keyof TFormValues, + values: TClosingAccountFormValues, + field_name: string, setFieldValue: (name: string, values: string | boolean) => void ) => void; character_limit_no: number; @@ -48,6 +23,59 @@ type TClosingAccountReasonFormProps = { remaining_characters: number; onBackClick: () => void; }; +const initial_form_values: TClosingAccountFormValues = { + 'financial-priorities': false, + 'stop-trading': false, + 'not-interested': false, + 'another-website': false, + 'not-user-friendly': false, + 'difficult-transactions': false, + 'lack-of-features': false, + 'unsatisfactory-service': false, + 'other-reasons': false, + other_trading_platforms: '', + do_to_improve: '', +}; + +const account_closing_reasons = [ + { + name: 'financial-priorities', + label: , + }, + { + name: 'stop-trading', + label: , + }, + { + name: 'not-interested', + label: , + }, + { + name: 'another-website', + label: , + }, + { + name: 'not-user-friendly', + label: , + }, + { + name: 'difficult-transactions', + label: , + }, + { + name: 'lack-of-features', + label: , + }, + { + name: 'unsatisfactory-service', + label: , + }, + { + name: 'other-reasons', + label: , + }, +]; + const ClosingAccountReasonForm = ({ validateFields, onSubmit, @@ -58,196 +86,98 @@ const ClosingAccountReasonForm = ({ onInputPaste, remaining_characters, onBackClick, -}: TClosingAccountReasonFormProps) => ( - - {({ values, setFieldValue, errors, handleChange, handleSubmit, dirty }) => ( -
- - {({ field }: FormikValues) => ( - { - onChangeCheckbox(values, field.name, setFieldValue); - }} - /> - )} - - - {({ field }: FormikValues) => ( - { - onChangeCheckbox(values, field.name, setFieldValue); - }} - /> - )} - - - {({ field }: FormikValues) => ( - { - onChangeCheckbox(values, field.name, setFieldValue); - }} - /> - )} - - - {({ field }: FormikValues) => ( - { - onChangeCheckbox(values, field.name, setFieldValue); - }} - /> - )} - - - {({ field }: FormikValues) => ( - { - onChangeCheckbox(values, field.name, setFieldValue); - }} - /> - )} - - - {({ field }: FormikValues) => ( - { - onChangeCheckbox(values, field.name, setFieldValue); - }} - /> - )} - - - {({ field }: FormikValues) => ( - { - onChangeCheckbox(values, field.name, setFieldValue); - }} - /> - )} - - - {({ field }: FormikValues) => ( - { - onChangeCheckbox(values, field.name, setFieldValue); - }} - /> - )} - - - {({ field }: FormikValues) => ( - { - onChangeCheckbox(values, field.name, setFieldValue); - }} - /> - )} - - - {({ field }: FormikValues) => ( - { + return ( + + {({ values, setFieldValue, errors, handleChange, dirty }) => ( + + {account_closing_reasons.map(reason => ( + + {({ field }: FieldProps) => ( + { + onChangeCheckbox(values, field.name, setFieldValue); + }} + /> )} - name='other_trading_platforms' - value={values.other_trading_platforms} - max_characters={character_limit_no} - onChange={e => onInputChange(e, values.other_trading_platforms, handleChange)} - onPaste={onInputPaste} - /> - )} - - - {({ field }: FormikValues) => ( - onInputChange(e, values.do_to_improve, handleChange)} - onPaste={onInputPaste} - /> - )} - -
-
- - + ))} + + {({ field }: FieldProps) => ( + onInputChange(e, values.other_trading_platforms, handleChange)} + onPaste={onInputPaste} + /> + )} + + + {({ field }: FieldProps) => ( + onInputChange(e, values.do_to_improve, handleChange)} + onPaste={onInputPaste} /> - - {Object.keys(errors).length > 0 && - Object.entries(errors).map(([key, value]) => ( - - {value} - - ))} + )} + +
+
+ + + + {Object.keys(errors).length > 0 && + Object.entries(errors).map(([key, value]) => ( + + {value} + + ))} +
+ 0} + label={localize('Continue')} + has_cancel + cancel_label={localize('Back')} + onCancel={onBackClick} + />
- 0} - label={localize('Continue')} - has_cancel - cancel_label={localize('Back')} - onCancel={onBackClick} - /> -
- - )} - -); + + )} + + ); +}; export default ClosingAccountReasonForm; diff --git a/packages/account/src/Sections/Security/ClosingAccount/closing-account-reason.tsx b/packages/account/src/Sections/Security/ClosingAccount/closing-account-reason.tsx index e00dc180ca49..a44b80bec7b6 100644 --- a/packages/account/src/Sections/Security/ClosingAccount/closing-account-reason.tsx +++ b/packages/account/src/Sections/Security/ClosingAccount/closing-account-reason.tsx @@ -1,10 +1,11 @@ import React from 'react'; import { Redirect } from 'react-router-dom'; -import { FormikValues } from 'formik'; +import { FormikValues, FormikErrors } from 'formik'; import { Loading, Modal, Text } from '@deriv/components'; import { routes, WS } from '@deriv/shared'; import { localize, Localize } from '@deriv/translations'; -import ClosingAccountHasPendingConditions from './closing-account-has-pending-conditions'; +import { TClosingAccountFormValues } from 'Types'; +import ClosingAccountHasPendingConditions from './closing-account-pending-conditions/closing-account-has-pending-conditions'; import ClosingAccountReasonForm from './closing-account-reason-form'; import ClosingAccountWarningModal from './closing-account-warning-modal'; import ClosingAccountGeneralErrorContent from './closing-account-general-error-content'; @@ -13,16 +14,11 @@ type TClosingAccountReasonProps = { onBackClick: () => void; }; -type Error = { - characters_limits?: string; - empty_reason?: string; -}; - -const character_limit_no = 110; -const max_allowed_reasons = 3; +const CHARACTER_LIMIT = 110; +const MAX_ALLOWED_REASONS = 3; -const preparingReason = (values: FormikValues) => { - let selected_reasons = selectedReasons(values) +const formatReasonsForCloseAccount = (values: TClosingAccountFormValues) => { + let selected_reasons = selectedReasonsForCloseAccount(values) .map(val => val[0]) .toString(); const is_other_trading_platform__has_value = !!values.other_trading_platforms.length; @@ -37,39 +33,37 @@ const preparingReason = (values: FormikValues) => { return selected_reasons.replace(/(\r\n|\n|\r)/gm, ' '); }; -const selectedReasons = (values: FormikValues) => { - return Object.entries(values).filter( +const selectedReasonsForCloseAccount = (values: TClosingAccountFormValues) => + Object.entries(values).filter( ([key, value]) => !['other_trading_platforms', 'do_to_improve'].includes(key) && value ); -}; const ClosingAccountReason = ({ onBackClick }: TClosingAccountReasonProps) => { const [is_account_closed, setIsAccountClosed] = React.useState(false); const [is_loading, setIsLoading] = React.useState(false); const [is_modal_open, setIsModalOpen] = React.useState(false); - const [which_modal_should_render, setWhichModalShouldRender] = React.useState(''); - const [reason, setReason] = React.useState(''); + const [modal_type, setModalType] = React.useState(''); + const [reason, setReason] = React.useState(''); const [is_checkbox_disabled, setIsCheckboxDisabled] = React.useState(false); const [total_checkbox_checked, setTotalCheckboxChecked] = React.useState(0); - const [remaining_characters, setRemainingCharacters] = React.useState(character_limit_no); + const [remaining_characters, setRemainingCharacters] = React.useState(CHARACTER_LIMIT); const [total_accumulated_characters, setTotalAccumulatedCharacters] = React.useState(0); const [api_error_message, setApiErrorMessage] = React.useState(''); const [details, setDetails] = React.useState(); React.useEffect(() => { - if (total_checkbox_checked === max_allowed_reasons) setIsCheckboxDisabled(true); + if (total_checkbox_checked === MAX_ALLOWED_REASONS) setIsCheckboxDisabled(true); else if (is_checkbox_disabled) setIsCheckboxDisabled(false); - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [total_checkbox_checked]); + }, [total_checkbox_checked, is_checkbox_disabled]); - const validateFields = (values: FormikValues) => { - const error: Error = {}; - const selected_reason_count = selectedReasons(values).length; + const validateFields = (values: TClosingAccountFormValues) => { + const error: FormikErrors = {}; + const selected_reason_count = selectedReasonsForCloseAccount(values).length; const text_inputs_length = (values.other_trading_platforms + values.do_to_improve).length; - let remaining_chars = character_limit_no - text_inputs_length; + let remaining_chars = CHARACTER_LIMIT - text_inputs_length; if (selected_reason_count) { - const final_value = preparingReason(values); + const final_value = formatReasonsForCloseAccount(values); remaining_chars = remaining_chars >= 0 ? remaining_chars : 0; if (!/^[a-zA-Z0-9.,'\-\s]*$/.test(final_value)) { @@ -85,11 +79,11 @@ const ClosingAccountReason = ({ onBackClick }: TClosingAccountReasonProps) => { return error; }; - const handleSubmitForm = (values: FormikValues) => { - const final_reason = preparingReason(values); + const handleSubmitForm = (values: TClosingAccountFormValues) => { + const final_reason = formatReasonsForCloseAccount(values); setIsModalOpen(true); - setWhichModalShouldRender('warning_modal'); + setModalType('warning_modal'); setReason(final_reason); }; @@ -115,7 +109,7 @@ const ClosingAccountReason = ({ onBackClick }: TClosingAccountReasonProps) => { const value = e.target.value; const is_delete_action = old_value.length > value.length; - if ((remaining_characters <= 0 || total_accumulated_characters >= character_limit_no) && !is_delete_action) { + if ((remaining_characters <= 0 || total_accumulated_characters >= CHARACTER_LIMIT) && !is_delete_action) { e.preventDefault(); } else { onChange(e); @@ -131,10 +125,10 @@ const ClosingAccountReason = ({ onBackClick }: TClosingAccountReasonProps) => { }; const getModalTitle = () => { - if (which_modal_should_render === 'error_modal') return ; - else if (which_modal_should_render === 'inaccessible_modal') + if (modal_type === 'error_modal') return ; + else if (modal_type === 'inaccessible_modal') return ; - else if (which_modal_should_render !== 'warning_modal') return ; + else if (modal_type !== 'warning_modal') return ; return ''; }; @@ -160,7 +154,7 @@ const ClosingAccountReason = ({ onBackClick }: TClosingAccountReasonProps) => { return 'error_modal'; }; - setWhichModalShouldRender(getModalToRender()); + setModalType(getModalToRender()); setDetails(errorDetails); setApiErrorMessage(message); setIsModalOpen(true); @@ -176,8 +170,8 @@ const ClosingAccountReason = ({ onBackClick }: TClosingAccountReasonProps) => {
{ onSubmit={handleSubmitForm} is_checkbox_disabled={is_checkbox_disabled} onChangeCheckbox={handleChangeCheckbox} - character_limit_no={character_limit_no} + character_limit_no={CHARACTER_LIMIT} onInputChange={handleInputChange} onInputPaste={handleInputPaste} remaining_characters={remaining_characters} @@ -197,16 +191,16 @@ const ClosingAccountReason = ({ onBackClick }: TClosingAccountReasonProps) => { toggleModal={() => setIsModalOpen(!is_modal_open)} title={getModalTitle()} > - {which_modal_should_render === 'warning_modal' && ( + {modal_type === 'warning_modal' && ( setIsModalOpen(false)} startDeactivating={startDeactivating} /> )} - {which_modal_should_render === 'AccountHasPendingConditions' && ( + {modal_type === 'AccountHasPendingConditions' && ( )} - {which_modal_should_render === 'inaccessible_modal' && ( + {modal_type === 'inaccessible_modal' && ( setIsModalOpen(false)} diff --git a/packages/account/src/Sections/Security/ClosingAccount/closing-account-steps.tsx b/packages/account/src/Sections/Security/ClosingAccount/closing-account-steps.tsx index 00dae72ae05e..3a0b4c88f18c 100644 --- a/packages/account/src/Sections/Security/ClosingAccount/closing-account-steps.tsx +++ b/packages/account/src/Sections/Security/ClosingAccount/closing-account-steps.tsx @@ -9,9 +9,8 @@ type TClosingAccountStepsProps = { }; const ClosingAccountSteps = observer(({ redirectToReasons }: TClosingAccountStepsProps) => { - const { - common: { is_from_derivgo }, - } = useStore(); + const { common } = useStore(); + const { is_from_derivgo } = common; return (
diff --git a/packages/account/src/Sections/Security/ClosingAccount/closing-account-warning-modal.tsx b/packages/account/src/Sections/Security/ClosingAccount/closing-account-warning-modal.tsx index 88430fe12050..19e3482724c6 100644 --- a/packages/account/src/Sections/Security/ClosingAccount/closing-account-warning-modal.tsx +++ b/packages/account/src/Sections/Security/ClosingAccount/closing-account-warning-modal.tsx @@ -20,13 +20,12 @@ const ClosingAccountWarningModal = ({ closeModal, startDeactivating }: TClosingA
startDeactivating()} - onCancel={() => closeModal()} + onClick={startDeactivating} + onCancel={closeModal} />
); diff --git a/packages/account/src/Sections/Security/ClosingAccount/closing-account.tsx b/packages/account/src/Sections/Security/ClosingAccount/closing-account.tsx index 71b022de32b0..5d9ec2b3e097 100644 --- a/packages/account/src/Sections/Security/ClosingAccount/closing-account.tsx +++ b/packages/account/src/Sections/Security/ClosingAccount/closing-account.tsx @@ -3,7 +3,7 @@ import ClosingAccountSteps from './closing-account-steps'; import ClosingAccountReason from './closing-account-reason'; const ClosingAccount = () => { - const [render_close_account_reason, setRenderCloseAccountReason] = React.useState(false); + const [render_close_account_reason, setRenderCloseAccountReason] = React.useState(false); const redirectToReasons = () => { setRenderCloseAccountReason(true); }; @@ -14,9 +14,9 @@ const ClosingAccount = () => { return (
{render_close_account_reason ? ( - redirectToSteps()} /> + ) : ( - redirectToReasons()} /> + )}
); diff --git a/packages/account/src/Sections/Security/ClosingAccount/index.js b/packages/account/src/Sections/Security/ClosingAccount/index.ts similarity index 100% rename from packages/account/src/Sections/Security/ClosingAccount/index.js rename to packages/account/src/Sections/Security/ClosingAccount/index.ts diff --git a/packages/account/src/Types/common-prop.type.ts b/packages/account/src/Types/common-prop.type.ts index 5aa820af2bbd..10073de1f117 100644 --- a/packages/account/src/Types/common-prop.type.ts +++ b/packages/account/src/Types/common-prop.type.ts @@ -1,12 +1,13 @@ /** Add types that are shared between components */ -import { FormikHandlers, FormikProps, FormikValues } from 'formik'; import { Authorize, DetailsOfEachMT5Loginid, IdentityVerificationAddDocumentResponse, ResidenceList, } from '@deriv/api-types'; +import { FormikHandlers, FormikProps, FormikValues } from 'formik'; import { Redirect, RouteProps } from 'react-router-dom'; +import { CFD_PLATFORMS } from '@deriv/shared'; import { TPage404 } from '../Constants/routes-config'; export type TToken = { @@ -195,6 +196,21 @@ export type TIDVFormValues = { document_additional?: string; error_message?: string; }; +export type TCFDPlatform = typeof CFD_PLATFORMS[keyof typeof CFD_PLATFORMS]; + +export type TClosingAccountFormValues = { + 'financial-priorities': boolean; + 'stop-trading': boolean; + 'not-interested': boolean; + 'another-website': boolean; + 'not-user-friendly': boolean; + 'difficult-transactions': boolean; + 'lack-of-features': boolean; + 'unsatisfactory-service': boolean; + 'other-reasons': boolean; + other_trading_platforms: string; + do_to_improve: string; +}; export type TAccounts = { account?: { @@ -224,3 +240,15 @@ export type TAccounts = { mt5_login_list?: DetailsOfEachMT5Loginid[]; title?: string; }; + +type TPendingAccountDetails = { + balance?: number; + currency?: string; + display_login?: string; + positions?: number; + withdrawals?: number; +}; + +export type TDetailsOfDerivAccount = TAccounts & TPendingAccountDetails; +export type TDetailsOfMT5Account = DetailsOfEachMT5Loginid & TPendingAccountDetails; +export type TDetailsOfDerivXAccount = TDetailsOfMT5Account & { account_id?: string }; From c577b358e26378070010609be4fc65ed9ecc29f4 Mon Sep 17 00:00:00 2001 From: amina-deriv Date: Mon, 28 Aug 2023 15:57:24 +0400 Subject: [PATCH 13/13] fix: resolve review comments --- .../closing-account-reason-form.spec.tsx | 6 +- .../__tests__/closing-account-reason.spec.tsx | 6 +- .../__tests__/closing-account.spec.tsx | 4 +- ...ng-account-has-pending-conditions.spec.tsx | 2 +- .../closing-account-pending-balance.spec.tsx | 2 +- ...closing-account-has-pending-conditions.tsx | 6 +- .../ClosingAccount/closing-account-reason.tsx | 232 +++++++++++++----- .../ClosingAccount/closing-account.tsx | 2 +- 8 files changed, 180 insertions(+), 80 deletions(-) diff --git a/packages/account/src/Sections/Security/ClosingAccount/__tests__/closing-account-reason-form.spec.tsx b/packages/account/src/Sections/Security/ClosingAccount/__tests__/closing-account-reason-form.spec.tsx index 387b21c3b4ea..6dab4f286967 100644 --- a/packages/account/src/Sections/Security/ClosingAccount/__tests__/closing-account-reason-form.spec.tsx +++ b/packages/account/src/Sections/Security/ClosingAccount/__tests__/closing-account-reason-form.spec.tsx @@ -1,5 +1,5 @@ import React from 'react'; -import { render, screen, fireEvent, act } from '@testing-library/react'; +import { render, screen, fireEvent } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import ClosingAccountReasonForm from '../closing-account-reason-form'; @@ -39,9 +39,7 @@ describe('', () => { const el_checkbox = screen.getByRole('checkbox', { name: /i’m closing my account for other reasons\./i, }); - act(() => { - userEvent.click(el_checkbox); - }); + userEvent.click(el_checkbox); expect(mock_props.onChangeCheckbox).toHaveBeenCalled(); }); diff --git a/packages/account/src/Sections/Security/ClosingAccount/__tests__/closing-account-reason.spec.tsx b/packages/account/src/Sections/Security/ClosingAccount/__tests__/closing-account-reason.spec.tsx index c43e3a15ad78..65eca0f6c510 100644 --- a/packages/account/src/Sections/Security/ClosingAccount/__tests__/closing-account-reason.spec.tsx +++ b/packages/account/src/Sections/Security/ClosingAccount/__tests__/closing-account-reason.spec.tsx @@ -6,7 +6,7 @@ import ClosingAccountReason from '../closing-account-reason'; describe('', () => { const mockRootStore: ReturnType = mockStore({}); const mock_props = { - onBackClick: jest.fn(), + redirectToSteps: jest.fn(), }; let modal_root_el: HTMLDivElement; beforeAll(() => { @@ -66,7 +66,7 @@ describe('', () => { expect(screen.getByText(/Remaining characters: 97/i)).toBeInTheDocument(); }); - it('should call onBackClick when back button is clicked', async () => { + it('should call redirectToSteps when back button is clicked', async () => { renderComponent(); const el_checkbox = screen.getByRole('checkbox', { @@ -77,7 +77,7 @@ describe('', () => { fireEvent.click(screen.getByRole('button', { name: /Back/i })); await waitFor(() => { - expect(mock_props.onBackClick).toHaveBeenCalledTimes(1); + expect(mock_props.redirectToSteps).toHaveBeenCalledTimes(1); }); }); }); diff --git a/packages/account/src/Sections/Security/ClosingAccount/__tests__/closing-account.spec.tsx b/packages/account/src/Sections/Security/ClosingAccount/__tests__/closing-account.spec.tsx index d4cdcedac2d9..48f7ff3d5d6e 100644 --- a/packages/account/src/Sections/Security/ClosingAccount/__tests__/closing-account.spec.tsx +++ b/packages/account/src/Sections/Security/ClosingAccount/__tests__/closing-account.spec.tsx @@ -12,7 +12,9 @@ jest.mock('../closing-account-steps', () => ({ jest.mock('../closing-account-reason', () => ({ __esModule: true, - default: ({ onBackClick }: { onBackClick: () => void }) =>
ClosingAccountReason
, + default: ({ redirectToSteps }: { redirectToSteps: () => void }) => ( +
ClosingAccountReason
+ ), })); describe('', () => { diff --git a/packages/account/src/Sections/Security/ClosingAccount/closing-account-pending-conditions/__tests__/closing-account-has-pending-conditions.spec.tsx b/packages/account/src/Sections/Security/ClosingAccount/closing-account-pending-conditions/__tests__/closing-account-has-pending-conditions.spec.tsx index 5341d36e7f3e..f00e2e2d0c64 100644 --- a/packages/account/src/Sections/Security/ClosingAccount/closing-account-pending-conditions/__tests__/closing-account-has-pending-conditions.spec.tsx +++ b/packages/account/src/Sections/Security/ClosingAccount/closing-account-pending-conditions/__tests__/closing-account-has-pending-conditions.spec.tsx @@ -23,7 +23,7 @@ describe('', () => { }, }, }, - onBackClick: jest.fn(), + onConfirm: jest.fn(), }; store = mockStore({ client: { diff --git a/packages/account/src/Sections/Security/ClosingAccount/closing-account-pending-conditions/__tests__/closing-account-pending-balance.spec.tsx b/packages/account/src/Sections/Security/ClosingAccount/closing-account-pending-conditions/__tests__/closing-account-pending-balance.spec.tsx index 22a40ac497c1..fcee642d49cf 100644 --- a/packages/account/src/Sections/Security/ClosingAccount/closing-account-pending-conditions/__tests__/closing-account-pending-balance.spec.tsx +++ b/packages/account/src/Sections/Security/ClosingAccount/closing-account-pending-conditions/__tests__/closing-account-pending-balance.spec.tsx @@ -23,7 +23,7 @@ describe('', () => { }, }, }, - onBackClick: jest.fn(), + onConfirm: jest.fn(), }; store = mockStore({ client: { diff --git a/packages/account/src/Sections/Security/ClosingAccount/closing-account-pending-conditions/closing-account-has-pending-conditions.tsx b/packages/account/src/Sections/Security/ClosingAccount/closing-account-pending-conditions/closing-account-has-pending-conditions.tsx index d5999018104b..11a2216f90f2 100644 --- a/packages/account/src/Sections/Security/ClosingAccount/closing-account-pending-conditions/closing-account-has-pending-conditions.tsx +++ b/packages/account/src/Sections/Security/ClosingAccount/closing-account-pending-conditions/closing-account-has-pending-conditions.tsx @@ -16,7 +16,7 @@ type TClosingAccountHasPendingConditionsProps = { open_positions?: Record; balance?: Record; }; - onBackClick: () => void; + onConfirm: () => void; }; const getDerivAccount = (client_accounts: TAccounts[], login_id: string) => @@ -29,7 +29,7 @@ const getCurrentDxtradeAccount = (dxtrade_accounts_list: TDetailsOfDerivXAccount dxtrade_accounts_list.find(account_obj => account_obj.account_id === login_id); const ClosingAccountHasPendingConditions = observer( - ({ details, onBackClick }: TClosingAccountHasPendingConditionsProps) => { + ({ details, onConfirm }: TClosingAccountHasPendingConditionsProps) => { const { client } = useStore(); const { dxtrade_accounts_list, mt5_login_list, account_list } = client; @@ -197,7 +197,7 @@ const ClosingAccountHasPendingConditions = observer( )}
-
diff --git a/packages/account/src/Sections/Security/ClosingAccount/closing-account-reason.tsx b/packages/account/src/Sections/Security/ClosingAccount/closing-account-reason.tsx index a44b80bec7b6..2376a20dcfef 100644 --- a/packages/account/src/Sections/Security/ClosingAccount/closing-account-reason.tsx +++ b/packages/account/src/Sections/Security/ClosingAccount/closing-account-reason.tsx @@ -11,12 +11,98 @@ import ClosingAccountWarningModal from './closing-account-warning-modal'; import ClosingAccountGeneralErrorContent from './closing-account-general-error-content'; type TClosingAccountReasonProps = { - onBackClick: () => void; + redirectToSteps: () => void; }; +type TFormError = FormikErrors & { + empty_reason?: string; + characters_limits?: string; +}; + +type TCustomState = { + is_account_closed: boolean; + is_loading: boolean; + is_modal_open: boolean; + modal_type: string; + reason: string; + is_checkbox_disabled: boolean; + total_checkbox_checked: number; + remaining_characters: number; + total_accumulated_characters: number; + api_error_message: string; + details: Record; +}; +type TAction = + | { type: 'SET_ACCOUNT_CLOSED'; payload: boolean } + | { type: 'SET_LOADING'; payload: boolean } + | { type: 'SET_MODAL'; payload: { is_modal_open: boolean; modal_type: string } } + | { type: 'SET_REASON'; payload: string } + | { type: 'SET_CHECKBOX_DISABLED'; payload: boolean } + | { type: 'SET_TOTAL_CHECKBOX_CHECKED'; payload: number } + | { type: 'SET_REMAINING_CHARACTERS'; payload: number } + | { type: 'SET_TOTAL_ACCUMULATED_CHARACTERS'; payload: number } + | { type: 'SET_API_ERROR_MESSAGE'; payload: string } + | { type: 'SET_DETAILS'; payload: Record }; + const CHARACTER_LIMIT = 110; const MAX_ALLOWED_REASONS = 3; +const SET_ACCOUNT_CLOSED = 'SET_ACCOUNT_CLOSED'; +const SET_LOADING = 'SET_LOADING'; +const SET_MODAL = 'SET_MODAL'; +const SET_REASON = 'SET_REASON'; +const SET_CHECKBOX_DISABLED = 'SET_CHECKBOX_DISABLED'; +const SET_TOTAL_CHECKBOX_CHECKED = 'SET_TOTAL_CHECKBOX_CHECKED'; +const SET_REMAINING_CHARACTERS = 'SET_REMAINING_CHARACTERS'; +const SET_TOTAL_ACCUMULATED_CHARACTERS = 'SET_TOTAL_ACCUMULATED_CHARACTERS'; +const SET_API_ERROR_MESSAGE = 'SET_API_ERROR_MESSAGE'; +const SET_DETAILS = 'SET_DETAILS'; + +const initial_state = { + is_account_closed: false, + is_loading: false, + is_modal_open: false, + modal_type: '', + reason: '', + is_checkbox_disabled: false, + total_checkbox_checked: 0, + remaining_characters: CHARACTER_LIMIT, + total_accumulated_characters: 0, + api_error_message: '', + details: {}, +}; + +const reducer = (state: TCustomState, action: TAction) => { + switch (action.type) { + case SET_ACCOUNT_CLOSED: + return { ...state, is_account_closed: action.payload }; + case SET_LOADING: + return { ...state, is_loading: action.payload }; + case SET_MODAL: + return { + ...state, + is_modal_open: action.payload.is_modal_open, + modal_type: action.payload.modal_type, + }; + case SET_REASON: + return { ...state, reason: action.payload }; + case SET_CHECKBOX_DISABLED: + return { ...state, is_checkbox_disabled: action.payload }; + case SET_TOTAL_CHECKBOX_CHECKED: + return { ...state, total_checkbox_checked: action.payload }; + case SET_REMAINING_CHARACTERS: + return { ...state, remaining_characters: action.payload }; + case SET_TOTAL_ACCUMULATED_CHARACTERS: + return { ...state, total_accumulated_characters: action.payload }; + case SET_API_ERROR_MESSAGE: + return { ...state, api_error_message: action.payload }; + case SET_DETAILS: + return { ...state, details: action.payload }; + default: + return state; + } +}; + const formatReasonsForCloseAccount = (values: TClosingAccountFormValues) => { let selected_reasons = selectedReasonsForCloseAccount(values) .map(val => val[0]) @@ -38,26 +124,31 @@ const selectedReasonsForCloseAccount = (values: TClosingAccountFormValues) => ([key, value]) => !['other_trading_platforms', 'do_to_improve'].includes(key) && value ); -const ClosingAccountReason = ({ onBackClick }: TClosingAccountReasonProps) => { - const [is_account_closed, setIsAccountClosed] = React.useState(false); - const [is_loading, setIsLoading] = React.useState(false); - const [is_modal_open, setIsModalOpen] = React.useState(false); - const [modal_type, setModalType] = React.useState(''); - const [reason, setReason] = React.useState(''); - const [is_checkbox_disabled, setIsCheckboxDisabled] = React.useState(false); - const [total_checkbox_checked, setTotalCheckboxChecked] = React.useState(0); - const [remaining_characters, setRemainingCharacters] = React.useState(CHARACTER_LIMIT); - const [total_accumulated_characters, setTotalAccumulatedCharacters] = React.useState(0); - const [api_error_message, setApiErrorMessage] = React.useState(''); - const [details, setDetails] = React.useState(); +const ClosingAccountReason = ({ redirectToSteps }: TClosingAccountReasonProps) => { + const [state, dispatch] = React.useReducer(reducer, initial_state); + + const { + is_account_closed, + is_loading, + is_modal_open, + modal_type, + reason, + is_checkbox_disabled, + total_checkbox_checked, + remaining_characters, + total_accumulated_characters, + api_error_message, + details, + } = state; React.useEffect(() => { - if (total_checkbox_checked === MAX_ALLOWED_REASONS) setIsCheckboxDisabled(true); - else if (is_checkbox_disabled) setIsCheckboxDisabled(false); + if (total_checkbox_checked === MAX_ALLOWED_REASONS) { + dispatch({ type: SET_CHECKBOX_DISABLED, payload: true }); + } else if (is_checkbox_disabled) dispatch({ type: SET_CHECKBOX_DISABLED, payload: false }); }, [total_checkbox_checked, is_checkbox_disabled]); const validateFields = (values: TClosingAccountFormValues) => { - const error: FormikErrors = {}; + const error: TFormError = {}; const selected_reason_count = selectedReasonsForCloseAccount(values).length; const text_inputs_length = (values.other_trading_platforms + values.do_to_improve).length; let remaining_chars = CHARACTER_LIMIT - text_inputs_length; @@ -73,8 +164,8 @@ const ClosingAccountReason = ({ onBackClick }: TClosingAccountReasonProps) => { error.empty_reason = localize('Please select at least one reason'); } - setTotalAccumulatedCharacters(text_inputs_length); - setRemainingCharacters(remaining_chars); + dispatch({ type: SET_TOTAL_ACCUMULATED_CHARACTERS, payload: text_inputs_length }); + dispatch({ type: SET_REMAINING_CHARACTERS, payload: remaining_chars }); return error; }; @@ -82,9 +173,8 @@ const ClosingAccountReason = ({ onBackClick }: TClosingAccountReasonProps) => { const handleSubmitForm = (values: TClosingAccountFormValues) => { const final_reason = formatReasonsForCloseAccount(values); - setIsModalOpen(true); - setModalType('warning_modal'); - setReason(final_reason); + dispatch({ type: SET_MODAL, payload: { is_modal_open: true, modal_type: 'warning_modal' } }); + dispatch({ type: SET_REASON, payload: final_reason }); }; const handleChangeCheckbox = ( @@ -93,26 +183,28 @@ const ClosingAccountReason = ({ onBackClick }: TClosingAccountReasonProps) => { setFieldValue: (name: string, values: string | boolean) => void ) => { if (!values[name]) { - setTotalCheckboxChecked(total_checkbox_checked + 1); + dispatch({ type: SET_TOTAL_CHECKBOX_CHECKED, payload: total_checkbox_checked + 1 }); + setFieldValue(name, !values[name]); } else { - setTotalCheckboxChecked(total_checkbox_checked - 1); + dispatch({ type: SET_TOTAL_CHECKBOX_CHECKED, payload: total_checkbox_checked - 1 }); + setFieldValue(name, !values[name]); } }; const handleInputChange = ( - e: React.ChangeEvent, + event: React.ChangeEvent, old_value: string, - onChange: (e: React.ChangeEvent) => void + onChange: (event: React.ChangeEvent) => void ) => { - const value = e.target.value; + const value = event.target.value; const is_delete_action = old_value.length > value.length; if ((remaining_characters <= 0 || total_accumulated_characters >= CHARACTER_LIMIT) && !is_delete_action) { - e.preventDefault(); + event.preventDefault(); } else { - onChange(e); + onChange(event); } }; @@ -125,28 +217,49 @@ const ClosingAccountReason = ({ onBackClick }: TClosingAccountReasonProps) => { }; const getModalTitle = () => { - if (modal_type === 'error_modal') return ; - else if (modal_type === 'inaccessible_modal') - return ; - else if (modal_type !== 'warning_modal') return ; - return ''; + switch (modal_type) { + case 'error_modal': + return ; + case 'inaccessible_modal': + return ; + case 'warning_modal': + return ''; + default: + return ; + } + }; + const getModalContent = () => { + switch (modal_type) { + case 'warning_modal': + return ; + case 'account_has_pending_conditions_modal': + return ; + case 'inaccessible_modal': + return ; + default: + return null; + } + }; + + const closeModal = () => { + dispatch({ type: SET_MODAL, payload: { is_modal_open: false, modal_type: '' } }); }; const startDeactivating = async () => { - setIsModalOpen(false); - setIsLoading(true); + closeModal(); + dispatch({ type: SET_LOADING, payload: true }); const account_closure_response = await WS.authorized.accountClosure({ account_closure: 1, reason, }); if (account_closure_response.account_closure === 1) { - setIsAccountClosed(true); + dispatch({ type: SET_ACCOUNT_CLOSED, payload: true }); } else { - const { code, message, details: errorDetails } = account_closure_response.error; + const { code, message, details } = account_closure_response.error; const getModalToRender = () => { if (code === 'AccountHasPendingConditions') { - return 'AccountHasPendingConditions'; + return 'account_has_pending_conditions_modal'; } if (code === 'MT5AccountInaccessible') { return 'inaccessible_modal'; @@ -154,11 +267,10 @@ const ClosingAccountReason = ({ onBackClick }: TClosingAccountReasonProps) => { return 'error_modal'; }; - setModalType(getModalToRender()); - setDetails(errorDetails); - setApiErrorMessage(message); - setIsModalOpen(true); - setIsLoading(false); + dispatch({ type: SET_MODAL, payload: { is_modal_open: true, modal_type: getModalToRender() } }); + dispatch({ type: SET_DETAILS, payload: details }); + dispatch({ type: SET_API_ERROR_MESSAGE, payload: message }); + dispatch({ type: SET_LOADING, payload: false }); } }; @@ -183,30 +295,18 @@ const ClosingAccountReason = ({ onBackClick }: TClosingAccountReasonProps) => { onInputChange={handleInputChange} onInputPaste={handleInputPaste} remaining_characters={remaining_characters} - onBackClick={onBackClick} + onBackClick={redirectToSteps} /> - setIsModalOpen(!is_modal_open)} - title={getModalTitle()} - > - {modal_type === 'warning_modal' && ( - setIsModalOpen(false)} - startDeactivating={startDeactivating} - /> - )} - {modal_type === 'AccountHasPendingConditions' && ( - - )} - {modal_type === 'inaccessible_modal' && ( - setIsModalOpen(false)} - /> - )} - + {is_modal_open && modal_type && ( + + {getModalContent()} + + )}
); }; diff --git a/packages/account/src/Sections/Security/ClosingAccount/closing-account.tsx b/packages/account/src/Sections/Security/ClosingAccount/closing-account.tsx index 5d9ec2b3e097..a924ef8ec7a0 100644 --- a/packages/account/src/Sections/Security/ClosingAccount/closing-account.tsx +++ b/packages/account/src/Sections/Security/ClosingAccount/closing-account.tsx @@ -14,7 +14,7 @@ const ClosingAccount = () => { return (
{render_close_account_reason ? ( - + ) : ( )}