Skip to content

Commit

Permalink
[FEQ] P2P-V2 update advert (deriv-com#14509)
Browse files Browse the repository at this point in the history
* feat: update advert

* fix: failing test fix

* fix: style fixes

* fix: route -changes
  • Loading branch information
nada-deriv authored Apr 5, 2024
1 parent 220baf3 commit 0ae2b0a
Show file tree
Hide file tree
Showing 31 changed files with 586 additions and 188 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
.p2p-v2-ad-cancel-create-edit-modal {
border-radius: 8px;
width: 44rem;
height: fit-content;
@include mobile {
max-width: calc(100vw - 3.2rem);
}

&__header {
height: unset;
padding: 2.4rem;
@include mobile {
padding: 1.6rem;
}
}
&__body {
padding: 0.8rem 2.4rem;
@include mobile {
padding: 0.8rem 1.6rem;
}
}

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

@include mobile {
padding-bottom: 1.6rem;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import React from 'react';
import { useHistory } from 'react-router-dom';
import { MY_ADS_URL } from '@/constants';
import { useQueryString } from '@/hooks';
import { Button, Modal, Text, useDevice } from '@deriv-com/ui';
import './AdCancelCreateEditModal.scss';

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

const AdCancelCreateEditModal = ({ isModalOpen, onRequestClose }: TAdCancelCreateEditModalProps) => {
const { isMobile } = useDevice();
const history = useHistory();
const { queryString } = useQueryString();
const { advertId = '' } = queryString;
const isEdit = !!advertId;
const textSize = isMobile ? 'md' : 'sm';
return (
<Modal
ariaHideApp={false}
className='p2p-v2-ad-cancel-create-edit-modal'
isOpen={isModalOpen}
shouldCloseOnOverlayClick={false}
>
<Modal.Header className='p2p-v2-ad-cancel-create-edit-modal__header' hideBorder hideCloseIcon>
<Text weight='bold'>{isEdit ? 'Cancel your edits?' : 'Cancel ad creation?'}</Text>
</Modal.Header>
<Modal.Body className='p2p-v2-ad-cancel-create-edit-modal__body'>
<Text size='sm'>
{isEdit
? `If you choose to cancel, the edited details will be lost.`
: `If you choose to cancel, the details you've entered will be lost.`}
</Text>
</Modal.Body>
<Modal.Footer className='p2p-v2-ad-cancel-create-edit-modal__footer' hideBorder>
<Button
color='black'
onClick={() => history.push(MY_ADS_URL)}
size='lg'
textSize={textSize}
variant='outlined'
>
Cancel
</Button>
<Button onClick={onRequestClose} size='lg' textSize={textSize}>
Don’t cancel
</Button>
</Modal.Footer>
</Modal>
);
};

export default AdCancelCreateEditModal;
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import React from 'react';
import { MY_ADS_URL } from '@/constants';
import { useQueryString } from '@/hooks';
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import AdCancelCreateEditModal from '../AdCancelCreateEditModal';

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

jest.mock('@/hooks', () => ({
...jest.requireActual('@/hooks'),
useQueryString: jest.fn().mockReturnValue({ queryString: { advertId: '' } }),
}));

const mockUseQueryString = useQueryString as jest.Mock;

const mockFn = jest.fn();
jest.mock('react-router-dom', () => ({
...jest.requireActual('react-router-dom'),
useHistory: () => ({ push: mockFn }),
}));

const mockProps = {
isModalOpen: true,
onRequestClose: jest.fn(),
};

describe('AdCancelCreateEditModal', () => {
it('should render the component as expected', () => {
render(<AdCancelCreateEditModal {...mockProps} />);
expect(screen.getByText('Cancel ad creation?')).toBeInTheDocument();
});
it('should render the component as expected when isEdit is true', () => {
mockUseQueryString.mockReturnValueOnce({ queryString: { advertId: '123' } });
render(<AdCancelCreateEditModal {...mockProps} />);
expect(screen.getByText('Cancel your edits?')).toBeInTheDocument();
});
it('should redirect to my ads page on clicking cancel button', () => {
render(<AdCancelCreateEditModal {...mockProps} />);
const button = screen.getByRole('button', { name: 'Cancel' });
userEvent.click(button);
expect(mockFn).toHaveBeenCalledWith(MY_ADS_URL);
});
it("should close the modal on clicking don't cancel button", () => {
render(<AdCancelCreateEditModal {...mockProps} />);
const button = screen.getByRole('button', { name: 'Don’t cancel' });
userEvent.click(button);
expect(mockProps.onRequestClose).toHaveBeenCalledTimes(1);
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default as AdCancelCreateEditModal } from './AdCancelCreateEditModal';
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import './AdCreateEditErrorModal.scss';

type TAdCreateEditErrorModalProps = {
errorCode?: ErrorCodes;
errorMessage?: string;
isModalOpen: boolean;
onRequestClose: () => void;
};
Expand All @@ -31,7 +32,12 @@ const errorContent: ErrorContent = {
},
};

const AdCreateEditErrorModal = ({ errorCode, isModalOpen, onRequestClose }: TAdCreateEditErrorModalProps) => {
const AdCreateEditErrorModal = ({
errorCode,
errorMessage,
isModalOpen,
onRequestClose,
}: TAdCreateEditErrorModalProps) => {
const { isMobile } = useDevice();
const textSize = isMobile ? 'md' : 'sm';
return (
Expand All @@ -45,13 +51,11 @@ const AdCreateEditErrorModal = ({ errorCode, isModalOpen, onRequestClose }: TAdC
<Text weight='bold'>{(errorCode && errorContent?.[errorCode]?.title) ?? 'Something’s not right'}</Text>
</Modal.Header>
<Modal.Body className='p2p-v2-ad-create-edit-error-modal__body'>
<Text size={textSize}>
{(errorCode && errorContent?.[errorCode]?.description) ?? 'Something’s not right'}
</Text>
<Text size={textSize}>{(errorCode && errorContent?.[errorCode]?.description) ?? errorMessage}</Text>
</Modal.Body>
<Modal.Footer className='p2p-v2-ad-create-edit-error-modal__footer' hideBorder>
<Button onClick={onRequestClose} size='lg' textSize={textSize}>
{errorCode ? 'Update ad' : 'Ok'}
{errorCode && errorContent?.[errorCode]?.title ? 'Update ad' : 'Ok'}
</Button>
</Modal.Footer>
</Modal>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ describe('AdCreateEditErrorModal', () => {
expect(screen.getByText('You already have an ad with this rate')).toBeInTheDocument();
});
it('should render the general error message if no error code is provided', () => {
render(<AdCreateEditErrorModal {...mockProps} errorCode={undefined} />);
expect(screen.getAllByText('Something’s not right')).toHaveLength(2);
render(<AdCreateEditErrorModal {...mockProps} errorCode={undefined} errorMessage='error message' />);
expect(screen.getByText('Something’s not right')).toBeInTheDocument();
});
it('should call onRequestClose when the button is clicked', () => {
render(<AdCreateEditErrorModal {...mockProps} />);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,20 +19,27 @@ const PreferredCountriesDropdown = ({
setSelectedCountries,
setShouldDisplayFooter,
}: TPreferredCountriesDropdownProps) => {
const [searchResults, setSearchResults] = useState<TItem[]>(list);
const [searchResults, setSearchResults] = useState<TItem[]>([
...list.filter(item => selectedCountries.includes(item.value)),
...list.filter(item => !selectedCountries.includes(item.value)),
]);
const [searchValue, setSearchValue] = useState('');

const onSearch = (value: string) => {
if (!value) {
setShouldDisplayFooter(true);
setSearchValue('');
setSearchResults(list);
setSearchResults([
...list.filter(item => selectedCountries.includes(item.value)),
...list.filter(item => !selectedCountries.includes(item.value)),
]);
return;
}
setShouldDisplayFooter(false);
setSearchValue(value);
setSearchResults(list.filter(item => item.text.toLowerCase().includes(value.toLowerCase())));
};

return (
<div className='p2p-v2-preferred-countries-dropdown'>
<div className='px-[1.6rem] py-[0.8rem]'>
Expand Down
1 change: 1 addition & 0 deletions packages/p2p-v2/src/components/Modals/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export * from './AdCancelCreateEditModal';
export * from './AdConditionsModal';
export * from './AdCreateEditErrorModal';
export * from './AdCreateEditSuccessModal';
Expand Down
23 changes: 14 additions & 9 deletions packages/p2p-v2/src/components/PopoverDropdown/PopoverDropdown.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React, { useRef, useState } from 'react';
import { useOnClickOutside } from 'usehooks-ts';
import { LabelPairedEllipsisVerticalMdRegularIcon } from '@deriv/quill-icons';
import { Button, Text } from '@deriv-com/ui';
import { Button, Text, Tooltip, useDevice } from '@deriv-com/ui';
import './PopoverDropdown.scss';

type TItem = {
Expand All @@ -10,23 +10,26 @@ type TItem = {
};

type TPopoverDropdownProps = {
dataTestId?: string;
dropdownList: TItem[];
onClick: (value: string) => void;
tooltipMessage: string;
};

const PopoverDropdown = ({ dataTestId, dropdownList, onClick }: TPopoverDropdownProps) => {
const PopoverDropdown = ({ dropdownList, onClick, tooltipMessage }: TPopoverDropdownProps) => {
const [visible, setVisible] = useState(false);
const ref = useRef(null);
useOnClickOutside(ref, () => setVisible(false));
const { isMobile } = useDevice();

return (
<div className='p2p-v2-popover-dropdown' ref={ref}>
<LabelPairedEllipsisVerticalMdRegularIcon
className='p2p-v2-popover-dropdown__icon'
data-testid={dataTestId}
onClick={() => setVisible(prevState => !prevState)}
/>
<Tooltip message={tooltipMessage} position='bottom' triggerAction='hover'>
<LabelPairedEllipsisVerticalMdRegularIcon
className='p2p-v2-popover-dropdown__icon'
data-testid='dt_p2p_v2_popover_dropdown_icon'
onClick={() => setVisible(prevState => !prevState)}
/>
</Tooltip>
{visible && (
<div className='p2p-v2-popover-dropdown__list'>
{dropdownList.map(item => (
Expand All @@ -40,7 +43,9 @@ const PopoverDropdown = ({ dataTestId, dropdownList, onClick }: TPopoverDropdown
}}
variant='ghost'
>
<Text key={item.value}>{item.label}</Text>
<Text key={item.value} size={isMobile ? 'md' : 'sm'}>
{item.label}
</Text>
</Button>
))}
</div>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import React from 'react';
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import PopoverDropdown from '../PopoverDropdown';

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

const mockProps = {
dropdownList: [
{
label: 'label 1',
value: 'value 1',
},
{
label: 'label 2',
value: 'value 2',
},
],
onClick: jest.fn(),
tooltipMessage: 'test tooltip message',
};

describe('PopoverDropdown', () => {
it('should render', () => {
render(<PopoverDropdown {...mockProps} />);
expect(screen.getByTestId('dt_p2p_v2_popover_dropdown_icon')).toBeInTheDocument();
});
it('should render the dropdown list on clicking on the icon', () => {
render(<PopoverDropdown {...mockProps} />);
userEvent.click(screen.getByTestId('dt_p2p_v2_popover_dropdown_icon'));
expect(screen.getByText('label 1')).toBeInTheDocument();
});
it('should call onClick when item is clicked', () => {
render(<PopoverDropdown {...mockProps} />);
userEvent.click(screen.getByTestId('dt_p2p_v2_popover_dropdown_icon'));
userEvent.click(screen.getByText('label 1'));
expect(mockProps.onClick).toHaveBeenCalledWith('value 1');
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@ jest.mock('@deriv-com/ui', () => ({
useDevice: jest.fn(() => ({ isMobile: false })),
}));

jest.mock('@/hooks', () => ({
useQueryString: jest.fn().mockReturnValue({ queryString: { advertId: '' } }),
}));

const mockSetValue = jest.fn();
jest.mock('react-hook-form', () => ({
...jest.requireActual('react-hook-form'),
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import React, { MouseEventHandler } from 'react';
import { useQueryString } from '@/hooks';
import { Button, useDevice } from '@deriv-com/ui';
import './AdFormController.scss';

Expand All @@ -21,13 +22,17 @@ const AdFormController = ({
}: TAdFormControllerProps) => {
const { isMobile } = useDevice();
const textSize = isMobile ? 'md' : 'sm';
const { queryString } = useQueryString();
const { advertId = '' } = queryString;
const isEdit = !!advertId;
return (
<div className='p2p-v2-ad-form-controller'>
<Button
color='black'
onClick={() => (onCancel ? onCancel() : goToPreviousStep())}
size='lg'
textSize={textSize}
type='button'
variant='outlined'
>
{onCancel ? 'Cancel' : 'Previous'}
Expand All @@ -38,13 +43,14 @@ const AdFormController = ({
onClick={goToNextStep}
size='lg'
textSize={textSize}
type='button'
variant='contained'
>
Next
</Button>
) : (
<Button size='lg' textSize={textSize}>
Post ad
{`${isEdit ? 'Save changes' : 'Post ad'}`}
</Button>
)}
</div>
Expand Down
Loading

0 comments on commit 0ae2b0a

Please sign in to comment.