From f304bb069adc4432148cbadd05b021ce28a3c056 Mon Sep 17 00:00:00 2001 From: moo-onthelawn <70078372+moo-onthelawn@users.noreply.github.com> Date: Fri, 12 Jan 2024 14:44:09 -0500 Subject: [PATCH] TRCL-1979 Show open positions / orders in portfolio sidebar (#228) * add tags for open orders + positions * clean up, use new num selector function * update logic for open orders --- src/pages/portfolio/Portfolio.tsx | 27 ++++++++++++++++++++++++--- src/state/accountCalculators.ts | 9 +-------- src/state/accountSelectors.ts | 16 +++++++++++----- 3 files changed, 36 insertions(+), 16 deletions(-) diff --git a/src/pages/portfolio/Portfolio.tsx b/src/pages/portfolio/Portfolio.tsx index 53eae6c..f3652b0 100644 --- a/src/pages/portfolio/Portfolio.tsx +++ b/src/pages/portfolio/Portfolio.tsx @@ -17,11 +17,14 @@ import { TransferHistoryTable } from '@/views/tables/TransferHistoryTable'; import { Button } from '@/components/Button'; import { Icon, IconName } from '@/components/Icon'; import { NavigationMenu } from '@/components/NavigationMenu'; +import { Tag, TagType } from '@/components/Tag'; import { WithSidebar } from '@/components/WithSidebar'; -import { getOnboardingState, getSubaccount } from '@/state/accountSelectors'; +import { getOnboardingState, getSubaccount, getTradeInfoNumbers } from '@/state/accountSelectors'; import { openDialog } from '@/state/dialogs'; +import { shortenNumberForDisplay } from '@/lib/numbers'; + import { PortfolioNavMobile } from './PortfolioNavMobile'; import { LoadingSpace } from '@/components/Loading/LoadingSpinner'; @@ -42,6 +45,10 @@ export default () => { const { freeCollateral } = useSelector(getSubaccount, shallowEqual) || {}; const { nativeTokenBalance } = useAccountBalance(); + const { numTotalPositions, numTotalOpenOrders } = useSelector(getTradeInfoNumbers, shallowEqual) || {}; + const numPositions = shortenNumberForDisplay(numTotalPositions); + const numOrders = shortenNumberForDisplay(numTotalOpenOrders); + const usdcBalance = freeCollateral?.current || 0; useDocumentTitle(stringGetter({ key: STRING_KEYS.PORTFOLIO })); @@ -119,13 +126,27 @@ export default () => { { value: PortfolioRoute.Positions, slotBefore: , - label: stringGetter({ key: STRING_KEYS.POSITIONS }), + label: ( + <> + {stringGetter({ key: STRING_KEYS.POSITIONS })} + {numPositions > 0 && ( + {numPositions} + )} + + ), href: PortfolioRoute.Positions, }, { value: PortfolioRoute.Orders, slotBefore: , - label: stringGetter({ key: STRING_KEYS.ORDERS }), + label: ( + <> + {stringGetter({ key: STRING_KEYS.ORDERS })} + {numOrders > 0 && ( + {numOrders} + )} + + ), href: PortfolioRoute.Orders, }, { diff --git a/src/state/accountCalculators.ts b/src/state/accountCalculators.ts index cc1abad..e78b4a9 100644 --- a/src/state/accountCalculators.ts +++ b/src/state/accountCalculators.ts @@ -1,10 +1,8 @@ import { createSelector } from 'reselect'; -import { SubaccountPosition } from '@/constants/abacus'; import { OnboardingState, OnboardingSteps } from '@/constants/account'; import { - getExistingOpenPositions, getOnboardingGuards, getOnboardingState, getSubaccountId, @@ -60,13 +58,8 @@ export const calculateIsAccountViewOnly = createSelector( ); /** - * @description calculate whether the subaccount has open positions + * @description calculate whether the subaccount has uncommitted positions */ -export const calculateHasOpenPositions = createSelector( - [getExistingOpenPositions], - (openPositions?: SubaccountPosition[]) => (openPositions?.length || 0) > 0 -); - export const calculateHasUncommittedOrders = createSelector( [getUncommittedOrderClientIds], (uncommittedOrderClientIds: number[]) => uncommittedOrderClientIds.length > 0 diff --git a/src/state/accountSelectors.ts b/src/state/accountSelectors.ts index 9594b46..809a027 100644 --- a/src/state/accountSelectors.ts +++ b/src/state/accountSelectors.ts @@ -2,6 +2,7 @@ import { OrderSide } from '@dydxprotocol/v4-client-js'; import { createSelector } from 'reselect'; import { + type AbacusOrderStatuses, type SubaccountOrder, type SubaccountFill, type SubaccountFundingPayment, @@ -43,7 +44,6 @@ export const getSubaccountBuyingPower = (state: RootState) => state.account.suba export const getSubaccountEquity = (state: RootState) => state.account.subaccount?.equity; export const getSubaccountHistoricalPnl = (state: RootState) => state.account?.historicalPnl; - /** * @param state * @returns list of a subaccount's open positions. Each item in the list is an open position in a different market. @@ -258,6 +258,14 @@ export const getCurrentMarketFundingPayments = createSelector( !currentMarketId ? [] : marketFundingPayments[currentMarketId] ); +/** + * @param state + * @returns boolean on whether an order status is considered open + */ +const isOpenOrderStatus = (status: AbacusOrderStatuses) => { + return status !== AbacusOrderStatus.filled && status !== AbacusOrderStatus.cancelled; +}; + /** * @param state * @returns Total numbers of the subaccount's open positions, open orders and fills @@ -266,8 +274,7 @@ export const getTradeInfoNumbers = createSelector( [getExistingOpenPositions, getSubaccountOrders, getSubaccountFills, getSubaccountFundingPayments], (positions, orders, fills, fundingPayments) => ({ numTotalPositions: positions?.length, - numTotalOpenOrders: orders?.filter((order) => order.status !== AbacusOrderStatus.cancelled) - .length, + numTotalOpenOrders: orders?.filter((order) => isOpenOrderStatus(order.status)).length, numTotalFills: fills?.length, numTotalFundingPayments: fundingPayments?.length, }) @@ -281,8 +288,7 @@ export const getCurrentMarketTradeInfoNumbers = createSelector( [getCurrentMarketOrders, getCurrentMarketFills, getCurrentMarketFundingPayments], (marketOrders, marketFills, marketFundingPayments) => { return { - numOpenOrders: marketOrders?.filter((order) => order.status !== AbacusOrderStatus.cancelled) - .length, + numOpenOrders: marketOrders?.filter((order) => isOpenOrderStatus(order.status)).length, numFills: marketFills?.length, numFundingPayments: marketFundingPayments?.length, };