feat(trading): add liquidity provision link to orders table (#3432)
This commit is contained in:
parent
2346b2f1a0
commit
045dace274
@ -29,7 +29,10 @@ import { LiquidityContainer } from '../liquidity/liquidity';
|
|||||||
import { useNavigate } from 'react-router-dom';
|
import { useNavigate } from 'react-router-dom';
|
||||||
import type { PinnedAsset } from '@vegaprotocol/accounts';
|
import type { PinnedAsset } from '@vegaprotocol/accounts';
|
||||||
import { useScreenDimensions } from '@vegaprotocol/react-helpers';
|
import { useScreenDimensions } from '@vegaprotocol/react-helpers';
|
||||||
import { useMarketClickHandler } from '../../lib/hooks/use-market-click-handler';
|
import {
|
||||||
|
useMarketClickHandler,
|
||||||
|
useMarketLiquidityClickHandler,
|
||||||
|
} from '../../lib/hooks/use-market-click-handler';
|
||||||
|
|
||||||
type MarketDependantView =
|
type MarketDependantView =
|
||||||
| typeof CandlesChartContainer
|
| typeof CandlesChartContainer
|
||||||
@ -79,6 +82,7 @@ const MarketBottomPanel = memo(
|
|||||||
({ marketId, pinnedAsset }: BottomPanelProps) => {
|
({ marketId, pinnedAsset }: BottomPanelProps) => {
|
||||||
const { screenSize } = useScreenDimensions();
|
const { screenSize } = useScreenDimensions();
|
||||||
const onMarketClick = useMarketClickHandler(true);
|
const onMarketClick = useMarketClickHandler(true);
|
||||||
|
const onOrderTypeClick = useMarketLiquidityClickHandler(true);
|
||||||
|
|
||||||
return 'xxxl' === screenSize ? (
|
return 'xxxl' === screenSize ? (
|
||||||
<ResizableGrid proportionalLayout minSize={200}>
|
<ResizableGrid proportionalLayout minSize={200}>
|
||||||
@ -94,6 +98,7 @@ const MarketBottomPanel = memo(
|
|||||||
<TradingViews.Orders
|
<TradingViews.Orders
|
||||||
marketId={marketId}
|
marketId={marketId}
|
||||||
onMarketClick={onMarketClick}
|
onMarketClick={onMarketClick}
|
||||||
|
onOrderTypeClick={onOrderTypeClick}
|
||||||
enforceBottomPlaceholder
|
enforceBottomPlaceholder
|
||||||
/>
|
/>
|
||||||
</VegaWalletContainer>
|
</VegaWalletContainer>
|
||||||
@ -150,6 +155,7 @@ const MarketBottomPanel = memo(
|
|||||||
<TradingViews.Orders
|
<TradingViews.Orders
|
||||||
marketId={marketId}
|
marketId={marketId}
|
||||||
onMarketClick={onMarketClick}
|
onMarketClick={onMarketClick}
|
||||||
|
onOrderTypeClick={onOrderTypeClick}
|
||||||
enforceBottomPlaceholder
|
enforceBottomPlaceholder
|
||||||
/>
|
/>
|
||||||
</VegaWalletContainer>
|
</VegaWalletContainer>
|
||||||
@ -293,6 +299,7 @@ interface TradePanelsProps {
|
|||||||
market: Market | null;
|
market: Market | null;
|
||||||
onSelect: (marketId: string, metaKey?: boolean) => void;
|
onSelect: (marketId: string, metaKey?: boolean) => void;
|
||||||
onMarketClick?: (marketId: string) => void;
|
onMarketClick?: (marketId: string) => void;
|
||||||
|
onOrderTypeClick?: (marketId: string) => void;
|
||||||
onClickCollateral: () => void;
|
onClickCollateral: () => void;
|
||||||
pinnedAsset?: PinnedAsset;
|
pinnedAsset?: PinnedAsset;
|
||||||
}
|
}
|
||||||
@ -303,12 +310,16 @@ export const TradePanels = ({
|
|||||||
onClickCollateral,
|
onClickCollateral,
|
||||||
pinnedAsset,
|
pinnedAsset,
|
||||||
}: TradePanelsProps) => {
|
}: TradePanelsProps) => {
|
||||||
|
const onMarketClick = useMarketClickHandler(true);
|
||||||
|
const onOrderTypeClick = useMarketLiquidityClickHandler(true);
|
||||||
|
|
||||||
const [view, setView] = useState<TradingView>('Candles');
|
const [view, setView] = useState<TradingView>('Candles');
|
||||||
const renderView = () => {
|
const renderView = () => {
|
||||||
const Component = memo<{
|
const Component = memo<{
|
||||||
marketId: string;
|
marketId: string;
|
||||||
onSelect: (marketId: string, metaKey?: boolean) => void;
|
onSelect: (marketId: string, metaKey?: boolean) => void;
|
||||||
onMarketClick?: (marketId: string) => void;
|
onMarketClick?: (marketId: string) => void;
|
||||||
|
onOrderTypeClick?: (marketId: string) => void;
|
||||||
onClickCollateral: () => void;
|
onClickCollateral: () => void;
|
||||||
pinnedAsset?: PinnedAsset;
|
pinnedAsset?: PinnedAsset;
|
||||||
}>(TradingViews[view]);
|
}>(TradingViews[view]);
|
||||||
@ -325,6 +336,8 @@ export const TradePanels = ({
|
|||||||
onSelect={onSelect}
|
onSelect={onSelect}
|
||||||
onClickCollateral={onClickCollateral}
|
onClickCollateral={onClickCollateral}
|
||||||
pinnedAsset={pinnedAsset}
|
pinnedAsset={pinnedAsset}
|
||||||
|
onMarketClick={onMarketClick}
|
||||||
|
onOrderTypeClick={onOrderTypeClick}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -19,7 +19,10 @@ import { usePageTitleStore } from '../../stores';
|
|||||||
import { LedgerContainer } from '@vegaprotocol/ledger';
|
import { LedgerContainer } from '@vegaprotocol/ledger';
|
||||||
import { AccountsContainer } from '../../components/accounts-container';
|
import { AccountsContainer } from '../../components/accounts-container';
|
||||||
import { AccountHistoryContainer } from './account-history-container';
|
import { AccountHistoryContainer } from './account-history-container';
|
||||||
import { useMarketClickHandler } from '../../lib/hooks/use-market-click-handler';
|
import {
|
||||||
|
useMarketClickHandler,
|
||||||
|
useMarketLiquidityClickHandler,
|
||||||
|
} from '../../lib/hooks/use-market-click-handler';
|
||||||
|
|
||||||
export const Portfolio = () => {
|
export const Portfolio = () => {
|
||||||
const { updateTitle } = usePageTitleStore((store) => ({
|
const { updateTitle } = usePageTitleStore((store) => ({
|
||||||
@ -31,6 +34,7 @@ export const Portfolio = () => {
|
|||||||
}, [updateTitle]);
|
}, [updateTitle]);
|
||||||
|
|
||||||
const onMarketClick = useMarketClickHandler(true);
|
const onMarketClick = useMarketClickHandler(true);
|
||||||
|
const onOrderTypeClick = useMarketLiquidityClickHandler(true);
|
||||||
|
|
||||||
const wrapperClasses = 'h-full max-h-full flex flex-col';
|
const wrapperClasses = 'h-full max-h-full flex flex-col';
|
||||||
return (
|
return (
|
||||||
@ -54,7 +58,10 @@ export const Portfolio = () => {
|
|||||||
</Tab>
|
</Tab>
|
||||||
<Tab id="orders" name={t('Orders')}>
|
<Tab id="orders" name={t('Orders')}>
|
||||||
<VegaWalletContainer>
|
<VegaWalletContainer>
|
||||||
<OrderListContainer onMarketClick={onMarketClick} />
|
<OrderListContainer
|
||||||
|
onMarketClick={onMarketClick}
|
||||||
|
onOrderTypeClick={onOrderTypeClick}
|
||||||
|
/>
|
||||||
</VegaWalletContainer>
|
</VegaWalletContainer>
|
||||||
</Tab>
|
</Tab>
|
||||||
<Tab id="fills" name={t('Fills')}>
|
<Tab id="fills" name={t('Fills')}>
|
||||||
|
@ -19,3 +19,21 @@ export const useMarketClickHandler = (replace = false) => {
|
|||||||
[navigate, marketId, replace, isMarketPage]
|
[navigate, marketId, replace, isMarketPage]
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const useMarketLiquidityClickHandler = (replace = false) => {
|
||||||
|
const navigate = useNavigate();
|
||||||
|
const { marketId } = useParams();
|
||||||
|
const { pathname } = useLocation();
|
||||||
|
const isLiquidityPage = pathname.match(/^\/liquidity\/(.+)/);
|
||||||
|
return useCallback(
|
||||||
|
(selectedId: string, metaKey?: boolean) => {
|
||||||
|
const link = Links[Routes.LIQUIDITY](selectedId);
|
||||||
|
if (metaKey) {
|
||||||
|
window.open(`/#${link}`, '_blank');
|
||||||
|
} else if (selectedId !== marketId || !isLiquidityPage) {
|
||||||
|
navigate(link, { replace });
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[navigate, marketId, replace, isLiquidityPage]
|
||||||
|
);
|
||||||
|
};
|
||||||
|
@ -31,7 +31,7 @@ export enum Routes {
|
|||||||
MARKET = '/markets',
|
MARKET = '/markets',
|
||||||
MARKETS = '/markets/all',
|
MARKETS = '/markets/all',
|
||||||
PORTFOLIO = '/portfolio',
|
PORTFOLIO = '/portfolio',
|
||||||
LIQUIDITY = 'liquidity/:marketId',
|
LIQUIDITY = '/liquidity',
|
||||||
}
|
}
|
||||||
|
|
||||||
type ConsoleLinks = { [r in Routes]: (...args: string[]) => string };
|
type ConsoleLinks = { [r in Routes]: (...args: string[]) => string };
|
||||||
@ -41,8 +41,10 @@ export const Links: ConsoleLinks = {
|
|||||||
marketId ? trimEnd(`${Routes.MARKET}/${marketId}`, '/') : Routes.MARKET,
|
marketId ? trimEnd(`${Routes.MARKET}/${marketId}`, '/') : Routes.MARKET,
|
||||||
[Routes.MARKETS]: () => Routes.MARKETS,
|
[Routes.MARKETS]: () => Routes.MARKETS,
|
||||||
[Routes.PORTFOLIO]: () => Routes.PORTFOLIO,
|
[Routes.PORTFOLIO]: () => Routes.PORTFOLIO,
|
||||||
[Routes.LIQUIDITY]: (marketId: string) =>
|
[Routes.LIQUIDITY]: (marketId: string | null | undefined) =>
|
||||||
Routes.LIQUIDITY.replace(':marketId', marketId),
|
marketId
|
||||||
|
? trimEnd(`${Routes.LIQUIDITY}/${marketId}`, '/')
|
||||||
|
: Routes.LIQUIDITY,
|
||||||
};
|
};
|
||||||
|
|
||||||
const routerConfig: RouteObject[] = [
|
const routerConfig: RouteObject[] = [
|
||||||
@ -70,6 +72,16 @@ const routerConfig: RouteObject[] = [
|
|||||||
{
|
{
|
||||||
path: Routes.LIQUIDITY,
|
path: Routes.LIQUIDITY,
|
||||||
element: <LazyLiquidity />,
|
element: <LazyLiquidity />,
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
index: true,
|
||||||
|
element: <LazyLiquidity />,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: ':marketId',
|
||||||
|
element: <LazyLiquidity />,
|
||||||
|
},
|
||||||
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: Routes.PORTFOLIO,
|
path: Routes.PORTFOLIO,
|
||||||
|
@ -10,6 +10,7 @@ export * from './lib/cells/price-flash-cell';
|
|||||||
export * from './lib/cells/vol-cell';
|
export * from './lib/cells/vol-cell';
|
||||||
export * from './lib/cells/centered-grid-cell';
|
export * from './lib/cells/centered-grid-cell';
|
||||||
export * from './lib/cells/market-name-cell';
|
export * from './lib/cells/market-name-cell';
|
||||||
|
export * from './lib/cells/order-type-cell';
|
||||||
|
|
||||||
export * from './lib/filters/date-range-filter';
|
export * from './lib/filters/date-range-filter';
|
||||||
export * from './lib/filters/set-filter';
|
export * from './lib/filters/set-filter';
|
||||||
|
52
libs/datagrid/src/lib/cells/order-type-cell.tsx
Normal file
52
libs/datagrid/src/lib/cells/order-type-cell.tsx
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
import type { MouseEvent } from 'react';
|
||||||
|
import { useMemo } from 'react';
|
||||||
|
import { useCallback } from 'react';
|
||||||
|
import { t } from '@vegaprotocol/i18n';
|
||||||
|
import * as Schema from '@vegaprotocol/types';
|
||||||
|
|
||||||
|
interface OrderTypeCellProps {
|
||||||
|
value?: Schema.OrderType;
|
||||||
|
data?: Schema.Order;
|
||||||
|
onClick?: (marketId: string, metaKey?: boolean) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const OrderTypeCell = ({
|
||||||
|
value,
|
||||||
|
data: order,
|
||||||
|
onClick,
|
||||||
|
}: OrderTypeCellProps) => {
|
||||||
|
const id = order ? order.market.id : '';
|
||||||
|
|
||||||
|
const label = useMemo(() => {
|
||||||
|
if (!order) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
if (!value) return '-';
|
||||||
|
if (order?.peggedOrder) {
|
||||||
|
return t('Pegged');
|
||||||
|
}
|
||||||
|
if (order?.liquidityProvision) {
|
||||||
|
return t('Liquidity provision');
|
||||||
|
}
|
||||||
|
return Schema.OrderTypeMapping[value];
|
||||||
|
}, [order, value]);
|
||||||
|
|
||||||
|
const handleOnClick = useCallback(
|
||||||
|
(ev: MouseEvent<HTMLButtonElement>) => {
|
||||||
|
ev.preventDefault();
|
||||||
|
ev.stopPropagation();
|
||||||
|
if (onClick) {
|
||||||
|
onClick(id, ev.metaKey || ev.ctrlKey);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[id, onClick]
|
||||||
|
);
|
||||||
|
if (!order) return null;
|
||||||
|
return order?.liquidityProvision ? (
|
||||||
|
<button onClick={handleOnClick} tabIndex={0} className="underline">
|
||||||
|
{label}
|
||||||
|
</button>
|
||||||
|
) : (
|
||||||
|
<span>{label}</span>
|
||||||
|
);
|
||||||
|
};
|
@ -6,10 +6,12 @@ import { OrderListManager } from './order-list-manager';
|
|||||||
export const OrderListContainer = ({
|
export const OrderListContainer = ({
|
||||||
marketId,
|
marketId,
|
||||||
onMarketClick,
|
onMarketClick,
|
||||||
|
onOrderTypeClick,
|
||||||
enforceBottomPlaceholder,
|
enforceBottomPlaceholder,
|
||||||
}: {
|
}: {
|
||||||
marketId?: string;
|
marketId?: string;
|
||||||
onMarketClick?: (marketId: string, metaKey?: boolean) => void;
|
onMarketClick?: (marketId: string, metaKey?: boolean) => void;
|
||||||
|
onOrderTypeClick?: (marketId: string, metaKey?: boolean) => void;
|
||||||
enforceBottomPlaceholder?: boolean;
|
enforceBottomPlaceholder?: boolean;
|
||||||
}) => {
|
}) => {
|
||||||
const { pubKey, isReadOnly } = useVegaWallet();
|
const { pubKey, isReadOnly } = useVegaWallet();
|
||||||
@ -23,6 +25,7 @@ export const OrderListContainer = ({
|
|||||||
partyId={pubKey}
|
partyId={pubKey}
|
||||||
marketId={marketId}
|
marketId={marketId}
|
||||||
onMarketClick={onMarketClick}
|
onMarketClick={onMarketClick}
|
||||||
|
onOrderTypeClick={onOrderTypeClick}
|
||||||
isReadOnly={isReadOnly}
|
isReadOnly={isReadOnly}
|
||||||
enforceBottomPlaceholder={enforceBottomPlaceholder}
|
enforceBottomPlaceholder={enforceBottomPlaceholder}
|
||||||
/>
|
/>
|
||||||
|
@ -25,6 +25,7 @@ export interface OrderListManagerProps {
|
|||||||
partyId: string;
|
partyId: string;
|
||||||
marketId?: string;
|
marketId?: string;
|
||||||
onMarketClick?: (marketId: string, metaKey?: boolean) => void;
|
onMarketClick?: (marketId: string, metaKey?: boolean) => void;
|
||||||
|
onOrderTypeClick?: (marketId: string, metaKey?: boolean) => void;
|
||||||
isReadOnly: boolean;
|
isReadOnly: boolean;
|
||||||
enforceBottomPlaceholder?: boolean;
|
enforceBottomPlaceholder?: boolean;
|
||||||
}
|
}
|
||||||
@ -52,6 +53,7 @@ export const OrderListManager = ({
|
|||||||
partyId,
|
partyId,
|
||||||
marketId,
|
marketId,
|
||||||
onMarketClick,
|
onMarketClick,
|
||||||
|
onOrderTypeClick,
|
||||||
isReadOnly,
|
isReadOnly,
|
||||||
enforceBottomPlaceholder,
|
enforceBottomPlaceholder,
|
||||||
}: OrderListManagerProps) => {
|
}: OrderListManagerProps) => {
|
||||||
@ -165,6 +167,7 @@ export const OrderListManager = ({
|
|||||||
cancel={cancel}
|
cancel={cancel}
|
||||||
setEditOrder={setEditOrder}
|
setEditOrder={setEditOrder}
|
||||||
onMarketClick={onMarketClick}
|
onMarketClick={onMarketClick}
|
||||||
|
onOrderTypeClick={onOrderTypeClick}
|
||||||
isReadOnly={isReadOnly}
|
isReadOnly={isReadOnly}
|
||||||
blockLoadDebounceMillis={100}
|
blockLoadDebounceMillis={100}
|
||||||
suppressLoadingOverlay
|
suppressLoadingOverlay
|
||||||
|
@ -16,6 +16,7 @@ import {
|
|||||||
negativeClassNames,
|
negativeClassNames,
|
||||||
positiveClassNames,
|
positiveClassNames,
|
||||||
MarketNameCell,
|
MarketNameCell,
|
||||||
|
OrderTypeCell,
|
||||||
} from '@vegaprotocol/datagrid';
|
} from '@vegaprotocol/datagrid';
|
||||||
import type {
|
import type {
|
||||||
TypedDataAgGrid,
|
TypedDataAgGrid,
|
||||||
@ -31,12 +32,16 @@ export type OrderListTableProps = OrderListProps & {
|
|||||||
cancel: (order: Order) => void;
|
cancel: (order: Order) => void;
|
||||||
setEditOrder: (order: Order) => void;
|
setEditOrder: (order: Order) => void;
|
||||||
onMarketClick?: (marketId: string, metaKey?: boolean) => void;
|
onMarketClick?: (marketId: string, metaKey?: boolean) => void;
|
||||||
|
onOrderTypeClick?: (marketId: string, metaKey?: boolean) => void;
|
||||||
isReadOnly: boolean;
|
isReadOnly: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const OrderListTable = memo(
|
export const OrderListTable = memo(
|
||||||
forwardRef<AgGridReact, OrderListTableProps>(
|
forwardRef<AgGridReact, OrderListTableProps>(
|
||||||
({ cancel, setEditOrder, onMarketClick, ...props }, ref) => {
|
(
|
||||||
|
{ cancel, setEditOrder, onMarketClick, onOrderTypeClick, ...props },
|
||||||
|
ref
|
||||||
|
) => {
|
||||||
return (
|
return (
|
||||||
<AgGrid
|
<AgGrid
|
||||||
ref={ref}
|
ref={ref}
|
||||||
@ -51,7 +56,7 @@ export const OrderListTable = memo(
|
|||||||
height: '100%',
|
height: '100%',
|
||||||
}}
|
}}
|
||||||
getRowId={({ data }) => data.id}
|
getRowId={({ data }) => data.id}
|
||||||
components={{ MarketNameCell }}
|
components={{ MarketNameCell, OrderTypeCell }}
|
||||||
{...props}
|
{...props}
|
||||||
>
|
>
|
||||||
<AgGridColumn
|
<AgGridColumn
|
||||||
@ -103,17 +108,9 @@ export const OrderListTable = memo(
|
|||||||
filterParams={{
|
filterParams={{
|
||||||
set: Schema.OrderTypeMapping,
|
set: Schema.OrderTypeMapping,
|
||||||
}}
|
}}
|
||||||
valueFormatter={({
|
cellRenderer="OrderTypeCell"
|
||||||
data: order,
|
cellRendererParams={{
|
||||||
value,
|
onClick: onOrderTypeClick,
|
||||||
}: VegaValueFormatterParams<Order, 'type'>) => {
|
|
||||||
if (!order) {
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
if (!value) return '-';
|
|
||||||
if (order?.peggedOrder) return t('Pegged');
|
|
||||||
if (order?.liquidityProvision) return t('Liquidity provision');
|
|
||||||
return Schema.OrderTypeMapping[value];
|
|
||||||
}}
|
}}
|
||||||
minWidth={80}
|
minWidth={80}
|
||||||
/>
|
/>
|
||||||
|
Loading…
Reference in New Issue
Block a user