chore(trading): make loading masks in tabs consistent along the app (#3155)

This commit is contained in:
Maciek 2023-03-15 16:08:48 +01:00 committed by GitHub
parent 47b3d5b55f
commit 5dbc5d7997
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 106 additions and 58 deletions

View File

@ -25,7 +25,8 @@ export const DepositsContainer = () => {
<div className="h-full relative"> <div className="h-full relative">
<DepositsTable <DepositsTable
rowData={data || []} rowData={data || []}
noRowsOverlayComponent={() => null} suppressLoadingOverlay
suppressNoRowsOverlay
ref={gridRef} ref={gridRef}
{...bottomPlaceholderProps} {...bottomPlaceholderProps}
/> />

View File

@ -24,7 +24,8 @@ export const WithdrawalsContainer = () => {
<WithdrawalsTable <WithdrawalsTable
data-testid="withdrawals-history" data-testid="withdrawals-history"
rowData={data} rowData={data}
noRowsOverlayComponent={() => null} suppressLoadingOverlay
suppressNoRowsOverlay
/> />
<div className="pointer-events-none absolute inset-0"> <div className="pointer-events-none absolute inset-0">
<AsyncRenderer <AsyncRenderer

View File

@ -15,51 +15,29 @@ jest.mock('@vegaprotocol/react-helpers', () => ({
})); }));
describe('AccountManager', () => { describe('AccountManager', () => {
beforeEach(() => { describe('when rerender', () => {
mockedUseDataProvider beforeEach(() => {
.mockImplementationOnce((args) => { mockedUseDataProvider
return { .mockImplementationOnce((args) => {
data: [], return {
}; data: [],
}) };
.mockImplementationOnce((args) => { })
return { .mockImplementationOnce((args) => {
data: [ return {
{ asset: { id: 'a1' }, party: { id: 't1' } }, data: [
{ asset: { id: 'a2' }, party: { id: 't2' } }, { asset: { id: 'a1' }, party: { id: 't1' } },
], { asset: { id: 'a2' }, party: { id: 't2' } },
}; ],
}); };
}); });
it('change partyId should reload data provider', async () => {
const { rerender } = render(
<AccountManager
partyId="partyOne"
onClickAsset={jest.fn}
isReadOnly={false}
/>
);
expect(
(helpers.useDataProvider as jest.Mock).mock.calls[0][0].variables.partyId
).toEqual('partyOne');
await act(() => {
rerender(
<AccountManager
partyId="partyTwo"
onClickAsset={jest.fn}
isReadOnly={false}
/>
);
}); });
expect(
(helpers.useDataProvider as jest.Mock).mock.calls[1][0].variables.partyId
).toEqual('partyTwo');
});
it('update method should return proper result', async () => { afterEach(() => {
let rerenderer: (ui: React.ReactElement) => void; jest.clearAllMocks();
await act(() => { });
it('change partyId should reload data provider', async () => {
const { rerender } = render( const { rerender } = render(
<AccountManager <AccountManager
partyId="partyOne" partyId="partyOne"
@ -67,13 +45,67 @@ describe('AccountManager', () => {
isReadOnly={false} isReadOnly={false}
/> />
); );
rerenderer = rerender; expect(
(helpers.useDataProvider as jest.Mock).mock.calls[0][0].variables
.partyId
).toEqual('partyOne');
await act(() => {
rerender(
<AccountManager
partyId="partyTwo"
onClickAsset={jest.fn}
isReadOnly={false}
/>
);
});
expect(
(helpers.useDataProvider as jest.Mock).mock.calls[1][0].variables
.partyId
).toEqual('partyTwo');
}); });
await waitFor(() => {
expect(screen.getByText('No accounts')).toBeInTheDocument(); it('update method should return proper result', async () => {
let rerenderer: (ui: React.ReactElement) => void;
await act(() => {
const { rerender } = render(
<AccountManager
partyId="partyOne"
onClickAsset={jest.fn}
isReadOnly={false}
/>
);
rerenderer = rerender;
});
await waitFor(() => {
expect(screen.getByText('No accounts')).toBeInTheDocument();
});
await act(() => {
rerenderer(
<AccountManager
partyId="partyOne"
onClickAsset={jest.fn}
isReadOnly={false}
/>
);
});
const container = document.querySelector('.ag-center-cols-container');
await waitFor(() => {
expect(container).toBeInTheDocument();
});
expect(getAllByRole(container as HTMLDivElement, 'row')).toHaveLength(2);
});
});
it('splash loading should be displayed', async () => {
mockedUseDataProvider.mockImplementation((args) => {
return {
loading: true,
data: null,
};
}); });
await act(() => { await act(() => {
rerenderer( render(
<AccountManager <AccountManager
partyId="partyOne" partyId="partyOne"
onClickAsset={jest.fn} onClickAsset={jest.fn}
@ -81,11 +113,15 @@ describe('AccountManager', () => {
/> />
); );
}); });
const container = document.querySelector('.ag-center-cols-container');
await waitFor(() => { await waitFor(() => {
expect(container).toBeInTheDocument(); expect(
screen.getByText(
(content, element) =>
Boolean(
element?.className.endsWith('flex items-center justify-center')
) && content.startsWith('Loading')
)
).toBeInTheDocument();
}); });
expect(getAllByRole(container as HTMLDivElement, 'row')).toHaveLength(2);
}); });
}); });

View File

@ -60,7 +60,8 @@ export const AccountManager = ({
onClickDeposit={onClickDeposit} onClickDeposit={onClickDeposit}
onClickWithdraw={onClickWithdraw} onClickWithdraw={onClickWithdraw}
isReadOnly={isReadOnly} isReadOnly={isReadOnly}
noRowsOverlayComponent={() => null} suppressLoadingOverlay
suppressNoRowsOverlay
pinnedAsset={pinnedAsset} pinnedAsset={pinnedAsset}
getRowHeight={getRowHeight} getRowHeight={getRowHeight}
{...bottomPlaceholderProps} {...bottomPlaceholderProps}

View File

@ -1,7 +1,8 @@
import { useCallback, useRef } from 'react'; import { useCallback, useEffect, useRef, useState } from 'react';
import { AsyncRenderer } from '@vegaprotocol/ui-toolkit'; import { AsyncRenderer } from '@vegaprotocol/ui-toolkit';
import type { Position } from '../'; import type { Position } from '../';
import { usePositionsData, PositionsTable } from '../'; import { usePositionsData, PositionsTable } from '../';
import type { FilterChangedEvent } from 'ag-grid-community';
import type { AgGridReact } from 'ag-grid-react'; import type { AgGridReact } from 'ag-grid-react';
import * as Schema from '@vegaprotocol/types'; import * as Schema from '@vegaprotocol/types';
import { useVegaTransactionStore } from '@vegaprotocol/wallet'; import { useVegaTransactionStore } from '@vegaprotocol/wallet';
@ -22,6 +23,7 @@ export const PositionsManager = ({
noBottomPlaceholder, noBottomPlaceholder,
}: PositionsManagerProps) => { }: PositionsManagerProps) => {
const gridRef = useRef<AgGridReact | null>(null); const gridRef = useRef<AgGridReact | null>(null);
const [dataCount, setDataCount] = useState(0);
const { data, error, loading, reload } = usePositionsData( const { data, error, loading, reload } = usePositionsData(
partyId, partyId,
gridRef, gridRef,
@ -67,7 +69,12 @@ export const PositionsManager = ({
gridRef, gridRef,
setId, setId,
}); });
useEffect(() => {
setDataCount(gridRef.current?.api?.getModel().getRowCount() ?? 0);
}, [data]);
const onFilterChanged = useCallback((event: FilterChangedEvent) => {
setDataCount(gridRef.current?.api?.getModel().getRowCount() ?? 0);
}, []);
return ( return (
<div className="h-full relative"> <div className="h-full relative">
<PositionsTable <PositionsTable
@ -75,8 +82,10 @@ export const PositionsManager = ({
ref={gridRef} ref={gridRef}
onMarketClick={onMarketClick} onMarketClick={onMarketClick}
onClose={onClose} onClose={onClose}
noRowsOverlayComponent={() => null} suppressLoadingOverlay
suppressNoRowsOverlay
isReadOnly={isReadOnly} isReadOnly={isReadOnly}
onFilterChanged={onFilterChanged}
{...(noBottomPlaceholder ? null : bottomPlaceholderProps)} {...(noBottomPlaceholder ? null : bottomPlaceholderProps)}
/> />
<div className="pointer-events-none absolute inset-0"> <div className="pointer-events-none absolute inset-0">
@ -85,7 +94,7 @@ export const PositionsManager = ({
error={error} error={error}
data={data} data={data}
noDataMessage={t('No positions')} noDataMessage={t('No positions')}
noDataCondition={(data) => !(data && data.length)} noDataCondition={(data) => !dataCount}
reload={reload} reload={reload}
/> />
</div> </div>