feat: added asset details dialog to market select (1226) (#1260)

* feat: added asset details dialog to market select (1226)

* Update libs/ui-toolkit/src/components/dialog/dialog.tsx

Co-authored-by: Matthew Russell <mattrussell36@gmail.com>

* removed focus complexity from popover, refactored

* chore: after rebase fixes

* fix: fixed console-lite asset details dialog func - after rebase

* fix: added mock for one failing test, removed console.log

* fix: removed increased timeout - not needed

Co-authored-by: Matthew Russell <mattrussell36@gmail.com>
This commit is contained in:
Art
2022-09-23 15:14:52 +02:00
committed by GitHub
co-authored by Matthew Russell
parent d60cf3e5e6
commit ebf2bfc7a9
17 changed files with 292 additions and 123 deletions
@@ -28,11 +28,7 @@ interface Props {
}
const AccountsManager = ({ partyId }: Props) => {
const {
isAssetDetailsDialogOpen,
assetDetailsDialogSymbol,
setAssetDetailsDialogOpen,
} = useAssetDetailsDialogStore();
const { isOpen, symbol, setOpen } = useAssetDetailsDialogStore();
const gridRef = useRef<AgGridReact | null>(null);
const variables = useMemo(() => ({ partyId }), [partyId]);
const update = useMemo(() => accountsManagerUpdate(gridRef), []);
@@ -58,9 +54,9 @@ const AccountsManager = ({ partyId }: Props) => {
/>
</AsyncRenderer>
<AssetDetailsDialog
assetSymbol={assetDetailsDialogSymbol}
open={isAssetDetailsDialogOpen}
onChange={(open) => setAssetDetailsDialogOpen(open)}
assetSymbol={symbol}
open={isOpen}
onChange={(open) => setOpen(open)}
/>
</>
);
@@ -42,8 +42,7 @@ const comparator = (
};
const useAccountColumnDefinitions = () => {
const { setAssetDetailsDialogOpen, setAssetDetailsDialogSymbol } =
useAssetDetailsDialogStore();
const { open } = useAssetDetailsDialogStore();
const columnDefs: ColDef[] = useMemo(() => {
return [
{
@@ -60,8 +59,7 @@ const useAccountColumnDefinitions = () => {
<button
className="hover:underline"
onClick={() => {
setAssetDetailsDialogOpen(true);
setAssetDetailsDialogSymbol(value);
open(value);
}}
>
{value}
@@ -97,7 +95,7 @@ const useAccountColumnDefinitions = () => {
addDecimalsFormatNumber(value, data.asset.decimals),
},
];
}, [setAssetDetailsDialogOpen, setAssetDetailsDialogSymbol]);
}, [open]);
const defaultColDef = useMemo(() => {
return {
@@ -1,4 +1,6 @@
import { connectVegaWallet } from '../support/vega-wallet';
import { aliasQuery } from '@vegaprotocol/cypress';
import { generateNetworkParameters } from '../support/mocks/generate-network-parameters';
describe('vega wallet', { tags: '@smoke' }, () => {
const connectVegaBtn = 'connect-vega-wallet';
@@ -66,11 +68,16 @@ describe('ethereum wallet', { tags: '@smoke' }, () => {
cy.mockWeb3Provider();
// Using portfolio withdrawals tab is it requires Ethereum wallet connection
cy.visit('/portfolio');
cy.mockGQL((req) => {
aliasQuery(req, 'NetworkParamsQuery', generateNetworkParameters());
});
cy.mockGQLSubscription();
cy.get('main[data-testid="portfolio"]').should('exist');
cy.getByTestId('Withdrawals').click();
});
it('can connect', () => {
cy.wait('@NetworkParamsQuery');
cy.getByTestId('connect-eth-wallet-btn').click();
cy.getByTestId('web3-connector-list').should('exist');
cy.getByTestId('web3-connector-MetaMask').click();
+5 -8
View File
@@ -20,11 +20,7 @@ function AppBody({ Component, pageProps }: AppProps) {
connectDialog: store.connectDialog,
update: store.update,
}));
const {
isAssetDetailsDialogOpen,
assetDetailsDialogSymbol,
setAssetDetailsDialogOpen,
} = useAssetDetailsDialogStore();
const { isOpen, symbol, trigger, setOpen } = useAssetDetailsDialogStore();
const [theme, toggleTheme] = useThemeSwitcher();
return (
@@ -46,9 +42,10 @@ function AppBody({ Component, pageProps }: AppProps) {
setDialogOpen={(open) => update({ connectDialog: open })}
/>
<AssetDetailsDialog
assetSymbol={assetDetailsDialogSymbol}
open={isAssetDetailsDialogOpen}
onChange={(open) => setAssetDetailsDialogOpen(open)}
assetSymbol={symbol}
trigger={trigger || null}
open={isOpen}
onChange={setOpen}
/>
<RiskNoticeDialog />
</AppLoader>
@@ -1,5 +1,6 @@
import { gql } from '@apollo/client';
import { SelectMarketDialog } from '@vegaprotocol/market-list';
import { useAssetDetailsDialogStore } from '@vegaprotocol/assets';
import { ColumnKind, SelectMarketDialog } from '@vegaprotocol/market-list';
import { t } from '@vegaprotocol/react-helpers';
import { Interval } from '@vegaprotocol/types';
import { Splash } from '@vegaprotocol/ui-toolkit';
@@ -91,6 +92,7 @@ const MarketPage = ({ id }: { id?: string }) => {
const { update: updateStore } = useGlobalStore((store) => ({
update: store.update,
}));
const { open: openAssetDetailsDialog } = useAssetDetailsDialogStore();
// Default to first marketId query item if found
const marketId =
@@ -152,6 +154,11 @@ const MarketPage = ({ id }: { id?: string }) => {
update({ landingDialog: isOpen })
}
onSelect={onSelect}
onCellClick={(e, kind, value) => {
if (value && kind === ColumnKind.Asset) {
openAssetDetailsDialog(value, e.target as HTMLElement);
}
}}
/>
</>
);
+12 -6
View File
@@ -1,6 +1,8 @@
import { DealTicketContainer } from '@vegaprotocol/deal-ticket';
import { MarketInfoContainer } from '@vegaprotocol/market-info';
import { OrderbookContainer } from '@vegaprotocol/market-depth';
import { ColumnKind, SelectMarketPopover } from '@vegaprotocol/market-list';
import type { OnCellClickHandler } from '@vegaprotocol/market-list';
import { OrderListContainer } from '@vegaprotocol/orders';
import { FillsContainer } from '@vegaprotocol/fills';
import { PositionsContainer } from '@vegaprotocol/positions';
@@ -28,7 +30,6 @@ import {
getDateFormat,
t,
} from '@vegaprotocol/react-helpers';
import { SelectMarketPopover } from '@vegaprotocol/market-list';
import { useAssetDetailsDialogStore } from '@vegaprotocol/assets';
import { useEnvironment } from '@vegaprotocol/environment';
import type { CandleClose } from '@vegaprotocol/types';
@@ -116,8 +117,7 @@ export const TradeMarketHeader = ({
onSelect,
}: TradeMarketHeaderProps) => {
const { VEGA_EXPLORER_URL } = useEnvironment();
const { setAssetDetailsDialogOpen, setAssetDetailsDialogSymbol } =
useAssetDetailsDialogStore();
const { open: openAssetDetailsDialog } = useAssetDetailsDialogStore();
const candlesClose: string[] = (market?.candlesConnection?.edges || [])
.map((candle) => candle?.node.close)
@@ -125,12 +125,19 @@ export const TradeMarketHeader = ({
const symbol =
market.tradableInstrument.instrument.product?.settlementAsset?.symbol;
const onCellClick: OnCellClickHandler = (e, kind, value) => {
if (value && kind === ColumnKind.Asset) {
openAssetDetailsDialog(value, e.target as HTMLElement);
}
};
return (
<Header
title={
<SelectMarketPopover
marketName={market.tradableInstrument.instrument.name}
onSelect={onSelect}
onCellClick={onCellClick}
/>
}
>
@@ -196,9 +203,8 @@ export const TradeMarketHeader = ({
<HeaderStat heading={t('Settlement asset')}>
<div data-testid="trading-mode">
<ButtonLink
onClick={() => {
setAssetDetailsDialogOpen(true);
setAssetDetailsDialogSymbol(symbol);
onClick={(e) => {
openAssetDetailsDialog(symbol, e.target as HTMLElement);
}}
>
{symbol}
@@ -13,7 +13,6 @@ export const WithdrawalsContainer = () => {
const { withdrawals, loading, error } = useWithdrawals();
const [withdrawDialog, setWithdrawDialog] = useState(false);
console.log('render');
return (
<Web3Container>
<VegaWalletContainer>
+3 -5
View File
@@ -92,8 +92,7 @@ const comparator = (
export const AccountsTable = forwardRef<AgGridReact, AccountsTableProps>(
({ data }, ref) => {
const { setAssetDetailsDialogOpen, setAssetDetailsDialogSymbol } =
useAssetDetailsDialogStore();
const { open: openAssetDetailsDialog } = useAssetDetailsDialogStore();
return (
<AgGrid
style={{ width: '100%', height: '100%' }}
@@ -130,9 +129,8 @@ export const AccountsTable = forwardRef<AgGridReact, AccountsTableProps>(
value && value.length > 0 ? (
<button
className="hover:underline"
onClick={() => {
setAssetDetailsDialogOpen(true);
setAssetDetailsDialogSymbol(value);
onClick={(e) => {
openAssetDetailsDialog(value, e.target as HTMLElement);
}}
>
{value}
+16
View File
@@ -0,0 +1,16 @@
query Asset($assetId: ID!) {
asset(assetId: $assetId) {
id
name
symbol
decimals
quantum
source {
... on ERC20 {
contractAddress
lifetimeLimit
withdrawThreshold
}
}
}
}
@@ -0,0 +1,59 @@
import * as Types from '@vegaprotocol/types/types';
import { gql } from '@apollo/client';
import * as Apollo from '@apollo/client';
const defaultOptions = {} as const;
export type AssetQueryVariables = Types.Exact<{
assetId: Types.Scalars['ID'];
}>;
export type AssetQuery = { __typename?: 'Query', asset?: { __typename?: 'Asset', id: string, name: string, symbol: string, decimals: number, quantum: string, source: { __typename?: 'BuiltinAsset' } | { __typename?: 'ERC20', contractAddress: string, lifetimeLimit: string, withdrawThreshold: string } } | null };
export const AssetDocument = gql`
query Asset($assetId: ID!) {
asset(assetId: $assetId) {
id
name
symbol
decimals
quantum
source {
... on ERC20 {
contractAddress
lifetimeLimit
withdrawThreshold
}
}
}
}
`;
/**
* __useAssetQuery__
*
* To run a query within a React component, call `useAssetQuery` and pass it any options that fit your needs.
* When your component renders, `useAssetQuery` returns an object from Apollo Client that contains loading, error, and data properties
* you can use to render your UI.
*
* @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options;
*
* @example
* const { data, loading, error } = useAssetQuery({
* variables: {
* assetId: // value for 'assetId'
* },
* });
*/
export function useAssetQuery(baseOptions: Apollo.QueryHookOptions<AssetQuery, AssetQueryVariables>) {
const options = {...defaultOptions, ...baseOptions}
return Apollo.useQuery<AssetQuery, AssetQueryVariables>(AssetDocument, options);
}
export function useAssetLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions<AssetQuery, AssetQueryVariables>) {
const options = {...defaultOptions, ...baseOptions}
return Apollo.useLazyQuery<AssetQuery, AssetQueryVariables>(AssetDocument, options);
}
export type AssetQueryHookResult = ReturnType<typeof useAssetQuery>;
export type AssetLazyQueryHookResult = ReturnType<typeof useAssetLazyQuery>;
export type AssetQueryResult = Apollo.QueryResult<AssetQuery, AssetQueryVariables>;
+34 -11
View File
@@ -14,21 +14,27 @@ import type { Schema } from '@vegaprotocol/types';
import create from 'zustand';
export type AssetDetailsDialogStore = {
isAssetDetailsDialogOpen: boolean;
assetDetailsDialogSymbol: string | Asset;
setAssetDetailsDialogOpen: (isOpen: boolean) => void;
setAssetDetailsDialogSymbol: (symbol: string | Asset) => void;
isOpen: boolean;
symbol: string | Asset;
trigger: HTMLElement | null | undefined;
setOpen: (isOpen: boolean) => void;
open: (symbol: string | Asset, trigger?: HTMLElement | null) => void;
};
export const useAssetDetailsDialogStore = create<AssetDetailsDialogStore>(
(set) => ({
isAssetDetailsDialogOpen: false,
assetDetailsDialogSymbol: '',
setAssetDetailsDialogOpen: (isOpen: boolean) => {
set({ isAssetDetailsDialogOpen: isOpen });
isOpen: false,
symbol: '',
trigger: null,
setOpen: (isOpen) => {
set({ isOpen: isOpen });
},
setAssetDetailsDialogSymbol: (symbol: string | Asset) => {
set({ assetDetailsDialogSymbol: symbol });
open: (symbol, trigger?) => {
set({
isOpen: true,
symbol: symbol,
trigger: trigger,
});
},
})
);
@@ -42,12 +48,14 @@ type AssetDetails = {
export interface AssetDetailsDialogProps {
assetSymbol: string | Asset;
trigger?: HTMLElement | null;
open: boolean;
onChange: (open: boolean) => void;
}
export const AssetDetailsDialog = ({
assetSymbol,
trigger,
open,
onChange,
}: AssetDetailsDialogProps) => {
@@ -148,10 +156,25 @@ export const AssetDetailsDialog = ({
icon={<Icon name="info-sign"></Icon>}
open={open}
onChange={(isOpen) => onChange(isOpen)}
onCloseAutoFocus={(e) => {
/**
* This mimics radix's default behaviour that focuses the dialog's
* trigger after closing itself
*/
if (trigger) {
e.preventDefault();
trigger.focus();
}
}}
>
{content}
<div className="w-1/4">
<Button fill={true} size="sm" onClick={() => onChange(false)}>
<Button
data-testid="close-asset-details-dialog"
fill={true}
size="sm"
onClick={() => onChange(false)}
>
Close
</Button>
</div>
+3 -5
View File
@@ -65,8 +65,7 @@ export const DepositForm = ({
allowance,
isFaucetable,
}: DepositFormProps) => {
const { setAssetDetailsDialogOpen, setAssetDetailsDialogSymbol } =
useAssetDetailsDialogStore();
const { open: openAssetDetailsDialog } = useAssetDetailsDialogStore();
const { account } = useWeb3React();
const { keypair } = useVegaWallet();
const {
@@ -185,9 +184,8 @@ export const DepositForm = ({
<button
data-testid="view-asset-details"
className="text-sm underline"
onClick={() => {
setAssetDetailsDialogOpen(true);
setAssetDetailsDialogSymbol(selectedAsset);
onClick={(e) => {
openAssetDetailsDialog(selectedAsset, e.target as HTMLElement);
}}
>
{t('View asset details')}
@@ -37,8 +37,7 @@ type MarketListTableValueFormatterParams = Omit<
export const getRowId = ({ data }: { data: { id: string } }) => data.id;
export const MarketListTable = forwardRef<AgGridReact, Props>((props, ref) => {
const { setAssetDetailsDialogOpen, setAssetDetailsDialogSymbol } =
useAssetDetailsDialogStore();
const { open: openAssetDetailsDialog } = useAssetDetailsDialogStore();
return (
<AgGrid
style={{ width: '100%', height: '100%' }}
@@ -67,9 +66,8 @@ export const MarketListTable = forwardRef<AgGridReact, Props>((props, ref) => {
value && value.length > 0 ? (
<button
className="hover:underline"
onClick={() => {
setAssetDetailsDialogOpen(true);
setAssetDetailsDialogSymbol(value);
onClick={(e) => {
openAssetDetailsDialog(value, e.target as HTMLElement);
}}
>
{value}
@@ -45,65 +45,96 @@ const FeesInfo = () => {
);
};
export enum ColumnKind {
Market,
LastPrice,
Change24,
Asset,
Sparkline,
High24,
Low24,
TradingMode,
Volume,
Fee,
Position,
FullName,
}
export interface Column {
kind: ColumnKind;
value: string | React.ReactNode;
className: string;
onlyOnDetailed: boolean;
dataTestId?: string;
}
export const columnHeadersPositionMarkets: Column[] = [
const headers: Column[] = [
{
kind: ColumnKind.Market,
value: t('Market'),
className: cellClassNames,
onlyOnDetailed: false,
},
{
kind: ColumnKind.LastPrice,
value: t('Last price'),
className: cellClassNames,
onlyOnDetailed: false,
},
{
kind: ColumnKind.Change24,
value: t('Change (24h)'),
className: cellClassNames,
onlyOnDetailed: false,
},
{
kind: ColumnKind.Asset,
value: t('Settlement asset'),
className: `${cellClassNames} hidden sm:table-cell`,
onlyOnDetailed: false,
},
{
kind: ColumnKind.Sparkline,
value: t(''),
className: `${cellClassNames} hidden lg:table-cell`,
onlyOnDetailed: false,
},
{
kind: ColumnKind.High24,
value: t('24h high'),
className: `${cellClassNames} hidden xl:table-cell`,
onlyOnDetailed: true,
},
{
kind: ColumnKind.Low24,
value: t('24h low'),
className: `${cellClassNames} hidden xl:table-cell`,
onlyOnDetailed: true,
},
{
kind: ColumnKind.TradingMode,
value: t('Trading mode'),
className: `${cellClassNames} hidden lg:table-cell`,
onlyOnDetailed: true,
},
{
kind: ColumnKind.Volume,
value: t('Volume'),
className: `${cellClassNames} hidden lg:table-cell`,
onlyOnDetailed: true,
},
{
kind: ColumnKind.Fee,
value: <FeesInfo />,
className: `${cellClassNames} hidden xl:table-cell`,
onlyOnDetailed: true,
},
];
export const columnHeadersPositionMarkets: Column[] = [
...headers,
{
kind: ColumnKind.Position,
value: t('Position'),
className: `${cellClassNames} hidden xxl:table-cell`,
onlyOnDetailed: true,
@@ -111,68 +142,27 @@ export const columnHeadersPositionMarkets: Column[] = [
];
export const columnHeaders: Column[] = [
...headers,
{
value: t('Market'),
className: cellClassNames,
onlyOnDetailed: false,
},
{
value: t('Last price'),
className: cellClassNames,
onlyOnDetailed: false,
},
{
value: t('Change (24h)'),
className: cellClassNames,
onlyOnDetailed: false,
},
{
value: t('Settlement asset'),
className: `${cellClassNames} hidden sm:table-cell`,
onlyOnDetailed: false,
},
{
value: t(''),
className: `${cellClassNames} hidden lg:table-cell`,
onlyOnDetailed: false,
},
{
value: t('24h high'),
className: `${cellClassNames} hidden xl:table-cell`,
onlyOnDetailed: true,
},
{
value: t('24h low'),
className: `${cellClassNames} hidden xl:table-cell`,
onlyOnDetailed: true,
},
{
value: t('Trading mode'),
className: `${cellClassNames} hidden lg:table-cell`,
onlyOnDetailed: true,
},
{
value: t('Volume'),
className: `${cellClassNames} hidden lg:table-cell`,
onlyOnDetailed: true,
},
{
value: <FeesInfo />,
className: `${cellClassNames} hidden xl:table-cell`,
onlyOnDetailed: true,
},
{
kind: ColumnKind.FullName,
value: t('Full name'),
className: `${cellClassNames} hidden xxl:block`,
onlyOnDetailed: true,
},
];
export type OnCellClickHandler = (
e: React.MouseEvent,
kind: ColumnKind,
value: string
) => void;
export const columns = (
market: Market,
marketData: MarketData | undefined,
candles: Candle[] | undefined,
onSelect: (id: string) => void
onSelect: (id: string) => void,
onCellClick: OnCellClickHandler
) => {
const candlesClose = candles
?.map((candle) => candle?.close)
@@ -189,6 +179,7 @@ export const columns = (
const candleHigh = candles && calcCandleHigh(candles);
const selectMarketColumns: Column[] = [
{
kind: ColumnKind.Market,
value: (
<Link href={`/markets/${market.id}`} passHref={true}>
{/* eslint-disable-next-line jsx-a11y/anchor-is-valid,jsx-a11y/no-static-element-interactions */}
@@ -207,6 +198,7 @@ export const columns = (
onlyOnDetailed: false,
},
{
kind: ColumnKind.LastPrice,
value: marketData?.markPrice ? (
<PriceCell
value={Number(marketData?.markPrice)}
@@ -223,6 +215,7 @@ export const columns = (
onlyOnDetailed: false,
},
{
kind: ColumnKind.Change24,
value: candlesClose && (
<PriceCellChange
candles={candlesClose}
@@ -233,13 +226,29 @@ export const columns = (
onlyOnDetailed: false,
},
{
value:
market.tradableInstrument.instrument.product.settlementAsset.symbol,
kind: ColumnKind.Asset,
value: (
<button
data-dialog-trigger
className="inline hover:underline"
onClick={(e) =>
onCellClick(
e,
ColumnKind.Asset,
market.tradableInstrument.instrument.product.settlementAsset
.symbol
)
}
>
{market.tradableInstrument.instrument.product.settlementAsset.symbol}
</button>
),
dataTestId: 'settlement-asset',
className: `${cellClassNames} hidden sm:table-cell`,
onlyOnDetailed: false,
},
{
kind: ColumnKind.Sparkline,
value: candles && (
<Sparkline
width={100}
@@ -252,6 +261,7 @@ export const columns = (
onlyOnDetailed: false && candlesClose,
},
{
kind: ColumnKind.High24,
value: candleHigh ? (
<PriceCell
value={Number(candleHigh)}
@@ -268,6 +278,7 @@ export const columns = (
onlyOnDetailed: true,
},
{
kind: ColumnKind.Low24,
value: candleLow ? (
<PriceCell
value={Number(candleLow)}
@@ -284,6 +295,7 @@ export const columns = (
onlyOnDetailed: true,
},
{
kind: ColumnKind.TradingMode,
value:
market.tradingMode ===
MarketTradingMode.TRADING_MODE_MONITORING_AUCTION &&
@@ -297,6 +309,7 @@ export const columns = (
dataTestId: 'trading-mode',
},
{
kind: ColumnKind.Volume,
value:
marketData?.indicativeVolume && marketData.indicativeVolume !== '0'
? addDecimalsFormatNumber(
@@ -309,12 +322,14 @@ export const columns = (
dataTestId: 'market-volume',
},
{
kind: ColumnKind.Fee,
value: <FeesCell feeFactors={market.fees.factors} />,
className: `${cellClassNames} hidden xl:table-cell font-mono`,
onlyOnDetailed: true,
dataTestId: 'taker-fee',
},
{
kind: ColumnKind.FullName,
value: market.tradableInstrument.instrument.name,
className: `${cellClassNames} hidden xxl:block`,
onlyOnDetailed: true,
@@ -329,7 +344,8 @@ export const columnsPositionMarkets = (
marketData: MarketData | undefined,
candles: Candle[] | undefined,
onSelect: (id: string) => void,
openVolume?: string
openVolume?: string,
onCellClick?: OnCellClickHandler
) => {
const candlesClose = candles
?.map((candle) => candle?.close)
@@ -346,6 +362,7 @@ export const columnsPositionMarkets = (
};
const selectMarketColumns: Column[] = [
{
kind: ColumnKind.Market,
value: (
<Link href={`/markets/${market.id}`} passHref={true}>
{/* eslint-disable-next-line jsx-a11y/anchor-is-valid,jsx-a11y/no-static-element-interactions */}
@@ -364,6 +381,7 @@ export const columnsPositionMarkets = (
onlyOnDetailed: false,
},
{
kind: ColumnKind.LastPrice,
value: marketData?.markPrice ? (
<PriceCell
value={Number(marketData.markPrice)}
@@ -380,6 +398,7 @@ export const columnsPositionMarkets = (
onlyOnDetailed: false,
},
{
kind: ColumnKind.Change24,
value: candlesClose && (
<PriceCellChange
candles={candlesClose}
@@ -390,12 +409,29 @@ export const columnsPositionMarkets = (
onlyOnDetailed: false,
},
{
value:
market.tradableInstrument.instrument.product.settlementAsset.symbol,
kind: ColumnKind.Asset,
value: (
<button
data-dialog-trigger
className="inline hover:underline"
onClick={(e) => {
if (!onCellClick) return;
onCellClick(
e,
ColumnKind.Asset,
market.tradableInstrument.instrument.product.settlementAsset
.symbol
);
}}
>
{market.tradableInstrument.instrument.product.settlementAsset.symbol}
</button>
),
className: `${cellClassNames} hidden sm:table-cell`,
onlyOnDetailed: false,
},
{
kind: ColumnKind.Sparkline,
value: candlesClose && (
<Sparkline
width={100}
@@ -408,6 +444,7 @@ export const columnsPositionMarkets = (
onlyOnDetailed: false,
},
{
kind: ColumnKind.High24,
value: candleHigh ? (
<PriceCell
value={Number(candleHigh)}
@@ -424,6 +461,7 @@ export const columnsPositionMarkets = (
onlyOnDetailed: true,
},
{
kind: ColumnKind.Low24,
value: candleLow ? (
<PriceCell
value={Number(candleLow)}
@@ -440,6 +478,7 @@ export const columnsPositionMarkets = (
onlyOnDetailed: true,
},
{
kind: ColumnKind.TradingMode,
value:
market.tradingMode ===
MarketTradingMode.TRADING_MODE_MONITORING_AUCTION &&
@@ -453,6 +492,7 @@ export const columnsPositionMarkets = (
dataTestId: 'trading-mode',
},
{
kind: ColumnKind.Volume,
value:
marketData && marketData.indicativeVolume !== '0'
? addDecimalsFormatNumber(
@@ -464,11 +504,13 @@ export const columnsPositionMarkets = (
onlyOnDetailed: true,
},
{
kind: ColumnKind.Fee,
value: <FeesCell feeFactors={market.fees.factors} />,
className: `${cellClassNames} hidden xl:table-cell font-mono`,
onlyOnDetailed: true,
},
{
kind: ColumnKind.Position,
value: (
<p className={signedNumberCssClass(openVolume || '')}>{openVolume}</p>
),
@@ -8,7 +8,7 @@ export const SelectMarketTableHeader = ({
}) => {
return (
<tr className="sticky top-0 z-10 border-b border-default bg-inherit">
{headers.map(({ value, className, onlyOnDetailed }, i) => {
{headers.map(({ kind, value, className, onlyOnDetailed }) => {
const thClass = classNames(
'font-normal text-neutral-500 dark:text-neutral-400',
className
@@ -16,7 +16,7 @@ export const SelectMarketTableHeader = ({
if (!onlyOnDetailed || detailed === onlyOnDetailed) {
return (
<th key={i} className={thClass}>
<th key={kind} className={thClass}>
{value}
</th>
);
@@ -39,11 +39,11 @@ export const SelectMarketTableRow = ({
<tr
className={`hover:bg-neutral-200 dark:hover:bg-neutral-700 cursor-pointer relative h-[34px]`}
>
{columns.map(({ value, className, dataTestId, onlyOnDetailed }, i) => {
{columns.map(({ kind, value, className, dataTestId, onlyOnDetailed }) => {
if (!onlyOnDetailed || detailed === onlyOnDetailed) {
const tdClass = classNames(className);
return (
<td key={i} data-testid={dataTestId} className={tdClass}>
<td key={kind} data-testid={dataTestId} className={tdClass}>
{value}
</td>
);
@@ -10,7 +10,7 @@ import {
import type { ReactNode } from 'react';
import { useMemo, useState } from 'react';
import type { Column } from './select-market-columns';
import type { Column, OnCellClickHandler } from './select-market-columns';
import {
columnHeadersPositionMarkets,
columnsPositionMarkets,
@@ -36,11 +36,13 @@ export const SelectMarketLandingTable = ({
marketsData,
marketsCandles,
onSelect,
onCellClick,
}: {
markets: Market[] | undefined;
marketsData: MarketData[] | undefined;
marketsCandles: MarketCandles[] | undefined;
onSelect: (id: string) => void;
onCellClick: OnCellClickHandler;
}) => {
return (
<>
@@ -65,7 +67,8 @@ export const SelectMarketLandingTable = ({
marketsCandles?.find(
(marketCandles) => marketCandles.marketId === market.id
)?.candles,
onSelect
onSelect,
onCellClick
)}
/>
))}
@@ -83,9 +86,10 @@ export const SelectAllMarketsTableBody = ({
marketsCandles,
positions,
onSelect,
onCellClick,
headers = columnHeaders,
tableColumns = (market, marketData, candles) =>
columns(market, marketData, candles, onSelect),
columns(market, marketData, candles, onSelect, onCellClick),
}: {
markets: Market[] | undefined;
marketsData: MarketData[] | undefined;
@@ -93,6 +97,7 @@ export const SelectAllMarketsTableBody = ({
positions?: Positions_party_positionsConnection_edges_node[];
title?: string;
onSelect: (id: string) => void;
onCellClick: OnCellClickHandler;
headers?: Column[];
tableColumns?: (
market: Market,
@@ -134,9 +139,11 @@ export const SelectAllMarketsTableBody = ({
export const SelectMarketPopover = ({
marketName,
onSelect,
onCellClick,
}: {
marketName: string;
onSelect: (id: string) => void;
onCellClick: OnCellClickHandler;
}) => {
const triggerClasses =
'sm:text-lg md:text-xl lg:text-2xl flex items-center gap-2 whitespace-nowrap hover:text-neutral-500 dark:hover:text-neutral-300';
@@ -203,6 +210,7 @@ export const SelectMarketPopover = ({
?.filter((edge) => edge.node)
.map((edge) => edge.node)}
onSelect={onSelectMarket}
onCellClick={onCellClick}
headers={columnHeadersPositionMarkets}
tableColumns={(market, marketData, candles, openVolume) =>
columnsPositionMarkets(
@@ -210,7 +218,8 @@ export const SelectMarketPopover = ({
marketData,
candles,
onSelectMarket,
openVolume
openVolume,
onCellClick
)
}
/>
@@ -223,6 +232,7 @@ export const SelectMarketPopover = ({
marketsData={data?.marketsData}
marketsCandles={data?.marketsCandles}
onSelect={onSelectMarket}
onCellClick={onCellClick}
/>
</table>
</>
@@ -248,11 +258,13 @@ export const SelectMarketDialog = ({
dialogOpen,
setDialogOpen,
onSelect,
onCellClick,
}: {
dialogOpen: boolean;
setDialogOpen: (open: boolean) => void;
title?: string;
onSelect: (id: string) => void;
onCellClick: OnCellClickHandler;
}) => {
const onSelectMarket = (id: string) => {
onSelect(id);
@@ -267,16 +279,23 @@ export const SelectMarketDialog = ({
onChange={() => setDialogOpen(false)}
size="small"
>
<LandingDialogContainer onSelect={onSelectMarket} />
<LandingDialogContainer
onSelect={onSelectMarket}
onCellClick={onCellClick}
/>
</Dialog>
);
};
interface LandingDialogContainerProps {
onSelect: (id: string) => void;
onCellClick: OnCellClickHandler;
}
const LandingDialogContainer = ({ onSelect }: LandingDialogContainerProps) => {
const LandingDialogContainer = ({
onSelect,
onCellClick,
}: LandingDialogContainerProps) => {
const { data, loading, error } = useMarketList();
if (error) {
return (
@@ -300,6 +319,7 @@ const LandingDialogContainer = ({ onSelect }: LandingDialogContainerProps) => {
marketsData={data?.marketsData}
marketsCandles={data?.marketsCandles}
onSelect={onSelect}
onCellClick={onCellClick}
/>
);
};
@@ -11,6 +11,7 @@ interface DialogProps {
children: ReactNode;
open: boolean;
onChange?: (isOpen: boolean) => void;
onCloseAutoFocus?: (e: Event) => void;
title?: string;
icon?: ReactNode;
intent?: Intent;
@@ -21,6 +22,7 @@ export function Dialog({
children,
open,
onChange,
onCloseAutoFocus,
title,
icon,
intent,
@@ -59,7 +61,10 @@ export function Dialog({
className="fixed inset-0 bg-black/50 z-10"
data-testid="dialog-overlay"
/>
<DialogPrimitives.Content className={contentClasses}>
<DialogPrimitives.Content
className={contentClasses}
onCloseAutoFocus={onCloseAutoFocus}
>
<div className={wrapperClasses}>
{onChange && (
<DialogPrimitives.Close