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
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';
32 changes: 32 additions & 0 deletions src/components/Modals/FundsModal/FundsModal.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
.funds-modal {
@include default-modal;

&__header {
padding-top: 1rem !important;

@include mobile-or-tablet-screen {
padding-top: 0 !important;
padding-left: 1.6rem;
ameerul-deriv marked this conversation as resolved.
Show resolved Hide resolved
}
}

&__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-bottom: 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 className='funds-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
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import clsx from 'clsx';
import { TCurrencyListItem } from 'types';
import { useOnClickOutside } from 'usehooks-ts';
import { FullPageMobileWrapper } from '@/components';
import { api } from '@/hooks';
import { api, useQueryString } from '@/hooks';
import { LabelPairedChevronDownMdRegularIcon } from '@deriv/quill-icons';
import { Localize } from '@deriv-com/translations';
import { Text, useDevice } from '@deriv-com/ui';
Expand All @@ -19,6 +19,15 @@ const CurrencyDropdown = ({ selectedCurrency, setSelectedCurrency }: TCurrencyDr
const { data } = api.settings.useSettings();
const { isDesktop, isMobile } = useDevice();
const [showCurrencySelector, setShowCurrencySelector] = useState<boolean>(false);
const { deleteQueryString, setQueryString } = useQueryString();

const onToggleCurrencyDropdown = (shouldShow: boolean) => {
setShowCurrencySelector(shouldShow);
if (!isDesktop) {
if (shouldShow) setQueryString({ modal: 'CurrencyFilterModal' });
else deleteQueryString('modal');
}
};
Comment on lines +22 to +30
Copy link
Contributor Author

Choose a reason for hiding this comment

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

reason why i added this queryString to modal directly is to ensure we hide the banner if currency selector is shown. And in the index.tsx file, I have some logic that handles showing the banner if its either the RadioGroupModal or FundsModal or if there is no Modal showing at all. Below you can see the issue

Screen.Recording.2024-11-11.at.4.25.55.PM.mov
fix.mov

Copy link
Contributor Author

Choose a reason for hiding this comment

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

also you cannot use isModalOpenFor check because it only returns true in whatever component you have called showModal in


const currencySelectorRef = useRef<HTMLDivElement>(null);
useOnClickOutside(currencySelectorRef, () => {
Expand All @@ -39,7 +48,7 @@ const CurrencyDropdown = ({ selectedCurrency, setSelectedCurrency }: TCurrencyDr
}, [data?.currencyList, selectedCurrency]) ?? [];

const onSelectItem = (currency: string) => {
setShowCurrencySelector(false);
onToggleCurrencyDropdown(false);
setSelectedCurrency(currency);
};

Expand All @@ -48,7 +57,7 @@ const CurrencyDropdown = ({ selectedCurrency, setSelectedCurrency }: TCurrencyDr
<FullPageMobileWrapper
className='currency-dropdown__full-page-modal'
onBack={() => {
setShowCurrencySelector(false);
onToggleCurrencyDropdown(false);
}}
renderHeader={() => (
<Text size='lg' weight='bold'>
Expand All @@ -70,7 +79,7 @@ const CurrencyDropdown = ({ selectedCurrency, setSelectedCurrency }: TCurrencyDr
className={clsx('currency-dropdown__dropdown', {
'currency-dropdown__dropdown--active': showCurrencySelector,
})}
onClick={() => setShowCurrencySelector(prev => !prev)}
onClick={() => onToggleCurrencyDropdown(!showCurrencySelector)}
>
<Text className='currency-dropdown__dropdown-text' size={isMobile ? 'xs' : '2xs'}>
<Localize i18n_default_text='Currency' />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,12 @@ jest.mock('@/hooks', () => ({
},
}));

jest.mock('@/hooks/custom-hooks', () => ({
...jest.requireActual('@/hooks/custom-hooks'),
useQueryString: jest
.fn()
.mockReturnValue({ deleteQueryString: jest.fn(), queryString: { modal: '' }, setQueryString: jest.fn() }),
}));
let mockIsDesktop = true;

jest.mock('@deriv-com/ui', () => ({
Expand Down
12 changes: 11 additions & 1 deletion src/pages/buy-sell/screens/BuySell/BuySell.scss
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
& .buy-sell-table {
& .table {
@include mobile-or-tablet-screen {
height: calc(100% - 26rem);
height: calc(100% - 37rem);
}
}
}
Expand All @@ -30,6 +30,16 @@
}
}

&--not-advertiser {
& .buy-sell-table {
& .table {
@include mobile-or-tablet-screen {
height: calc(100% - 26rem);
}
}
}
}

&--outside-hours {
& .mobile-wrapper {
top: -8.5rem;
Expand Down
4 changes: 3 additions & 1 deletion src/pages/buy-sell/screens/BuySell/BuySell.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import clsx from 'clsx';
import { useHistory, useLocation } from 'react-router-dom';
import { OutsideBusinessHoursHint, PageReturn, TemporarilyBarredHint, Verification } from '@/components';
import { BUY_SELL_URL } from '@/constants';
import { useGetBusinessHours, useIsAdvertiserBarred } from '@/hooks/custom-hooks';
import { useGetBusinessHours, useIsAdvertiser, useIsAdvertiserBarred } from '@/hooks/custom-hooks';
import { useTranslations } from '@deriv-com/translations';
import { BuySellTable } from '../BuySellTable';
import './BuySell.scss';
Expand All @@ -14,6 +14,7 @@ const BuySell = () => {
const history = useHistory();
const location = useLocation();
const poiPoaVerified = new URLSearchParams(location.search).get('poi_poa_verified');
const isAdvertiser = useIsAdvertiser();

if (poiPoaVerified === 'false') {
return (
Expand All @@ -32,6 +33,7 @@ const BuySell = () => {
<div
className={clsx('buy-sell relative', {
'buy-sell--barred': isAdvertiserBarred,
'buy-sell--not-advertiser': !isAdvertiser,
'buy-sell--outside-hours': !isScheduleAvailable && !isAdvertiserBarred,
})}
>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ jest.mock('@/hooks/custom-hooks', () => ({
useGetBusinessHours: jest.fn().mockReturnValue({
isScheduleAvailable: true,
}),
useIsAdvertiser: jest.fn().mockReturnValue(true),
useIsAdvertiserBarred: jest.fn().mockReturnValue(false),
}));

Expand Down
6 changes: 5 additions & 1 deletion src/pages/guide/components/GuideTooltip/GuideTooltip.scss
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,15 @@
position: absolute;
top: 0;
right: 0;
margin-top: 1rem;
margin-top: 8.2rem;

&:hover {
cursor: pointer;
}

&--not-advertiser {
margin-top: 1rem;
}
}

@include mobile-or-tablet-screen {
Expand Down
Loading
Loading