diff --git a/packages/core/src/App/Containers/Layout/header/__tests__/dtrader-contract-details-header.spec.tsx b/packages/core/src/App/Containers/Layout/header/__tests__/dtrader-contract-details-header.spec.tsx index a587b56adf2e..85854d8314c2 100644 --- a/packages/core/src/App/Containers/Layout/header/__tests__/dtrader-contract-details-header.spec.tsx +++ b/packages/core/src/App/Containers/Layout/header/__tests__/dtrader-contract-details-header.spec.tsx @@ -1,22 +1,39 @@ import React from 'react'; import { render, screen } from '@testing-library/react'; -import '@testing-library/jest-dom'; -import { Router } from 'react-router-dom'; -import { createMemoryHistory } from 'history'; +import { BrowserRouter, useHistory, useLocation } from 'react-router-dom'; import DTraderContractDetailsHeader from '../dtrader-v2-contract-detail-header'; import userEvent from '@testing-library/user-event'; +import { StoreProvider, mockStore } from '@deriv/stores'; jest.mock('@deriv-com/quill-ui', () => ({ Text: () =>
Contract Details
, })); +jest.mock('react-router-dom', () => ({ + ...jest.requireActual('react-router-dom'), + useLocation: jest.fn().mockReturnValue({ pathname: '' }), + useHistory: jest.fn().mockReturnValue({ + goBack: jest.fn(), + }), +})); describe('DTraderV2Header', () => { + const mock_store = mockStore({ + contract_replay: { + onClickCancel: jest.fn(), + onClickSell: jest.fn(), + is_sell_requested: false, + }, + common: { + routeBackInApp: jest.fn(), + }, + }); test('renders the header with localized text and an icon', () => { - const history = createMemoryHistory(); render( - - - + + + + + ); expect(screen.getByText('Contract Details')).toBeInTheDocument(); @@ -25,19 +42,39 @@ describe('DTraderV2Header', () => { expect(icon).toBeInTheDocument(); }); - test('clicking the back arrow calls history.goBack', () => { - const history = createMemoryHistory(); + test('clicking the back arrow calls routeBackInApp from DTrader page', () => { + render( + + + + + + ); - history.goBack = jest.fn(); + userEvent.click(screen.getByTestId('arrow')); + + expect(mock_store.common.routeBackInApp).toHaveBeenCalled(); + }); + test('clicking the back arrow calls history go back from Reports page', () => { + const historyMock = { + goBack: jest.fn(), + }; + (useLocation as jest.Mock).mockReturnValue({ + pathname: '', + state: { from_table_row: true }, + }); + (useHistory as jest.Mock).mockReturnValue(historyMock); render( - - - + + + + + ); userEvent.click(screen.getByTestId('arrow')); - expect(history.goBack).toHaveBeenCalled(); + expect(historyMock.goBack).toHaveBeenCalled(); }); }); diff --git a/packages/core/src/App/Containers/Layout/header/dtrader-v2-contract-detail-header.tsx b/packages/core/src/App/Containers/Layout/header/dtrader-v2-contract-detail-header.tsx index f7aaf1372b3a..9f481e7b9e8a 100644 --- a/packages/core/src/App/Containers/Layout/header/dtrader-v2-contract-detail-header.tsx +++ b/packages/core/src/App/Containers/Layout/header/dtrader-v2-contract-detail-header.tsx @@ -1,12 +1,21 @@ import React from 'react'; -import { observer } from '@deriv/stores'; +import { observer, useStore } from '@deriv/stores'; import { Text } from '@deriv-com/quill-ui'; import { LabelPairedArrowLeftSmBoldIcon } from '@deriv/quill-icons'; import { Localize } from '@deriv/translations'; -import { useHistory } from 'react-router-dom'; +import { useHistory, useLocation } from 'react-router-dom'; +import { isEmptyObject } from '@deriv/shared'; const DTraderContractDetailsHeader = observer(() => { + const { state } = useLocation(); const history = useHistory(); + const { common } = useStore(); + const { routeBackInApp } = common; + + const handleBack = () => { + const is_from_table_row = !isEmptyObject(state) ? state.from_table_row : false; + return is_from_table_row ? history.goBack() : routeBackInApp(history); + }; return (
@@ -16,7 +25,7 @@ const DTraderContractDetailsHeader = observer(() => { width='13px' className='arrow' data-testid='arrow' - onClick={() => history.goBack()} + onClick={handleBack} /> diff --git a/packages/core/src/sass/app/_common/layout/header.scss b/packages/core/src/sass/app/_common/layout/header.scss index 3aa2ba26793b..02fc57f2ea47 100644 --- a/packages/core/src/sass/app/_common/layout/header.scss +++ b/packages/core/src/sass/app/_common/layout/header.scss @@ -437,6 +437,7 @@ padding: var(--core-spacing-600) var(--core-spacing-50); .arrow { position: absolute; + cursor: pointer; left: var(--core-size-1200); } } diff --git a/packages/shared/src/utils/constants/contract.ts b/packages/shared/src/utils/constants/contract.ts index 913b703a7f78..65d5764a96bd 100644 --- a/packages/shared/src/utils/constants/contract.ts +++ b/packages/shared/src/utils/constants/contract.ts @@ -312,6 +312,59 @@ export const getCardLabels = () => WON: localize('Won'), } as const); +export const getCardLabelsV2 = () => + ({ + APPLY: localize('Apply'), + BARRIER: localize('Barrier'), + BUY_PRICE: localize('Buy price'), + CANCEL: localize('Cancel'), + CLOSE: localize('Close'), + CLOSED: localize('Closed'), + COMMISSION: localize('Commission'), + CONTRACT_COST: localize('Contract cost'), + CONTRACT_VALUE: localize('Contract value'), + CURRENT_STAKE: localize('Current stake'), + DAY: localize('day'), + DAYS: localize('days'), + DEAL_CANCEL_FEE: localize('Deal cancel. fee'), + DECREMENT_VALUE: localize('Decrement value'), + DONT_SHOW_THIS_AGAIN: localize("Don't show this again"), + DURATION: localize('Duration'), + ENTRY_SPOT: localize('Entry spot'), + GROWTH_RATE: localize('Growth rate'), + INCREMENT_VALUE: localize('Increment value'), + INDICATIVE_PRICE: localize('Indicative price'), + INITIAL_STAKE: localize('Initial stake'), + LOST: localize('Lost'), + MULTIPLIER: localize('Multiplier'), + NOT_AVAILABLE: localize('N/A'), + NOT_SET: localize('Not set'), + PAYOUT: localize('Sell price'), + PAYOUT_PER_POINT: localize('Payout per point'), + POTENTIAL_PAYOUT: localize('Potential payout'), + POTENTIAL_PROFIT_LOSS: localize('Potential profit/loss'), + PROFIT_LOSS: localize('Profit/Loss'), + PURCHASE_PRICE: localize('Buy price'), + REFERENCE_ID: localize('Reference ID'), + RESALE_NOT_OFFERED: localize('Resale not offered'), + SELL: localize('Sell'), + STAKE: localize('Stake'), + STOP_LOSS: localize('Stop loss'), + STOP_OUT_LEVEL: localize('Stop out level'), + STRIKE: localize('Strike'), + STRIKE_PRICE: localize('Strike Price'), + TAKE_PROFIT: localize('Take profit'), + TAKE_PROFIT_IS_NOT_AVAILABLE: localize("Take profit can't be adjusted for ongoing accumulator contracts."), + TAKE_PROFIT_LOSS_NOT_AVAILABLE: localize( + 'Take profit and/or stop loss are not available while deal cancellation is active.' + ), + TARGET: localize('Target'), + TICK: localize('Tick'), + TICKS: localize('Ticks'), + TOTAL_PROFIT_LOSS: localize('Total profit/loss'), + WON: localize('Won'), + } as const); + export const getMarketNamesMap = () => ({ FRXAUDCAD: localize('AUD/CAD'), diff --git a/packages/trader/src/AppV2/Components/ContractDetailsFooter/__tests__/contract-details-footer.spec.tsx b/packages/trader/src/AppV2/Components/ContractDetailsFooter/__tests__/contract-details-footer.spec.tsx index 588632321b50..649b33ea53a4 100644 --- a/packages/trader/src/AppV2/Components/ContractDetailsFooter/__tests__/contract-details-footer.spec.tsx +++ b/packages/trader/src/AppV2/Components/ContractDetailsFooter/__tests__/contract-details-footer.spec.tsx @@ -2,13 +2,12 @@ import React from 'react'; import { render, screen } from '@testing-library/react'; import '@testing-library/jest-dom'; import { StoreProvider, mockStore } from '@deriv/stores'; -import { getCardLabels, isValidToSell, isValidToCancel, isMultiplierContract } from '@deriv/shared'; +import { isValidToSell, isValidToCancel, isMultiplierContract } from '@deriv/shared'; import ContractDetailsFooter from '../contract-details-footer'; import userEvent from '@testing-library/user-event'; jest.mock('@deriv/shared', () => ({ ...jest.requireActual('@deriv/shared'), - getCardLabels: jest.fn(), isValidToSell: jest.fn(), isValidToCancel: jest.fn(), isMultiplierContract: jest.fn(), @@ -34,15 +33,6 @@ describe('ContractDetailsFooter', () => { }, }); - beforeEach(() => { - (getCardLabels as jest.Mock).mockImplementation(() => ({ - CLOSE: 'Close', - CANCEL: 'Cancel', - RESALE_NOT_OFFERED: 'Resale not offered', - })); - jest.clearAllMocks(); - }); - const renderFooter = () => { render( @@ -94,6 +84,16 @@ describe('ContractDetailsFooter', () => { expect(mock_store.contract_replay.onClickSell).toHaveBeenCalledWith(1); }); + it('should not call onClickSell if not valid to sell', () => { + (isMultiplierContract as jest.Mock).mockImplementation(() => false); + (isValidToSell as jest.Mock).mockImplementation(() => false); + + renderFooter(); + + const closeButton = screen.queryByRole('button'); + expect(closeButton).toBeDisabled(); + }); + it('should disable cancel button when profit is non-negative', () => { (isMultiplierContract as jest.Mock).mockImplementation(() => true); (isValidToCancel as jest.Mock).mockImplementation(() => true); @@ -114,20 +114,6 @@ describe('ContractDetailsFooter', () => { expect(cancelButton).not.toBeInTheDocument(); }); - it('should not call onClickSell if not valid to sell', () => { - (isMultiplierContract as jest.Mock).mockImplementation(() => false); - (isValidToSell as jest.Mock).mockImplementation(() => false); - - renderFooter(); - - const closeButton = screen.queryByRole('button', { name: /close @ 100.00 usd/i }); - if (closeButton) { - userEvent.click(closeButton); - } - - expect(mock_store.contract_replay.onClickSell).not.toHaveBeenCalled(); - }); - it('should render correct button label for non-multiplier contract when not valid to sell', () => { (isMultiplierContract as jest.Mock).mockImplementation(() => false); (isValidToSell as jest.Mock).mockImplementation(() => false); diff --git a/packages/trader/src/AppV2/Components/ContractDetailsFooter/contract-details-footer.tsx b/packages/trader/src/AppV2/Components/ContractDetailsFooter/contract-details-footer.tsx index 28e55ac41399..63ad62ac6820 100644 --- a/packages/trader/src/AppV2/Components/ContractDetailsFooter/contract-details-footer.tsx +++ b/packages/trader/src/AppV2/Components/ContractDetailsFooter/contract-details-footer.tsx @@ -1,10 +1,11 @@ import { Button, TButtonColor, TButtonVariant } from '@deriv-com/quill-ui'; import { RemainingTime } from '@deriv/components'; -import { TContractInfo, getCardLabels, isMultiplierContract, isValidToCancel, isValidToSell } from '@deriv/shared'; +import { TContractInfo, getCardLabels, getCardLabelsV2, isMultiplierContract, isValidToCancel, isValidToSell } from '@deriv/shared'; import { useStore } from '@deriv/stores'; import React from 'react'; import { observer } from 'mobx-react'; import { TRegularSizesWithExtraLarge } from '@deriv-com/quill-ui/dist/types'; +import { FormatUtils } from '@deriv-com/utils'; type ContractInfoProps = { contract_info: TContractInfo; @@ -34,7 +35,7 @@ const ContractDetailsFooter = observer(({ contract_info }: ContractInfoProps) => const is_valid_to_cancel = isValidToCancel(contract_info); const is_multiplier = isMultiplierContract(contract_type); - const cardLabels = getCardLabels(); + const cardLabels = getCardLabelsV2(); const bidDetails = !is_valid_to_cancel ? `@${bid_price} ${currency}` : ''; const label = `${cardLabels.CLOSE} ${bidDetails}`; @@ -61,14 +62,14 @@ const ContractDetailsFooter = observer(({ contract_info }: ContractInfoProps) => onClick={() => onClickCancel(contract_id)} label={ <> - {getCardLabels().CANCEL} + {cardLabels.CANCEL} {' '} @@ -82,8 +83,8 @@ const ContractDetailsFooter = observer(({ contract_info }: ContractInfoProps) =>