Skip to content

Commit

Permalink
[WALL] Aizad/WALL-2807/Create Reset Password Popup and Success Popup (#…
Browse files Browse the repository at this point in the history
…11906)

* feat: intermediate result

* feat: add formik

* feat: separate components to different screens

* refactor: create mt5ChangeInvestorPasswordScreens scss file

* chore: adding logic and stitching for the last modal
- created the remaining modals for the user flow
- implement logic that will send request for resetting the password
- added some props to ModalStepWrapper

* fix: typescript errors and refactor some stuffs

* fix: resolve pt.1

* feat: add send email handler

* feat: rename form submit handler

* fix: resolve comments

* feat: complete reset mt5 investor password

* feat: fix small issue

* feat: implement review suggestions

* feat: change imports

* fix: build errors

* fix: test case

* fix: sonarcloud issue

* fix: updated WalletPasswordField component to WalletPasswordFieldLazy

* fix: ui issues on desktop and mobile view

* fix: sonarcloud issue

* fix: sonarcloud issue

* fix: failed test

* fix: failed test

* fix: font size for reset mt5 password modal

* fix: added mobile styling differences

---------

Co-authored-by: Sergei Baranovski <[email protected]>
Co-authored-by: lubega-deriv <[email protected]>
  • Loading branch information
3 people authored Jan 22, 2024
1 parent b252dde commit 278a8b2
Show file tree
Hide file tree
Showing 18 changed files with 403 additions and 25 deletions.
18 changes: 13 additions & 5 deletions packages/core/src/App/Containers/Redirect/redirect.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -95,27 +95,28 @@ const Redirect = observer(() => {
if (redirect_to) {
let pathname = '';
let hash = '';
const main_screen_route = is_next_wallet ? routes.wallets : routes.traders_hub;
switch (redirect_to) {
case '1':
pathname = routes.traders_hub;
break;
case '10':
pathname = routes.traders_hub;
pathname = main_screen_route;
hash = 'real';
break;
case '11':
pathname = routes.traders_hub;
pathname = main_screen_route;
hash = 'demo';
break;
case '2':
pathname = routes.traders_hub;
break;
case '20':
pathname = routes.traders_hub;
pathname = main_screen_route;
hash = 'real';
break;
case '21':
pathname = routes.traders_hub;
pathname = main_screen_route;
hash = 'demo';
break;
case '3':
Expand Down Expand Up @@ -191,7 +192,14 @@ const Redirect = observer(() => {
case 'trading_platform_investor_password_reset': {
localStorage.setItem('cfd_reset_password_code', code_param);
const is_demo = localStorage.getItem('cfd_reset_password_intent')?.includes('demo');
history.push(`${routes.traders_hub}#${is_demo ? 'demo' : 'real'}#reset-password`);
if (is_next_wallet) {
history.push({
pathname: routes.wallets,
search: url_query_string,
});
} else {
history.push(`${routes.traders_hub}#${is_demo ? 'demo' : 'real'}#reset-password`);
}
redirected_to_route = true;
break;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
.wallets-modal-step-wrapper {
background-color: #ffffff;
background: var(--system-light-8-primary-background, #fff);
border-radius: 0.8rem;
animation: popup 0.4s;

Expand Down
9 changes: 6 additions & 3 deletions packages/wallets/src/components/Base/Tabs/TabTitle.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,17 @@
import React, { FC, useCallback } from 'react';
import classNames from 'classnames';
import { WalletText } from '../WalletText';
import WalletText, { WalletTextProps } from '../WalletText/WalletText';

export type TabTitleProps = {
icon?: React.ReactNode;
index: number;
isActive?: boolean;
setSelectedTab: (index: number) => void;
size: WalletTextProps['size'];
title: string;
};

const TabTitle: FC<TabTitleProps> = ({ icon, index, isActive, setSelectedTab, title }) => {
const TabTitle: FC<TabTitleProps> = ({ icon, index, isActive, setSelectedTab, size = 'md', title }) => {
const handleOnClick = useCallback(() => {
setSelectedTab(index);
}, [setSelectedTab, index]);
Expand All @@ -23,7 +24,9 @@ const TabTitle: FC<TabTitleProps> = ({ icon, index, isActive, setSelectedTab, ti
onClick={handleOnClick}
>
{icon}
<WalletText weight={isActive ? 'bold' : 'normal'}>{title}</WalletText>
<WalletText size={size} weight={isActive ? 'bold' : 'normal'}>
{title}
</WalletText>
</button>
);
};
Expand Down
4 changes: 3 additions & 1 deletion packages/wallets/src/components/Base/Tabs/Tabs.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,12 @@ import './Tabs.scss';

type TabsProps = {
children: ReactElement<TabTitleProps>[];
fontSize?: TabTitleProps['size'];
preSelectedTab?: number;
wrapperClassName?: string;
};

const Tabs: FC<TabsProps> = ({ children, preSelectedTab, wrapperClassName }): JSX.Element => {
const Tabs: FC<TabsProps> = ({ children, fontSize = 'md', preSelectedTab, wrapperClassName }): JSX.Element => {
const [selectedTabIndex, setSelectedTabIndex] = useState(preSelectedTab || 0);

return (
Expand All @@ -21,6 +22,7 @@ const Tabs: FC<TabsProps> = ({ children, preSelectedTab, wrapperClassName }): JS
isActive={index === selectedTabIndex}
key={`wallets-tab-${item.props.title}`}
setSelectedTab={setSelectedTabIndex}
size={fontSize}
title={item.props.title}
/>
))}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ const SentEmailContent: FC<SentEmailContentProps> = ({ description, isInvestorPa
const { mutate: verifyEmail } = useVerifyEmail();
const { isMobile } = useDevice();
const mt5Platform = PlatformDetails.mt5.platform;
const title = PlatformDetails[platform ?? mt5Platform].title;
const { title } = PlatformDetails[platform ?? mt5Platform];
const titleSize = 'md';
const descriptionSize = 'sm';
const emailLinkSize = isMobile ? 'lg' : 'md';
Expand All @@ -39,6 +39,10 @@ const SentEmailContent: FC<SentEmailContentProps> = ({ description, isInvestorPa

const { data: activeWallet } = useActiveWalletAccount();

const mt5ResetType = isInvestorPassword
? 'trading_platform_investor_password_reset'
: 'trading_platform_mt5_password_reset';

return (
<div className='wallets-sent-email-content'>
<WalletsActionScreen
Expand Down Expand Up @@ -80,7 +84,7 @@ const SentEmailContent: FC<SentEmailContentProps> = ({ description, isInvestorPa
verifyEmail({
type:
platform === mt5Platform
? 'trading_platform_mt5_password_reset'
? mt5ResetType
: 'trading_platform_dxtrade_password_reset',
url_parameters: {
redirect_to: platformPasswordResetRedirectLink(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import React, { FC, useCallback } from 'react';
import { Trans } from 'react-i18next';
import useDevice from '../../hooks/useDevice';
import MT5PasswordUpdatedIcon from '../../public/images/ic-mt5-password-updated.svg';
import MT5SuccessPasswordReset from '../../public/images/mt5-success-password-reset.svg';
import { ModalStepWrapper, WalletButton } from '../Base';
import { useModal } from '../ModalProvider';
import { WalletsActionScreen } from '../WalletsActionScreen';

type WalletSuccessResetMT5PasswordProps = {
isInvestorPassword?: boolean;
title: string;
};

const WalletSuccessResetMT5Password: FC<WalletSuccessResetMT5PasswordProps> = ({
isInvestorPassword = false,
title,
}) => {
const { hide } = useModal();
const { isDesktop, isMobile } = useDevice();

const renderFooter = useCallback(() => {
return isMobile ? (
<WalletButton isFullWidth onClick={() => hide()} size='lg'>
<Trans defaults='Done' />
</WalletButton>
) : null;
}, [isMobile, hide]);

const renderButtons = useCallback(() => {
return isDesktop ? (
<WalletButton onClick={() => hide()} size='lg'>
<Trans defaults='Done' />
</WalletButton>
) : null;
}, [isDesktop, hide]);

return (
<ModalStepWrapper
renderFooter={isMobile ? renderFooter : undefined}
shouldFixedFooter={isMobile}
title={`Manage ${title} password`}
>
<div className='wallets-reset-mt5-password'>
<WalletsActionScreen
description={
isInvestorPassword
? 'Your investor password has been changed.'
: `You have a new ${title} password to log in to your ${title} accounts on the web and mobile apps.`
}
descriptionSize='sm'
icon={isInvestorPassword ? <MT5PasswordUpdatedIcon /> : <MT5SuccessPasswordReset />}
renderButtons={renderButtons}
title={isInvestorPassword ? 'Password saved' : 'Success'}
/>
</div>
</ModalStepWrapper>
);
};

export default WalletSuccessResetMT5Password;
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
.wallets-reset-mt5-password {
width: 44rem;
padding: 2.4rem;
display: flex;
flex-direction: column;
gap: 2.4rem;

@include mobile {
align-items: center;
width: 100%;
padding-inline: 1.6rem;
}

&__button-group {
display: flex;
justify-content: flex-end;
gap: 0.8rem;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
import React, { useEffect } from 'react';
import { Trans } from 'react-i18next';
import { useTradingPlatformInvestorPasswordReset, useTradingPlatformPasswordReset } from '@deriv/api';
import { PlatformDetails } from '../../features/cfd/constants';
import useDevice from '../../hooks/useDevice';
import { TPlatforms } from '../../types';
import { validPassword } from '../../utils/password';
import { ModalStepWrapper, WalletButton, WalletButtonGroup, WalletPasswordFieldLazy, WalletText } from '../Base';
import { WalletPasswordFieldProps } from '../Base/WalletPasswordFieldLazy/WalletPasswordFieldLazy';
import { useModal } from '../ModalProvider';
import WalletSuccessResetMT5Password from './WalletSuccessResetMT5Password';
import './WalletsResetMT5Password.scss';

type WalletsResetMT5PasswordProps = {
actionParams: string;
isInvestorPassword?: boolean;
onChange: WalletPasswordFieldProps['onChange'];
password: WalletPasswordFieldProps['password'];
platform: Exclude<TPlatforms.All, 'ctrader'>;
verificationCode: string;
};

const WalletsResetMT5Password = ({
actionParams,
isInvestorPassword = false,
onChange,
password,
platform,
verificationCode,
}: WalletsResetMT5PasswordProps) => {
const { title } = PlatformDetails[platform];
const {
isError: isChangePasswordError,
isLoading: isChangePasswordLoading,
isSuccess: isChangePasswordSuccess,
mutate: changePassword,
} = useTradingPlatformPasswordReset();
const {
isError: isChangeInvestorPasswordError,
isLoading: isChangeInvestorPasswordLoading,
isSuccess: isChangeInvestorPasswordSuccess,
mutate: changeInvestorPassword,
} = useTradingPlatformInvestorPasswordReset();

const { hide, show } = useModal();
const { isDesktop, isMobile } = useDevice();

const handleSubmit = () => {
if (isInvestorPassword) {
const accountId = localStorage.getItem('trading_platform_investor_password_reset_account_id') ?? '';
changeInvestorPassword({
account_id: accountId,
new_password: password,
platform: 'mt5',
verification_code: verificationCode,
});
} else {
changePassword({
new_password: password,
platform,
verification_code: verificationCode,
});
}
};

useEffect(() => {
if (isChangePasswordSuccess) {
localStorage.removeItem(`verification_code.${actionParams}`); // TODO:Remove verification code from local storage
show(<WalletSuccessResetMT5Password title={title} />);
} else if (isChangePasswordError) {
hide();
}
}, [hide, platform, title, show, actionParams, isChangePasswordSuccess, isChangePasswordError]);

useEffect(() => {
if (isChangeInvestorPasswordSuccess) {
localStorage.removeItem(`verification_code.${actionParams}`); // TODO:Remove verification code from local storage
show(<WalletSuccessResetMT5Password isInvestorPassword title={title} />);
} else if (isChangeInvestorPasswordError) {
hide();
}
}, [hide, platform, title, show, actionParams, isChangeInvestorPasswordSuccess, isChangeInvestorPasswordError]);

const renderFooter = () => {
return isMobile ? (
<WalletButtonGroup isFullWidth>
<WalletButton onClick={() => hide()} size='lg' variant='outlined'>
<Trans defaults='Cancel' />
</WalletButton>
<WalletButton
disabled={!validPassword(password)}
isLoading={isChangeInvestorPasswordLoading || isChangePasswordLoading}
onClick={handleSubmit}
size='lg'
variant='contained'
>
<Trans defaults='Create' />
</WalletButton>
</WalletButtonGroup>
) : null;
};

return (
<ModalStepWrapper renderFooter={renderFooter} shouldHideHeader={isDesktop} title={`Manage ${title} password`}>
<div className='wallets-reset-mt5-password'>
<WalletText weight='bold'>
Create a new {title} {isInvestorPassword && 'investor'} Password
</WalletText>
<WalletPasswordFieldLazy
label={isInvestorPassword ? 'New investor password' : `${title} password`}
onChange={onChange}
password={password}
/>
{!isInvestorPassword && (
<WalletText size='sm'>
Strong passwords contain at least 8 characters, combine uppercase and lowercase letters,
numbers, and symbols.
</WalletText>
)}
{isDesktop && (
<div className='wallets-reset-mt5-password__button-group'>
<WalletButton onClick={() => hide()} variant='outlined'>
<Trans defaults='Cancel' />
</WalletButton>
<WalletButton
disabled={!validPassword(password)}
isLoading={isChangeInvestorPasswordLoading || isChangePasswordLoading}
onClick={handleSubmit}
variant='contained'
>
<Trans defaults='Create' />
</WalletButton>
</div>
)}
</div>
</ModalStepWrapper>
);
};

export default WalletsResetMT5Password;
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default as WalletsResetMT5Password } from './WalletsResetMT5Password';
1 change: 1 addition & 0 deletions packages/wallets/src/components/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,5 +37,6 @@ export * from './WalletsCarouselContent';
export * from './WalletsErrorScreen';
export * from './WalletsPercentageSelector';
export * from './WalletsPrimaryTabs';
export * from './WalletsResetMT5Password';
export * from './WalletSuccess';
export * from './WalletTourGuide';
Loading

1 comment on commit 278a8b2

@vercel
Copy link

@vercel vercel bot commented on 278a8b2 Jan 22, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

deriv-app – ./

deriv-app.vercel.app
deriv-app.binary.sx
binary.sx
deriv-app-git-master.binary.sx

Please sign in to comment.