chore(trading): add market dropdown to account history (#2971)
This commit is contained in:
parent
0ba54cd8a4
commit
e4bf61c2e2
@ -3,12 +3,14 @@ query AccountHistory(
|
|||||||
$assetId: ID!
|
$assetId: ID!
|
||||||
$accountTypes: [AccountType!]
|
$accountTypes: [AccountType!]
|
||||||
$dateRange: DateRange
|
$dateRange: DateRange
|
||||||
|
$marketIds: [ID!]
|
||||||
) {
|
) {
|
||||||
balanceChanges(
|
balanceChanges(
|
||||||
filter: {
|
filter: {
|
||||||
partyIds: [$partyId]
|
partyIds: [$partyId]
|
||||||
accountTypes: $accountTypes
|
accountTypes: $accountTypes
|
||||||
assetId: $assetId
|
assetId: $assetId
|
||||||
|
marketIds: $marketIds
|
||||||
}
|
}
|
||||||
dateRange: $dateRange
|
dateRange: $dateRange
|
||||||
) {
|
) {
|
||||||
|
@ -8,6 +8,7 @@ export type AccountHistoryQueryVariables = Types.Exact<{
|
|||||||
assetId: Types.Scalars['ID'];
|
assetId: Types.Scalars['ID'];
|
||||||
accountTypes?: Types.InputMaybe<Array<Types.AccountType> | Types.AccountType>;
|
accountTypes?: Types.InputMaybe<Array<Types.AccountType> | Types.AccountType>;
|
||||||
dateRange?: Types.InputMaybe<Types.DateRange>;
|
dateRange?: Types.InputMaybe<Types.DateRange>;
|
||||||
|
marketIds?: Types.InputMaybe<Array<Types.Scalars['ID']> | Types.Scalars['ID']>;
|
||||||
}>;
|
}>;
|
||||||
|
|
||||||
|
|
||||||
@ -23,9 +24,9 @@ export type AccountsWithBalanceQuery = { __typename?: 'Query', balanceChanges: {
|
|||||||
|
|
||||||
|
|
||||||
export const AccountHistoryDocument = gql`
|
export const AccountHistoryDocument = gql`
|
||||||
query AccountHistory($partyId: ID!, $assetId: ID!, $accountTypes: [AccountType!], $dateRange: DateRange) {
|
query AccountHistory($partyId: ID!, $assetId: ID!, $accountTypes: [AccountType!], $dateRange: DateRange, $marketIds: [ID!]) {
|
||||||
balanceChanges(
|
balanceChanges(
|
||||||
filter: {partyIds: [$partyId], accountTypes: $accountTypes, assetId: $assetId}
|
filter: {partyIds: [$partyId], accountTypes: $accountTypes, assetId: $assetId, marketIds: $marketIds}
|
||||||
dateRange: $dateRange
|
dateRange: $dateRange
|
||||||
) {
|
) {
|
||||||
edges {
|
edges {
|
||||||
@ -58,6 +59,7 @@ export const AccountHistoryDocument = gql`
|
|||||||
* assetId: // value for 'assetId'
|
* assetId: // value for 'assetId'
|
||||||
* accountTypes: // value for 'accountTypes'
|
* accountTypes: // value for 'accountTypes'
|
||||||
* dateRange: // value for 'dateRange'
|
* dateRange: // value for 'dateRange'
|
||||||
|
* marketIds: // value for 'marketIds'
|
||||||
* },
|
* },
|
||||||
* });
|
* });
|
||||||
*/
|
*/
|
||||||
|
@ -7,7 +7,7 @@ import {
|
|||||||
import { useVegaWallet } from '@vegaprotocol/wallet';
|
import { useVegaWallet } from '@vegaprotocol/wallet';
|
||||||
import compact from 'lodash/compact';
|
import compact from 'lodash/compact';
|
||||||
import type { ChangeEvent } from 'react';
|
import type { ChangeEvent } from 'react';
|
||||||
import { useMemo, useState } from 'react';
|
import { useCallback, useEffect, useMemo, useState } from 'react';
|
||||||
import type { AccountHistoryQuery } from './__generated__/AccountHistory';
|
import type { AccountHistoryQuery } from './__generated__/AccountHistory';
|
||||||
import { useAccountHistoryQuery } from './__generated__/AccountHistory';
|
import { useAccountHistoryQuery } from './__generated__/AccountHistory';
|
||||||
import * as Schema from '@vegaprotocol/types';
|
import * as Schema from '@vegaprotocol/types';
|
||||||
@ -25,8 +25,10 @@ import {
|
|||||||
import { AccountTypeMapping } from '@vegaprotocol/types';
|
import { AccountTypeMapping } from '@vegaprotocol/types';
|
||||||
import { PriceChart } from 'pennant';
|
import { PriceChart } from 'pennant';
|
||||||
import 'pennant/dist/style.css';
|
import 'pennant/dist/style.css';
|
||||||
import { accountsOnlyDataProvider } from '@vegaprotocol/accounts';
|
import type { Account } from '@vegaprotocol/accounts';
|
||||||
|
import { accountsDataProvider } from '@vegaprotocol/accounts';
|
||||||
import { useDataProvider } from '@vegaprotocol/react-helpers';
|
import { useDataProvider } from '@vegaprotocol/react-helpers';
|
||||||
|
import type { Market } from '@vegaprotocol/market-list';
|
||||||
|
|
||||||
const DateRange = {
|
const DateRange = {
|
||||||
RANGE_1D: '1D',
|
RANGE_1D: '1D',
|
||||||
@ -97,7 +99,7 @@ const AccountHistoryManager = ({
|
|||||||
);
|
);
|
||||||
|
|
||||||
const { data: accounts } = useDataProvider({
|
const { data: accounts } = useDataProvider({
|
||||||
dataProvider: accountsOnlyDataProvider,
|
dataProvider: accountsDataProvider,
|
||||||
variables: variablesForOneTimeQuery,
|
variables: variablesForOneTimeQuery,
|
||||||
skip: !pubKey,
|
skip: !pubKey,
|
||||||
});
|
});
|
||||||
@ -118,6 +120,45 @@ const AccountHistoryManager = ({
|
|||||||
const [range, setRange] = useState<typeof DateRange[keyof typeof DateRange]>(
|
const [range, setRange] = useState<typeof DateRange[keyof typeof DateRange]>(
|
||||||
DateRange.RANGE_1M
|
DateRange.RANGE_1M
|
||||||
);
|
);
|
||||||
|
const [market, setMarket] = useState<Market | null>(null);
|
||||||
|
const marketFilterCb = useCallback(
|
||||||
|
(item: Market) =>
|
||||||
|
!asset?.id ||
|
||||||
|
item.tradableInstrument.instrument.product.settlementAsset.id ===
|
||||||
|
asset?.id,
|
||||||
|
[asset?.id]
|
||||||
|
);
|
||||||
|
const markets = useMemo<Market[] | null>(() => {
|
||||||
|
const arr =
|
||||||
|
accounts
|
||||||
|
?.filter((item: Account) => Boolean(item && item.market))
|
||||||
|
.map<Market>((item) => item.market as Market) ?? null;
|
||||||
|
return arr
|
||||||
|
? Array.from(
|
||||||
|
new Set(
|
||||||
|
arr
|
||||||
|
.filter(marketFilterCb)
|
||||||
|
.sort((a, b) =>
|
||||||
|
a.tradableInstrument.instrument.code.localeCompare(
|
||||||
|
b.tradableInstrument.instrument.code
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
: null;
|
||||||
|
}, [accounts, marketFilterCb]);
|
||||||
|
const resolveMarket = useCallback(
|
||||||
|
(m: Market) => {
|
||||||
|
setMarket(m);
|
||||||
|
const newAssetId =
|
||||||
|
m.tradableInstrument.instrument.product.settlementAsset.id;
|
||||||
|
const newAsset = assets.find((item) => item.id === newAssetId);
|
||||||
|
if ((!asset || (assets && newAssetId !== asset.id)) && newAsset) {
|
||||||
|
setAsset(newAsset);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[asset, assets]
|
||||||
|
);
|
||||||
|
|
||||||
const variables = useMemo(
|
const variables = useMemo(
|
||||||
() => ({
|
() => ({
|
||||||
@ -126,62 +167,110 @@ const AccountHistoryManager = ({
|
|||||||
accountTypes: accountType ? [accountType] : undefined,
|
accountTypes: accountType ? [accountType] : undefined,
|
||||||
dateRange:
|
dateRange:
|
||||||
range === 'All' ? undefined : { start: calculateStartDate(range) },
|
range === 'All' ? undefined : { start: calculateStartDate(range) },
|
||||||
|
marketIds: market?.id ? [market.id] : undefined,
|
||||||
}),
|
}),
|
||||||
[pubKey, asset, accountType, range]
|
[pubKey, asset, accountType, range, market?.id]
|
||||||
);
|
);
|
||||||
|
|
||||||
const { data } = useAccountHistoryQuery({
|
const { data } = useAccountHistoryQuery({
|
||||||
variables,
|
variables,
|
||||||
skip: !asset || !pubKey,
|
skip: !asset || !pubKey,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const accountTypeMenu = useMemo(() => {
|
||||||
|
return (
|
||||||
|
<DropdownMenu
|
||||||
|
trigger={
|
||||||
|
<DropdownMenuTrigger>
|
||||||
|
{accountType
|
||||||
|
? `${
|
||||||
|
AccountTypeMapping[
|
||||||
|
accountType as keyof typeof Schema.AccountType
|
||||||
|
]
|
||||||
|
} Account`
|
||||||
|
: t('Select account type')}
|
||||||
|
</DropdownMenuTrigger>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<DropdownMenuContent>
|
||||||
|
{[
|
||||||
|
Schema.AccountType.ACCOUNT_TYPE_GENERAL,
|
||||||
|
Schema.AccountType.ACCOUNT_TYPE_BOND,
|
||||||
|
Schema.AccountType.ACCOUNT_TYPE_MARGIN,
|
||||||
|
].map((type) => (
|
||||||
|
<DropdownMenuItem
|
||||||
|
key={type}
|
||||||
|
onClick={() => setAccountType(type as Schema.AccountType)}
|
||||||
|
>
|
||||||
|
{AccountTypeMapping[type as keyof typeof Schema.AccountType]}
|
||||||
|
</DropdownMenuItem>
|
||||||
|
))}
|
||||||
|
</DropdownMenuContent>
|
||||||
|
</DropdownMenu>
|
||||||
|
);
|
||||||
|
}, [accountType]);
|
||||||
|
const assetsMenu = useMemo(() => {
|
||||||
|
return (
|
||||||
|
<DropdownMenu
|
||||||
|
trigger={
|
||||||
|
<DropdownMenuTrigger>
|
||||||
|
{asset ? asset.symbol : t('Select asset')}
|
||||||
|
</DropdownMenuTrigger>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<DropdownMenuContent>
|
||||||
|
{assets.map((a) => (
|
||||||
|
<DropdownMenuItem key={a.id} onClick={() => setAsset(a)}>
|
||||||
|
{a.symbol}
|
||||||
|
</DropdownMenuItem>
|
||||||
|
))}
|
||||||
|
</DropdownMenuContent>
|
||||||
|
</DropdownMenu>
|
||||||
|
);
|
||||||
|
}, [assets, asset]);
|
||||||
|
const marketsMenu = useMemo(() => {
|
||||||
|
return accountType === Schema.AccountType.ACCOUNT_TYPE_MARGIN &&
|
||||||
|
markets?.length ? (
|
||||||
|
<DropdownMenu
|
||||||
|
trigger={
|
||||||
|
<DropdownMenuTrigger>
|
||||||
|
{market
|
||||||
|
? market.tradableInstrument.instrument.code
|
||||||
|
: t('Select market')}
|
||||||
|
</DropdownMenuTrigger>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<DropdownMenuContent>
|
||||||
|
{markets?.map((m) => (
|
||||||
|
<DropdownMenuItem key={m.id} onClick={() => resolveMarket(m)}>
|
||||||
|
{m.tradableInstrument.instrument.code}
|
||||||
|
</DropdownMenuItem>
|
||||||
|
))}
|
||||||
|
</DropdownMenuContent>
|
||||||
|
</DropdownMenu>
|
||||||
|
) : null;
|
||||||
|
}, [markets, market, accountType, resolveMarket]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (
|
||||||
|
accountType !== Schema.AccountType.ACCOUNT_TYPE_MARGIN ||
|
||||||
|
(asset &&
|
||||||
|
market &&
|
||||||
|
market.tradableInstrument.instrument.product.settlementAsset.id !==
|
||||||
|
asset.id)
|
||||||
|
) {
|
||||||
|
setMarket(null);
|
||||||
|
}
|
||||||
|
}, [accountType, asset, market]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="h-full w-full flex flex-col gap-8">
|
<div className="h-full w-full flex flex-col gap-8">
|
||||||
<div className="w-full flex flex-col-reverse lg:flex-row items-start lg:items-center justify-between gap-4 px-2">
|
<div className="w-full flex flex-col-reverse lg:flex-row items-start lg:items-center justify-between gap-4 px-2">
|
||||||
<div className="flex items-center gap-4 shrink-0">
|
<div className="flex items-center gap-4 shrink-0">
|
||||||
<DropdownMenu
|
<>
|
||||||
trigger={
|
{accountTypeMenu}
|
||||||
<DropdownMenuTrigger>
|
{assetsMenu}
|
||||||
{accountType
|
{marketsMenu}
|
||||||
? `${
|
</>
|
||||||
AccountTypeMapping[
|
|
||||||
accountType as keyof typeof Schema.AccountType
|
|
||||||
]
|
|
||||||
} Account`
|
|
||||||
: t('Select account type')}
|
|
||||||
</DropdownMenuTrigger>
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<DropdownMenuContent>
|
|
||||||
{[
|
|
||||||
Schema.AccountType.ACCOUNT_TYPE_GENERAL,
|
|
||||||
Schema.AccountType.ACCOUNT_TYPE_BOND,
|
|
||||||
Schema.AccountType.ACCOUNT_TYPE_MARGIN,
|
|
||||||
].map((type) => (
|
|
||||||
<DropdownMenuItem
|
|
||||||
key={type}
|
|
||||||
onClick={() => setAccountType(type as Schema.AccountType)}
|
|
||||||
>
|
|
||||||
{AccountTypeMapping[type as keyof typeof Schema.AccountType]}
|
|
||||||
</DropdownMenuItem>
|
|
||||||
))}
|
|
||||||
</DropdownMenuContent>
|
|
||||||
</DropdownMenu>
|
|
||||||
<DropdownMenu
|
|
||||||
trigger={
|
|
||||||
<DropdownMenuTrigger>
|
|
||||||
{asset ? asset.symbol : t('Select asset')}
|
|
||||||
</DropdownMenuTrigger>
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<DropdownMenuContent>
|
|
||||||
{assets.map((a) => (
|
|
||||||
<DropdownMenuItem key={a.id} onClick={() => setAsset(a)}>
|
|
||||||
{a.symbol}
|
|
||||||
</DropdownMenuItem>
|
|
||||||
))}
|
|
||||||
</DropdownMenuContent>
|
|
||||||
</DropdownMenu>
|
|
||||||
</div>
|
</div>
|
||||||
<div className="pt-1 justify-items-end">
|
<div className="pt-1 justify-items-end">
|
||||||
<Toggle
|
<Toggle
|
||||||
|
4
libs/types/src/__generated__/types.ts
generated
4
libs/types/src/__generated__/types.ts
generated
@ -2761,12 +2761,16 @@ export type PositionUpdate = {
|
|||||||
__typename?: 'PositionUpdate';
|
__typename?: 'PositionUpdate';
|
||||||
/** Average entry price for this position */
|
/** Average entry price for this position */
|
||||||
averageEntryPrice: Scalars['String'];
|
averageEntryPrice: Scalars['String'];
|
||||||
|
/** The total amount of profit and loss that was not transferred due to loss socialisation */
|
||||||
|
lossSocializationAmount: Scalars['String'];
|
||||||
/** Market relating to this position */
|
/** Market relating to this position */
|
||||||
marketId: Scalars['ID'];
|
marketId: Scalars['ID'];
|
||||||
/** Open volume (int64) */
|
/** Open volume (int64) */
|
||||||
openVolume: Scalars['String'];
|
openVolume: Scalars['String'];
|
||||||
/** The party holding this position */
|
/** The party holding this position */
|
||||||
partyId: Scalars['ID'];
|
partyId: Scalars['ID'];
|
||||||
|
/** Enum set if the position was closed out or orders were removed because party was distressed */
|
||||||
|
positionStatus: PositionStatus;
|
||||||
/** Realised Profit and Loss (int64) */
|
/** Realised Profit and Loss (int64) */
|
||||||
realisedPNL: Scalars['String'];
|
realisedPNL: Scalars['String'];
|
||||||
/** Unrealised Profit and Loss (int64) */
|
/** Unrealised Profit and Loss (int64) */
|
||||||
|
Loading…
Reference in New Issue
Block a user