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

Ameerul / P2PS-4363 Banner on Buy/Sell page #401

Open
wants to merge 12 commits into
base: master
Choose a base branch
from
Open
7 changes: 6 additions & 1 deletion src/components/AppHeader/MenuItems/MenuItems.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { api } from '@/hooks';
import { useTranslations } from '@deriv-com/translations';
import { MenuItem, Text, useDevice } from '@deriv-com/ui';
import { getMenuItems } from '../HeaderConfig';
Expand All @@ -6,7 +7,11 @@ import './MenuItems.scss';
const MenuItems = () => {
const { localize } = useTranslations();
const { isDesktop } = useDevice();
const items = getMenuItems(localize);
const { data: activeAccountData } = api.account.useActiveAccount();
const menuItems = getMenuItems(localize);
const items = activeAccountData?.hasMigratedToWallets
? menuItems.filter(item => !item.label.includes(localize('Cashier')))
: menuItems;

return (
<>
Expand Down
8 changes: 7 additions & 1 deletion src/components/AppHeader/MobileMenu/MenuContent.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
import clsx from 'clsx';
import { api } from '@/hooks';
import { useTranslations } from '@deriv-com/translations';
import { MenuItem, Text, useDevice } from '@deriv-com/ui';
import { PlatformSwitcher } from '../PlatformSwitcher';
import { MobileMenuConfig } from './MobileMenuConfig';

export const MenuContent = () => {
const { localize } = useTranslations();
const { isDesktop } = useDevice();
const textSize = isDesktop ? 'sm' : 'md';
const { data: activeAccountData } = api.account.useActiveAccount();

return (
<div className='flex flex-col h-full overflow-hidden'>
Expand All @@ -15,7 +19,6 @@ export const MenuContent = () => {
<div className='relative h-full pt-4 overflow-scroll'>
{MobileMenuConfig().map((item, index) => {
const removeBorderBottom = item.find(({ removeBorderBottom }) => removeBorderBottom);

return (
<div
className={clsx('pl-[4.8rem] pr-[1.6rem]', {
Expand All @@ -25,6 +28,9 @@ export const MenuContent = () => {
key={index}
>
{item.map(({ LeftComponent, RightComponent, as, href, label, onClick, target }) => {
if (activeAccountData?.hasMigratedToWallets && label === localize('Cashier')) {
return null;
}
if (as === 'a') {
return (
<MenuItem
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import userEvent from '@testing-library/user-event';
import { MenuContent } from '../MenuContent';

const mockSettingsButtonClick = jest.fn();
const mockActiveAccountData = { hasMigratedToWallets: false };

jest.mock('@deriv-com/ui', () => ({
...jest.requireActual('@deriv-com/ui'),
Expand All @@ -16,6 +17,16 @@ jest.mock('@deriv-com/api-hooks', () => ({
}),
}));

jest.mock('@/hooks', () => ({
api: {
account: {
useActiveAccount: jest.fn(() => ({
data: mockActiveAccountData,
})),
},
},
}));

jest.mock('../../PlatformSwitcher', () => ({
PlatformSwitcher: () => <div>PlatformSwitcher</div>,
}));
Expand All @@ -30,6 +41,13 @@ jest.mock('../MobileMenuConfig', () => ({
LeftComponent: () => <span>Home Icon</span>,
removeBorderBottom: false,
},
{
as: 'a',
href: '/cashier',
label: 'Cashier',
LeftComponent: () => <span>Cashier Icon</span>,
removeBorderBottom: false,
},
],
[
{
Expand Down Expand Up @@ -102,4 +120,10 @@ describe('MenuContent Component', () => {
expect(screen.getAllByTestId('dt_menu_item')[0]).toHaveClass('border-b');
expect(screen.getAllByTestId('dt_menu_item')[1]).not.toHaveClass('border-b');
});

it('does not render Cashier menu item when hasMigratedToWallets is true', () => {
mockActiveAccountData.hasMigratedToWallets = true;
render(<MenuContent />);
expect(screen.queryByText('Cashier')).not.toBeInTheDocument();
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,11 @@ import userEvent from '@testing-library/user-event';
import MobileMenu from '../MobileMenu';

jest.mock('@/hooks', () => ({
api: {
account: {
useActiveAccount: jest.fn().mockReturnValue({ data: { hasMigratedToWallets: false } }),
},
},
useModalManager: jest.fn().mockReturnValue({
hideModal: jest.fn(),
isModalOpenFor: jest.fn().mockReturnValue(false),
Expand Down
18 changes: 18 additions & 0 deletions src/components/AppHeader/__tests__/AppHeader.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,7 @@ describe('<AppHeader/>', () => {
mockUseAuthData.mockReturnValue({ activeLoginid: '12345', logout: jest.fn() });
mockUseActiveAccountValues.data = {
currency: 'USD',
hasMigratedToWallets: false,
is_virtual: 0,
} as ReturnType<typeof useActiveAccount>['data'];

Expand Down Expand Up @@ -152,4 +153,21 @@ describe('<AppHeader/>', () => {
await userEvent.click(logoutButton);
expect(logout).toHaveBeenCalled();
});

it('should not render Cashier menu item when hasMigratedToWallets is true', () => {
mockUseAuthData.mockReturnValue({ activeLoginid: '12345', logout: jest.fn() });
mockUseActiveAccountValues.data = {
currency: 'USD',
hasMigratedToWallets: true,
is_virtual: 0,
} as ReturnType<typeof useActiveAccount>['data'];
render(
<BrowserRouter>
<QueryParamProvider adapter={ReactRouter5Adapter}>
<AppHeader />
</QueryParamProvider>
</BrowserRouter>
);
expect(screen.queryByText('Cashier')).not.toBeInTheDocument();
});
});
35 changes: 35 additions & 0 deletions src/components/FundsBanner/FundsBanner.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
.funds-banner {
@include mobile-or-tablet-screen {
padding: 1.6rem 1.6rem 0.8rem;
}

&__inline-message {
background-color: rgba(44, 154, 255, 0.08);
border-radius: 1.6rem;
padding: 1.6rem;
margin-bottom: 1.5rem;

@include mobile-or-tablet-screen {
margin-bottom: 0;
}

&__button {
padding: 0;
text-decoration: underline;
cursor: pointer;

&:hover {
background-color: transparent !important;

& > span {
color: #0e0e0e !important;
}
}
}
}
Comment on lines +21 to +29
Copy link
Contributor Author

Choose a reason for hiding this comment

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

even though I used hideHoverStyles in the button, it didn't work 😅 so i had to manually disable it here


.deriv-inline-message__icon {
width: 24px;
height: 24px;
}
}
41 changes: 41 additions & 0 deletions src/components/FundsBanner/FundsBanner.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { FundsModal } from '@/components/Modals';
import { useModalManager } from '@/hooks/custom-hooks';
import { LabelPairedCircleInfoLgBoldIcon } from '@deriv/quill-icons';
import { Localize } from '@deriv-com/translations';
import { Button, InlineMessage, Text, useDevice } from '@deriv-com/ui';
import './FundsBanner.scss';

const FundsBanner = () => {
const { isDesktop } = useDevice();
const { hideModal, isModalOpenFor, showModal } = useModalManager();
const textSize = isDesktop ? 'sm' : 'md';

return (
<div className='funds-banner'>
<InlineMessage
className='funds-banner__inline-message'
icon={<LabelPairedCircleInfoLgBoldIcon fill='#0777C4' height={24} width={24} />}
iconPosition='center'
>
<div>
<Text className='mr-1' size={textSize}>
<Localize i18n_default_text='Your P2P funds are accessible through your Options trading account.' />
</Text>
<Button
className='funds-banner__inline-message__button'
color='black'
hideHoverStyles
onClick={() => showModal('FundsModal')}
textSize={textSize}
variant='ghost'
>
<Localize i18n_default_text='Learn more' />
</Button>
</div>
</InlineMessage>
{!!isModalOpenFor('FundsModal') && <FundsModal isModalOpen onRequestClose={hideModal} />}
</div>
);
};

export default FundsBanner;
61 changes: 61 additions & 0 deletions src/components/FundsBanner/__tests__/FundsBanner.spec.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import { fireEvent, render, screen } from '@testing-library/react';
import FundsBanner from '../FundsBanner';

const mockModalManager = {
hideModal: jest.fn(),
isModalOpenFor: jest.fn().mockReturnValue(false),
showModal: jest.fn(),
};

jest.mock('@deriv-com/ui', () => ({
...jest.requireActual('@deriv-com/ui'),
useDevice: jest.fn().mockReturnValue({
isMobile: false,
}),
}));

jest.mock('@/hooks/custom-hooks', () => ({
useModalManager: jest.fn(() => mockModalManager),
}));

describe('<FundsBanner />', () => {
it('should render the FundsBanner', () => {
render(<FundsBanner />);

expect(
screen.getByText(/Your P2P funds are accessible through your Options trading account./)
).toBeInTheDocument();
expect(screen.getByRole('button', { name: /Learn more/ })).toBeInTheDocument();
});

it('should call showModal when the Learn more button is clicked and show the FundsModal', () => {
render(<FundsBanner />);
fireEvent.click(screen.getByRole('button', { name: /Learn more/ }));

expect(mockModalManager.showModal).toHaveBeenCalledWith('FundsModal');
});

it('should render the FundsModal if it is open', () => {
mockModalManager.isModalOpenFor.mockImplementation((modalName: string) => modalName === 'FundsModal');
render(<FundsBanner />);

expect(screen.getByText('How to fund your trades?')).toBeInTheDocument();
expect(screen.getByText('For Options trading:')).toBeInTheDocument();
expect(screen.getByText('Trade directly with funds from your Options trading account.')).toBeInTheDocument();
expect(screen.getByText('For CFDs trading:')).toBeInTheDocument();
expect(
screen.getByText('1. Transfer funds from your Options trading account to your USD Wallet.')
).toBeInTheDocument();
expect(
screen.getByText('2. Then, move the funds from your USD Wallet to your CFDs account.')
).toBeInTheDocument();
expect(screen.getByRole('button', { name: 'OK' })).toBeInTheDocument();
});

it('should call hideModal when the OK button is clicked', () => {
render(<FundsBanner />);

fireEvent.click(screen.getByRole('button', { name: 'OK' }));
expect(mockModalManager.hideModal).toHaveBeenCalled();
});
});
1 change: 1 addition & 0 deletions src/components/FundsBanner/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default as FundsBanner } from './FundsBanner';
31 changes: 31 additions & 0 deletions src/components/Modals/FundsModal/FundsModal.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
.funds-modal {
@include default-modal;
.deriv-modal__header {
padding-top: 1rem;

@include mobile-or-tablet-screen {
padding-top: 0 !important;
padding-left: 1.6rem;
}
}

&__body {
display: flex;
flex-direction: column;
padding: 1rem 2.4rem;
gap: 2.4rem;

@include mobile-or-tablet-screen {
padding: 0 1.6rem;
}
}

&__footer {
padding-bottom: 2.4rem;
gap: 0.8rem;

@include mobile-or-tablet-screen {
padding: 1.6rem;
}
}
}
48 changes: 48 additions & 0 deletions src/components/Modals/FundsModal/FundsModal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import { Localize } from '@deriv-com/translations';
import { Button, Modal, Text } from '@deriv-com/ui';
import './FundsModal.scss';

type TFundsModalProps = {
isModalOpen: boolean;
onRequestClose: () => void;
};

const FundsModal = ({ isModalOpen, onRequestClose }: TFundsModalProps) => {
return (
<Modal ariaHideApp={false} className='funds-modal' isOpen={isModalOpen} shouldCloseOnOverlayClick={false}>
<Modal.Header hideBorder hideCloseIcon>
<Text size='md' weight='bold'>
<Localize i18n_default_text='How to fund your trades?' />
</Text>
</Modal.Header>
<Modal.Body className='funds-modal__body'>
<div className='flex flex-col'>
<Text size='sm' weight='bold'>
<Localize i18n_default_text='For Options trading:' />
</Text>
<Text size='sm'>
<Localize i18n_default_text='Trade directly with funds from your Options trading account.' />
</Text>
</div>
<div className='flex flex-col'>
<Text size='sm' weight='bold'>
<Localize i18n_default_text='For CFDs trading:' />
</Text>
<Text size='sm'>
<Localize i18n_default_text='1. Transfer funds from your Options trading account to your USD Wallet.' />
</Text>
<Text size='sm'>
<Localize i18n_default_text='2. Then, move the funds from your USD Wallet to your CFDs account.' />
</Text>
</div>
</Modal.Body>
<Modal.Footer className='funds-modal__footer' hideBorder>
<Button onClick={() => onRequestClose()} size='lg' textSize='sm'>
<Localize i18n_default_text='OK' />
</Button>
</Modal.Footer>
</Modal>
);
};

export default FundsModal;
1 change: 1 addition & 0 deletions src/components/Modals/FundsModal/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default as FundsModal } from './FundsModal';
1 change: 1 addition & 0 deletions src/components/Modals/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ export * from './EmailVerificationModal';
export * from './ErrorModal';
export * from './FallbackErrorModal';
export * from './FilterModal';
export * from './FundsModal';
export * from './InvalidVerificationLinkModal';
export * from './LeaveFilterModal';
export * from './LoadingModal';
Expand Down
1 change: 1 addition & 0 deletions src/components/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ export * from './FileDropzone';
export * from './FloatingRate';
export * from './FormProgress';
export * from './FullPageMobileWrapper';
export * from './FundsBanner';
export * from './LightDivider';
export * from './MobileTabs';
export * from './OnboardingTooltip';
Expand Down
Loading
Loading