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,
};