feat(trading): deposit to trade collateral tab pinned row (#2921)

This commit is contained in:
m.ray 2023-02-17 08:32:20 -05:00 committed by GitHub
parent 989a0456c0
commit c22fec97b4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 178 additions and 78 deletions

View File

@ -96,7 +96,15 @@ export const MarketPage = () => {
const tradeView = useMemo(() => { const tradeView = useMemo(() => {
if (w > 960) { if (w > 960) {
return <TradeGrid market={data} onSelect={onSelect} />; return (
<TradeGrid
market={data}
onSelect={onSelect}
pinnedAsset={
data?.tradableInstrument.instrument.product.settlementAsset
}
/>
);
} }
return ( return (
<TradePanels <TradePanels

View File

@ -28,6 +28,7 @@ import { NO_MARKET } from './constants';
import { LiquidityContainer } from '../liquidity/liquidity'; import { LiquidityContainer } from '../liquidity/liquidity';
import { useNavigate } from 'react-router-dom'; import { useNavigate } from 'react-router-dom';
import { Links, Routes } from '../../pages/client-router'; import { Links, Routes } from '../../pages/client-router';
import type { PinnedAsset } from '@vegaprotocol/accounts';
type MarketDependantView = type MarketDependantView =
| typeof CandlesChartContainer | typeof CandlesChartContainer
@ -65,14 +66,17 @@ type TradingView = keyof typeof TradingViews;
interface TradeGridProps { interface TradeGridProps {
market: Market | null; market: Market | null;
onSelect: (marketId: string) => void; onSelect: (marketId: string) => void;
pinnedAsset?: PinnedAsset;
} }
const MainGrid = ({ const MainGrid = ({
marketId, marketId,
onSelect, onSelect,
pinnedAsset,
}: { }: {
marketId: string; marketId: string;
onSelect?: (marketId: string) => void; onSelect?: (marketId: string) => void;
pinnedAsset?: PinnedAsset;
}) => { }) => {
const navigate = useNavigate(); const navigate = useNavigate();
const onMarketClick = (marketId: string) => { const onMarketClick = (marketId: string) => {
@ -175,7 +179,7 @@ const MainGrid = ({
</Tab> </Tab>
<Tab id="accounts" name={t('Collateral')}> <Tab id="accounts" name={t('Collateral')}>
<VegaWalletContainer> <VegaWalletContainer>
<TradingViews.Collateral /> <TradingViews.Collateral pinnedAsset={pinnedAsset} />
</VegaWalletContainer> </VegaWalletContainer>
</Tab> </Tab>
</Tabs> </Tabs>
@ -186,11 +190,19 @@ const MainGrid = ({
}; };
const MainGridWrapped = memo(MainGrid); const MainGridWrapped = memo(MainGrid);
export const TradeGrid = ({ market, onSelect }: TradeGridProps) => { export const TradeGrid = ({
market,
onSelect,
pinnedAsset,
}: TradeGridProps) => {
return ( return (
<div className="h-full grid grid-rows-[min-content_1fr]"> <div className="h-full grid grid-rows-[min-content_1fr]">
<TradeMarketHeader market={market} onSelect={onSelect} /> <TradeMarketHeader market={market} onSelect={onSelect} />
<MainGridWrapped marketId={market?.id || ''} onSelect={onSelect} /> <MainGridWrapped
marketId={market?.id || ''}
onSelect={onSelect}
pinnedAsset={pinnedAsset}
/>
</div> </div>
); );
}; };
@ -214,12 +226,14 @@ interface TradePanelsProps {
onSelect: (marketId: string) => void; onSelect: (marketId: string) => void;
onMarketClick?: (marketId: string) => void; onMarketClick?: (marketId: string) => void;
onClickCollateral: () => void; onClickCollateral: () => void;
pinnedAsset?: PinnedAsset;
} }
export const TradePanels = ({ export const TradePanels = ({
market, market,
onSelect, onSelect,
onClickCollateral, onClickCollateral,
pinnedAsset,
}: TradePanelsProps) => { }: TradePanelsProps) => {
const [view, setView] = useState<TradingView>('Candles'); const [view, setView] = useState<TradingView>('Candles');
const renderView = () => { const renderView = () => {
@ -228,6 +242,7 @@ export const TradePanels = ({
onSelect: (marketId: string) => void; onSelect: (marketId: string) => void;
onMarketClick?: (marketId: string) => void; onMarketClick?: (marketId: string) => void;
onClickCollateral: () => void; onClickCollateral: () => void;
pinnedAsset?: PinnedAsset;
}>(TradingViews[view]); }>(TradingViews[view]);
if (!Component) { if (!Component) {
@ -241,6 +256,7 @@ export const TradePanels = ({
marketId={market?.id} marketId={market?.id}
onSelect={onSelect} onSelect={onSelect}
onClickCollateral={onClickCollateral} onClickCollateral={onClickCollateral}
pinnedAsset={pinnedAsset}
/> />
); );
}; };

View File

@ -5,10 +5,15 @@ import { useWithdrawalDialog } from '@vegaprotocol/withdraws';
import { useAssetDetailsDialogStore } from '@vegaprotocol/assets'; import { useAssetDetailsDialogStore } from '@vegaprotocol/assets';
import { Splash } from '@vegaprotocol/ui-toolkit'; import { Splash } from '@vegaprotocol/ui-toolkit';
import { useVegaWallet } from '@vegaprotocol/wallet'; import { useVegaWallet } from '@vegaprotocol/wallet';
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';
export const AccountsContainer = () => { export const AccountsContainer = ({
pinnedAsset,
}: {
pinnedAsset?: PinnedAsset;
}) => {
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);
@ -39,6 +44,7 @@ export const AccountsContainer = () => {
onClickWithdraw={openWithdrawalDialog} onClickWithdraw={openWithdrawalDialog}
onClickDeposit={openDepositDialog} onClickDeposit={openDepositDialog}
isReadOnly={isReadOnly} isReadOnly={isReadOnly}
pinnedAsset={pinnedAsset}
/> />
</div> </div>
{!isReadOnly && ( {!isReadOnly && (

View File

@ -4,6 +4,7 @@ import type { AgGridReact } from 'ag-grid-react';
import { useRef, useMemo, memo } from 'react'; import { useRef, useMemo, memo } from 'react';
import type { AccountFields } from './accounts-data-provider'; import type { AccountFields } from './accounts-data-provider';
import { aggregatedAccountsDataProvider } from './accounts-data-provider'; import { aggregatedAccountsDataProvider } from './accounts-data-provider';
import type { PinnedAsset } from './accounts-table';
import { AccountTable } from './accounts-table'; import { AccountTable } from './accounts-table';
interface AccountManagerProps { interface AccountManagerProps {
@ -12,6 +13,7 @@ interface AccountManagerProps {
onClickWithdraw?: (assetId?: string) => void; onClickWithdraw?: (assetId?: string) => void;
onClickDeposit?: (assetId?: string) => void; onClickDeposit?: (assetId?: string) => void;
isReadOnly: boolean; isReadOnly: boolean;
pinnedAsset?: PinnedAsset;
} }
export const AccountManager = ({ export const AccountManager = ({
@ -20,6 +22,7 @@ export const AccountManager = ({
onClickDeposit, onClickDeposit,
partyId, partyId,
isReadOnly, isReadOnly,
pinnedAsset,
}: AccountManagerProps) => { }: AccountManagerProps) => {
const gridRef = useRef<AgGridReact | null>(null); const gridRef = useRef<AgGridReact | null>(null);
const variables = useMemo(() => ({ partyId }), [partyId]); const variables = useMemo(() => ({ partyId }), [partyId]);
@ -41,6 +44,7 @@ export const AccountManager = ({
onClickWithdraw={onClickWithdraw} onClickWithdraw={onClickWithdraw}
isReadOnly={isReadOnly} isReadOnly={isReadOnly}
noRowsOverlayComponent={() => null} noRowsOverlayComponent={() => null}
pinnedAsset={pinnedAsset}
/> />
<div className="pointer-events-none absolute inset-0"> <div className="pointer-events-none absolute inset-0">
<AsyncRenderer <AsyncRenderer
@ -48,7 +52,7 @@ export const AccountManager = ({
noDataCondition={(data) => !(data && data.length)} noDataCondition={(data) => !(data && data.length)}
error={error} error={error}
loading={loading} loading={loading}
noDataMessage={t('No accounts')} noDataMessage={pinnedAsset ? ' ' : t('No accounts')}
reload={reload} reload={reload}
/> />
</div> </div>

View File

@ -72,10 +72,31 @@ describe('AccountsTable', () => {
cells.forEach((cell, i) => { cells.forEach((cell, i) => {
expect(cell).toHaveTextContent(expectedValues[i]); expect(cell).toHaveTextContent(expectedValues[i]);
}); });
const rows = await screen.findAllByRole('row');
expect(rows.length).toBe(6);
}); });
});
it('should get correct account data', () => { it('should add first asset as pinned', async () => {
await act(async () => {
render(
<AccountTable
rowData={singleRowData}
onClickAsset={() => null}
isReadOnly={false}
pinnedAsset={{
decimals: 5,
id: '5cfa87844724df6069b94e4c8a6f03af21907d7bc251593d08e4251043ee9f7c',
symbol: 'tBTC',
name: 'tBTC',
}}
/>
);
});
const rows = await screen.findAllByRole('row');
expect(rows.length).toBe(9);
});
it('should get correct account data', () => {
const result = getAccountData([singleRow]); const result = getAccountData([singleRow]);
const expected = [ const expected = [
{ {
@ -120,4 +141,5 @@ it('should get correct account data', () => {
}, },
]; ];
expect(result).toEqual(expected); expect(result).toEqual(expected);
});
}); });

View File

@ -1,4 +1,4 @@
import { forwardRef, useState } from 'react'; import { forwardRef, useMemo, useState } from 'react';
import { import {
addDecimalsFormatNumber, addDecimalsFormatNumber,
isNumeric, isNumeric,
@ -14,6 +14,8 @@ import type { AgGridReact, AgGridReactProps } from 'ag-grid-react';
import type { VegaValueFormatterParams } from '@vegaprotocol/ui-toolkit'; import type { VegaValueFormatterParams } from '@vegaprotocol/ui-toolkit';
import BreakdownTable from './breakdown-table'; 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 BigNumber from 'bignumber.js';
export interface GetRowsParams extends Omit<IGetRowsParams, 'successCallback'> { export interface GetRowsParams extends Omit<IGetRowsParams, 'successCallback'> {
successCallback(rowsThisBlock: AccountFields[], lastRow?: number): void; successCallback(rowsThisBlock: AccountFields[], lastRow?: number): void;
@ -23,6 +25,8 @@ export interface Datasource extends IDatasource {
getRows(params: GetRowsParams): void; getRows(params: GetRowsParams): void;
} }
export type PinnedAsset = Pick<Asset, 'symbol' | 'name' | 'id' | 'decimals'>;
export interface AccountTableProps extends AgGridReactProps { export interface AccountTableProps extends AgGridReactProps {
rowData?: AccountFields[] | null; rowData?: AccountFields[] | null;
datasource?: Datasource; datasource?: Datasource;
@ -30,12 +34,33 @@ export interface AccountTableProps extends AgGridReactProps {
onClickWithdraw?: (assetId: string) => void; onClickWithdraw?: (assetId: string) => void;
onClickDeposit?: (assetId: string) => void; onClickDeposit?: (assetId: string) => void;
isReadOnly: boolean; isReadOnly: boolean;
pinnedAsset?: PinnedAsset;
} }
export const AccountTable = forwardRef<AgGridReact, AccountTableProps>( export const AccountTable = forwardRef<AgGridReact, AccountTableProps>(
({ onClickAsset, onClickWithdraw, onClickDeposit, ...props }, ref) => { ({ onClickAsset, onClickWithdraw, onClickDeposit, ...props }, ref) => {
const [openBreakdown, setOpenBreakdown] = useState(false); const [openBreakdown, setOpenBreakdown] = useState(false);
const [breakdown, setBreakdown] = useState<AccountFields[] | null>(null); const [breakdown, setBreakdown] = useState<AccountFields[] | null>(null);
const pinnedAssetId = props.pinnedAsset?.id;
const pinnedAssetRow = useMemo(() => {
const currentPinnedAssetRow = props.rowData?.find(
(row) => row.asset.id === pinnedAssetId
);
if (!currentPinnedAssetRow) {
if (props.pinnedAsset) {
return {
asset: props.pinnedAsset,
available: '0',
used: '0',
deposited: '0',
balance: '0',
};
}
}
return currentPinnedAssetRow;
}, [pinnedAssetId, props.pinnedAsset, props.rowData]);
return ( return (
<> <>
<AgGrid <AgGrid
@ -51,6 +76,7 @@ export const AccountTable = forwardRef<AgGridReact, AccountTableProps>(
sortable: true, sortable: true,
}} }}
{...props} {...props}
pinnedTopRowData={pinnedAssetRow ? [pinnedAssetRow] : undefined}
> >
<AgGridColumn <AgGridColumn
headerName={t('Asset')} headerName={t('Asset')}
@ -138,7 +164,24 @@ export const AccountTable = forwardRef<AgGridReact, AccountTableProps>(
cellRenderer={({ cellRenderer={({
data, data,
}: VegaICellRendererParams<AccountFields>) => { }: VegaICellRendererParams<AccountFields>) => {
return data ? ( if (!data) return null;
else {
if (
data.asset.id === pinnedAssetId &&
new BigNumber(data.deposited).isLessThanOrEqualTo(0)
) {
return (
<ButtonLink
data-testid="deposit"
onClick={() => {
onClickDeposit && onClickDeposit(data.asset.id);
}}
>
{t('Deposit to trade')}
</ButtonLink>
);
}
return (
<> <>
<ButtonLink <ButtonLink
data-testid="breakdown" data-testid="breakdown"
@ -168,7 +211,8 @@ export const AccountTable = forwardRef<AgGridReact, AccountTableProps>(
{t('Withdraw')} {t('Withdraw')}
</ButtonLink> </ButtonLink>
</> </>
) : null; );
}
}} }}
/> />
)} )}