fix(accounts): avoid last row re-rendering (#3950)

This commit is contained in:
Bartłomiej Głownia 2023-06-05 12:40:34 +02:00 committed by GitHub
parent 18c034b910
commit d6e2432955
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 379 additions and 269 deletions

View File

@ -1,11 +1,12 @@
import { assetsProvider } from '@vegaprotocol/assets'; import { assetsMapProvider } from '@vegaprotocol/assets';
import { marketsProvider } from '@vegaprotocol/markets';
import { removePaginationWrapper } from '@vegaprotocol/utils'; import { removePaginationWrapper } from '@vegaprotocol/utils';
import { marketsMapProvider } from '@vegaprotocol/markets';
import { import {
makeDataProvider, makeDataProvider,
makeDerivedDataProvider, makeDerivedDataProvider,
} from '@vegaprotocol/data-provider'; } from '@vegaprotocol/data-provider';
import * as Schema from '@vegaprotocol/types'; import * as Schema from '@vegaprotocol/types';
import type { Market } from '@vegaprotocol/markets';
import produce from 'immer'; import produce from 'immer';
import { import {
@ -20,7 +21,6 @@ import type {
AccountEventsSubscription, AccountEventsSubscription,
AccountsQueryVariables, AccountsQueryVariables,
} from './__generated__/Accounts'; } from './__generated__/Accounts';
import type { Market } from '@vegaprotocol/markets';
import type { Asset } from '@vegaprotocol/assets'; import type { Asset } from '@vegaprotocol/assets';
const AccountType = Schema.AccountType; const AccountType = Schema.AccountType;
@ -45,9 +45,9 @@ export const getId = (
? `${account.type}-${account.asset.id}-${account.market?.id || 'null'}` ? `${account.type}-${account.asset.id}-${account.market?.id || 'null'}`
: `${account.type}-${account.assetId}-${account.marketId || 'null'}`; : `${account.type}-${account.assetId}-${account.marketId || 'null'}`;
export type Account = Omit<AccountFieldsFragment, 'market' | 'asset'> & { export type Account = Omit<AccountFieldsFragment, 'asset' | 'market'> & {
market?: Market | null;
asset: Asset; asset: Asset;
market?: Market | null;
}; };
const update = ( const update = (
@ -170,31 +170,22 @@ export const accountsDataProvider = makeDerivedDataProvider<
>( >(
[ [
accountsOnlyDataProvider, accountsOnlyDataProvider,
(callback, client) => marketsProvider(callback, client, undefined), (callback, client) => marketsMapProvider(callback, client, undefined),
(callback, client) => assetsProvider(callback, client, undefined), (callback, client) => assetsMapProvider(callback, client, undefined),
], ],
([accounts, markets, assets]): Account[] | null => { ([accounts, markets, assets]): Account[] | null => {
return accounts return accounts
? accounts ? accounts
.map((account: AccountFieldsFragment) => { .map((account: AccountFieldsFragment) => {
const market = markets.find( const asset = (assets as Record<string, Asset>)[account.asset.id];
(market: Market) => market.id === account.market?.id const market =
); account.market?.id &&
const asset = assets.find( (markets as Record<string, Asset>)[account.market?.id];
(asset: Asset) => asset.id === account.asset?.id
);
if (asset) { if (asset) {
return { return {
...account, ...account,
partyId: account.party?.id, asset,
asset: { market,
...asset,
},
market: market
? {
...market,
}
: null,
}; };
} }
return null; return null;
@ -212,3 +203,18 @@ export const aggregatedAccountsDataProvider = makeDerivedDataProvider<
[accountsDataProvider], [accountsDataProvider],
(parts) => parts[0] && getAccountData(parts[0] as Account[]) (parts) => parts[0] && getAccountData(parts[0] as Account[])
); );
export const aggregatedAccountDataProvider = makeDerivedDataProvider<
AccountFields,
never,
AccountsQueryVariables & { assetId: string }
>(
[
(callback, client, { partyId }) =>
aggregatedAccountsDataProvider(callback, client, { partyId }),
],
(parts, { assetId }) =>
(parts[0] as AccountFields[]).find(
(account) => account.asset.id === assetId
) || null
);

View File

@ -1,12 +1,53 @@
import { useRef, useMemo, memo } from 'react'; import { useRef, memo, useCallback, useState, useEffect } from 'react';
import { addDecimalsFormatNumber } from '@vegaprotocol/utils';
import { t } from '@vegaprotocol/i18n'; import { t } from '@vegaprotocol/i18n';
import { useBottomPlaceholder } from '@vegaprotocol/datagrid'; import { useBottomPlaceholder } from '@vegaprotocol/datagrid';
import { useDataProvider } from '@vegaprotocol/data-provider'; import { useDataProvider } from '@vegaprotocol/data-provider';
import { AsyncRenderer } from '@vegaprotocol/ui-toolkit'; import { AsyncRenderer } from '@vegaprotocol/ui-toolkit';
import type { AgGridReact } from 'ag-grid-react'; import type { AgGridReact } from 'ag-grid-react';
import { aggregatedAccountsDataProvider } from './accounts-data-provider'; import type { RowDataUpdatedEvent } from 'ag-grid-community';
import type { AccountFields } from './accounts-data-provider';
import {
aggregatedAccountsDataProvider,
aggregatedAccountDataProvider,
} from './accounts-data-provider';
import type { PinnedAsset } from './accounts-table'; import type { PinnedAsset } from './accounts-table';
import { AccountTable } from './accounts-table'; import { AccountTable } from './accounts-table';
import isEqual from 'lodash/isEqual';
import { Dialog } from '@vegaprotocol/ui-toolkit';
import BreakdownTable from './breakdown-table';
const AccountBreakdown = ({
assetId,
partyId,
}: {
assetId: string;
partyId: string;
}) => {
const { data } = useDataProvider({
dataProvider: aggregatedAccountDataProvider,
variables: { partyId, assetId },
});
return (
<div
className="h-[35vh] w-full m-auto flex flex-col"
data-testid="usage-breakdown"
>
<h1 className="text-xl mb-4">
{data?.asset?.symbol} {t('usage breakdown')}
</h1>
{data && (
<p className="mb-2 text-sm">
{t('You have %s %s in total.', [
addDecimalsFormatNumber(data.total, data.asset.decimals),
data.asset.symbol,
])}
</p>
)}
<BreakdownTable data={data?.breakdown || null} domLayout="autoHeight" />
</div>
);
};
interface AccountManagerProps { interface AccountManagerProps {
partyId: string; partyId: string;
@ -30,16 +71,59 @@ export const AccountManager = ({
storeKey, storeKey,
}: AccountManagerProps) => { }: AccountManagerProps) => {
const gridRef = useRef<AgGridReact | null>(null); const gridRef = useRef<AgGridReact | null>(null);
const variables = useMemo(() => ({ partyId }), [partyId]); const [hasData, setHasData] = useState(Boolean(pinnedAsset));
const [breakdownAssetId, setBreakdownAssetId] = useState<string>();
const update = useCallback(
({ data }: { data: AccountFields[] | null }) => {
if (!data || !gridRef.current?.api) {
return false;
}
const pinnedAssetRowData =
pinnedAsset && data.find((d) => d.asset.id === pinnedAsset.id);
if (pinnedAssetRowData) {
const pinnedTopRow = gridRef.current.api.getPinnedTopRow(0);
if (
pinnedTopRow?.data?.balance === '0' &&
pinnedAssetRowData.balance !== '0'
) {
return false;
}
if (!isEqual(pinnedTopRow?.data, pinnedAssetRowData)) {
gridRef.current.api.setPinnedTopRowData([pinnedAssetRowData]);
}
}
gridRef.current.api.setRowData(
pinnedAssetRowData
? data?.filter((d) => d !== pinnedAssetRowData)
: data
);
return true;
},
[gridRef, pinnedAsset]
);
const { data, loading, error, reload } = useDataProvider({ const { data, loading, error, reload } = useDataProvider({
dataProvider: aggregatedAccountsDataProvider, dataProvider: aggregatedAccountsDataProvider,
variables, variables: { partyId },
update,
}); });
const bottomPlaceholderProps = useBottomPlaceholder({ const bottomPlaceholderProps = useBottomPlaceholder({
gridRef, gridRef,
disabled: noBottomPlaceholder, disabled: noBottomPlaceholder,
}); });
useEffect(
() => setHasData(Boolean(pinnedAsset || data?.length)),
[data, pinnedAsset]
);
const onRowDataUpdated = useCallback(
(event: RowDataUpdatedEvent) => {
setHasData(Boolean(pinnedAsset || event.api?.getModel().getRowCount()));
},
[pinnedAsset]
);
return ( return (
<div className="relative h-full"> <div className="relative h-full">
<AccountTable <AccountTable
@ -48,6 +132,8 @@ export const AccountManager = ({
onClickAsset={onClickAsset} onClickAsset={onClickAsset}
onClickDeposit={onClickDeposit} onClickDeposit={onClickDeposit}
onClickWithdraw={onClickWithdraw} onClickWithdraw={onClickWithdraw}
onClickBreakdown={setBreakdownAssetId}
onRowDataUpdated={onRowDataUpdated}
isReadOnly={isReadOnly} isReadOnly={isReadOnly}
suppressLoadingOverlay suppressLoadingOverlay
suppressNoRowsOverlay suppressNoRowsOverlay
@ -58,13 +144,26 @@ export const AccountManager = ({
<div className="pointer-events-none absolute inset-0"> <div className="pointer-events-none absolute inset-0">
<AsyncRenderer <AsyncRenderer
data={data} data={data}
noDataCondition={(data) => !(data && data.length)} noDataCondition={() => !hasData}
error={error} error={error}
loading={loading} loading={loading}
noDataMessage={pinnedAsset ? ' ' : t('No accounts')} noDataMessage={pinnedAsset ? ' ' : t('No accounts')}
reload={reload} reload={reload}
/> />
</div> </div>
<Dialog
size="medium"
open={Boolean(breakdownAssetId)}
onChange={(isOpen) => {
if (!isOpen) {
setBreakdownAssetId(undefined);
}
}}
>
{breakdownAssetId && (
<AccountBreakdown assetId={breakdownAssetId} partyId={partyId} />
)}
</Dialog>
</div> </div>
); );
}; };

View File

@ -10,13 +10,6 @@ const singleRow = {
balance: '125600000', balance: '125600000',
market: { market: {
__typename: 'Market', __typename: 'Market',
tradableInstrument: {
__typename: 'TradableInstrument',
instrument: {
__typename: 'Instrument',
name: 'BTCUSD Monthly (30 Jun 2022)',
},
},
id: '10cd0a793ad2887b340940337fa6d97a212e0e517fe8e9eab2b5ef3a38633f35', id: '10cd0a793ad2887b340940337fa6d97a212e0e517fe8e9eab2b5ef3a38633f35',
}, },
asset: { asset: {
@ -136,13 +129,6 @@ describe('AccountsTable', () => {
market: { market: {
__typename: 'Market', __typename: 'Market',
id: '10cd0a793ad2887b340940337fa6d97a212e0e517fe8e9eab2b5ef3a38633f35', id: '10cd0a793ad2887b340940337fa6d97a212e0e517fe8e9eab2b5ef3a38633f35',
tradableInstrument: {
__typename: 'TradableInstrument',
instrument: {
__typename: 'Instrument',
name: 'BTCUSD Monthly (30 Jun 2022)',
},
},
}, },
type: 'ACCOUNT_TYPE_MARGIN', type: 'ACCOUNT_TYPE_MARGIN',
used: '125600000', used: '125600000',

View File

@ -1,4 +1,4 @@
import { forwardRef, useCallback, useMemo, useState } from 'react'; import { forwardRef, useMemo, useCallback } from 'react';
import { import {
addDecimalsFormatNumber, addDecimalsFormatNumber,
isNumeric, isNumeric,
@ -11,28 +11,25 @@ import type {
} from '@vegaprotocol/datagrid'; } from '@vegaprotocol/datagrid';
import { COL_DEFS } from '@vegaprotocol/datagrid'; import { COL_DEFS } from '@vegaprotocol/datagrid';
import { import {
Button,
ButtonLink, ButtonLink,
Dialog, Button,
VegaIcon, VegaIcon,
VegaIconNames, VegaIconNames,
} from '@vegaprotocol/ui-toolkit'; } from '@vegaprotocol/ui-toolkit';
import { TooltipCellComponent } from '@vegaprotocol/ui-toolkit'; import { TooltipCellComponent } from '@vegaprotocol/ui-toolkit';
import { import { AgGridLazy as AgGrid } from '@vegaprotocol/datagrid';
AgGridLazy as AgGrid,
CenteredGridCellWrapper,
} from '@vegaprotocol/datagrid';
import { AgGridColumn } from 'ag-grid-react'; import { AgGridColumn } from 'ag-grid-react';
import type { import type {
IDatasource, IDatasource,
IGetRowsParams, IGetRowsParams,
RowHeightParams,
RowNode, RowNode,
RowHeightParams,
} from 'ag-grid-community'; } from 'ag-grid-community';
import type { AgGridReact, AgGridReactProps } from 'ag-grid-react'; import type { AgGridReact, AgGridReactProps } from 'ag-grid-react';
import BreakdownTable from './breakdown-table';
import type { AccountFields } from './accounts-data-provider'; import type { AccountFields } from './accounts-data-provider';
import type { Asset } from '@vegaprotocol/types'; import type { Asset } from '@vegaprotocol/types';
import { CenteredGridCellWrapper } from '@vegaprotocol/datagrid';
import BigNumber from 'bignumber.js'; import BigNumber from 'bignumber.js';
import classNames from 'classnames'; import classNames from 'classnames';
import { AccountsActionsDropdown } from './accounts-actions-dropdown'; import { AccountsActionsDropdown } from './accounts-actions-dropdown';
@ -96,23 +93,32 @@ export interface AccountTableProps extends AgGridReactProps {
onClickAsset: (assetId: string) => void; onClickAsset: (assetId: string) => void;
onClickWithdraw?: (assetId: string) => void; onClickWithdraw?: (assetId: string) => void;
onClickDeposit?: (assetId: string) => void; onClickDeposit?: (assetId: string) => void;
onClickBreakdown?: (assetId: string) => void;
isReadOnly: boolean; isReadOnly: boolean;
pinnedAsset?: PinnedAsset; pinnedAsset?: PinnedAsset;
storeKey?: string; storeKey?: string;
} }
export const AccountTable = forwardRef<AgGridReact, AccountTableProps>( export const AccountTable = forwardRef<AgGridReact, AccountTableProps>(
({ onClickAsset, onClickWithdraw, onClickDeposit, ...props }, ref) => { (
const [openBreakdown, setOpenBreakdown] = useState(false); {
const [row, setRow] = useState<AccountFields>(); onClickAsset,
const pinnedAssetId = props.pinnedAsset?.id; onClickWithdraw,
onClickDeposit,
onClickBreakdown,
rowData,
...props
},
ref
) => {
const pinnedAsset = useMemo(() => { const pinnedAsset = useMemo(() => {
const currentPinnedAssetRow = props.rowData?.find( if (!props.pinnedAsset) {
(row) => row.asset.id === pinnedAssetId return;
}
const currentPinnedAssetRow = rowData?.find(
(row) => row.asset.id === props.pinnedAsset?.id
); );
if (!currentPinnedAssetRow) { if (!currentPinnedAssetRow) {
if (props.pinnedAsset) {
return { return {
asset: props.pinnedAsset, asset: props.pinnedAsset,
available: '0', available: '0',
@ -121,9 +127,8 @@ export const AccountTable = forwardRef<AgGridReact, AccountTableProps>(
balance: '0', balance: '0',
}; };
} }
}
return currentPinnedAssetRow; return currentPinnedAssetRow;
}, [pinnedAssetId, props.pinnedAsset, props.rowData]); }, [props.pinnedAsset, rowData]);
const { getRowHeight } = props; const { getRowHeight } = props;
@ -131,25 +136,19 @@ export const AccountTable = forwardRef<AgGridReact, AccountTableProps>(
(params: RowHeightParams) => { (params: RowHeightParams) => {
if ( if (
params.node.rowPinned && params.node.rowPinned &&
params.data.asset.id === pinnedAssetId && params.data.asset.id === props.pinnedAsset?.id &&
new BigNumber(params.data.total).isLessThanOrEqualTo(0) new BigNumber(params.data.total).isLessThanOrEqualTo(0)
) { ) {
return 32; return 32;
} }
return getRowHeight ? getRowHeight(params) : undefined; return getRowHeight ? getRowHeight(params) : undefined;
}, },
[pinnedAssetId, getRowHeight] [props.pinnedAsset?.id, getRowHeight]
); );
const accountForPinnedAsset = props?.rowData?.find( const showDepositButton = pinnedAsset?.balance === '0';
(a) => a.asset.id === pinnedAssetId
);
const showDepositButton = accountForPinnedAsset
? new BigNumber(accountForPinnedAsset.total).isLessThanOrEqualTo(0)
: true;
return ( return (
<>
<AgGrid <AgGrid
{...props} {...props}
style={{ width: '100%', height: '100%' }} style={{ width: '100%', height: '100%' }}
@ -161,8 +160,8 @@ export const AccountTable = forwardRef<AgGridReact, AccountTableProps>(
}) => (data.isLastPlaceholder && data.id ? data.id : data.asset.id)} }) => (data.isLastPlaceholder && data.id ? data.id : data.asset.id)}
ref={ref} ref={ref}
tooltipShowDelay={500} tooltipShowDelay={500}
rowData={props.rowData?.filter( rowData={rowData?.filter(
(data) => data.asset.id !== pinnedAssetId (data) => data.asset.id !== props.pinnedAsset?.id
)} )}
defaultColDef={{ defaultColDef={{
resizable: true, resizable: true,
@ -217,8 +216,7 @@ export const AccountTable = forwardRef<AgGridReact, AccountTableProps>(
<ButtonLink <ButtonLink
data-testid="breakdown" data-testid="breakdown"
onClick={() => { onClick={() => {
setOpenBreakdown(!openBreakdown); onClickBreakdown && onClickBreakdown(data.asset.id);
setRow(data);
}} }}
> >
<span>{valueFormatted}</span> <span>{valueFormatted}</span>
@ -277,15 +275,16 @@ export const AccountTable = forwardRef<AgGridReact, AccountTableProps>(
/> />
<AgGridColumn <AgGridColumn
colId="accounts-actions" colId="accounts-actions"
field="asset.id"
{...COL_DEFS.actions} {...COL_DEFS.actions}
minWidth={showDepositButton ? 130 : COL_DEFS.actions.minWidth} minWidth={showDepositButton ? 130 : COL_DEFS.actions.minWidth}
maxWidth={showDepositButton ? 130 : COL_DEFS.actions.maxWidth} maxWidth={showDepositButton ? 130 : COL_DEFS.actions.maxWidth}
cellRenderer={({ cellRenderer={({
data, value: assetId,
}: VegaICellRendererParams<AccountFields>) => { node,
if (!data) return null; }: VegaICellRendererParams<AccountFields, 'asset.id'>) => {
else { if (!assetId) return null;
if (showDepositButton && data.asset.id === pinnedAssetId) { if (node.rowPinned && node.data?.balance === '0') {
return ( return (
<CenteredGridCellWrapper className="h-[30px] justify-end py-1"> <CenteredGridCellWrapper className="h-[30px] justify-end py-1">
<Button <Button
@ -293,7 +292,7 @@ export const AccountTable = forwardRef<AgGridReact, AccountTableProps>(
variant="primary" variant="primary"
data-testid="deposit" data-testid="deposit"
onClick={() => { onClick={() => {
onClickDeposit && onClickDeposit(data.asset.id); onClickDeposit && onClickDeposit(assetId);
}} }}
> >
<VegaIcon name={VegaIconNames.DEPOSIT} /> {t('Deposit')} <VegaIcon name={VegaIconNames.DEPOSIT} /> {t('Deposit')}
@ -301,55 +300,28 @@ export const AccountTable = forwardRef<AgGridReact, AccountTableProps>(
</CenteredGridCellWrapper> </CenteredGridCellWrapper>
); );
} }
return ( return props.isReadOnly ? null : (
!props.isReadOnly && (
<AccountsActionsDropdown <AccountsActionsDropdown
assetId={data.asset.id} assetId={assetId}
assetContractAddress={ assetContractAddress={
data.asset.source?.__typename === 'ERC20' node.data?.asset.source?.__typename === 'ERC20'
? data.asset.source.contractAddress ? node.data.asset.source.contractAddress
: undefined : undefined
} }
onClickDeposit={() => { onClickDeposit={() => {
onClickDeposit && onClickDeposit(data.asset.id); onClickDeposit && onClickDeposit(assetId);
}} }}
onClickWithdraw={() => { onClickWithdraw={() => {
onClickWithdraw && onClickWithdraw(data.asset.id); onClickWithdraw && onClickWithdraw(assetId);
}} }}
onClickBreakdown={() => { onClickBreakdown={() => {
setOpenBreakdown(!openBreakdown); onClickBreakdown && onClickBreakdown(assetId);
setRow(data);
}} }}
/> />
)
); );
}
}} }}
/> />
</AgGrid> </AgGrid>
<Dialog size="medium" open={openBreakdown} onChange={setOpenBreakdown}>
<div
className="h-[35vh] w-full m-auto flex flex-col"
data-testid="usage-breakdown"
>
<h1 className="text-xl mb-4">
{row?.asset?.symbol} {t('usage breakdown')}
</h1>
{row && (
<p className="mb-2 text-sm">
{t('You have %s %s in total.', [
addDecimalsFormatNumber(row.total, row.asset.decimals),
row.asset.symbol,
])}
</p>
)}
<BreakdownTable
data={row?.breakdown || null}
domLayout="autoHeight"
/>
</div>
</Dialog>
</>
); );
} }
); );

View File

@ -31,6 +31,29 @@ export const assetsProvider = makeDataProvider<
getData, getData,
}); });
export const assetsMapProvider = makeDerivedDataProvider<
Record<string, Asset>,
never,
undefined
>(
[(callback, client) => assetsProvider(callback, client, undefined)],
([assets]) => {
return ((assets as ReturnType<typeof getData>) || []).reduce(
(assets, asset) => {
assets[asset.id] = asset;
return assets;
},
{} as Record<string, Asset>
);
}
);
export const useAssetsMapProvider = () =>
useDataProvider({
dataProvider: assetsMapProvider,
variables: undefined,
});
export const enabledAssetsProvider = makeDerivedDataProvider< export const enabledAssetsProvider = makeDerivedDataProvider<
ReturnType<typeof getData>, ReturnType<typeof getData>,
never never

View File

@ -4,17 +4,18 @@ import type {
ValueFormatterParams, ValueFormatterParams,
ValueGetterParams, ValueGetterParams,
} from 'ag-grid-community'; } from 'ag-grid-community';
import type { IDatasource, IGetRowsParams } from 'ag-grid-community'; import type { IDatasource, IGetRowsParams, RowNode } from 'ag-grid-community';
import type { AgGridReactProps } from 'ag-grid-react'; import type { AgGridReactProps } from 'ag-grid-react';
type Field = string | readonly string[]; type Field = string | readonly string[];
type RowHelper<TObj, TRow, TField extends Field> = Omit< type RowHelper<TObj, TRow, TField extends Field> = Omit<
TObj, TObj,
'data' | 'value' 'data' | 'value' | 'node'
> & { > & {
data?: TRow; data?: TRow;
value?: Get<TRow, TField>; value?: Get<TRow, TField>;
node: (Omit<RowNode, 'data'> & { data?: TRow }) | null;
}; };
export type VegaValueFormatterParams<TRow, TField extends Field> = RowHelper< export type VegaValueFormatterParams<TRow, TField extends Field> = RowHelper<
@ -29,10 +30,10 @@ export type VegaValueGetterParams<TRow, TField extends Field> = RowHelper<
TField TField
>; >;
export type VegaICellRendererParams< export type VegaICellRendererParams<TRow, TField extends Field = string> = Omit<
TRow, RowHelper<ICellRendererParams, TRow, TField>,
TField extends Field = string 'node'
> = RowHelper<ICellRendererParams, TRow, TField>; > & { node: NonNullable<RowHelper<ICellRendererParams, TRow, TField>['node']> };
export interface GetRowsParams<T> extends IGetRowsParams { export interface GetRowsParams<T> extends IGetRowsParams {
successCallback(rowsThisBlock: T[], lastRow?: number): void; successCallback(rowsThisBlock: T[], lastRow?: number): void;

View File

@ -41,6 +41,29 @@ export const marketsProvider = makeDataProvider<
fetchPolicy: 'cache-first', fetchPolicy: 'cache-first',
}); });
export const marketsMapProvider = makeDerivedDataProvider<
Record<string, Market>,
never,
undefined
>(
[(callback, client) => marketsProvider(callback, client, undefined)],
([markets]) => {
return ((markets as ReturnType<typeof getData>) || []).reduce(
(markets, market) => {
markets[market.id] = market;
return markets;
},
{} as Record<string, Market>
);
}
);
export const useMarketsMapProvider = () =>
useDataProvider({
dataProvider: marketsMapProvider,
variables: undefined,
});
export const marketProvider = makeDerivedDataProvider< export const marketProvider = makeDerivedDataProvider<
Market, Market,
never, never,

View File

@ -27,7 +27,7 @@ describe('WithdrawFormContainer', () => {
const account1: Account = { const account1: Account = {
type: Types.AccountType.ACCOUNT_TYPE_GENERAL, type: Types.AccountType.ACCOUNT_TYPE_GENERAL,
balance: '200099689', balance: '200099689',
market: null, market: undefined,
asset: { asset: {
id: 'assetId-1', id: 'assetId-1',
name: 'tBTC TEST', name: 'tBTC TEST',