Skip to content

Commit

Permalink
[DTRA] Kate/Maryia/DTRA-1279/Redesign: Positions page (deriv-com#15234)
Browse files Browse the repository at this point in the history
* chore: empty commit

* feat: tabs + background + initialized EmptyMessage component

* Maryia/Positions-redesign/improve EmptyMessage component + add tests (#50)

* feat: redirect to trade upon button click on the empty page

* test: EmptyMessage

* chore: empty commit

* DTRA-1279 / Kate / Filter [WIP] (#51)

* feat: add dropdowm and action sheet

* feat: add apply functionality

* chore: remove unused functionality

* refactor: separate apply logic

* feat: add clear all functionality

* feat: apply filtration logic

* fix: filtration bug

* chore: rename variables

* refactor: extract filtration logic into a util function

* chore: empty commit

* fix: sonarcloud issues

* chore: empty commit

* chore: add modules store  and useclosedposition hook (#52)

* refactor: remove todo and change some prop based on quill updates (#54)

* DTRA-1279 / Kate / Use hook for real data (#55)

* feat: use hook for real data

* refactor: apply suggestions

* Maryia/positions-redesign/Contract cards [WIP] (#53)

* feat: init ContractCard

* feat: Contract cards

* feat: use ReportsStoreProvider

* style: remove unnecessary comment

* fix: key

* fix: remove old card styles

* fix: types

* fix: use contract_info in filterPositions

* fix: do not show buttons for sold contracts

* DTRA-1279 / Kate / Refactor handling open and closed positions and their filtration (#56)

* refactor: move stor values to poitions content file

* chore: remove code smell

* Maryia/positions-redesign/Contract cards improvements + fetching Open positions + formatProfitTableTransactions TS migration (#58)

* refactor: contract-card-list and card

* feat: buttons demo + animation improvements

* feat: finilize Duration component for the card

* chore: ts migration for closed positions

* fix: console error with remaining time & showing empty message only when empty

* feat: connect real open postions + style and filter fixes

* fix: style

* DTRA-1279/ Kate / Create filter component  (#57)

* feat: create new filter component

* feat: apply radio button

* refactor: default time filter logic

* feat: add time filtration

* refactor: remove unused css

* DTRA-1279 / Kate / Refactor: add new content for empty page (#59)

* refactor: add new content for empty page

* chore: test text update

* Maryia/positions-redesign/Contract cards data update fix (#61)

* fix: Accumulators tick passed count

* fix: contract cards update

* fix: show loading only when should not show empty message or cards

* chore: update quill version (#63)

* Maryia/positions-redesign/Contract card loading state and status timer updates + EmptyPositions update (#64)

* feat: loading functionality + fix for status timer

* chore: update copy for empty-positions

* revert: use hasActionButtons prop instead of impicit onClose

* DTRA-1279/ Kate/ Feat: add Date picker (#62)

* feat: add second action sheet

* feat: add date range formatting and refactored existing code

* feat: add range selection filtration

* refactor: chip and time filter

* fix: empty posituions after filtration

* refactor: do clean up

* chore: rename variables

* chore: localization

* DTRA-1279 / Kate/ Add filtration hooks  (#65)

* feat: create hooks

* refactor: rename methods

* DTRA-1279 / Kate / Add tests  (#66)

* refactor: add tests for chip component

* refactor: add tests for date picker

* refactor: add tests for contract type filter

* refactor: add tests for custom time filter button

* refactor: add tests for positions utils

* DTRA-1279 / Kate / Double filtration and extra filter options (#67)

* fix: filtration for today and yersterday

* fix: double filter

* refactor: change style after design confirmation and sort props

* refactor: start adding tets for time filter

* chore: apply suggestions

* chore: update quill and token library version

* DTRA-1279 / Kate / Add section separator  (#68)

* feat: add sections with date

* feat: make filter always visible

* refactor: style for date separator

* refactor: format time function

* refactor: add tests

* chore: remove unused wrapper

* chore: apply suggestions

* DTRA-1279 / Kate / Tech Debt (#69)

* refactor: add more test cases for time-filter

* refactor: add tests for hooks

* refactor: removed some todos

* Maryia/positions-redesign/finilise contract card + add total profit loss + initiate pagination in closed positions (#70)

* refactor: utilize Tag in ContractCardStatusTimer

* chore: add opacity transition to buttons when revealing/hiding them

* feat: add total profit + improve card

* fix: card deletion transition + total pnl positioning

* feat: add pagination on scroll (initial version)

* fix: loading state and loading more on infinite scroll in Closed tab (#71)

* DTRA-1279 / Kate / Tech Debt part 2 [WIP] (#72)

* refactor: add tests for utils functions + removed unused hook

* refactor: move total profit loss to a separate folder and add  tests

* refactor: add tests for positions

* refactor: add tests for position content file

* Maryia/positions-redesign/test contract card + fix scroll behavior, dates formatting, and filtering Closed positions (#73)

* test: contract-card

* fix: hide filters on scroll + utilize moment for formatting date in closed tab

* refactor: update quill version and refactor

* refactor: chip component (#74)

* refactor: position content page

* Maryia/positions-redesign/test: ContractCardList, ContractCardStatusTimer, PositionsStore, getCurrentTick() + refactoring (#75)

* test: contract-card-list

* test: ContractCardStatusTimer

* test: getCurrentTick() in contract.tsx in shared

* test: PositionsStore

* test: add more tests to ContractCardList

* refactor: desctructure props in mocked component

* Maryia/positions-redesign/fix: tests + address sonarcloud + use clsx (#76)

* fix: tests + address sonarcloud

* refactor: use clsx instead of classnames

* refactor: sonarcloud - reduce complexity

* fix: cards filtering in PositionsContent + tests + style+bug fixes

* build: trigger checks

* fix: hasNoActiveFilters condition

* fix: update package version and remove prop from action sheet

* chore: rename function

* Maryia/positions-redesign/feat: display correct active positions count (deriv-com#77)

* feat: display correct active positions count

* fix: BottomNav tests

* refactor: filter behaviour

* chore: add padding

* fix: positions count in footer to not show 0 (deriv-com#78)

* refactor: total profit loss

* chore: add tests for tpl and refactor date picker

* refactor: add loadre inside of empty positions

* fix: tests

* Maryia/positions-redesign/fix: loader on infinite scroll in Closed tab + make redirectTo prop optional in ContractCard (deriv-com#79)

* fix: place loading after contract cards sections

* chore: make redirection optional when clicking on contract card

* chore: rename timet

* DTRA-1279 / Kate / Add a single date selection (deriv-com#80)

* feat: add partial range

* refactor: tests

* refactor: callback

---------

Co-authored-by: kate-deriv <[email protected]>
Co-authored-by: kate-deriv <[email protected]>
Co-authored-by: balakrishna-deriv <[email protected]>
  • Loading branch information
4 people authored Jun 5, 2024
1 parent 83adf48 commit 672615a
Show file tree
Hide file tree
Showing 71 changed files with 4,055 additions and 115 deletions.
157 changes: 153 additions & 4 deletions package-lock.json

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,15 @@ import { formatDuration, getDiffDuration } from '@deriv/shared';
import { TGetCardLables } from '../types';

type TRemainingTimeProps = {
as?: React.ElementType;
end_time?: number;
start_time: moment.Moment;
format?: string;
getCardLabels: TGetCardLables;
};

const RemainingTime = ({ end_time, format, getCardLabels, start_time }: TRemainingTimeProps) => {
const RemainingTime = ({ as = 'div', end_time, format, getCardLabels, start_time }: TRemainingTimeProps) => {
const Tag = as;
if (!end_time || start_time.unix() > +end_time) {
return <React.Fragment>{''}</React.Fragment>;
}
Expand All @@ -24,7 +26,7 @@ const RemainingTime = ({ end_time, format, getCardLabels, start_time }: TRemaini
}
const is_zeroes = /^00:00$/.test(remaining_time);

return <React.Fragment>{!is_zeroes && <div className='dc-remaining-time'>{remaining_time}</div>}</React.Fragment>;
return <React.Fragment>{!is_zeroes && <Tag className='dc-remaining-time'>{remaining_time}</Tag>}</React.Fragment>;
};

export default RemainingTime;
4 changes: 2 additions & 2 deletions packages/core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -96,8 +96,8 @@
"@babel/polyfill": "^7.4.4",
"@datadog/browser-rum": "^5.11.0",
"@deriv-com/analytics": "1.5.9",
"@deriv-com/quill-tokens": "^2.0.2",
"@deriv-com/quill-ui": "^1.10.8",
"@deriv-com/quill-tokens": "^2.0.4",
"@deriv-com/quill-ui": "^1.10.13",
"@deriv-com/translations": "^1.2.3",
"@deriv-com/utils": "^0.0.24",
"@deriv/account": "^1.0.0",
Expand Down
3 changes: 1 addition & 2 deletions packages/reports/src/Containers/open-positions.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -655,8 +655,7 @@ const OpenPositions = observer(({ component_icon, ...props }: TOpenPositions) =>
/>
);
};
// TODO: Uncomment and update this when DTrader 2.0 development starts:
// if (useFeatureFlags().is_dtrader_v2_enabled) return <Text size='l'>I am Open positions for DTrader 2.0.</Text>;

return (
<React.Fragment>
<NotificationMessages />
Expand Down
5 changes: 3 additions & 2 deletions packages/reports/src/Stores/useReportsStores.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,11 @@ import React from 'react';
import { useStore } from '@deriv/stores';
import ProfitStores from './Modules/Profit/profit-store';
import StatementStores from './Modules/Statement/statement-store';
import { formatProfitTableTransactions } from './Modules/Profit/Helpers/format-response';

type TOverrideProfitStore = Omit<ProfitStores, 'data' | 'date_from' | 'totals'> & {
date_from: number;
data: { [key: string]: string }[];
data: ReturnType<typeof formatProfitTableTransactions>[];
totals: { [key: string]: unknown };
};

Expand Down Expand Up @@ -39,7 +40,7 @@ type TOverrideStatementStore = Omit<
suffix_icon: string;
};

type TReportsStore = {
export type TReportsStore = {
profit_table: TOverrideProfitStore;
statement: TOverrideStatementStore;
};
Expand Down
73 changes: 73 additions & 0 deletions packages/shared/src/utils/contract/__tests__/contract.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -786,3 +786,76 @@ describe('isForwardStartingBuyTransaction', () => {
).toBe(false);
});
});

describe('getCurrentTick', () => {
const tickStreamWithFourTicks = [
{
epoch: 1716910930,
tick: 1338.44,
tick_display_value: '1338.44',
},
{
epoch: 1716910932,
tick: 1338.71,
tick_display_value: '1338.71',
},
{
epoch: 1716910934,
tick: 1338.69,
tick_display_value: '1338.69',
},
{
epoch: 1716910936,
tick: 1338.94,
tick_display_value: '1338.94',
},
];
it('should return tick_passed if tick_passed is available for a non-digit/non-asian contract', () => {
const mockedAccuContractInfo = mockContractInfo({
contract_type: CONTRACT_TYPES.ACCUMULATOR,
tick_passed: 2,
});
expect(ContractUtils.getCurrentTick(mockedAccuContractInfo)).toEqual(2);
});
it('should return tick_stream.length - 1 if tick_passed is missing for a non-digit/non-asian contract', () => {
const mockedRiseContractInfo = mockContractInfo({
contract_type: CONTRACT_TYPES.RISE,
tick_stream: tickStreamWithFourTicks,
});
expect(ContractUtils.getCurrentTick(mockedRiseContractInfo)).toEqual(3);
});
it('should return tick_stream.length for a digit/asian contract', () => {
const mockedDigitContractInfo = mockContractInfo({
contract_type: CONTRACT_TYPES.MATCH_DIFF.MATCH,
tick_stream: tickStreamWithFourTicks,
});
const mockedAsianContractInfo = mockContractInfo({
contract_type: CONTRACT_TYPES.ASIAN.UP,
tick_stream: tickStreamWithFourTicks,
});
expect(ContractUtils.getCurrentTick(mockedDigitContractInfo)).toEqual(4);
expect(ContractUtils.getCurrentTick(mockedAsianContractInfo)).toEqual(4);
});
it('should return 0 if tick_stream is empty/missing for a digit/asian contract', () => {
const mockedDigitContractInfo = mockContractInfo({
contract_type: CONTRACT_TYPES.MATCH_DIFF.MATCH,
});
const mockedAsianContractInfo = mockContractInfo({
contract_type: CONTRACT_TYPES.ASIAN.UP,
tick_stream: [],
});
expect(ContractUtils.getCurrentTick(mockedDigitContractInfo)).toEqual(0);
expect(ContractUtils.getCurrentTick(mockedAsianContractInfo)).toEqual(0);
});
it('should return 0 if both tick_stream and tick_passed are empty/missing for a non-digit/non-asian contract', () => {
const mockedAccuContractInfo = mockContractInfo({
contract_type: CONTRACT_TYPES.ACCUMULATOR,
});
const mockedRiseContractInfo = mockContractInfo({
contract_type: CONTRACT_TYPES.RISE,
tick_stream: [],
});
expect(ContractUtils.getCurrentTick(mockedAccuContractInfo)).toEqual(0);
expect(ContractUtils.getCurrentTick(mockedRiseContractInfo)).toEqual(0);
});
});
2 changes: 1 addition & 1 deletion packages/shared/src/utils/contract/contract.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,7 @@ export const getCurrentTick = (contract_info: TContractInfo) => {
const current_tick =
isDigitContract(contract_info.contract_type) || isAsiansContract(contract_info.contract_type)
? tick_stream.length
: tick_stream.length - 1;
: contract_info.tick_passed ?? tick_stream.length - 1;
return !current_tick || current_tick < 0 ? 0 : current_tick;
};

Expand Down
11 changes: 11 additions & 0 deletions packages/stores/src/mockStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -575,6 +575,7 @@ const mock = (): TStores & { is_mock: boolean } => {
barriers: [],
error: '',
getPositionById: jest.fn(),
is_active_empty: false,
is_loading: false,
is_accumulator: false,
is_multiplier: false,
Expand Down Expand Up @@ -632,6 +633,16 @@ const mock = (): TStores & { is_mock: boolean } => {
setAccountType: jest.fn(),
setMigratedMT5Accounts: jest.fn(),
},
positions: {
openContractTypeFilter: [],
closedContractTypeFilter: [],
timeFilter: '',
customTimeRangeFilter: '',
setClosedContractTypeFilter: jest.fn(),
setOpenContractTypeFilter: jest.fn(),
setTimeFilter: jest.fn(),
setCustomTimeRangeFilter: jest.fn(),
},
trade: {
accumulator_range_list: [],
active_symbols: [],
Expand Down
5 changes: 5 additions & 0 deletions packages/stores/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -152,12 +152,14 @@ type BrandConfig = {
};

export type TPortfolioPosition = {
barrier?: number;
contract_info: ProposalOpenContract &
Portfolio1 & {
contract_update?: ContractUpdate;
};
details?: string;
display_name: string;
entry_spot?: number;
id?: number;
indicative: number;
payout?: number;
Expand All @@ -167,7 +169,9 @@ export type TPortfolioPosition = {
is_unsupported: boolean;
contract_update: ProposalOpenContract['limit_order'];
is_sell_requested: boolean;
is_valid_to_sell?: boolean;
profit_loss: number;
status?: null | string;
};

type TAppRoutingHistory = {
Expand Down Expand Up @@ -801,6 +805,7 @@ type TPortfolioStore = {
barriers: TBarriers;
error: string;
getPositionById: (id: number) => TPortfolioPosition;
is_active_empty: boolean;
is_loading: boolean;
is_multiplier: boolean;
is_accumulator: boolean;
Expand Down
6 changes: 4 additions & 2 deletions packages/trader/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -89,8 +89,8 @@
"dependencies": {
"@cloudflare/stream-react": "^1.9.1",
"@deriv-com/analytics": "1.5.9",
"@deriv-com/quill-tokens": "^2.0.2",
"@deriv-com/quill-ui": "^1.10.8",
"@deriv-com/quill-tokens": "^2.0.4",
"@deriv-com/quill-ui": "^1.10.13",
"@deriv-com/utils": "^0.0.24",
"@deriv/api-types": "1.0.172",
"@deriv/components": "^1.0.0",
Expand All @@ -104,6 +104,7 @@
"@deriv/quill-icons": "^1.22.10",
"@types/react-loadable": "^5.5.6",
"classnames": "^2.2.6",
"clsx": "^2.1.1",
"extend": "^3.0.2",
"formik": "^2.1.4",
"framer-motion": "^6.5.1",
Expand All @@ -121,6 +122,7 @@
"react-loadable": "^5.5.0",
"react-router": "^5.2.0",
"react-router-dom": "^5.2.0",
"react-swipeable": "^6.2.1",
"react-transition-group": "4.4.2"
}
}
60 changes: 33 additions & 27 deletions packages/trader/src/App/Components/Routes/binary-link.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,39 +3,45 @@ import { NavLink } from 'react-router-dom';
import { findRouteByPath, normalizePath } from './helpers';
import getRoutesConfig from '../../Constants/routes-config';

type TBinaryLinkProps = React.PropsWithChildren<{
active_class?: string;
className?: string;
to?: string;
onClick?: () => void;
}>;
type TBinaryLinkProps = Omit<React.HTMLProps<HTMLAnchorElement>, 'title' | 'ref'> &
React.PropsWithChildren<{
active_class?: string;
className?: string;
to?: string;
onClick?: () => void;
}>;

// TODO: solve circular dependency problem
// when binary link is imported into components present in routes config
// or into their descendants
const BinaryLink = ({ active_class = '', to, children, ...props }: TBinaryLinkProps) => {
const path = normalizePath(to);
const route = findRouteByPath(path, getRoutesConfig());
const BinaryLink = React.forwardRef<HTMLAnchorElement, TBinaryLinkProps>(
({ active_class = '', to, children, ...props }, ref) => {
const path = normalizePath(to);
const route = findRouteByPath(path, getRoutesConfig());

if (!route) {
throw new Error(`Route not found: ${to}`);
if (!route) {
throw new Error(`Route not found: ${to}`);
}

return to ? (
<NavLink
data-testid='dt_binary_link'
to={path}
activeClassName={active_class || 'active'}
exact={route.exact}
ref={ref}
{...props}
>
{children}
</NavLink>
) : (
<a data-testid='dt_binary_link' ref={ref} {...props}>
{children}
</a>
);
}
);

return to ? (
<NavLink
data-testid='dt_binary_link'
to={path}
activeClassName={active_class || 'active'}
exact={route.exact}
{...props}
>
{children}
</NavLink>
) : (
<a data-testid='dt_binary_link' {...props}>
{children}
</a>
);
};
BinaryLink.displayName = 'BinaryLink';

export default BinaryLink;
15 changes: 9 additions & 6 deletions packages/trader/src/App/app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import initStore from './init-store';
import 'Sass/app.scss';
import type { TCoreStores } from '@deriv/stores/types';
import TraderProviders from '../trader-providers';
import ModulesProvider from 'Stores/Providers/modules-providers';

type Apptypes = {
passthrough: {
Expand All @@ -31,12 +32,14 @@ const App = ({ passthrough }: Apptypes) => {

return (
<TraderProviders store={root_store}>
<Routes />
<TradeModals />
<NetworkStatusToastErrorPopup />
<TradeHeaderExtensions store={root_store} />
<TradeFooterExtensions />
<TradeSettingsExtensions store={root_store} />
<ModulesProvider store={root_store}>
<Routes />
<TradeModals />
<NetworkStatusToastErrorPopup />
<TradeHeaderExtensions store={root_store} />
<TradeFooterExtensions />
<TradeSettingsExtensions store={root_store} />
</ModulesProvider>
</TraderProviders>
);
};
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import React from 'react';
import { render, screen } from '@testing-library/react';
import BottomNav from '../bottom-nav';
import userEvent from '@testing-library/user-event';
import { StoreProvider, mockStore } from '@deriv/stores';
import BottomNav from '../bottom-nav';

jest.mock('../bottom-nav-item', () => {
return jest.fn(({ index, setSelectedIndex }) => (
Expand All @@ -19,11 +20,13 @@ describe('BottomNav', () => {
const mockedMarketsContainer = <div>MockedMarkets</div>;
const mockedPositionsContainer = <div>MockedPositions</div>;
const renderedBottomNav = (
<BottomNav>
<div>{mockedTradeContainer}</div>
<div>{mockedMarketsContainer}</div>
<div>{mockedPositionsContainer}</div>
</BottomNav>
<StoreProvider store={mockStore({})}>
<BottomNav>
<div>{mockedTradeContainer}</div>
<div>{mockedMarketsContainer}</div>
<div>{mockedPositionsContainer}</div>
</BottomNav>
</StoreProvider>
);
it('should render correctly', () => {
const { container } = render(renderedBottomNav);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
gap: var(--core-spacing-500);
width: 100%;
border-top: 1px solid var(--core-color-opacity-black-100); // waiting on quill tokens in deriv-app
background-color: var(--core-color-solid-slate-50);
}

&-selection {
Expand Down
Loading

0 comments on commit 672615a

Please sign in to comment.