diff --git a/packages/p2p-v2/src/components/Modals/AdCancelCreateEditModal/AdCancelCreateEditModal.scss b/packages/p2p-v2/src/components/Modals/AdCancelCreateEditModal/AdCancelCreateEditModal.scss new file mode 100644 index 000000000000..34eddc0aca4b --- /dev/null +++ b/packages/p2p-v2/src/components/Modals/AdCancelCreateEditModal/AdCancelCreateEditModal.scss @@ -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; + } + } +} diff --git a/packages/p2p-v2/src/components/Modals/AdCancelCreateEditModal/AdCancelCreateEditModal.tsx b/packages/p2p-v2/src/components/Modals/AdCancelCreateEditModal/AdCancelCreateEditModal.tsx new file mode 100644 index 000000000000..754844b0daf4 --- /dev/null +++ b/packages/p2p-v2/src/components/Modals/AdCancelCreateEditModal/AdCancelCreateEditModal.tsx @@ -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 ( + + + {isEdit ? 'Cancel your edits?' : 'Cancel ad creation?'} + + + + {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.`} + + + + + + + + ); +}; + +export default AdCancelCreateEditModal; diff --git a/packages/p2p-v2/src/components/Modals/AdCancelCreateEditModal/__tests__/AdCancelCreateEditModal.spec.tsx b/packages/p2p-v2/src/components/Modals/AdCancelCreateEditModal/__tests__/AdCancelCreateEditModal.spec.tsx new file mode 100644 index 000000000000..16fee0aba35e --- /dev/null +++ b/packages/p2p-v2/src/components/Modals/AdCancelCreateEditModal/__tests__/AdCancelCreateEditModal.spec.tsx @@ -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(); + expect(screen.getByText('Cancel ad creation?')).toBeInTheDocument(); + }); + it('should render the component as expected when isEdit is true', () => { + mockUseQueryString.mockReturnValueOnce({ queryString: { advertId: '123' } }); + render(); + expect(screen.getByText('Cancel your edits?')).toBeInTheDocument(); + }); + it('should redirect to my ads page on clicking cancel button', () => { + render(); + 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(); + const button = screen.getByRole('button', { name: 'Don’t cancel' }); + userEvent.click(button); + expect(mockProps.onRequestClose).toHaveBeenCalledTimes(1); + }); +}); diff --git a/packages/p2p-v2/src/components/Modals/AdCancelCreateEditModal/index.ts b/packages/p2p-v2/src/components/Modals/AdCancelCreateEditModal/index.ts new file mode 100644 index 000000000000..2fa88352cf18 --- /dev/null +++ b/packages/p2p-v2/src/components/Modals/AdCancelCreateEditModal/index.ts @@ -0,0 +1 @@ +export { default as AdCancelCreateEditModal } from './AdCancelCreateEditModal'; diff --git a/packages/p2p-v2/src/components/Modals/AdCreateEditErrorModal/AdCreateEditErrorModal.tsx b/packages/p2p-v2/src/components/Modals/AdCreateEditErrorModal/AdCreateEditErrorModal.tsx index 7efa91b7b2ee..996d7c09b829 100644 --- a/packages/p2p-v2/src/components/Modals/AdCreateEditErrorModal/AdCreateEditErrorModal.tsx +++ b/packages/p2p-v2/src/components/Modals/AdCreateEditErrorModal/AdCreateEditErrorModal.tsx @@ -5,6 +5,7 @@ import './AdCreateEditErrorModal.scss'; type TAdCreateEditErrorModalProps = { errorCode?: ErrorCodes; + errorMessage?: string; isModalOpen: boolean; onRequestClose: () => void; }; @@ -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 ( @@ -45,13 +51,11 @@ const AdCreateEditErrorModal = ({ errorCode, isModalOpen, onRequestClose }: TAdC {(errorCode && errorContent?.[errorCode]?.title) ?? 'Something’s not right'} - - {(errorCode && errorContent?.[errorCode]?.description) ?? 'Something’s not right'} - + {(errorCode && errorContent?.[errorCode]?.description) ?? errorMessage} diff --git a/packages/p2p-v2/src/components/Modals/AdCreateEditErrorModal/__tests__/AdCreateEditErrorModal.spec.tsx b/packages/p2p-v2/src/components/Modals/AdCreateEditErrorModal/__tests__/AdCreateEditErrorModal.spec.tsx index bb7941b4bb7d..5c21adb792d1 100644 --- a/packages/p2p-v2/src/components/Modals/AdCreateEditErrorModal/__tests__/AdCreateEditErrorModal.spec.tsx +++ b/packages/p2p-v2/src/components/Modals/AdCreateEditErrorModal/__tests__/AdCreateEditErrorModal.spec.tsx @@ -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(); - expect(screen.getAllByText('Something’s not right')).toHaveLength(2); + render(); + expect(screen.getByText('Something’s not right')).toBeInTheDocument(); }); it('should call onRequestClose when the button is clicked', () => { render(); diff --git a/packages/p2p-v2/src/components/Modals/PreferredCountriesModal/PreferredCountriesDropdown/PreferredCountriesDropdown.tsx b/packages/p2p-v2/src/components/Modals/PreferredCountriesModal/PreferredCountriesDropdown/PreferredCountriesDropdown.tsx index 787739b80e8b..0f735123c40e 100644 --- a/packages/p2p-v2/src/components/Modals/PreferredCountriesModal/PreferredCountriesDropdown/PreferredCountriesDropdown.tsx +++ b/packages/p2p-v2/src/components/Modals/PreferredCountriesModal/PreferredCountriesDropdown/PreferredCountriesDropdown.tsx @@ -19,20 +19,27 @@ const PreferredCountriesDropdown = ({ setSelectedCountries, setShouldDisplayFooter, }: TPreferredCountriesDropdownProps) => { - const [searchResults, setSearchResults] = useState(list); + const [searchResults, setSearchResults] = useState([ + ...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 (
diff --git a/packages/p2p-v2/src/components/Modals/index.ts b/packages/p2p-v2/src/components/Modals/index.ts index ef05adf1403f..95714e4b0511 100644 --- a/packages/p2p-v2/src/components/Modals/index.ts +++ b/packages/p2p-v2/src/components/Modals/index.ts @@ -1,3 +1,4 @@ +export * from './AdCancelCreateEditModal'; export * from './AdConditionsModal'; export * from './AdCreateEditErrorModal'; export * from './AdCreateEditSuccessModal'; diff --git a/packages/p2p-v2/src/components/PopoverDropdown/PopoverDropdown.tsx b/packages/p2p-v2/src/components/PopoverDropdown/PopoverDropdown.tsx index e66a1b5b5260..077b98db3b28 100644 --- a/packages/p2p-v2/src/components/PopoverDropdown/PopoverDropdown.tsx +++ b/packages/p2p-v2/src/components/PopoverDropdown/PopoverDropdown.tsx @@ -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 = { @@ -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 (
- setVisible(prevState => !prevState)} - /> + + setVisible(prevState => !prevState)} + /> + {visible && (
{dropdownList.map(item => ( @@ -40,7 +43,9 @@ const PopoverDropdown = ({ dataTestId, dropdownList, onClick }: TPopoverDropdown }} variant='ghost' > - {item.label} + + {item.label} + ))}
diff --git a/packages/p2p-v2/src/components/PopoverDropdown/__tests__/PopoverDropdown.spec.tsx b/packages/p2p-v2/src/components/PopoverDropdown/__tests__/PopoverDropdown.spec.tsx new file mode 100644 index 000000000000..ed1702e5a962 --- /dev/null +++ b/packages/p2p-v2/src/components/PopoverDropdown/__tests__/PopoverDropdown.spec.tsx @@ -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(); + expect(screen.getByTestId('dt_p2p_v2_popover_dropdown_icon')).toBeInTheDocument(); + }); + it('should render the dropdown list on clicking on the icon', () => { + render(); + 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(); + userEvent.click(screen.getByTestId('dt_p2p_v2_popover_dropdown_icon')); + userEvent.click(screen.getByText('label 1')); + expect(mockProps.onClick).toHaveBeenCalledWith('value 1'); + }); +}); diff --git a/packages/p2p-v2/src/pages/my-ads/components/AdConditionsSection/__tests__/AdConditionsSection.spec.tsx b/packages/p2p-v2/src/pages/my-ads/components/AdConditionsSection/__tests__/AdConditionsSection.spec.tsx index f5256d0a3c5e..0bf1af58a314 100644 --- a/packages/p2p-v2/src/pages/my-ads/components/AdConditionsSection/__tests__/AdConditionsSection.spec.tsx +++ b/packages/p2p-v2/src/pages/my-ads/components/AdConditionsSection/__tests__/AdConditionsSection.spec.tsx @@ -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'), diff --git a/packages/p2p-v2/src/pages/my-ads/components/AdFormController/AdFormController.tsx b/packages/p2p-v2/src/pages/my-ads/components/AdFormController/AdFormController.tsx index 944e82fcfafc..05ec2486d7c9 100644 --- a/packages/p2p-v2/src/pages/my-ads/components/AdFormController/AdFormController.tsx +++ b/packages/p2p-v2/src/pages/my-ads/components/AdFormController/AdFormController.tsx @@ -1,4 +1,5 @@ import React, { MouseEventHandler } from 'react'; +import { useQueryString } from '@/hooks'; import { Button, useDevice } from '@deriv-com/ui'; import './AdFormController.scss'; @@ -21,6 +22,9 @@ const AdFormController = ({ }: TAdFormControllerProps) => { const { isMobile } = useDevice(); const textSize = isMobile ? 'md' : 'sm'; + const { queryString } = useQueryString(); + const { advertId = '' } = queryString; + const isEdit = !!advertId; return (
) : ( )}
diff --git a/packages/p2p-v2/src/pages/my-ads/components/AdFormInput/AdFormInput.tsx b/packages/p2p-v2/src/pages/my-ads/components/AdFormInput/AdFormInput.tsx index 09e890d4a01b..a5bb7ddc0c94 100644 --- a/packages/p2p-v2/src/pages/my-ads/components/AdFormInput/AdFormInput.tsx +++ b/packages/p2p-v2/src/pages/my-ads/components/AdFormInput/AdFormInput.tsx @@ -1,25 +1,36 @@ import React, { ComponentProps, ReactNode } from 'react'; +import clsx from 'clsx'; import { Controller, useFormContext } from 'react-hook-form'; import { getValidationRules } from '@/utils'; import { Input } from '@deriv-com/ui'; type TAdFormInputProps = ComponentProps & { currency?: string; + isDisabled?: boolean; label: string; name: string; rightPlaceholder: ReactNode; triggerValidationFunction?: () => void; }; -const AdFormInput = ({ label, name, rightPlaceholder, triggerValidationFunction, ...props }: TAdFormInputProps) => { +const AdFormInput = ({ + isDisabled = false, + label, + name, + rightPlaceholder, + triggerValidationFunction, + ...props +}: TAdFormInputProps) => { const { control, getValues } = useFormContext(); return ( ( -
+
({ }), })); +jest.mock('@/hooks', () => ({ + ...jest.requireActual('@/hooks'), + useQueryString: jest.fn().mockReturnValue({ queryString: { advertId: '' } }), +})); + jest.mock('@deriv/api-v2', () => ({ p2p: { paymentMethods: { diff --git a/packages/p2p-v2/src/pages/my-ads/components/AdTypeSection/AdTypeSection.tsx b/packages/p2p-v2/src/pages/my-ads/components/AdTypeSection/AdTypeSection.tsx index 923eb51361bf..f77167ccc934 100644 --- a/packages/p2p-v2/src/pages/my-ads/components/AdTypeSection/AdTypeSection.tsx +++ b/packages/p2p-v2/src/pages/my-ads/components/AdTypeSection/AdTypeSection.tsx @@ -1,8 +1,8 @@ import React, { MouseEventHandler } from 'react'; import { Controller, useFormContext } from 'react-hook-form'; -import { useHistory } from 'react-router-dom'; import { RadioGroup } from '@/components'; -import { BUY_SELL, MY_ADS_URL, RATE_TYPE } from '@/constants'; +import { BUY_SELL, RATE_TYPE } from '@/constants'; +import { useQueryString } from '@/hooks'; import { Text, useDevice } from '@deriv-com/ui'; import { AdFormController } from '../AdFormController'; import { AdFormInput } from '../AdFormInput'; @@ -16,21 +16,24 @@ type TAdTypeSectionProps = { goToNextStep: MouseEventHandler; goToPreviousStep: MouseEventHandler; localCurrency?: string; + onCancel: () => void; rateType: string; }; -const AdTypeSection = ({ currency, localCurrency, rateType, ...props }: TAdTypeSectionProps) => { +const AdTypeSection = ({ currency, localCurrency, onCancel, rateType, ...props }: TAdTypeSectionProps) => { + const { queryString } = useQueryString(); + const { advertId = '' } = queryString; + const isEdit = !!advertId; const { isMobile } = useDevice(); const { control, - formState: { isDirty, isValid }, + formState: { isValid }, getValues, setValue, trigger, watch, } = useFormContext(); - const history = useHistory(); const isSell = watch('ad-type') === BUY_SELL.SELL; const onChangeAdTypeHandler = (userInput: 'buy' | 'sell') => { @@ -45,12 +48,6 @@ const AdTypeSection = ({ currency, localCurrency, rateType, ...props }: TAdTypeS } }; - const onCancel = () => { - if (isDirty) { - //TODO: display cancel modal - } else history.push(MY_ADS_URL); - }; - const triggerValidation = (fieldNames: string[]) => { // Loop through the provided field names fieldNames.forEach(fieldName => { @@ -64,33 +61,36 @@ const AdTypeSection = ({ currency, localCurrency, rateType, ...props }: TAdTypeS return (
- { - return ( -
- { - onChangeAdTypeHandler(event.target.value as 'buy' | 'sell'); - onChange(event); - }} - required - selected={value} - textSize={isMobile ? 'md' : 'sm'} - > - - - -
- ); - }} - rules={{ required: true }} - /> + {!isEdit && ( + { + return ( +
+ { + onChangeAdTypeHandler(event.target.value as 'buy' | 'sell'); + onChange(event); + }} + required + selected={value} + textSize={isMobile ? 'md' : 'sm'} + > + + + +
+ ); + }} + rules={{ required: true }} + /> + )}
{currency}} diff --git a/packages/p2p-v2/src/pages/my-ads/components/AdTypeSection/__tests__/AdTypeSection.spec.tsx b/packages/p2p-v2/src/pages/my-ads/components/AdTypeSection/__tests__/AdTypeSection.spec.tsx index 4062b643635f..ff8fef632392 100644 --- a/packages/p2p-v2/src/pages/my-ads/components/AdTypeSection/__tests__/AdTypeSection.spec.tsx +++ b/packages/p2p-v2/src/pages/my-ads/components/AdTypeSection/__tests__/AdTypeSection.spec.tsx @@ -1,5 +1,4 @@ import React from 'react'; -import { MY_ADS_URL } from '@/constants'; import { render, screen } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import AdTypeSection from '../AdTypeSection'; @@ -31,20 +30,16 @@ jest.mock('react-hook-form', () => ({ }), })); -const mockUseHistory = { - push: jest.fn(), -}; - -jest.mock('react-router-dom', () => ({ - ...jest.requireActual('react-router-dom'), - useHistory: () => mockUseHistory, -})); - jest.mock('@deriv-com/ui', () => ({ ...jest.requireActual('@deriv-com/ui'), useDevice: jest.fn().mockReturnValue({ isMobile: false }), })); +jest.mock('@/hooks', () => ({ + ...jest.requireActual('@/hooks'), + useQueryString: jest.fn().mockReturnValue({ queryString: { advertId: '' } }), +})); + const mockProps = { currency: 'usd', getCurrentStep: jest.fn(() => 1), @@ -52,6 +47,7 @@ const mockProps = { goToNextStep: jest.fn(), goToPreviousStep: jest.fn(), localCurrency: 'usd', + onCancel: jest.fn(), rateType: 'float', }; @@ -73,7 +69,7 @@ describe('AdTypeSection', () => { render(); const element = screen.getByRole('button', { name: 'Cancel' }); userEvent.click(element); - expect(mockUseHistory.push).toHaveBeenCalledWith(MY_ADS_URL); + expect(mockProps.onCancel).toHaveBeenCalled(); }); it('should handle the trigger validation', () => { render(); diff --git a/packages/p2p-v2/src/pages/my-ads/components/AdWizard/AdWizard.scss b/packages/p2p-v2/src/pages/my-ads/components/AdWizard/AdWizard.scss index 246b56beb7d4..b695c093d1b9 100644 --- a/packages/p2p-v2/src/pages/my-ads/components/AdWizard/AdWizard.scss +++ b/packages/p2p-v2/src/pages/my-ads/components/AdWizard/AdWizard.scss @@ -24,6 +24,7 @@ } .p2p-v2-wizard__main-step { + padding-top: 1rem; @include desktop { max-height: calc(100vh - 35rem); overflow-y: auto; diff --git a/packages/p2p-v2/src/pages/my-ads/components/AdWizard/AdWizard.tsx b/packages/p2p-v2/src/pages/my-ads/components/AdWizard/AdWizard.tsx index a68178570857..726d6efd5446 100644 --- a/packages/p2p-v2/src/pages/my-ads/components/AdWizard/AdWizard.tsx +++ b/packages/p2p-v2/src/pages/my-ads/components/AdWizard/AdWizard.tsx @@ -13,11 +13,12 @@ type TAdWizardNav = { countryList: TCountryListItem; currency: string; localCurrency?: string; + onCancel: () => void; rateType: string; steps: TStep[]; }; -const AdWizard = ({ countryList, steps, ...rest }: TAdWizardNav) => { +const AdWizard = ({ countryList, onCancel, steps, ...rest }: TAdWizardNav) => { const { isDesktop } = useDevice(); const [currentStep, setCurrentStep] = useState(0); @@ -44,14 +45,20 @@ const AdWizard = ({ countryList, steps, ...rest }: TAdWizardNav) => { )}
-
)}
} onStepChange={step => setCurrentStep(step.activeStep - 1)} > - + diff --git a/packages/p2p-v2/src/pages/my-ads/components/AlertComponent/AlertComponent.scss b/packages/p2p-v2/src/pages/my-ads/components/AlertComponent/AlertComponent.scss index 006cc3c348a9..3ae106fe373f 100644 --- a/packages/p2p-v2/src/pages/my-ads/components/AlertComponent/AlertComponent.scss +++ b/packages/p2p-v2/src/pages/my-ads/components/AlertComponent/AlertComponent.scss @@ -3,18 +3,12 @@ justify-content: center; position: absolute; align-items: center; - right: 4rem; - height: 99%; - .derivs-button { - background-color: #fff; - &__color--primary:hover:not(:disabled) { - background-color: var(--general-hover); - } - &__size--md { - padding: 0; - } - } + right: 4.7rem; + height: 100%; + span { + display: flex; + } @include mobile { position: unset; margin-left: 1rem; diff --git a/packages/p2p-v2/src/pages/my-ads/components/AlertComponent/AlertComponent.tsx b/packages/p2p-v2/src/pages/my-ads/components/AlertComponent/AlertComponent.tsx index 71015289ee01..b8b7b3a87768 100644 --- a/packages/p2p-v2/src/pages/my-ads/components/AlertComponent/AlertComponent.tsx +++ b/packages/p2p-v2/src/pages/my-ads/components/AlertComponent/AlertComponent.tsx @@ -9,11 +9,11 @@ type TProps = { const AlertComponent = ({ setIsModalOpen }: TProps) => (
- + +
); diff --git a/packages/p2p-v2/src/pages/my-ads/screens/CreateEditAd/CreateEditAd.tsx b/packages/p2p-v2/src/pages/my-ads/screens/CreateEditAd/CreateEditAd.tsx index a182dd25d29c..f18718e64c62 100644 --- a/packages/p2p-v2/src/pages/my-ads/screens/CreateEditAd/CreateEditAd.tsx +++ b/packages/p2p-v2/src/pages/my-ads/screens/CreateEditAd/CreateEditAd.tsx @@ -1,46 +1,68 @@ -import React, { useEffect, useState } from 'react'; +import React, { useCallback, useEffect, useState } from 'react'; import { FormProvider, useForm } from 'react-hook-form'; import { useHistory } from 'react-router-dom'; -import { AdCreateEditErrorModal, AdCreateEditSuccessModal } from '@/components/Modals'; +import { THooks } from 'types'; +import { AdCancelCreateEditModal, AdCreateEditErrorModal, AdCreateEditSuccessModal } from '@/components/Modals'; import { MY_ADS_URL } from '@/constants'; -import { useFloatingRate } from '@/hooks'; +import { useFloatingRate, useQueryString } from '@/hooks'; import { p2p, useActiveAccount } from '@deriv/api-v2'; +import { Loader } from '@deriv-com/ui'; import { AdWizard } from '../../components'; +const getSteps = (isEdit = false) => { + const text = isEdit ? 'Edit' : 'Set'; + const steps = [ + { header: { title: `${text} ad type and amount` } }, + { header: { title: `${text} payment details` } }, + { header: { title: `${text} ad conditions` } }, + ]; + return steps; +}; type FormValues = { 'ad-type': 'buy' | 'sell'; amount: string; + 'contact-details': string; instructions: string; 'max-order': string; 'min-completion-rate': string; 'min-join-days': string; 'min-order': string; 'order-completion-time': string; - 'payment-method': string[]; + 'payment-method': number[] | string[]; 'preferred-countries': string[]; 'rate-value': string; }; -const STEPS = [ - { header: { title: 'Set ad type and amount' } }, - { header: { title: 'Set payment details' } }, - { header: { title: 'Set ad conditions' } }, -]; - const CreateEditAd = () => { + const { queryString } = useQueryString(); + const { advertId = '' } = queryString; + const { data: advertInfo, isLoading } = p2p.advert.useGet( + { id: advertId }, + { enabled: !!advertId, refetchOnWindowFocus: false } + ); + const isEdit = !!advertId; const [isModalOpen, setIsModalOpen] = useState(false); const [isSuccessModalOpen, setIsSuccessModalOpen] = useState(false); + const [isCancelModalOpen, setIsCancelModalOpen] = useState(false); const { data: countryList = {} } = p2p.countryList.useGet(); + const { data: paymentMethodList = [] } = p2p.paymentMethods.useGet(); const { rateType } = useFloatingRate(); const { data: activeAccount } = useActiveAccount(); const { data: p2pSettings } = p2p.settings.useGetSettings(); const { order_payment_period: orderPaymentPeriod } = p2pSettings ?? {}; const { error, isError, isSuccess, mutate } = p2p.advert.useCreate(); + const { + error: updateError, + isError: isUpdateError, + isSuccess: isUpdateSuccess, + mutate: updateMutate, + } = p2p.advert.useUpdate(); const history = useHistory(); const methods = useForm({ defaultValues: { 'ad-type': 'buy', amount: '', + 'contact-details': '', instructions: '', 'max-order': '', 'min-completion-rate': '', @@ -54,7 +76,12 @@ const CreateEditAd = () => { mode: 'all', }); - const { getValues, handleSubmit, setValue } = methods; + const { + formState: { isDirty }, + getValues, + handleSubmit, + setValue, + } = methods; useEffect(() => { if (Object.keys(countryList).length > 0 && getValues('preferred-countries').length === 0) { setValue('preferred-countries', Object.keys(countryList)); @@ -62,6 +89,7 @@ const CreateEditAd = () => { }, [countryList, getValues, setValue]); const shouldNotShowArchiveMessageAgain = localStorage.getItem('should_not_show_auto_archive_message_again'); + const onSubmit = () => { const payload = { amount: Number(getValues('amount')), @@ -76,6 +104,7 @@ const CreateEditAd = () => { if (getValues('ad-type') === 'buy') { payload.payment_method_names = getValues('payment-method'); } else { + payload.contact_info = getValues('contact-details'); payload.payment_method_ids = getValues('payment-method'); } if (getValues('instructions')) { @@ -87,11 +116,18 @@ const CreateEditAd = () => { if (getValues('min-join-days')) { payload.min_join_days = Number(getValues('min-join-days')); } + + if (isEdit) { + delete payload.amount; + delete payload.type; + updateMutate({ id: advertId, ...payload }); + return; + } mutate(payload); }; useEffect(() => { - if (isSuccess) { + if (isSuccess || isUpdateSuccess) { // TODO: Show success modal and other 2 visibility modals after modal manager implementation or update ad impelementation // Redirect to the ad list page if (shouldNotShowArchiveMessageAgain !== 'true') { @@ -99,10 +135,51 @@ const CreateEditAd = () => { } else { history.push(MY_ADS_URL); } - } else if (isError) { + } else if (isError || isUpdateError) { setIsModalOpen(true); } - }, [isSuccess, history, shouldNotShowArchiveMessageAgain, isError]); + }, [isSuccess, history, shouldNotShowArchiveMessageAgain, isError, isUpdateSuccess, isUpdateError]); + + const setFormValues = useCallback( + (advertInfo: THooks.Advert.Get) => { + setValue('ad-type', advertInfo.type); + setValue('amount', advertInfo.amount); + setValue('instructions', advertInfo.description); + setValue('max-order', advertInfo.max_order_amount); + setValue('min-completion-rate', advertInfo.min_completion_rate); + setValue('min-join-days', advertInfo.min_join_days); + setValue('min-order', advertInfo.min_order_amount); + setValue('rate-value', advertInfo.rate); + setValue('preferred-countries', advertInfo.eligible_countries ?? Object.keys(countryList)); + setValue('order-completion-time', `${advertInfo.order_expiry_period}`); + if (advertInfo.type === 'sell') { + setValue('contact-details', advertInfo.contact_info); + setValue('payment-method', Object.keys(advertInfo.payment_method_details ?? {}).map(Number)); + } else { + const paymentMethodNames = advertInfo?.payment_method_names; + const paymentMethodKeys = paymentMethodNames?.map( + name => paymentMethodList.find(method => method.display_name === name)?.id + ); + setValue('payment-method', paymentMethodKeys); + } + }, + [setValue, countryList, paymentMethodList] + ); + + useEffect(() => { + if (advertInfo && isEdit) { + setFormValues(advertInfo); + } + }, [advertInfo, isEdit, setFormValues]); + + if ((isLoading && isEdit) || (isEdit && !advertInfo)) { + return ; + } + + const onClickCancel = () => { + if (isDirty) setIsCancelModalOpen(true); + else history.push(MY_ADS_URL); + }; return ( <> @@ -112,14 +189,16 @@ const CreateEditAd = () => { countryList={countryList} currency={activeAccount?.currency ?? 'USD'} localCurrency={p2pSettings?.localCurrency} + onCancel={onClickCancel} rateType={rateType} - steps={STEPS} + steps={getSteps(isEdit)} /> {isModalOpen && ( setIsModalOpen(false)} /> @@ -131,6 +210,12 @@ const CreateEditAd = () => { onRequestClose={() => setIsSuccessModalOpen(false)} /> )} + {isCancelModalOpen && ( + setIsCancelModalOpen(false)} + /> + )} ); }; diff --git a/packages/p2p-v2/src/pages/my-ads/screens/CreateEditAd/__tests__/CreateEditAd.spec.tsx b/packages/p2p-v2/src/pages/my-ads/screens/CreateEditAd/__tests__/CreateEditAd.spec.tsx index cc2e1f23528b..8f4aa0debd7a 100644 --- a/packages/p2p-v2/src/pages/my-ads/screens/CreateEditAd/__tests__/CreateEditAd.spec.tsx +++ b/packages/p2p-v2/src/pages/my-ads/screens/CreateEditAd/__tests__/CreateEditAd.spec.tsx @@ -1,11 +1,21 @@ import React from 'react'; +import { MY_ADS_URL } from '@/constants'; import { render, screen } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; import CreateEditAd from '../CreateEditAd'; +import '../../../components/AdFormInput'; +const mockOnChange = jest.fn(); jest.mock('react-hook-form', () => ({ ...jest.requireActual('react-hook-form'), FormProvider: ({ children }) =>
{children}
, + Controller: ({ control, defaultValue, name, render }) => + render({ + field: { control, name, onBlur: jest.fn(), onChange: mockOnChange, value: defaultValue }, + fieldState: { error: null }, + }), useFormContext: () => ({ + control: 'mockedControl', formState: { errors: {}, isValid: true }, getValues: () => ({ 'ad-type': 'buy', @@ -13,9 +23,25 @@ jest.mock('react-hook-form', () => ({ 'payment-method': [], 'rate-value': '1.2', }), + watch: jest.fn(), + }), +})); + +const mockFn = jest.fn(); +jest.mock('react-router-dom', () => ({ + ...jest.requireActual('react-router-dom'), + useHistory: () => ({ + push: mockFn, }), })); +jest.mock('../../../components/AdFormInput', () => ({ + AdFormInput: () =>
AdFormInput
, +})); + +jest.mock('../../../components/AdFormTextArea', () => ({ + AdFormTextArea: () =>
AdFormTextArea
, +})); jest.mock('@deriv/api-v2', () => ({ p2p: { advert: { @@ -25,6 +51,76 @@ jest.mock('@deriv/api-v2', () => ({ isSuccess: false, mutate: jest.fn(), }), + useGet: () => ({ + data: {}, + isLoading: false, + }), + useUpdate: () => ({ + error: undefined, + isError: false, + isSuccess: false, + mutate: jest.fn(), + }), + }, + paymentMethods: { + useGet: () => ({ + data: [ + { + display_name: 'Bank Transfer', + fields: { + account: { + display_name: 'Account Number', + required: 1, + type: 'text', + value: 'Account Number', + }, + bank_name: { display_name: 'Bank Transfer', required: 1, type: 'text', value: 'Bank Name' }, + }, + id: 'test1', + is_enabled: 0, + method: '', + type: 'bank', + used_by_adverts: null, + used_by_orders: null, + }, + { + display_name: 'Ali pay', + fields: { + account: { + display_name: 'Account Number', + required: 1, + type: 'text', + value: 'Account Number', + }, + bank_name: { display_name: 'Ali pay', required: 1, type: 'text', value: 'Bank Name' }, + }, + id: 'test2', + is_enabled: 0, + method: '', + type: 'wallet', + used_by_adverts: null, + used_by_orders: null, + }, + { + display_name: 'Skrill', + fields: { + account: { + display_name: 'Account Number', + required: 1, + type: 'text', + value: 'Account Number', + }, + bank_name: { display_name: 'Skrill', required: 1, type: 'text', value: 'Bank Name' }, + }, + id: 'test3', + is_enabled: 0, + method: '', + type: 'wallet', + used_by_adverts: null, + used_by_orders: null, + }, + ], + }), }, countryList: { useGet: () => ({ @@ -70,11 +166,9 @@ jest.mock('@deriv/api-v2', () => ({ })); jest.mock('@/hooks', () => ({ + ...jest.requireActual('@/hooks'), useFloatingRate: () => ({ rateType: 'floating' }), -})); - -jest.mock('../../../components/AdWizard', () => ({ - AdWizard: () =>
AdWizard
, + useQueryString: jest.fn().mockReturnValue({ queryString: { advertId: '' } }), })); jest.mock('@deriv-com/ui', () => ({ @@ -85,6 +179,13 @@ jest.mock('@deriv-com/ui', () => ({ describe('CreateEditAd', () => { it('should render the create edit ad component', () => { render(); - expect(screen.getByText('AdWizard')).toBeInTheDocument(); + expect(screen.getByText('Set ad type and amount')).toBeInTheDocument(); + }); + it('should handle clicking on Cancel button', () => { + render(); + const cancelButton = screen.getByRole('button', { name: 'Cancel' }); + expect(cancelButton).toBeInTheDocument(); + userEvent.click(cancelButton); + expect(mockFn).toHaveBeenCalledWith(MY_ADS_URL); }); }); diff --git a/packages/p2p-v2/src/pages/my-ads/screens/MyAds/MyAdsTable/MyAdsDisplayWrapper.tsx b/packages/p2p-v2/src/pages/my-ads/screens/MyAds/MyAdsTable/MyAdsDisplayWrapper.tsx index 945d3661729e..39d67fd20a74 100644 --- a/packages/p2p-v2/src/pages/my-ads/screens/MyAds/MyAdsTable/MyAdsDisplayWrapper.tsx +++ b/packages/p2p-v2/src/pages/my-ads/screens/MyAds/MyAdsTable/MyAdsDisplayWrapper.tsx @@ -14,7 +14,7 @@ const MyAdsDisplayWrapper = ({ children, isPaused, onClickToggle }: PropsWithChi const { isMobile } = useDevice(); const history = useHistory(); - const goToCreateAd = () => history.push(`${MY_ADS_URL}/create`); + const goToCreateAd = () => history.push(`${MY_ADS_URL}/adForm?formAction=create`); if (isMobile) { return ( diff --git a/packages/p2p-v2/src/pages/my-ads/screens/MyAds/MyAdsTable/MyAdsTable.tsx b/packages/p2p-v2/src/pages/my-ads/screens/MyAds/MyAdsTable/MyAdsTable.tsx index e3f34c37a561..fcdecdaa4fcf 100644 --- a/packages/p2p-v2/src/pages/my-ads/screens/MyAds/MyAdsTable/MyAdsTable.tsx +++ b/packages/p2p-v2/src/pages/my-ads/screens/MyAds/MyAdsTable/MyAdsTable.tsx @@ -1,9 +1,10 @@ import React, { memo, useEffect, useState } from 'react'; +import { useHistory } from 'react-router-dom'; import { THooks } from 'types'; import { Table } from '@/components'; import { MyAdsDeleteModal } from '@/components/Modals'; import { ShareAdsModal } from '@/components/Modals/ShareAdsModal'; -import { AD_ACTION } from '@/constants'; +import { AD_ACTION, MY_ADS_URL } from '@/constants'; import { p2p } from '@deriv/api-v2'; import { Loader } from '@deriv-com/ui'; import { MyAdsEmpty } from '../../MyAdsEmpty'; @@ -55,6 +56,7 @@ const MyAdsTable = () => { const [isModalOpen, setIsModalOpen] = useState(false); const [advertId, setAdvertId] = useState(''); const [isShareAdsModalOpen, setIsShareAdsModalOpen] = useState(false); + const history = useHistory(); useEffect(() => { if (isSuccess) { @@ -88,6 +90,10 @@ const MyAdsTable = () => { setIsShareAdsModalOpen(true); break; } + case AD_ACTION.EDIT: { + history.push(`${MY_ADS_URL}/adForm?formAction=edit&advertId=${id}`); + break; + } default: break; } diff --git a/packages/p2p-v2/src/pages/my-ads/screens/MyAds/MyAdsTableRow/MyAdsTableRow.scss b/packages/p2p-v2/src/pages/my-ads/screens/MyAds/MyAdsTableRow/MyAdsTableRow.scss index 6b253b718ad7..bfc09c1d5353 100644 --- a/packages/p2p-v2/src/pages/my-ads/screens/MyAds/MyAdsTableRow/MyAdsTableRow.scss +++ b/packages/p2p-v2/src/pages/my-ads/screens/MyAds/MyAdsTableRow/MyAdsTableRow.scss @@ -9,7 +9,7 @@ @include desktop { &:hover { - background-color: var(--general-hover); + background-color: #e6e9e9; border-radius: 0.5rem; } } @@ -26,7 +26,7 @@ position: relative; display: grid; align-items: center; - grid-template-columns: repeat(3, 1.6fr) 1.9fr 3fr 1.9fr; + grid-template-columns: repeat(3, 1.6fr) 1.9fr 3fr 1.7fr; &-disabled { span:not(.p2p-v2-my-ads-table-row__actions span) { @@ -70,7 +70,7 @@ } &__rate { - color: var(--text-profit-success); + color: #4bb4b3; font-weight: bold; } @@ -92,10 +92,11 @@ &__actions { display: flex; align-items: center; + justify-content: space-between; + margin-right: 1rem; &-popovers { - background-color: var(--general-main-1); + background-color: #fff; display: flex; - height: 99%; justify-content: center; min-width: 14rem; padding: 1.6rem; @@ -106,7 +107,7 @@ .derivs-button { background-color: #fff; &__color--primary:hover:not(:disabled) { - background-color: var(--general-hover); + background-color: #e6e9e9; } &__size--md { padding: 0.6rem 0.85rem; diff --git a/packages/p2p-v2/src/pages/my-ads/screens/MyAds/MyAdsTableRow/MyAdsTableRow.tsx b/packages/p2p-v2/src/pages/my-ads/screens/MyAds/MyAdsTableRow/MyAdsTableRow.tsx index c3af1904e20b..429e08d217f4 100644 --- a/packages/p2p-v2/src/pages/my-ads/screens/MyAds/MyAdsTableRow/MyAdsTableRow.tsx +++ b/packages/p2p-v2/src/pages/my-ads/screens/MyAds/MyAdsTableRow/MyAdsTableRow.tsx @@ -2,28 +2,22 @@ import React, { memo, useEffect, useState } from 'react'; import clsx from 'clsx'; import { PaymentMethodLabel, PopoverDropdown } from '@/components'; import { ADVERT_TYPE, RATE_TYPE } from '@/constants'; -import { useDevice } from '@/hooks'; +import { useFloatingRate } from '@/hooks'; import { formatMoney, generateEffectiveRate, shouldShowTooltipIcon } from '@/utils'; import { useExchangeRateSubscription } from '@deriv/api-v2'; -import { Button, Text, Tooltip } from '@deriv-com/ui'; -//TODO: Replace with quill icons once available -import DeactivateIcon from '../../../../../public/ic-archive.svg'; -import DeleteIcon from '../../../../../public/ic-delete.svg'; -import EditIcon from '../../../../../public/ic-edit.svg'; -import ShareIcon from '../../../../../public/ic-share.svg'; -import ActivateIcon from '../../../../../public/ic-unarchive.svg'; +import { Text, useDevice } from '@deriv-com/ui'; import { AdStatus, AdType, AlertComponent, ProgressIndicator } from '../../../components'; import { TMyAdsTableRowRendererProps } from '../MyAdsTable/MyAdsTable'; import './MyAdsTableRow.scss'; const BASE_CURRENCY = 'USD'; -//TODO: to be modified after design is updated. -const list = [ + +const getList = (isActive = false) => [ { label: 'Edit', value: 'edit' }, - { label: 'Delete', value: 'delete' }, - { label: 'Duplicate', value: 'duplicate' }, + { label: 'Copy', value: 'copy' }, { label: 'Share', value: 'share' }, - { label: 'Deactivate', value: 'deactivate' }, + { label: `${isActive ? 'Deactivate' : 'Activate'}`, value: `${isActive ? 'deactivate' : 'activate'}` }, + { label: 'Delete', value: 'delete' }, ]; type TProps = { @@ -36,6 +30,7 @@ type TMyAdsTableProps = Omit { const { isMobile } = useDevice(); const { data: exchangeRateValue, subscribe } = useExchangeRateSubscription(); + const { rateType: currentRateType } = useFloatingRate(); const { account_currency: accountCurrency, @@ -63,13 +58,14 @@ const MyAdsTableRow = ({ setIsModalOpen, ...rest }: TMyAdsTableProps) => { const isFloatingRate = rateType === RATE_TYPE.FLOAT; useEffect(() => { - subscribe({ - base_currency: BASE_CURRENCY, - target_currency: localCurrency, - }); + if (localCurrency) { + subscribe({ + base_currency: BASE_CURRENCY, + target_currency: localCurrency, + }); + } }, [localCurrency, subscribe]); - const [isActionsVisible, setIsActionsVisible] = useState(false); const [showAlertIcon, setShowAlertIcon] = useState(false); const isAdvertListed = isListed && !isBarred; const adPauseColor = isAdvertListed ? 'general' : 'less-prominent'; @@ -78,10 +74,8 @@ const MyAdsTableRow = ({ setIsModalOpen, ...rest }: TMyAdsTableProps) => { const isRowDisabled = !isActive || isBarred || !isListed; const isAdActive = !!isActive && !isBarred; - const exchangeRate = exchangeRateValue?.rates?.[localCurrency]; - //TODO: get the floating rate configs after completion of floating rate hook. - // check for rate type and if it is different from the current rate type then enable the action point. - const enableActionPoint = false; + const exchangeRate = exchangeRateValue?.rates?.[localCurrency ?? '']; + const enableActionPoint = currentRateType !== rateType; useEffect(() => { setShowAlertIcon(enableActionPoint || shouldShowTooltipIcon(visibilityStatus) || !isListed); @@ -96,8 +90,6 @@ const MyAdsTableRow = ({ setIsModalOpen, ...rest }: TMyAdsTableProps) => { rateType, }); - //TODO: get the floating rate configs after integration with usep2psettings to handle disabled case. - const advertType = type === 'buy' ? ADVERT_TYPE.BUY : ADVERT_TYPE.SELL; const onClickActionItem = (value: string) => { @@ -122,9 +114,9 @@ const MyAdsTableRow = ({ setIsModalOpen, ...rest }: TMyAdsTableProps) => { {showAlertIcon && } onClickActionItem(value)} + tooltipMessage='Manage ad' />
@@ -180,8 +172,6 @@ const MyAdsTableRow = ({ setIsModalOpen, ...rest }: TMyAdsTableProps) => { className={clsx('p2p-v2-my-ads-table-row__line', { 'p2p-v2-my-ads-table-row__line-disabled': isRowDisabled, })} - onMouseEnter={() => setIsActionsVisible(true)} - onMouseLeave={() => setIsActionsVisible(false)} > {advertType} {id} @@ -212,36 +202,12 @@ const MyAdsTableRow = ({ setIsModalOpen, ...rest }: TMyAdsTableProps) => { ))}
- {isActionsVisible ? ( -
- - - - -
- ) : ( - - )} + + onClickActionItem(value)} + tooltipMessage='Manage ad' + /> {showAlertIcon && }
diff --git a/packages/p2p-v2/src/pages/my-ads/screens/MyAds/MyAdsTableRow/__tests__/MyAdsTableRow.spec.tsx b/packages/p2p-v2/src/pages/my-ads/screens/MyAds/MyAdsTableRow/__tests__/MyAdsTableRow.spec.tsx index 0f2d58cd76f0..feb08ec496a1 100644 --- a/packages/p2p-v2/src/pages/my-ads/screens/MyAds/MyAdsTableRow/__tests__/MyAdsTableRow.spec.tsx +++ b/packages/p2p-v2/src/pages/my-ads/screens/MyAds/MyAdsTableRow/__tests__/MyAdsTableRow.spec.tsx @@ -1,6 +1,6 @@ import React from 'react'; -import { useDevice } from '@/hooks'; import { useExchangeRateSubscription } from '@deriv/api-v2'; +import { useDevice } from '@deriv-com/ui'; import { render, screen, waitFor } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import MyAdsTableRow from '../MyAdsTableRow'; @@ -74,11 +74,14 @@ jest.mock('@deriv/api-v2', () => ({ useExchangeRateSubscription: jest.fn(), })); -jest.mock('@/hooks/useDevice', () => ({ - __esModule: true, - default: jest.fn(() => ({ - isMobile: false, - })), +jest.mock('@/hooks', () => ({ + ...jest.requireActual('@/hooks'), + useFloatingRate: () => ({ rateType: 'fixed' }), +})); + +jest.mock('@deriv-com/ui', () => ({ + ...jest.requireActual('@deriv-com/ui'), + useDevice: jest.fn().mockReturnValue({ isMobile: false }), })); const mockUseExchangeRate = useExchangeRateSubscription as jest.Mock; @@ -107,17 +110,28 @@ describe('MyAdsTableRow', () => { expect(screen.getByText('Bank Transfer')).toBeInTheDocument(); expect(screen.getByText('Active')).toBeInTheDocument(); }); - it('should open the popover dropdown on clicking on menu in mobile view', async () => { - (useDevice as jest.Mock).mockReturnValue({ isMobile: true }); + it('should open the popover dropdown on clicking on menu', async () => { render(); - const button = screen.getByTestId('dt_p2p_v2_actions_menu'); + const button = screen.getByTestId('dt_p2p_v2_popover_dropdown_icon'); userEvent.click(button); await waitFor(() => { expect(screen.getByText('Edit')).toBeInTheDocument(); expect(screen.getByText('Deactivate')).toBeInTheDocument(); expect(screen.getByText('Delete')).toBeInTheDocument(); - expect(screen.getByText('Duplicate')).toBeInTheDocument(); + expect(screen.getByText('Copy')).toBeInTheDocument(); + }); + }); + it('should handle onClick for each menu item', async () => { + render(); + const button = screen.getByTestId('dt_p2p_v2_popover_dropdown_icon'); + userEvent.click(button); + await waitFor(() => { + const edit = screen.getByText('Edit'); + expect(edit).toBeInTheDocument(); + userEvent.click(edit); + }); + await waitFor(() => { + expect(mockProps.onClickIcon).toHaveBeenCalledWith('138', 'edit'); }); }); - //TODO: add test for onclick actions once the component is updated. }); diff --git a/packages/p2p-v2/src/pages/my-ads/screens/MyAdsEmpty/MyAdsEmpty.tsx b/packages/p2p-v2/src/pages/my-ads/screens/MyAdsEmpty/MyAdsEmpty.tsx index 382115ebc680..fd4e0f0cf1a6 100644 --- a/packages/p2p-v2/src/pages/my-ads/screens/MyAdsEmpty/MyAdsEmpty.tsx +++ b/packages/p2p-v2/src/pages/my-ads/screens/MyAdsEmpty/MyAdsEmpty.tsx @@ -13,7 +13,7 @@ const MyAdsEmpty = () => { history.push(`${MY_ADS_URL}?formAction=create`)} + onClick={() => history.push(`${MY_ADS_URL}/adForm?formAction=create`)} size='lg' textSize={isMobile ? 'md' : 'sm'} > diff --git a/packages/p2p-v2/src/pages/my-ads/screens/MyAdsEmpty/__tests__/MyAdsEmpty.spec.tsx b/packages/p2p-v2/src/pages/my-ads/screens/MyAdsEmpty/__tests__/MyAdsEmpty.spec.tsx index 07273d6a6f1b..e7d5c3be0fb8 100644 --- a/packages/p2p-v2/src/pages/my-ads/screens/MyAdsEmpty/__tests__/MyAdsEmpty.spec.tsx +++ b/packages/p2p-v2/src/pages/my-ads/screens/MyAdsEmpty/__tests__/MyAdsEmpty.spec.tsx @@ -29,6 +29,6 @@ describe('MyAdsEmpty', () => { render(); const createNewAdButton = screen.getByRole('button', { name: 'Create new ad' }); userEvent.click(createNewAdButton); - expect(mockFn).toHaveBeenCalledWith(`${MY_ADS_URL}?formAction=create`); + expect(mockFn).toHaveBeenCalledWith(`${MY_ADS_URL}/adForm?formAction=create`); }); }); diff --git a/packages/p2p-v2/src/routes/AppContent/__tests__/AppContent.spec.tsx b/packages/p2p-v2/src/routes/AppContent/__tests__/AppContent.spec.tsx index 7f31874f4451..fa1179e7157d 100644 --- a/packages/p2p-v2/src/routes/AppContent/__tests__/AppContent.spec.tsx +++ b/packages/p2p-v2/src/routes/AppContent/__tests__/AppContent.spec.tsx @@ -168,7 +168,7 @@ describe('', () => { it('should render the CreateEditAd component', async () => { const history = createMemoryHistory(); - history.push('/cashier/p2p-v2/my-ads/create'); + history.push('/cashier/p2p-v2/my-ads/adForm'); render( diff --git a/packages/p2p-v2/src/routes/routes-config.ts b/packages/p2p-v2/src/routes/routes-config.ts index 3d2ed20b6051..3b5598511348 100644 --- a/packages/p2p-v2/src/routes/routes-config.ts +++ b/packages/p2p-v2/src/routes/routes-config.ts @@ -37,7 +37,7 @@ export const routes = [ routes: [ { component: CreateEditAd, - path: `${MY_ADS_URL}/create`, + path: `${MY_ADS_URL}/adForm`, }, ], },