chore(trading): tweaks and improvements of floating bottom buttons (#3138)
This commit is contained in:
parent
af2e52d59c
commit
a575b4c502
@ -76,6 +76,9 @@ describe(
|
|||||||
cy.getByTestId(closeDialog).click();
|
cy.getByTestId(closeDialog).click();
|
||||||
cy.getByTestId('Trading').first().click();
|
cy.getByTestId('Trading').first().click();
|
||||||
cy.getByTestId(collateralTab).click();
|
cy.getByTestId(collateralTab).click();
|
||||||
|
cy.getByTestId(openTransferDialog).should('not.exist');
|
||||||
|
cy.getByTestId('Portfolio').eq(0).click();
|
||||||
|
cy.getByTestId(collateralTab).click();
|
||||||
cy.getByTestId(openTransferDialog).click();
|
cy.getByTestId(openTransferDialog).click();
|
||||||
cy.getByTestId(dialogTransferText).should(
|
cy.getByTestId(dialogTransferText).should(
|
||||||
'contain.text',
|
'contain.text',
|
||||||
|
@ -179,7 +179,10 @@ const MainGrid = ({
|
|||||||
</Tab>
|
</Tab>
|
||||||
<Tab id="accounts" name={t('Collateral')}>
|
<Tab id="accounts" name={t('Collateral')}>
|
||||||
<VegaWalletContainer>
|
<VegaWalletContainer>
|
||||||
<TradingViews.Collateral pinnedAsset={pinnedAsset} />
|
<TradingViews.Collateral
|
||||||
|
pinnedAsset={pinnedAsset}
|
||||||
|
hideButtons
|
||||||
|
/>
|
||||||
</VegaWalletContainer>
|
</VegaWalletContainer>
|
||||||
</Tab>
|
</Tab>
|
||||||
</Tabs>
|
</Tabs>
|
||||||
|
@ -49,7 +49,10 @@ export const Portfolio = () => {
|
|||||||
</Tab>
|
</Tab>
|
||||||
<Tab id="positions" name={t('Positions')}>
|
<Tab id="positions" name={t('Positions')}>
|
||||||
<VegaWalletContainer>
|
<VegaWalletContainer>
|
||||||
<PositionsContainer onMarketClick={onMarketClick} />
|
<PositionsContainer
|
||||||
|
onMarketClick={onMarketClick}
|
||||||
|
noBottomPlaceholder
|
||||||
|
/>
|
||||||
</VegaWalletContainer>
|
</VegaWalletContainer>
|
||||||
</Tab>
|
</Tab>
|
||||||
<Tab id="orders" name={t('Orders')}>
|
<Tab id="orders" name={t('Orders')}>
|
||||||
|
@ -8,15 +8,14 @@ import { useVegaWallet } from '@vegaprotocol/wallet';
|
|||||||
import type { PinnedAsset } from '@vegaprotocol/accounts';
|
import type { PinnedAsset } from '@vegaprotocol/accounts';
|
||||||
import { AccountManager, useTransferDialog } from '@vegaprotocol/accounts';
|
import { AccountManager, useTransferDialog } from '@vegaprotocol/accounts';
|
||||||
import { useDepositDialog } from '@vegaprotocol/deposits';
|
import { useDepositDialog } from '@vegaprotocol/deposits';
|
||||||
import { useParams } from 'react-router-dom';
|
|
||||||
|
|
||||||
export const AccountsContainer = ({
|
export const AccountsContainer = ({
|
||||||
pinnedAsset,
|
pinnedAsset,
|
||||||
|
hideButtons,
|
||||||
}: {
|
}: {
|
||||||
pinnedAsset?: PinnedAsset;
|
pinnedAsset?: PinnedAsset;
|
||||||
|
hideButtons?: boolean;
|
||||||
}) => {
|
}) => {
|
||||||
const params = useParams();
|
|
||||||
const hideButtons = 'marketId' in params;
|
|
||||||
const { pubKey, isReadOnly } = useVegaWallet();
|
const { pubKey, isReadOnly } = useVegaWallet();
|
||||||
const { open: openAssetDetailsDialog } = useAssetDetailsDialogStore();
|
const { open: openAssetDetailsDialog } = useAssetDetailsDialogStore();
|
||||||
const openWithdrawalDialog = useWithdrawalDialog((store) => store.open);
|
const openWithdrawalDialog = useWithdrawalDialog((store) => store.open);
|
||||||
@ -49,7 +48,7 @@ export const AccountsContainer = ({
|
|||||||
pinnedAsset={pinnedAsset}
|
pinnedAsset={pinnedAsset}
|
||||||
/>
|
/>
|
||||||
{!isReadOnly && !hideButtons && (
|
{!isReadOnly && !hideButtons && (
|
||||||
<div className="flex gap-2 justify-end p-2 px-[11px] fixed bottom-0 right-2 dark:bg-black/75 bg-white/75 rounded">
|
<div className="flex gap-2 justify-end p-2 px-[11px] absolute lg:fixed bottom-0 right-3 dark:bg-black/75 bg-white/75 rounded">
|
||||||
<Button
|
<Button
|
||||||
variant="primary"
|
variant="primary"
|
||||||
size="sm"
|
size="sm"
|
||||||
|
@ -14,7 +14,7 @@ export const Footer = () => {
|
|||||||
const { blockDiff, datanodeBlockHeight } = useNodeHealth();
|
const { blockDiff, datanodeBlockHeight } = useNodeHealth();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<footer className="px-4 py-1 text-xs border-t border-default text-vega-light-300 dark:text-vega-dark-300 fixed bottom-0 left-0 border-r bg-white dark:bg-black">
|
<footer className="px-4 py-1 text-xs border-t border-default text-vega-light-300 dark:text-vega-dark-300 lg:fixed bottom-0 left-0 border-r bg-white dark:bg-black">
|
||||||
{/* Pull left to align with top nav, due to button padding */}
|
{/* Pull left to align with top nav, due to button padding */}
|
||||||
<div className="-ml-2">
|
<div className="-ml-2">
|
||||||
{VEGA_URL && (
|
{VEGA_URL && (
|
||||||
|
@ -57,7 +57,10 @@ const update = (
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
export type Trade = Omit<FillFieldsFragment, 'market'> & { market?: Market };
|
export type Trade = Omit<FillFieldsFragment, 'market'> & {
|
||||||
|
market?: Market;
|
||||||
|
isLastPlaceholder?: boolean;
|
||||||
|
};
|
||||||
export type TradeEdge = Edge<Trade>;
|
export type TradeEdge = Edge<Trade>;
|
||||||
|
|
||||||
const getData = (responseData: FillsQuery | null): FillEdgeFragment[] =>
|
const getData = (responseData: FillsQuery | null): FillEdgeFragment[] =>
|
||||||
|
@ -1,10 +1,12 @@
|
|||||||
import type { AgGridReact } from 'ag-grid-react';
|
import type { AgGridReact } from 'ag-grid-react';
|
||||||
import { useRef } from 'react';
|
import { useCallback, useRef } from 'react';
|
||||||
import { AsyncRenderer } from '@vegaprotocol/ui-toolkit';
|
import { AsyncRenderer } from '@vegaprotocol/ui-toolkit';
|
||||||
import { t } from '@vegaprotocol/i18n';
|
import { t } from '@vegaprotocol/i18n';
|
||||||
import { FillsTable } from './fills-table';
|
import { FillsTable } from './fills-table';
|
||||||
import type { BodyScrollEvent, BodyScrollEndEvent } from 'ag-grid-community';
|
import type { BodyScrollEvent, BodyScrollEndEvent } from 'ag-grid-community';
|
||||||
import { useFillsList } from './use-fills-list';
|
import { useFillsList } from './use-fills-list';
|
||||||
|
import type { Trade } from './fills-data-provider';
|
||||||
|
import { useBottomPlaceholder } from '@vegaprotocol/react-helpers';
|
||||||
|
|
||||||
interface FillsManagerProps {
|
interface FillsManagerProps {
|
||||||
partyId: string;
|
partyId: string;
|
||||||
@ -19,22 +21,51 @@ export const FillsManager = ({
|
|||||||
}: FillsManagerProps) => {
|
}: FillsManagerProps) => {
|
||||||
const gridRef = useRef<AgGridReact | null>(null);
|
const gridRef = useRef<AgGridReact | null>(null);
|
||||||
const scrolledToTop = useRef(true);
|
const scrolledToTop = useRef(true);
|
||||||
const { data, error, loading, addNewRows, getRows, reload } = useFillsList({
|
const {
|
||||||
|
data,
|
||||||
|
error,
|
||||||
|
loading,
|
||||||
|
addNewRows,
|
||||||
|
getRows,
|
||||||
|
reload,
|
||||||
|
makeBottomPlaceholders,
|
||||||
|
} = useFillsList({
|
||||||
partyId,
|
partyId,
|
||||||
marketId,
|
marketId,
|
||||||
gridRef,
|
gridRef,
|
||||||
scrolledToTop,
|
scrolledToTop,
|
||||||
});
|
});
|
||||||
|
|
||||||
const onBodyScrollEnd = (event: BodyScrollEndEvent) => {
|
const checkBottomPlaceholder = useCallback(() => {
|
||||||
if (event.top === 0) {
|
const rowCont = gridRef.current?.api?.getModel().getRowCount() ?? 0;
|
||||||
addNewRows();
|
const lastRowIndex = gridRef.current?.api?.getLastDisplayedRow();
|
||||||
|
if (lastRowIndex && rowCont - 1 === lastRowIndex) {
|
||||||
|
const lastrow = gridRef.current?.api.getDisplayedRowAtIndex(lastRowIndex);
|
||||||
|
lastrow?.setRowHeight(50);
|
||||||
|
makeBottomPlaceholders(lastrow?.data);
|
||||||
|
gridRef.current?.api.onRowHeightChanged();
|
||||||
|
gridRef.current?.api.refreshInfiniteCache();
|
||||||
}
|
}
|
||||||
};
|
}, [makeBottomPlaceholders]);
|
||||||
|
|
||||||
const onBodyScroll = (event: BodyScrollEvent) => {
|
const onBodyScrollEnd = useCallback(
|
||||||
|
(event: BodyScrollEndEvent) => {
|
||||||
|
if (event.top === 0) {
|
||||||
|
addNewRows();
|
||||||
|
}
|
||||||
|
checkBottomPlaceholder();
|
||||||
|
},
|
||||||
|
[addNewRows, checkBottomPlaceholder]
|
||||||
|
);
|
||||||
|
|
||||||
|
const onBodyScroll = useCallback((event: BodyScrollEvent) => {
|
||||||
scrolledToTop.current = event.top <= 0;
|
scrolledToTop.current = event.top <= 0;
|
||||||
};
|
}, []);
|
||||||
|
|
||||||
|
const { isFullWidthRow, fullWidthCellRenderer, rowClassRules } =
|
||||||
|
useBottomPlaceholder<Trade>({
|
||||||
|
gridRef,
|
||||||
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="h-full relative">
|
<div className="h-full relative">
|
||||||
@ -48,6 +79,9 @@ export const FillsManager = ({
|
|||||||
onMarketClick={onMarketClick}
|
onMarketClick={onMarketClick}
|
||||||
suppressLoadingOverlay
|
suppressLoadingOverlay
|
||||||
suppressNoRowsOverlay
|
suppressNoRowsOverlay
|
||||||
|
isFullWidthRow={isFullWidthRow}
|
||||||
|
fullWidthCellRenderer={fullWidthCellRenderer}
|
||||||
|
rowClassRules={rowClassRules}
|
||||||
/>
|
/>
|
||||||
<div className="pointer-events-none absolute inset-0">
|
<div className="pointer-events-none absolute inset-0">
|
||||||
<AsyncRenderer
|
<AsyncRenderer
|
||||||
|
@ -22,6 +22,21 @@ export const useFillsList = ({
|
|||||||
const dataRef = useRef<(TradeEdge | null)[] | null>(null);
|
const dataRef = useRef<(TradeEdge | null)[] | null>(null);
|
||||||
const totalCountRef = useRef<number | undefined>(undefined);
|
const totalCountRef = useRef<number | undefined>(undefined);
|
||||||
const newRows = useRef(0);
|
const newRows = useRef(0);
|
||||||
|
const placeholderAdded = useRef(-1);
|
||||||
|
|
||||||
|
const makeBottomPlaceholders = useCallback((trade?: Trade) => {
|
||||||
|
if (!trade) {
|
||||||
|
if (placeholderAdded.current >= 0) {
|
||||||
|
dataRef.current?.splice(placeholderAdded.current, 1);
|
||||||
|
}
|
||||||
|
placeholderAdded.current = -1;
|
||||||
|
} else if (placeholderAdded.current === -1) {
|
||||||
|
dataRef.current?.push({
|
||||||
|
node: { ...trade, id: `${trade?.id}-1`, isLastPlaceholder: true },
|
||||||
|
});
|
||||||
|
placeholderAdded.current = (dataRef.current?.length || 0) - 1;
|
||||||
|
}
|
||||||
|
}, []);
|
||||||
|
|
||||||
const addNewRows = useCallback(() => {
|
const addNewRows = useCallback(() => {
|
||||||
if (newRows.current === 0) {
|
if (newRows.current === 0) {
|
||||||
@ -87,5 +102,13 @@ export const useFillsList = ({
|
|||||||
load,
|
load,
|
||||||
newRows
|
newRows
|
||||||
);
|
);
|
||||||
return { data, error, loading, addNewRows, getRows, reload };
|
return {
|
||||||
|
data,
|
||||||
|
error,
|
||||||
|
loading,
|
||||||
|
addNewRows,
|
||||||
|
getRows,
|
||||||
|
reload,
|
||||||
|
makeBottomPlaceholders,
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
@ -5,8 +5,10 @@ import { PositionsManager } from './positions-manager';
|
|||||||
|
|
||||||
export const PositionsContainer = ({
|
export const PositionsContainer = ({
|
||||||
onMarketClick,
|
onMarketClick,
|
||||||
|
noBottomPlaceholder,
|
||||||
}: {
|
}: {
|
||||||
onMarketClick?: (marketId: string) => void;
|
onMarketClick?: (marketId: string) => void;
|
||||||
|
noBottomPlaceholder?: boolean;
|
||||||
}) => {
|
}) => {
|
||||||
const { pubKey, isReadOnly } = useVegaWallet();
|
const { pubKey, isReadOnly } = useVegaWallet();
|
||||||
|
|
||||||
@ -22,6 +24,7 @@ export const PositionsContainer = ({
|
|||||||
partyId={pubKey}
|
partyId={pubKey}
|
||||||
onMarketClick={onMarketClick}
|
onMarketClick={onMarketClick}
|
||||||
isReadOnly={isReadOnly}
|
isReadOnly={isReadOnly}
|
||||||
|
noBottomPlaceholder={noBottomPlaceholder}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -1,21 +1,25 @@
|
|||||||
import { useRef } from 'react';
|
import { useCallback, useRef } from 'react';
|
||||||
import { AsyncRenderer } from '@vegaprotocol/ui-toolkit';
|
import { AsyncRenderer } from '@vegaprotocol/ui-toolkit';
|
||||||
|
import type { Position } from '../';
|
||||||
import { usePositionsData, PositionsTable } from '../';
|
import { usePositionsData, PositionsTable } from '../';
|
||||||
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';
|
||||||
import { t } from '@vegaprotocol/i18n';
|
import { t } from '@vegaprotocol/i18n';
|
||||||
|
import { useBottomPlaceholder } from '@vegaprotocol/react-helpers';
|
||||||
|
|
||||||
interface PositionsManagerProps {
|
interface PositionsManagerProps {
|
||||||
partyId: string;
|
partyId: string;
|
||||||
onMarketClick?: (marketId: string) => void;
|
onMarketClick?: (marketId: string) => void;
|
||||||
isReadOnly: boolean;
|
isReadOnly: boolean;
|
||||||
|
noBottomPlaceholder?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const PositionsManager = ({
|
export const PositionsManager = ({
|
||||||
partyId,
|
partyId,
|
||||||
onMarketClick,
|
onMarketClick,
|
||||||
isReadOnly,
|
isReadOnly,
|
||||||
|
noBottomPlaceholder,
|
||||||
}: PositionsManagerProps) => {
|
}: PositionsManagerProps) => {
|
||||||
const gridRef = useRef<AgGridReact | null>(null);
|
const gridRef = useRef<AgGridReact | null>(null);
|
||||||
const { data, error, loading, reload } = usePositionsData(
|
const { data, error, loading, reload } = usePositionsData(
|
||||||
@ -52,6 +56,18 @@ export const PositionsManager = ({
|
|||||||
],
|
],
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const setId = useCallback((data: Position) => {
|
||||||
|
return {
|
||||||
|
...data,
|
||||||
|
marketId: `${data.marketId}-1`,
|
||||||
|
};
|
||||||
|
}, []);
|
||||||
|
const bottomPlaceholderProps = useBottomPlaceholder<Position>({
|
||||||
|
gridRef,
|
||||||
|
setId,
|
||||||
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="h-full relative">
|
<div className="h-full relative">
|
||||||
<PositionsTable
|
<PositionsTable
|
||||||
@ -61,6 +77,7 @@ export const PositionsManager = ({
|
|||||||
onClose={onClose}
|
onClose={onClose}
|
||||||
noRowsOverlayComponent={() => null}
|
noRowsOverlayComponent={() => null}
|
||||||
isReadOnly={isReadOnly}
|
isReadOnly={isReadOnly}
|
||||||
|
{...(noBottomPlaceholder ? null : bottomPlaceholderProps)}
|
||||||
/>
|
/>
|
||||||
<div className="pointer-events-none absolute inset-0">
|
<div className="pointer-events-none absolute inset-0">
|
||||||
<AsyncRenderer
|
<AsyncRenderer
|
||||||
|
Loading…
Reference in New Issue
Block a user