chore: update fills tab - add tooltip with fees breakdown (#2606)
* chore: update fills tab - add tooltip with fees breakdown * chore: update fills tab - fix failing unit test * chore: update fills tab - add unit test * chore: update fills tab - adjust int test
This commit is contained in:
parent
6d3795f1f4
commit
2b28ff6c18
@ -66,7 +66,9 @@ describe('Portfolio page tabs', { tags: '@smoke' }, () => {
|
|||||||
|
|
||||||
it('data should be properly rendered', () => {
|
it('data should be properly rendered', () => {
|
||||||
cy.get('.ag-center-cols-container .ag-row').should('have.length', 5);
|
cy.get('.ag-center-cols-container .ag-row').should('have.length', 5);
|
||||||
cy.contains('.ag-center-cols-container button', 'tEURO').click();
|
cy.get('[role="gridcell"][col-id="account-asset"] button')
|
||||||
|
.contains('tEURO')
|
||||||
|
.click();
|
||||||
cy.getByTestId('dialog-title').should(
|
cy.getByTestId('dialog-title').should(
|
||||||
'have.text',
|
'have.text',
|
||||||
'Asset details - tEURO'
|
'Asset details - tEURO'
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import { act, render, screen, waitFor } from '@testing-library/react';
|
import { act, render, screen, waitFor } from '@testing-library/react';
|
||||||
|
import userEvent from '@testing-library/user-event';
|
||||||
import { getDateTimeFormat } from '@vegaprotocol/react-helpers';
|
import { getDateTimeFormat } from '@vegaprotocol/react-helpers';
|
||||||
import * as Schema from '@vegaprotocol/types';
|
import * as Schema from '@vegaprotocol/types';
|
||||||
import type { PartialDeep } from 'type-fest';
|
import type { PartialDeep } from 'type-fest';
|
||||||
@ -57,8 +58,8 @@ describe('FillsTable', () => {
|
|||||||
const expectedHeaders = [
|
const expectedHeaders = [
|
||||||
'Market',
|
'Market',
|
||||||
'Size',
|
'Size',
|
||||||
'Value',
|
'Price',
|
||||||
'Filled value',
|
'Notional',
|
||||||
'Role',
|
'Role',
|
||||||
'Fee',
|
'Fee',
|
||||||
'Date',
|
'Date',
|
||||||
@ -82,7 +83,7 @@ describe('FillsTable', () => {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
render(<FillsTable partyId={partyId} rowData={[buyerFill]} />);
|
render(<FillsTable partyId={partyId} rowData={[{ ...buyerFill }]} />);
|
||||||
await waitForGridToBeInTheDOM();
|
await waitForGridToBeInTheDOM();
|
||||||
await waitForDataToHaveLoaded();
|
await waitForDataToHaveLoaded();
|
||||||
|
|
||||||
@ -179,4 +180,38 @@ describe('FillsTable', () => {
|
|||||||
.find((c) => c.getAttribute('col-id') === 'aggressor')
|
.find((c) => c.getAttribute('col-id') === 'aggressor')
|
||||||
).toHaveTextContent('Maker');
|
).toHaveTextContent('Maker');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should render tooltip over fees', async () => {
|
||||||
|
const partyId = 'party-id';
|
||||||
|
const takerFill = generateFill({
|
||||||
|
seller: {
|
||||||
|
id: partyId,
|
||||||
|
},
|
||||||
|
aggressor: Schema.Side.SIDE_SELL,
|
||||||
|
});
|
||||||
|
act(() => {
|
||||||
|
render(<FillsTable partyId={partyId} rowData={[takerFill]} />);
|
||||||
|
});
|
||||||
|
await waitForGridToBeInTheDOM();
|
||||||
|
await waitForDataToHaveLoaded();
|
||||||
|
|
||||||
|
const feeCell = screen
|
||||||
|
.getAllByRole('gridcell')
|
||||||
|
.find(
|
||||||
|
(c) =>
|
||||||
|
c.getAttribute('col-id') ===
|
||||||
|
'market.tradableInstrument.instrument.product'
|
||||||
|
);
|
||||||
|
|
||||||
|
await waitFor(() => {
|
||||||
|
expect(feeCell).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
act(() => {
|
||||||
|
userEvent.hover(feeCell as HTMLElement);
|
||||||
|
});
|
||||||
|
|
||||||
|
await waitFor(() => {
|
||||||
|
expect(screen.getByTestId('fee-breakdown-tooltip')).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
@ -1,4 +1,9 @@
|
|||||||
import type { AgGridReact } from 'ag-grid-react';
|
import type {
|
||||||
|
AgGridReact,
|
||||||
|
AgGridReactProps,
|
||||||
|
AgReactUiProps,
|
||||||
|
} from 'ag-grid-react';
|
||||||
|
import type { ITooltipParams } from 'ag-grid-community';
|
||||||
import {
|
import {
|
||||||
addDecimal,
|
addDecimal,
|
||||||
addDecimalsFormatNumber,
|
addDecimalsFormatNumber,
|
||||||
@ -15,7 +20,6 @@ import type { VegaValueFormatterParams } from '@vegaprotocol/ui-toolkit';
|
|||||||
import { AgGridDynamic as AgGrid } from '@vegaprotocol/ui-toolkit';
|
import { AgGridDynamic as AgGrid } from '@vegaprotocol/ui-toolkit';
|
||||||
import { forwardRef } from 'react';
|
import { forwardRef } from 'react';
|
||||||
import BigNumber from 'bignumber.js';
|
import BigNumber from 'bignumber.js';
|
||||||
import type { AgGridReactProps, AgReactUiProps } from 'ag-grid-react';
|
|
||||||
import type { Trade } from './fills-data-provider';
|
import type { Trade } from './fills-data-provider';
|
||||||
|
|
||||||
export type Props = (AgGridReactProps | AgReactUiProps) & {
|
export type Props = (AgGridReactProps | AgReactUiProps) & {
|
||||||
@ -31,6 +35,8 @@ export const FillsTable = forwardRef<AgGridReact, Props>(
|
|||||||
defaultColDef={{ flex: 1, resizable: true }}
|
defaultColDef={{ flex: 1, resizable: true }}
|
||||||
style={{ width: '100%', height: '100%' }}
|
style={{ width: '100%', height: '100%' }}
|
||||||
getRowId={({ data }) => data?.id}
|
getRowId={({ data }) => data?.id}
|
||||||
|
tooltipShowDelay={0}
|
||||||
|
tooltipHideDelay={2000}
|
||||||
{...props}
|
{...props}
|
||||||
>
|
>
|
||||||
<AgGridColumn
|
<AgGridColumn
|
||||||
@ -54,13 +60,13 @@ export const FillsTable = forwardRef<AgGridReact, Props>(
|
|||||||
valueFormatter={formatSize(partyId)}
|
valueFormatter={formatSize(partyId)}
|
||||||
/>
|
/>
|
||||||
<AgGridColumn
|
<AgGridColumn
|
||||||
headerName={t('Value')}
|
headerName={t('Price')}
|
||||||
field="price"
|
field="price"
|
||||||
valueFormatter={formatPrice}
|
valueFormatter={formatPrice}
|
||||||
type="rightAligned"
|
type="rightAligned"
|
||||||
/>
|
/>
|
||||||
<AgGridColumn
|
<AgGridColumn
|
||||||
headerName={t('Filled value')}
|
headerName={t('Notional')}
|
||||||
field="price"
|
field="price"
|
||||||
valueFormatter={formatTotal}
|
valueFormatter={formatTotal}
|
||||||
type="rightAligned"
|
type="rightAligned"
|
||||||
@ -75,6 +81,9 @@ export const FillsTable = forwardRef<AgGridReact, Props>(
|
|||||||
field="market.tradableInstrument.instrument.product"
|
field="market.tradableInstrument.instrument.product"
|
||||||
valueFormatter={formatFee(partyId)}
|
valueFormatter={formatFee(partyId)}
|
||||||
type="rightAligned"
|
type="rightAligned"
|
||||||
|
tooltipField="market.tradableInstrument.instrument.product"
|
||||||
|
tooltipComponent={FeesBreakdownTooltip}
|
||||||
|
tooltipComponentParams={{ partyId }}
|
||||||
/>
|
/>
|
||||||
<AgGridColumn
|
<AgGridColumn
|
||||||
headerName={t('Date')}
|
headerName={t('Date')}
|
||||||
@ -148,16 +157,15 @@ const formatTotal = ({
|
|||||||
if (!data?.market || !isNumeric(value)) {
|
if (!data?.market || !isNumeric(value)) {
|
||||||
return '-';
|
return '-';
|
||||||
}
|
}
|
||||||
const asset =
|
const { symbol: assetSymbol, decimals: assetDecimals } =
|
||||||
data?.market.tradableInstrument.instrument.product.settlementAsset.symbol;
|
data?.market.tradableInstrument.instrument.product.settlementAsset ?? {};
|
||||||
const size = new BigNumber(
|
const size = new BigNumber(
|
||||||
addDecimal(data?.size, data?.market.positionDecimalPlaces)
|
addDecimal(data?.size, data?.market.positionDecimalPlaces)
|
||||||
);
|
);
|
||||||
const price = new BigNumber(addDecimal(value, data?.market.decimalPlaces));
|
const price = new BigNumber(addDecimal(value, data?.market.decimalPlaces));
|
||||||
|
|
||||||
const total = size.times(price).toString();
|
const total = size.times(price).toString();
|
||||||
const valueFormatted = formatNumber(total, data?.market.decimalPlaces);
|
const valueFormatted = formatNumber(total, assetDecimals);
|
||||||
return `${valueFormatted} ${asset}`;
|
return `${valueFormatted} ${assetSymbol}`;
|
||||||
};
|
};
|
||||||
|
|
||||||
const formatRole = (partyId: string) => {
|
const formatRole = (partyId: string) => {
|
||||||
@ -210,3 +218,50 @@ const formatFee = (partyId: string) => {
|
|||||||
return `${totalFees} ${asset.symbol}`;
|
return `${totalFees} ${asset.symbol}`;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const FeesBreakdownTooltip = ({
|
||||||
|
data,
|
||||||
|
value,
|
||||||
|
valueFormatted,
|
||||||
|
partyId,
|
||||||
|
}: ITooltipParams & { partyId?: string }) => {
|
||||||
|
if (!value?.settlementAsset || !data) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
const asset = value.settlementAsset;
|
||||||
|
let feesObj;
|
||||||
|
if (data?.buyer.id === partyId) {
|
||||||
|
feesObj = data?.buyerFee;
|
||||||
|
} else if (data?.seller.id === partyId) {
|
||||||
|
feesObj = data?.sellerFee;
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
data-testid="fee-breakdown-tooltip"
|
||||||
|
className="max-w-sm border border-neutral-600 bg-neutral-100 dark:bg-neutral-800 px-4 py-2 z-20 rounded text-sm break-word text-black dark:text-white"
|
||||||
|
>
|
||||||
|
<dl className="grid grid-cols-2 gap-x-2">
|
||||||
|
<dt>{t('Infrastructure fee')}</dt>
|
||||||
|
<dd className="text-right">
|
||||||
|
{addDecimalsFormatNumber(feesObj.infrastructureFee, asset.decimals)}{' '}
|
||||||
|
{asset.symbol}
|
||||||
|
</dd>
|
||||||
|
<dt>{t('Liquidity fee')}</dt>
|
||||||
|
<dd className="text-right">
|
||||||
|
{addDecimalsFormatNumber(feesObj.liquidityFee, asset.decimals)}{' '}
|
||||||
|
{asset.symbol}
|
||||||
|
</dd>
|
||||||
|
<dt>{t('Maker fee')}</dt>
|
||||||
|
<dd className="text-right">
|
||||||
|
{addDecimalsFormatNumber(feesObj.makerFee, asset.decimals)}{' '}
|
||||||
|
{asset.symbol}
|
||||||
|
</dd>
|
||||||
|
<dt>{t('Total fees')}</dt>
|
||||||
|
<dd className="text-right">{valueFormatted}</dd>
|
||||||
|
</dl>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user