vega-frontend-monorepo/libs/positions/src/lib/positions.tsx
Matthew Russell 3ff5bbb5a7
chore: use trading header and tidy tailwind usage (#1313)
* fix: border too thick, use grid head component

* fix: unused and superfluous classes, define border color in one place

* fix: tooltip should be on data not label
2022-09-13 09:19:41 +01:00

109 lines
3.7 KiB
TypeScript

import { useRef, useCallback, useMemo, memo } from 'react';
import { AsyncRenderer } from '@vegaprotocol/ui-toolkit';
import { BigNumber } from 'bignumber.js';
import { t, toBigNum, useDataProvider } from '@vegaprotocol/react-helpers';
import type { AgGridReact } from 'ag-grid-react';
import filter from 'lodash/filter';
import PositionsTable from './positions-table';
import type { GetRowsParams } from './positions-table';
import { positionsMetricsDataProvider as dataProvider } from './positions-data-providers';
import { AssetBalance } from '@vegaprotocol/accounts';
import type { Position } from './positions-data-providers';
interface PositionsProps {
partyId: string;
assetSymbol: string;
onClose: (position: Position) => void;
}
const getSummaryRow = (positions: Position[]) => {
const summaryRow = {
notional: new BigNumber(0),
realisedPNL: BigInt(0),
unrealisedPNL: BigInt(0),
};
positions.forEach((position) => {
summaryRow.notional = summaryRow.notional.plus(
toBigNum(position.notional, position.marketDecimalPlaces)
);
summaryRow.realisedPNL += BigInt(position.realisedPNL);
summaryRow.unrealisedPNL += BigInt(position.unrealisedPNL);
});
const decimals = positions[0]?.decimals || 0;
return {
marketName: t('Total'),
// we are using asset decimals instead of market decimals because each market can have different decimals
notional: summaryRow.notional
.multipliedBy(10 ** decimals)
.toFixed()
.toString(),
realisedPNL: summaryRow.realisedPNL.toString(),
unrealisedPNL: summaryRow.unrealisedPNL.toString(),
decimals,
};
};
export const Positions = memo(
({ partyId, assetSymbol, onClose }: PositionsProps) => {
const gridRef = useRef<AgGridReact | null>(null);
const variables = useMemo(() => ({ partyId }), [partyId]);
const dataRef = useRef<Position[] | null>(null);
const update = useCallback(
({ data }: { data: Position[] | null }) => {
if (!gridRef.current?.api) {
return false;
}
dataRef.current = filter(data, { assetSymbol });
gridRef.current.api.refreshInfiniteCache();
return true;
},
[assetSymbol]
);
const { data, error, loading } = useDataProvider<Position[], never>({
dataProvider,
update,
variables,
});
dataRef.current = filter(data, { assetSymbol });
const getRows = async ({
successCallback,
startRow,
endRow,
}: GetRowsParams) => {
const rowsThisBlock = dataRef.current
? dataRef.current.slice(startRow, endRow)
: [];
const lastRow = dataRef.current?.length ?? -1;
successCallback(rowsThisBlock, lastRow);
if (gridRef.current?.api) {
gridRef.current.api.setPinnedBottomRowData([
getSummaryRow(rowsThisBlock),
]);
}
};
return (
<AsyncRenderer loading={loading} error={error} data={data}>
<div className="flex justify-between items-center px-4 pt-3 pb-1">
<h4>
{assetSymbol} {t('markets')}
</h4>
<div className="text-sm text-neutral-500 dark:text-neutral-300">
{assetSymbol} {t('balance')}:
<span data-testid="balance" className="pl-1 font-mono">
<AssetBalance partyId={partyId} assetSymbol={assetSymbol} />
</span>
</div>
</div>
<PositionsTable
domLayout="autoHeight"
style={{ width: '100%' }}
ref={gridRef}
rowModelType={data?.length ? 'infinite' : 'clientSide'}
rowData={data?.length ? undefined : []}
datasource={{ getRows }}
onClose={onClose}
/>
</AsyncRenderer>
);
}
);