chore(trading): liquidity table DRY (#3346)

This commit is contained in:
Bartłomiej Głownia 2023-04-03 15:02:43 +02:00 committed by GitHub
parent 0914e7ce4b
commit 8463d371ad
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 103 additions and 183 deletions

View File

@ -1,5 +1,5 @@
import {
getId,
matchFilter,
liquidityProvisionsDataProvider,
LiquidityTable,
lpAggregatedDataProvider,
@ -17,7 +17,6 @@ import {
useNetworkParams,
updateGridData,
} from '@vegaprotocol/react-helpers';
import * as Schema from '@vegaprotocol/types';
import {
AsyncRenderer,
Tab,
@ -26,19 +25,18 @@ import {
Indicator,
} from '@vegaprotocol/ui-toolkit';
import { useVegaWallet } from '@vegaprotocol/wallet';
import { memo, useCallback, useEffect, useMemo, useRef, useState } from 'react';
import { memo, useCallback, useEffect, useRef, useState } from 'react';
import { Header, HeaderStat, HeaderTitle } from '../../components/header';
import type { AgGridReact } from 'ag-grid-react';
import type { IGetRowsParams } from 'ag-grid-community';
import type { LiquidityProvisionData } from '@vegaprotocol/liquidity';
import type { LiquidityProvisionData, Filter } from '@vegaprotocol/liquidity';
import { Link, useParams } from 'react-router-dom';
import { Links, Routes } from '../../pages/client-router';
import { useMarket, useStaticMarketData } from '@vegaprotocol/market-list';
import isEqual from 'lodash/isEqual';
const enum LiquidityTabs {
Active = 'active',
@ -67,8 +65,10 @@ const useReloadLiquidityData = (marketId: string | undefined) => {
export const LiquidityContainer = ({
marketId,
filter,
}: {
marketId: string | undefined;
filter?: Filter;
}) => {
const gridRef = useRef<AgGridReact | null>(null);
const { data: market } = useMarket(marketId);
@ -87,7 +87,7 @@ export const LiquidityContainer = ({
const { data, loading, error } = useDataProvider({
dataProvider: lpAggregatedDataProvider,
update,
variables: { marketId: marketId || '' },
variables: { marketId: marketId || '', filter },
skip: !marketId,
});
@ -216,178 +216,56 @@ const LiquidityViewHeader = memo(({ marketId }: { marketId?: string }) => {
});
LiquidityViewHeader.displayName = 'LiquidityViewHeader';
const filterLiquidities = (
tab: string,
liquidities?: LiquidityProvisionData[] | null,
pubKey?: string | null
) => {
switch (tab) {
case LiquidityTabs.MyLiquidityProvision:
return pubKey
? (liquidities || []).filter((e) => e.party.id === pubKey)
: [];
break;
case LiquidityTabs.Active:
return (liquidities || []).filter(
(e) => e.status === Schema.LiquidityProvisionStatus.STATUS_ACTIVE
);
case LiquidityTabs.Inactive:
return (liquidities || []).filter(
(e) => e.status !== Schema.LiquidityProvisionStatus.STATUS_ACTIVE
);
default:
return [];
}
};
export const LiquidityViewContainer = ({
marketId,
}: {
marketId: string | undefined;
}) => {
const [tab, setTab] = useState('');
const [tab, setTab] = useState<string | undefined>(undefined);
const { pubKey } = useVegaWallet();
const [liquidityProviders, setLiquidityProviders] = useState<
LiquidityProvisionData[] | null
>();
const gridRef = useRef<AgGridReact | null>(null);
const { data: market } = useMarket(marketId);
const dataRef = useRef<LiquidityProvisionData[] | null>(null);
// To be removed when liquidityProvision subscriptions are working
useReloadLiquidityData(marketId);
const update = useCallback(
({ data }: { data: LiquidityProvisionData[] | null }) => {
if (!dataRef.current) {
setLiquidityProviders(data);
dataRef.current = data;
}
if (!gridRef.current?.api) {
return false;
}
const updateRows: LiquidityProvisionData[] = [];
const addRows: LiquidityProvisionData[] = [];
if (gridRef.current?.api?.getModel().getType() === 'infinite') {
dataRef.current = data;
gridRef.current.api.refreshInfiniteCache();
} else {
const filteredData = filterLiquidities(tab, data, pubKey as string);
filteredData?.forEach((d) => {
const rowNode = gridRef.current?.api?.getRowNode(getId(d));
if (rowNode) {
if (!isEqual(rowNode.data, d)) {
updateRows.push(d);
}
} else {
addRows.push(d);
}
});
gridRef.current?.api?.applyTransaction({
update: updateRows,
add: addRows,
addIndex: 0,
});
}
return true;
},
[gridRef, tab, pubKey]
);
const { loading, error } = useDataProvider({
const { data } = useDataProvider({
dataProvider: lpAggregatedDataProvider,
update,
skipUpdates: true,
variables: { marketId: marketId || '' },
skip: !marketId,
});
const assetDecimalPlaces =
market?.tradableInstrument.instrument.product.settlementAsset.decimals || 0;
const symbol =
market?.tradableInstrument.instrument.product.settlementAsset.symbol;
const { params } = useNetworkParams([
NetworkParams.market_liquidity_stakeToCcyVolume,
NetworkParams.market_liquidity_targetstake_triggering_ratio,
]);
const stakeToCcyVolume = params.market_liquidity_stakeToCcyVolume;
const myLpEdges = useMemo(
() =>
filterLiquidities(
LiquidityTabs.MyLiquidityProvision,
liquidityProviders,
pubKey
),
[liquidityProviders, pubKey]
);
const activeEdges = useMemo(
() => filterLiquidities(LiquidityTabs.Active, liquidityProviders),
[liquidityProviders]
);
const inactiveEdges = useMemo(
() => filterLiquidities(LiquidityTabs.Inactive, liquidityProviders),
[liquidityProviders]
);
useEffect(() => {
if (tab) {
return;
if (data) {
if (pubKey && data.some((lp) => matchFilter({ partyId: pubKey }, lp))) {
setTab(LiquidityTabs.MyLiquidityProvision);
return;
}
if (data.some((lp) => matchFilter({ active: true }, lp))) {
setTab(LiquidityTabs.Active);
return;
}
setTab(LiquidityTabs.Inactive);
}
let initialTab = LiquidityTabs.Active;
if (myLpEdges.length > 0) {
initialTab = LiquidityTabs.MyLiquidityProvision;
}
if (activeEdges?.length) {
initialTab = LiquidityTabs.Active;
} else if (inactiveEdges.length > 0) {
initialTab = LiquidityTabs.Inactive;
}
setTab(initialTab);
}, [tab, myLpEdges?.length, activeEdges?.length, inactiveEdges?.length]);
}, [data, pubKey]);
return (
<AsyncRenderer loading={loading} error={error} data={liquidityProviders}>
<div className="h-full grid grid-rows-[min-content_1fr]">
<LiquidityViewHeader marketId={marketId} />
<Tabs value={tab} onValueChange={setTab}>
<Tab
id={LiquidityTabs.MyLiquidityProvision}
name={t('My liquidity provision')}
hidden={!pubKey}
>
{myLpEdges && (
<LiquidityTable
ref={gridRef}
rowData={myLpEdges}
symbol={symbol}
stakeToCcyVolume={stakeToCcyVolume}
assetDecimalPlaces={assetDecimalPlaces}
/>
)}
</Tab>
<Tab id={LiquidityTabs.Active} name={t('Active')}>
{activeEdges && (
<LiquidityTable
ref={gridRef}
rowData={activeEdges}
symbol={symbol}
assetDecimalPlaces={assetDecimalPlaces}
stakeToCcyVolume={stakeToCcyVolume}
/>
)}
</Tab>
<Tab id={LiquidityTabs.Inactive} name={t('Inactive')}>
{inactiveEdges && (
<LiquidityTable
ref={gridRef}
rowData={inactiveEdges}
symbol={symbol}
assetDecimalPlaces={assetDecimalPlaces}
stakeToCcyVolume={stakeToCcyVolume}
/>
)}
</Tab>
</Tabs>
</div>
</AsyncRenderer>
<div className="h-full grid grid-rows-[min-content_1fr]">
<LiquidityViewHeader marketId={marketId} />
<Tabs value={tab || LiquidityTabs.Active} onValueChange={setTab}>
<Tab
id={LiquidityTabs.MyLiquidityProvision}
name={t('My liquidity provision')}
hidden={!pubKey}
>
<LiquidityContainer
marketId={marketId}
filter={{ partyId: pubKey || undefined }}
/>
</Tab>
<Tab id={LiquidityTabs.Active} name={t('Active')}>
<LiquidityContainer marketId={marketId} filter={{ active: true }} />
</Tab>
<Tab id={LiquidityTabs.Inactive} name={t('Inactive')}>
<LiquidityContainer marketId={marketId} filter={{ active: false }} />
</Tab>
</Tabs>
</div>
);
};

View File

@ -153,35 +153,84 @@ export const liquidityFeeShareDataProvider = makeDataProvider<
},
});
export type Filter = { partyId?: string; active?: boolean };
export const lpAggregatedDataProvider = makeDerivedDataProvider<
ReturnType<typeof getLiquidityProvision>,
LiquidityProvisionData[],
never,
MarketLpQueryVariables
MarketLpQueryVariables & { filter?: Filter }
>(
[
liquidityProvisionsDataProvider,
marketLiquidityDataProvider,
liquidityFeeShareDataProvider,
(callback, client, variables) =>
liquidityProvisionsDataProvider(callback, client, {
marketId: variables.marketId,
}),
(callback, client, variables) =>
marketLiquidityDataProvider(callback, client, {
marketId: variables.marketId,
}),
(callback, client, variables) =>
liquidityFeeShareDataProvider(callback, client, {
marketId: variables.marketId,
}),
],
([
liquidityProvisions,
marketLiquidity,
liquidityFeeShare,
]): LiquidityProvisionData[] => {
(
[liquidityProvisions, marketLiquidity, liquidityFeeShare],
{ filter }
): LiquidityProvisionData[] => {
return getLiquidityProvision(
liquidityProvisions,
marketLiquidity,
liquidityFeeShare
liquidityFeeShare,
filter
);
}
);
export const matchFilter = (
filter: Filter,
lp: LiquidityProvisionFieldsFragment
) => {
if (filter.partyId && lp.party.id !== filter.partyId) {
return false;
}
if (
filter.active === true &&
lp.status !== Schema.LiquidityProvisionStatus.STATUS_ACTIVE
) {
return false;
}
if (
filter.active === false &&
lp.status === Schema.LiquidityProvisionStatus.STATUS_ACTIVE
) {
return false;
}
return true;
};
export const getLiquidityProvision = (
liquidityProvisions: LiquidityProvisionFieldsFragment[],
marketLiquidity: MarketLpQuery,
liquidityFeeShare: LiquidityProviderFeeShareFieldsFragment[]
liquidityFeeShare: LiquidityProviderFeeShareFieldsFragment[],
filter?: Filter
): LiquidityProvisionData[] => {
return liquidityProvisions
.filter((lp) => {
if (
![
Schema.LiquidityProvisionStatus.STATUS_ACTIVE,
Schema.LiquidityProvisionStatus.STATUS_UNDEPLOYED,
Schema.LiquidityProvisionStatus.STATUS_PENDING,
].includes(lp.status)
) {
return false;
}
if (filter && !matchFilter(filter, lp)) {
return false;
}
return true;
})
.map((lp) => {
const market = marketLiquidity?.market;
const feeShare = liquidityFeeShare.find(
@ -210,14 +259,7 @@ export const getLiquidityProvision = (
.decimals,
balance,
};
})
.filter((e) =>
[
Schema.LiquidityProvisionStatus.STATUS_ACTIVE,
Schema.LiquidityProvisionStatus.STATUS_UNDEPLOYED,
Schema.LiquidityProvisionStatus.STATUS_PENDING,
].includes(e.status)
);
});
};
export interface LiquidityProvisionData