Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

[WALL] Lubega / WALL-5049 / Enter existing mt5 password modal #17494

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@ import './WalletPasswordField.scss';
export const validatePassword = (
password: string,
mt5Policy: boolean,
localize: ReturnType<typeof useTranslations>['localize']
localize: ReturnType<typeof useTranslations>['localize'],
hideWarning?: boolean
) => {
const score = mt5Policy ? calculateScoreMT5(password) : calculateScoreCFD(password);
let validationErrorMessage = '';
Expand All @@ -38,7 +39,7 @@ export const validatePassword = (
} else {
cfdSchema(localize).validateSync(password);
}
validationErrorMessage = getWarningMessages(localize)[feedback.warning as passwordKeys] ?? '';
validationErrorMessage = hideWarning ? '' : getWarningMessages(localize)[feedback.warning as passwordKeys];
} catch (err) {
if (err instanceof ValidationError) {
validationErrorMessage = err?.message;
Expand All @@ -50,6 +51,7 @@ export const validatePassword = (

const WalletPasswordField: React.FC<WalletPasswordFieldProps> = ({
autoComplete,
hideWarning,
label,
mt5Policy = false,
name = 'walletPasswordField',
Expand All @@ -67,8 +69,8 @@ const WalletPasswordField: React.FC<WalletPasswordFieldProps> = ({
const [errorMessage, setErrorMessage] = useState('');

const { score, validationErrorMessage } = useMemo(
() => validatePassword(password, mt5Policy, localize),
[password, mt5Policy, localize]
() => validatePassword(password, mt5Policy, localize, hideWarning),
[hideWarning, password, mt5Policy, localize]
);
const passwordValidation = mt5Policy ? !validPasswordMT5(password) : !validPassword(password);

Expand Down Expand Up @@ -98,7 +100,7 @@ const WalletPasswordField: React.FC<WalletPasswordFieldProps> = ({
<div className='wallets-password'>
<WalletTextField
autoComplete={autoComplete}
errorMessage={isTouched && (serverErrorMessage || errorMessage)}
errorMessage={(isTouched || passwordError) && (serverErrorMessage || errorMessage)}
isInvalid={(passwordValidation && isTouched) || showErrorMessage || !!passwordError}
label={label}
messageVariant={validationErrorMessage ? 'warning' : undefined}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { Loader } from '@deriv-com/ui';
import { WalletTextFieldProps } from '../WalletTextField/WalletTextField';

export interface WalletPasswordFieldProps extends WalletTextFieldProps {
hideWarning?: boolean;
mt5Policy?: boolean; // This prop is used to utilize the new password validation for MT5.
password: string;
passwordError?: boolean;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,12 @@ import { Localize, useTranslations } from '@deriv-com/translations';
import { Button, Loader, useDevice } from '@deriv-com/ui';
import { SentEmailContent } from '../../../../components';
import { ModalStepWrapper, ModalWrapper } from '../../../../components/Base';
import { validatePassword } from '../../../../components/Base/WalletPasswordField/WalletPasswordField';
import { useModal } from '../../../../components/ModalProvider';
import { getPasswordErrorMessage } from '../../../../constants/password';
import { platformPasswordResetRedirectLink } from '../../../../utils/cfd';
import { validPassword, validPasswordMT5 } from '../../../../utils/password-validation';
import { CFD_PLATFORMS, JURISDICTION, MARKET_TYPE, PlatformDetails } from '../../constants';
import { validPasswordMT5 } from '../../../../utils/password-validation';
import { CFD_PLATFORMS, getMarketTypeDetails, JURISDICTION, MARKET_TYPE, PlatformDetails } from '../../constants';
import { CreatePassword, CreatePasswordMT5, EnterPassword, MT5ResetPasswordModal } from '../../screens';
import { TAvailableMT5Account } from '../../types';
import { MT5AccountAdded } from '../MT5AccountAdded';
Expand Down Expand Up @@ -79,10 +81,12 @@ const MT5PasswordModal: React.FC<TProps> = ({ account, isVirtual = false }) => {
const marketType = account.market_type ?? 'synthetic';
const platform = account.platform;
const product = account.product;
const marketTypeTitle = getMarketTypeDetails(localize, product)[marketType].title;

const isMT5PasswordNotSet = accountStatusData?.is_mt5_password_not_set;
const { platform: mt5Platform, title } = PlatformDetails.mt5;
const selectedJurisdiction = isVirtual ? JURISDICTION.SVG : getModalState('selectedJurisdiction');
const { validationErrorMessage: validateMT5ErrorMessage } = validatePassword(password, true, localize);

const isLoading = accountStatusLoading || createMT5AccountLoading || tradingPlatformPasswordChangeLoading;

Expand Down Expand Up @@ -183,16 +187,28 @@ const MT5PasswordModal: React.FC<TProps> = ({ account, isVirtual = false }) => {
);

const renderTitle = useCallback(() => {
const accountAction = isMT5PasswordNotSet ? localize('Create a') : localize('Enter your');
const accountTitle = isVirtual ? localize('demo {{title}}', { title }) : title;
let modalTitle;

return updateMT5Password
? localize('{{title}} latest password requirements', { title })
: localize('{{accountAction}} {{accountTitle}} password', {
accountAction,
accountTitle,
});
}, [isMT5PasswordNotSet, isVirtual, localize, title, updateMT5Password]);
if (updateMT5Password) {
modalTitle = localize('{{title}} latest password requirements', { title });
} else if (isMT5PasswordNotSet) {
modalTitle = isVirtual
? localize('Create a demo {{title}} password', { title })
: localize('Create a {{title}} password', { title });
} else {
modalTitle = isVirtual
? localize('Add an {{title}} {{marketTypeTitle}} demo account', {
marketTypeTitle,
title: CFD_PLATFORMS.MT5.toLocaleUpperCase(),
})
: localize('Add an {{title}} {{marketTypeTitle}} account', {
marketTypeTitle,
title: CFD_PLATFORMS.MT5.toLocaleUpperCase(),
});
}

return modalTitle;
}, [isMT5PasswordNotSet, isVirtual, localize, marketTypeTitle, title, updateMT5Password]);

const renderFooter = useCallback(() => {
if (isMT5PasswordNotSet)
Expand Down Expand Up @@ -224,7 +240,8 @@ const MT5PasswordModal: React.FC<TProps> = ({ account, isVirtual = false }) => {
!password ||
createMT5AccountLoading ||
tradingPlatformPasswordChangeLoading ||
!validPassword(password) ||
(!validPasswordMT5(password) &&
validateMT5ErrorMessage !== getPasswordErrorMessage(localize).missingCharacterMT5) ||
!isTncChecked
}
isLoading={tradingPlatformPasswordChangeLoading || createMT5AccountLoading}
Expand All @@ -234,15 +251,17 @@ const MT5PasswordModal: React.FC<TProps> = ({ account, isVirtual = false }) => {
</div>
);
}, [
createMT5AccountLoading,
isDesktop,
isMT5PasswordNotSet,
title,
onSubmit,
password,
sendEmailVerification,
createMT5AccountLoading,
tradingPlatformPasswordChangeLoading,
isTncChecked,
onSubmit,
isDesktop,
title,
validateMT5ErrorMessage,
localize,
sendEmailVerification,
]);

const PasswordComponent = useMemo(() => {
Expand Down Expand Up @@ -295,8 +314,14 @@ const MT5PasswordModal: React.FC<TProps> = ({ account, isVirtual = false }) => {
marketType={marketType}
modalTitle={
isVirtual
? localize('Enter your demo {{title}} password', { title })
: localize('Enter your {{title}} password', { title })
? localize('Add an {{title}} {{marketTypeTitle}} demo account', {
marketTypeTitle,
title: CFD_PLATFORMS.MT5.toLocaleUpperCase(),
})
: localize('Add an {{title}} {{marketTypeTitle}} account', {
marketTypeTitle,
title: CFD_PLATFORMS.MT5.toLocaleUpperCase(),
})
}
onPasswordChange={e => setPassword(e.target.value)}
onPrimaryClick={onSubmit}
Expand All @@ -321,14 +346,14 @@ const MT5PasswordModal: React.FC<TProps> = ({ account, isVirtual = false }) => {
account,
isTncChecked,
isVirtual,
product,
updateMT5Password,
tradingPasswordChangeError,
onSubmitPasswordChange,
marketType,
localize,
title,
marketTypeTitle,
createMT5AccountError?.error?.code,
product,
sendEmailVerification,
]);

Expand Down Expand Up @@ -358,6 +383,7 @@ const MT5PasswordModal: React.FC<TProps> = ({ account, isVirtual = false }) => {
/>
);
}

if (
createMT5AccountStatus === 'error' &&
createMT5AccountError?.error?.code === 'PasswordReset' &&
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ export const MT5PasswordModalFooter = ({ disabled, isLoading, onPrimaryClick, on
textSize='sm'
variant='outlined'
>
<Localize i18n_default_text='Forgot password?' />
<Localize i18n_default_text='Forgot password' />
</Button>
<Button
disabled={disabled}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -231,7 +231,7 @@ describe('MT5PasswordModal', () => {

expect(screen.getByText('EnterPassword')).toBeInTheDocument();
expect(screen.getByText('MT5PasswordModalFooter')).toBeInTheDocument();
expect(screen.getByText('Enter your Deriv MT5 password')).toBeInTheDocument();
expect(screen.getByText('Add an MT5 Standard account')).toBeInTheDocument();
});

it('renders default content for demo account', () => {
Expand All @@ -242,7 +242,7 @@ describe('MT5PasswordModal', () => {

expect(screen.getByText('EnterPassword')).toBeInTheDocument();
expect(screen.getByText('MT5PasswordModalFooter')).toBeInTheDocument();
expect(screen.getByText('Enter your demo Deriv MT5 password')).toBeInTheDocument();
expect(screen.getByText('Add an MT5 Standard demo account')).toBeInTheDocument();
});

it('renders WalletError for account creation errors', () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ describe('MT5PasswordModalFooter', () => {
onSecondaryClick={jest.fn()}
/>
);
expect(screen.getByText('Forgot password?')).toBeInTheDocument();
expect(screen.getByText('Forgot password')).toBeInTheDocument();
expect(screen.getByText('Add account')).toBeInTheDocument();
});

Expand All @@ -37,7 +37,7 @@ describe('MT5PasswordModalFooter', () => {
onSecondaryClick={mockSecondaryClick}
/>
);
await userEvent.click(screen.getByText('Forgot password?'));
await userEvent.click(screen.getByText('Forgot password'));
expect(mockSecondaryClick).toHaveBeenCalled();
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ import { useActiveWalletAccount } from '@deriv/api-v2';
import { Localize, useTranslations } from '@deriv-com/translations';
import { Button, Text, useDevice } from '@deriv-com/ui';
import { WalletPasswordFieldLazy } from '../../../../components/Base';
import { validatePassword } from '../../../../components/Base/WalletPasswordField/WalletPasswordField';
import { getPasswordErrorMessage } from '../../../../constants/password';
import { THooks, TMarketTypes, TPlatforms } from '../../../../types';
import { validPassword, validPasswordMT5 } from '../../../../utils/password-validation';
import { CFD_PLATFORMS, getMarketTypeDetails, JURISDICTION, PlatformDetails } from '../../constants';
Expand Down Expand Up @@ -53,7 +55,11 @@ const EnterPassword: React.FC<TProps> = ({
const { data } = useActiveWalletAccount();

const isMT5 = platform === CFD_PLATFORMS.MT5;
const disableButton = isMT5 ? !validPasswordMT5(password) : !validPassword(password);
const { validationErrorMessage } = validatePassword(password, isMT5, localize);
const disableButton = isMT5
? !validPasswordMT5(password) &&
validationErrorMessage !== getPasswordErrorMessage(localize).missingCharacterMT5
: !validPassword(password);
const accountType = data?.is_virtual ? localize('Demo') : localize('Real');
const title = PlatformDetails[platform].title;
const marketTypeTitle =
Expand All @@ -80,19 +86,31 @@ const EnterPassword: React.FC<TProps> = ({
)}
<div className='wallets-enter-password__content'>
<Text align='start' className='wallets-enter-password__description' size={isDesktop ? 'sm' : 'md'}>
<Localize
i18n_default_text='Enter your {{title}} password to add a {{accountTitle}} {{marketTypeTitle}} account'
values={{
accountTitle:
platform === CFD_PLATFORMS.MT5 && accountType === 'Demo'
? `${accountType.toLocaleLowerCase()} ${CFD_PLATFORMS.MT5.toLocaleUpperCase()}`
: title,
marketTypeTitle,
title,
}}
/>
{isMT5 ? (
<Localize
i18n_default_text='Enter your {{title}} password to add an {{accountTitle}} {{marketTypeTitle}} account'
values={{
accountTitle: CFD_PLATFORMS.MT5.toLocaleUpperCase(),
marketTypeTitle: isVirtual
? `${marketTypeTitle} ${accountType.toLocaleLowerCase()}`
: marketTypeTitle,
title,
}}
/>
) : (
<Localize
i18n_default_text='Enter your {{title}} password to add a {{title}} {{marketTypeTitle}} account'
values={{
marketTypeTitle: isVirtual
? `${marketTypeTitle} ${accountType.toLocaleLowerCase()}`
: marketTypeTitle,
title,
}}
/>
)}
</Text>
<WalletPasswordFieldLazy
hideWarning
label={localize('{{title}} password', { title })}
onChange={onPasswordChange}
password={password}
Expand All @@ -119,7 +137,7 @@ const EnterPassword: React.FC<TProps> = ({
textSize='sm'
variant='outlined'
>
<Localize i18n_default_text='Forgot password?' />
<Localize i18n_default_text='Forgot password' />
</Button>
<Button
disabled={!password || isLoading || disableButton || !isTncChecked}
Expand Down
Loading
Loading