feat(#2565): orderbook populate limit (#2690)

Co-authored-by: asiaznik <artur@vegaprotocol.io>
This commit is contained in:
m.ray 2023-01-25 14:38:26 -05:00 committed by GitHub
parent dad953b45b
commit 7ea7edc1e2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
34 changed files with 207 additions and 87 deletions

View File

@ -1,5 +1,5 @@
import BigNumber from 'bignumber.js'; import BigNumber from 'bignumber.js';
import create from 'zustand'; import { create } from 'zustand';
import type { UserTrancheBalance } from '../../contexts/app-state/app-state-context'; import type { UserTrancheBalance } from '../../contexts/app-state/app-state-context';
export interface AssociationBreakdown { export interface AssociationBreakdown {

View File

@ -1,6 +1,6 @@
import type ethers from 'ethers'; import type ethers from 'ethers';
import type { GetState, SetState } from 'zustand'; import type { GetState, SetState } from 'zustand';
import create from 'zustand'; import { create } from 'zustand';
export interface TxData { export interface TxData {
tx: ethers.ContractTransaction; tx: ethers.ContractTransaction;

View File

@ -43,8 +43,8 @@ export const HeaderStat = ({
testId?: string; testId?: string;
}) => { }) => {
const itemClass = const itemClass =
'min-w-min w-[120px] whitespace-nowrap pb-3 px-4 border-l border-default'; 'min-w-min w-[120px] whitespace-nowrap pb-3 px-4 border-l border-default text-neutral-500 dark:text-neutral-400';
const itemHeading = 'text-neutral-500 dark:text-neutral-400'; const itemHeading = 'text-black dark:text-white';
return ( return (
<div data-testid={testId} className={itemClass}> <div data-testid={testId} className={itemClass}>

View File

@ -95,7 +95,7 @@ const Details = ({
title?: string; title?: string;
}) => ( }) => (
<div className="pt-[5px]" data-testid="vega-tx-details" title={title}> <div className="pt-[5px]" data-testid="vega-tx-details" title={title}>
<div className="font-mono text-xs p-2 bg-neutral-100 rounded"> <div className="font-mono text-xs p-2 bg-neutral-100 rounded dark:bg-neutral-700 dark:text-white">
{children} {children}
</div> </div>
</div> </div>

View File

@ -1,5 +1,5 @@
import { LocalStorage } from '@vegaprotocol/react-helpers'; import { LocalStorage } from '@vegaprotocol/react-helpers';
import create from 'zustand'; import { create } from 'zustand';
import produce from 'immer'; import produce from 'immer';
interface GlobalStore { interface GlobalStore {

View File

@ -1,7 +1,7 @@
import { t } from '@vegaprotocol/react-helpers'; import { t } from '@vegaprotocol/react-helpers';
import { useAssetsDataProvider } from './assets-data-provider'; import { useAssetsDataProvider } from './assets-data-provider';
import { Button, Dialog, Icon, Splash } from '@vegaprotocol/ui-toolkit'; import { Button, Dialog, Icon, Splash } from '@vegaprotocol/ui-toolkit';
import create from 'zustand'; import { create } from 'zustand';
import { AssetDetailsTable } from './asset-details-table'; import { AssetDetailsTable } from './asset-details-table';
import { AssetProposalNotification } from '@vegaprotocol/governance'; import { AssetProposalNotification } from '@vegaprotocol/governance';

View File

@ -15,7 +15,6 @@ import { useVegaWallet } from '@vegaprotocol/wallet';
import { InputError } from '@vegaprotocol/ui-toolkit'; import { InputError } from '@vegaprotocol/ui-toolkit';
import { useOrderMarginValidation } from '../../hooks/use-order-margin-validation'; import { useOrderMarginValidation } from '../../hooks/use-order-margin-validation';
import { MarginWarning } from '../deal-ticket-validation/margin-warning'; import { MarginWarning } from '../deal-ticket-validation/margin-warning';
import { usePersistedOrderStore } from '../../hooks/use-persisted-order';
import { import {
getDefaultOrder, getDefaultOrder,
validateMarketState, validateMarketState,
@ -27,6 +26,10 @@ import { ZeroBalanceError } from '../deal-ticket-validation/zero-balance-error';
import { SummaryValidationType } from '../../constants'; import { SummaryValidationType } from '../../constants';
import { useHasNoBalance } from '../../hooks/use-has-no-balance'; import { useHasNoBalance } from '../../hooks/use-has-no-balance';
import type { MarketDealTicket } from '@vegaprotocol/market-list'; import type { MarketDealTicket } from '@vegaprotocol/market-list';
import {
usePersistedOrderStore,
usePersistedOrderStoreSubscription,
} from '@vegaprotocol/orders';
export type TransactionStatus = 'default' | 'pending'; export type TransactionStatus = 'default' | 'pending';
@ -43,13 +46,13 @@ export type DealTicketFormFields = OrderSubmissionBody['orderSubmission'] & {
export const DealTicket = ({ market, submit }: DealTicketProps) => { export const DealTicket = ({ market, submit }: DealTicketProps) => {
const { pubKey } = useVegaWallet(); const { pubKey } = useVegaWallet();
// const [persistedOrder, setPersistedOrder] = usePersistedOrder(market);
const { getPersistedOrder, setPersistedOrder } = usePersistedOrderStore( const { getPersistedOrder, setPersistedOrder } = usePersistedOrderStore(
(store) => ({ (store) => ({
getPersistedOrder: store.getOrder, getPersistedOrder: store.getOrder,
setPersistedOrder: store.setOrder, setPersistedOrder: store.setOrder,
}) })
); );
const { const {
register, register,
control, control,
@ -58,11 +61,23 @@ export const DealTicket = ({ market, submit }: DealTicketProps) => {
setError, setError,
clearErrors, clearErrors,
formState: { errors }, formState: { errors },
setValue,
} = useForm<DealTicketFormFields>({ } = useForm<DealTicketFormFields>({
defaultValues: getPersistedOrder(market.id) || getDefaultOrder(market), defaultValues: getPersistedOrder(market.id) || getDefaultOrder(market),
}); });
const order = watch(); const order = watch();
watch((orderData) => {
setPersistedOrder(orderData as DealTicketFormFields);
});
usePersistedOrderStoreSubscription(market.id, (storedOrder) => {
if (order.price !== storedOrder.price) {
setValue('price', storedOrder.price);
}
});
const marketStateError = validateMarketState(market.data.marketState); const marketStateError = validateMarketState(market.data.marketState);
const hasNoBalance = useHasNoBalance( const hasNoBalance = useHasNoBalance(
market.tradableInstrument.instrument.product.settlementAsset.id market.tradableInstrument.instrument.product.settlementAsset.id
@ -90,9 +105,6 @@ export const DealTicket = ({ market, submit }: DealTicketProps) => {
errors.summary?.type, errors.summary?.type,
]); ]);
// When order state changes persist it in local storage
useEffect(() => setPersistedOrder(order), [order, setPersistedOrder]);
const onSubmit = useCallback( const onSubmit = useCallback(
(order: OrderSubmissionBody['orderSubmission']) => { (order: OrderSubmissionBody['orderSubmission']) => {
if (!pubKey) { if (!pubKey) {

View File

@ -1,43 +0,0 @@
import type { OrderSubmissionBody } from '@vegaprotocol/wallet';
import produce from 'immer';
import create from 'zustand';
import { persist } from 'zustand/middleware';
type OrderData = OrderSubmissionBody['orderSubmission'] | null;
type PersistedOrderStore = {
orders: OrderData[];
getOrder: (marketId: string) => OrderData | undefined;
setOrder: (order: OrderData) => void;
clear: () => void;
};
export const usePersistedOrderStore = create(
persist<PersistedOrderStore>(
(set, get) => ({
orders: [],
getOrder: (marketId) => {
const persisted = get().orders.find((o) => o?.marketId === marketId);
return persisted;
},
setOrder: (order) => {
set(
produce((store: PersistedOrderStore) => {
const persisted = store.orders.find(
(o) => o?.marketId === order?.marketId
);
if (persisted) {
Object.assign(persisted, order);
} else {
store.orders.push(order);
}
})
);
},
clear: () => set({ orders: [] }),
}),
{
name: 'VEGA_DEAL_TICKET_ORDER_STORE',
}
)
);

View File

@ -1,4 +1,4 @@
import create from 'zustand'; import { create } from 'zustand';
import { t } from '@vegaprotocol/react-helpers'; import { t } from '@vegaprotocol/react-helpers';
import type { Intent } from '@vegaprotocol/ui-toolkit'; import type { Intent } from '@vegaprotocol/ui-toolkit';
import { Dialog } from '@vegaprotocol/ui-toolkit'; import { Dialog } from '@vegaprotocol/ui-toolkit';

View File

@ -1,7 +1,7 @@
import throttle from 'lodash/throttle'; import throttle from 'lodash/throttle';
import { AsyncRenderer } from '@vegaprotocol/ui-toolkit'; import { AsyncRenderer } from '@vegaprotocol/ui-toolkit';
import { Orderbook } from './orderbook'; import { Orderbook } from './orderbook';
import { useDataProvider } from '@vegaprotocol/react-helpers'; import { addDecimal, useDataProvider } from '@vegaprotocol/react-helpers';
import { marketDepthProvider } from './market-depth-provider'; import { marketDepthProvider } from './market-depth-provider';
import { marketDataProvider, marketProvider } from '@vegaprotocol/market-list'; import { marketDataProvider, marketProvider } from '@vegaprotocol/market-list';
import type { MarketData } from '@vegaprotocol/market-list'; import type { MarketData } from '@vegaprotocol/market-list';
@ -16,6 +16,7 @@ import {
mapMarketData, mapMarketData,
} from './orderbook-data'; } from './orderbook-data';
import type { OrderbookData } from './orderbook-data'; import type { OrderbookData } from './orderbook-data';
import { usePersistedOrderStore } from '@vegaprotocol/orders';
interface OrderbookManagerProps { interface OrderbookManagerProps {
marketId: string; marketId: string;
@ -122,7 +123,7 @@ export const OrderbookManager = ({ marketId }: OrderbookManagerProps) => {
marketDataRef.current = marketData; marketDataRef.current = marketData;
useEffect(() => { useEffect(() => {
const throttleRunnner = updateOrderbookData.current; const throttleRunner = updateOrderbookData.current;
if (!marketDataRef.current) { if (!marketDataRef.current) {
return; return;
} }
@ -139,7 +140,7 @@ export const OrderbookManager = ({ marketId }: OrderbookManagerProps) => {
setOrderbookData(dataRef.current); setOrderbookData(dataRef.current);
return () => { return () => {
throttleRunnner.cancel(); throttleRunner.cancel();
}; };
}, [data, marketData, resolution]); }, [data, marketData, resolution]);
@ -148,6 +149,8 @@ export const OrderbookManager = ({ marketId }: OrderbookManagerProps) => {
flush(); flush();
}, [resolution, flush]); }, [resolution, flush]);
const updatePrice = usePersistedOrderStore((store) => store.updatePrice);
return ( return (
<AsyncRenderer <AsyncRenderer
loading={loading || marketDataLoading || marketLoading} loading={loading || marketDataLoading || marketLoading}
@ -160,6 +163,12 @@ export const OrderbookManager = ({ marketId }: OrderbookManagerProps) => {
positionDecimalPlaces={market?.positionDecimalPlaces ?? 0} positionDecimalPlaces={market?.positionDecimalPlaces ?? 0}
resolution={resolution} resolution={resolution}
onResolutionChange={(resolution: number) => setResolution(resolution)} onResolutionChange={(resolution: number) => setResolution(resolution)}
onClick={(price?: string | number) => {
if (price) {
const priceValue = addDecimal(price, market?.decimalPlaces ?? 0);
updatePrice(marketId, priceValue);
}
}}
/> />
</AsyncRenderer> </AsyncRenderer>
); );

View File

@ -21,6 +21,7 @@ interface OrderbookRowProps {
price: string; price: string;
relativeAsk?: number; relativeAsk?: number;
relativeBid?: number; relativeBid?: number;
onClick?: (price?: string | number) => void;
} }
export const OrderbookRow = React.memo( export const OrderbookRow = React.memo(
@ -37,6 +38,7 @@ export const OrderbookRow = React.memo(
price, price,
relativeAsk, relativeAsk,
relativeBid, relativeBid,
onClick,
}: OrderbookRowProps) => { }: OrderbookRowProps) => {
return ( return (
<> <>
@ -57,6 +59,7 @@ export const OrderbookRow = React.memo(
<PriceCell <PriceCell
testId={`price-${price}`} testId={`price-${price}`}
value={BigInt(price)} value={BigInt(price)}
onClick={() => onClick && onClick(price)}
valueFormatted={addDecimalsFormatNumber(price, decimalPlaces)} valueFormatted={addDecimalsFormatNumber(price, decimalPlaces)}
/> />
<CumulativeVol <CumulativeVol

View File

@ -30,6 +30,7 @@ interface OrderbookProps extends OrderbookData {
positionDecimalPlaces: number; positionDecimalPlaces: number;
resolution: number; resolution: number;
onResolutionChange: (resolution: number) => void; onResolutionChange: (resolution: number) => void;
onClick?: (price?: string | number) => void;
fillGaps?: boolean; fillGaps?: boolean;
} }
@ -279,6 +280,7 @@ export const Orderbook = ({
resolution, resolution,
fillGaps: initialFillGaps, fillGaps: initialFillGaps,
onResolutionChange, onResolutionChange,
onClick,
}: OrderbookProps) => { }: OrderbookProps) => {
const { theme } = useThemeSwitcher(); const { theme } = useThemeSwitcher();
const scrollElement = useRef<HTMLDivElement>(null); const scrollElement = useRef<HTMLDivElement>(null);
@ -533,6 +535,7 @@ export const Orderbook = ({
<OrderbookRow <OrderbookRow
key={data.price} key={data.price}
price={(BigInt(data.price) / BigInt(resolution)).toString()} price={(BigInt(data.price) / BigInt(resolution)).toString()}
onClick={onClick}
decimalPlaces={decimalPlaces - Math.log10(resolution)} decimalPlaces={decimalPlaces - Math.log10(resolution)}
positionDecimalPlaces={positionDecimalPlaces} positionDecimalPlaces={positionDecimalPlaces}
bid={data.bid} bid={data.bid}

View File

@ -245,7 +245,7 @@ export const OrderListTable = forwardRef<AgGridReact, OrderListTableProps>(
colId="amend" colId="amend"
headerName="" headerName=""
field="status" field="status"
minWidth={150} minWidth={100}
type="rightAligned" type="rightAligned"
cellRenderer={({ data, node }: VegaICellRendererParams<Order>) => { cellRenderer={({ data, node }: VegaICellRendererParams<Order>) => {
return data && isOrderAmendable(data) ? ( return data && isOrderAmendable(data) ? (

View File

@ -4,3 +4,4 @@ export * from './use-order-cancel';
export * from './use-order-submit'; export * from './use-order-submit';
export * from './use-order-edit'; export * from './use-order-edit';
export * from './use-order-event'; export * from './use-order-event';
export * from './use-persisted-order';

View File

@ -0,0 +1,78 @@
import type { OrderSubmissionBody } from '@vegaprotocol/wallet';
import produce from 'immer';
import { create } from 'zustand';
import { persist, subscribeWithSelector } from 'zustand/middleware';
import isEqual from 'lodash/isEqual';
import { useEffect } from 'react';
type OrderData = OrderSubmissionBody['orderSubmission'] | null;
type PersistedOrderStore = {
orders: OrderData[];
getOrder: (marketId: string) => OrderData | undefined;
setOrder: (order: OrderData) => void;
clear: () => void;
updatePrice: (marketId: string, price: string) => void;
};
export const usePersistedOrderStore = create<PersistedOrderStore>()(
persist(
subscribeWithSelector((set, get) => ({
orders: [],
getOrder: (marketId: string) => {
const current = get() as PersistedOrderStore;
const persisted = current.orders.find((o) => o?.marketId === marketId);
return persisted;
},
setOrder: (order: OrderData) => {
set(
produce((store: PersistedOrderStore) => {
const persisted = store.orders.find(
(o) => o?.marketId === order?.marketId
);
if (persisted) {
if (!isEqual(persisted, order)) {
Object.assign(persisted, order);
} else {
// NOOP
}
} else {
store.orders.push(order);
}
})
);
},
clear: () => set({ orders: [] }),
updatePrice: (marketId: string, price: string) =>
set(
produce((store: PersistedOrderStore) => {
const persisted = store.orders.find(
(o) => o?.marketId === marketId
);
if (persisted) {
persisted.price = price;
}
})
),
})),
{
name: 'VEGA_DEAL_TICKET_ORDER_STORE',
}
)
);
export const usePersistedOrderStoreSubscription = (
marketId: string,
onOrderChange: (order: NonNullable<OrderData>) => void
) => {
const selector = (state: PersistedOrderStore) =>
state.orders.find((o) => o?.marketId === marketId);
const action = (storedOrder: OrderData | undefined) => {
if (storedOrder) {
onOrderChange(storedOrder);
}
};
const unsubscribe = usePersistedOrderStore.subscribe(selector, action);
useEffect(() => () => unsubscribe(), [unsubscribe]);
};

View File

@ -1,4 +1,4 @@
import create from 'zustand'; import { create } from 'zustand';
import { LocalStorage } from '../lib/storage'; import { LocalStorage } from '../lib/storage';
const THEME_STORAGE_KEY = 'theme'; const THEME_STORAGE_KEY = 'theme';

View File

@ -4,11 +4,12 @@ export interface IPriceCellProps {
value: number | bigint | null | undefined; value: number | bigint | null | undefined;
valueFormatted: string; valueFormatted: string;
testId?: string; testId?: string;
onClick?: (price?: string | number) => void;
} }
export const PriceCell = memo( export const PriceCell = memo(
forwardRef<HTMLSpanElement, IPriceCellProps>( forwardRef<HTMLSpanElement, IPriceCellProps>(
({ value, valueFormatted, testId }: IPriceCellProps, ref) => { ({ value, valueFormatted, testId, onClick }: IPriceCellProps, ref) => {
if (!isNumeric(value)) { if (!isNumeric(value)) {
return ( return (
<span data-testid="price" ref={ref}> <span data-testid="price" ref={ref}>
@ -20,7 +21,25 @@ export const PriceCell = memo(
const valueSplit: string[] = decimalSeparator const valueSplit: string[] = decimalSeparator
? valueFormatted.split(decimalSeparator).map((v) => `${v}`) ? valueFormatted.split(decimalSeparator).map((v) => `${v}`)
: [`${value}`]; : [`${value}`];
return ( return onClick ? (
<button
onClick={() => onClick(value)}
className="hover:dark:bg-neutral-800 hover:bg-neutral-200"
>
<span
ref={ref}
className="font-mono relative text-black dark:text-white whitespace-nowrap overflow-hidden text-ellipsis text-right rtl-dir"
data-testid={testId || 'price'}
title={valueFormatted}
>
{valueSplit[0]}
{valueSplit[1] ? decimalSeparator : null}
{valueSplit[1] ? (
<span className="opacity-60">{valueSplit[1]}</span>
) : null}
</span>
</button>
) : (
<span <span
ref={ref} ref={ref}
className="font-mono relative text-black dark:text-white whitespace-nowrap overflow-hidden text-ellipsis text-right rtl-dir" className="font-mono relative text-black dark:text-white whitespace-nowrap overflow-hidden text-ellipsis text-right rtl-dir"

View File

@ -10,6 +10,7 @@ import { MAX_TRADES, tradesWithMarketProvider } from './trades-data-provider';
import { TradesTable } from './trades-table'; import { TradesTable } from './trades-table';
import type { Trade, TradeEdge } from './trades-data-provider'; import type { Trade, TradeEdge } from './trades-data-provider';
import type { TradesQueryVariables } from './__generated__/Trades'; import type { TradesQueryVariables } from './__generated__/Trades';
import { usePersistedOrderStore } from '@vegaprotocol/orders';
interface TradesContainerProps { interface TradesContainerProps {
marketId: string; marketId: string;
@ -21,6 +22,7 @@ export const TradesContainer = ({ marketId }: TradesContainerProps) => {
const totalCountRef = useRef<number | undefined>(undefined); const totalCountRef = useRef<number | undefined>(undefined);
const newRows = useRef(0); const newRows = useRef(0);
const scrolledToTop = useRef(true); const scrolledToTop = useRef(true);
const updatePrice = usePersistedOrderStore((store) => store.updatePrice);
const variables = useMemo<TradesQueryVariables>( const variables = useMemo<TradesQueryVariables>(
() => ({ marketId, maxTrades: MAX_TRADES }), () => ({ marketId, maxTrades: MAX_TRADES }),
@ -113,6 +115,11 @@ export const TradesContainer = ({ marketId }: TradesContainerProps) => {
datasource={{ getRows }} datasource={{ getRows }}
onBodyScrollEnd={onBodyScrollEnd} onBodyScrollEnd={onBodyScrollEnd}
onBodyScroll={onBodyScroll} onBodyScroll={onBodyScroll}
onClick={(price?: string) => {
if (price) {
updatePrice(marketId, price);
}
}}
/> />
</AsyncRenderer> </AsyncRenderer>
); );

View File

@ -1,6 +1,7 @@
import type { AgGridReact } from 'ag-grid-react'; import type { AgGridReact } from 'ag-grid-react';
import { AgGridColumn } from 'ag-grid-react'; import { AgGridColumn } from 'ag-grid-react';
import { forwardRef } from 'react'; import { forwardRef } from 'react';
import type { VegaICellRendererParams } from '@vegaprotocol/ui-toolkit';
import { AgGridDynamic as AgGrid } from '@vegaprotocol/ui-toolkit'; import { AgGridDynamic as AgGrid } from '@vegaprotocol/ui-toolkit';
import { import {
addDecimal, addDecimal,
@ -49,6 +50,7 @@ export interface Datasource extends IDatasource {
interface Props extends AgGridReactProps { interface Props extends AgGridReactProps {
rowData?: Trade[] | null; rowData?: Trade[] | null;
datasource?: Datasource; datasource?: Datasource;
onClick?: (price?: string) => void;
} }
type TradesTableValueFormatterParams = Omit< type TradesTableValueFormatterParams = Omit<
@ -87,6 +89,27 @@ export const TradesTable = forwardRef<AgGridReact, Props>((props, ref) => {
} }
return addDecimalsFormatNumber(value, data.market.decimalPlaces); return addDecimalsFormatNumber(value, data.market.decimalPlaces);
}} }}
cellRenderer={({
value,
data,
}: VegaICellRendererParams<Trade, 'price'>) => {
if (!data?.market || !value) {
return null;
}
return (
<button
onClick={() =>
props.onClick &&
props.onClick(
addDecimal(value, data.market?.decimalPlaces || 0)
)
}
className="hover:dark:bg-neutral-800 hover:bg-neutral-200"
>
{addDecimalsFormatNumber(value, data.market.decimalPlaces)}
</button>
);
}}
/> />
<AgGridColumn <AgGridColumn
headerName={t('Size')} headerName={t('Size')}

View File

@ -133,7 +133,7 @@ export const Toast = ({
)} )}
</div> </div>
<div <div
className="flex-1 p-2 pr-6 text-sm overflow-auto" className="flex-1 p-2 pr-6 text-sm overflow-auto dark:bg-black dark:text-white"
data-testid="toast-content" data-testid="toast-content"
> >
{content} {content}

View File

@ -7,7 +7,7 @@ import random from 'lodash/random';
import sample from 'lodash/sample'; import sample from 'lodash/sample';
import uniqueId from 'lodash/uniqueId'; import uniqueId from 'lodash/uniqueId';
import { useToasts } from './use-toasts'; import { useToasts } from './use-toasts';
import create from 'zustand'; import { create } from 'zustand';
import { useEffect } from '@storybook/addons'; import { useEffect } from '@storybook/addons';
import { formatNumber } from '@vegaprotocol/react-helpers'; import { formatNumber } from '@vegaprotocol/react-helpers';

View File

@ -1,4 +1,4 @@
import create from 'zustand'; import { create } from 'zustand';
import type { Toast } from './toast'; import type { Toast } from './toast';
type ToastsStore = { type ToastsStore = {

View File

@ -1,12 +1,12 @@
import { act } from 'react-dom/test-utils'; import { act } from 'react-dom/test-utils';
const actualCreate = jest.requireActual('zustand').default; // if using jest const zu = jest.requireActual('zustand'); // if using jest
// a variable to hold reset functions for all stores declared in the app // a variable to hold reset functions for all stores declared in the app
const storeResetFns = new Set(); const storeResetFns = new Set();
// when creating a store, we get its initial state, create a reset function and add it in the set // when creating a store, we get its initial state, create a reset function and add it in the set
const create = (createState) => { export const create = (createState) => {
const store = actualCreate(createState); const store = zu.create(createState);
const initialState = store.getState(); const initialState = store.getState();
storeResetFns.add(() => store.setState(initialState, true)); storeResetFns.add(() => store.setState(initialState, true));
return store; return store;
@ -16,5 +16,3 @@ const create = (createState) => {
beforeEach(() => { beforeEach(() => {
act(() => storeResetFns.forEach((resetFn) => resetFn())); act(() => storeResetFns.forEach((resetFn) => resetFn()));
}); });
export default create;

View File

@ -23,10 +23,13 @@ import { ChainIdDocument } from '@vegaprotocol/react-helpers';
const mockUpdateDialogOpen = jest.fn(); const mockUpdateDialogOpen = jest.fn();
const mockCloseVegaDialog = jest.fn(); const mockCloseVegaDialog = jest.fn();
jest.mock('zustand', () => () => () => ({
updateVegaWalletDialog: mockUpdateDialogOpen, jest.mock('zustand', () => ({
closeVegaWalletDialog: mockCloseVegaDialog, create: () => () => ({
vegaWalletDialogOpen: true, updateVegaWalletDialog: mockUpdateDialogOpen,
closeVegaWalletDialog: mockCloseVegaDialog,
vegaWalletDialogOpen: true,
}),
})); }));
let defaultProps: VegaConnectDialogProps; let defaultProps: VegaConnectDialogProps;

View File

@ -1,4 +1,4 @@
import create from 'zustand'; import { create } from 'zustand';
import { import {
Button, Button,
Dialog, Dialog,

View File

@ -9,7 +9,7 @@ import {
} from './connectors'; } from './connectors';
import { determineId } from './utils'; import { determineId } from './utils';
import create from 'zustand'; import { create } from 'zustand';
import type { VegaTxState } from './use-vega-transaction'; import type { VegaTxState } from './use-vega-transaction';
import { VegaTxStatus } from './use-vega-transaction'; import { VegaTxStatus } from './use-vega-transaction';
import type { import type {

View File

@ -1,12 +1,12 @@
import { act } from 'react-dom/test-utils'; import { act } from 'react-dom/test-utils';
const actualCreate = jest.requireActual('zustand').default; // if using jest const zu = jest.requireActual('zustand'); // if using jest
// a variable to hold reset functions for all stores declared in the app // a variable to hold reset functions for all stores declared in the app
const storeResetFns = new Set(); const storeResetFns = new Set();
// when creating a store, we get its initial state, create a reset function and add it in the set // when creating a store, we get its initial state, create a reset function and add it in the set
const create = (createState) => { export const create = (createState) => {
const store = actualCreate(createState); const store = zu.create(createState);
const initialState = store.getState(); const initialState = store.getState();
storeResetFns.add(() => store.setState(initialState, true)); storeResetFns.add(() => store.setState(initialState, true));
return store; return store;

View File

@ -1,4 +1,4 @@
import create from 'zustand'; import { create } from 'zustand';
import produce from 'immer'; import produce from 'immer';
import type { MultisigControl } from '@vegaprotocol/smart-contracts'; import type { MultisigControl } from '@vegaprotocol/smart-contracts';
import type { CollateralBridge } from '@vegaprotocol/smart-contracts'; import type { CollateralBridge } from '@vegaprotocol/smart-contracts';

View File

@ -1,4 +1,4 @@
import create from 'zustand'; import { create } from 'zustand';
import produce from 'immer'; import produce from 'immer';
import type BigNumber from 'bignumber.js'; import type BigNumber from 'bignumber.js';
import type { WithdrawalBusEventFieldsFragment } from '@vegaprotocol/wallet'; import type { WithdrawalBusEventFieldsFragment } from '@vegaprotocol/wallet';

View File

@ -1,4 +1,4 @@
import create from 'zustand'; import { create } from 'zustand';
import type { Web3ReactHooks } from '@web3-react/core'; import type { Web3ReactHooks } from '@web3-react/core';
import type { Connector } from '@web3-react/types'; import type { Connector } from '@web3-react/types';

View File

@ -1,6 +1,6 @@
import type { Asset } from '@vegaprotocol/assets'; import type { Asset } from '@vegaprotocol/assets';
import BigNumber from 'bignumber.js'; import BigNumber from 'bignumber.js';
import create from 'zustand'; import { create } from 'zustand';
export interface WithdrawStore { export interface WithdrawStore {
asset: Asset | undefined; asset: Asset | undefined;

View File

@ -1,4 +1,4 @@
import create from 'zustand'; import { create } from 'zustand';
import { t } from '@vegaprotocol/react-helpers'; import { t } from '@vegaprotocol/react-helpers';
import { Dialog } from '@vegaprotocol/ui-toolkit'; import { Dialog } from '@vegaprotocol/ui-toolkit';
import { useVegaWallet } from '@vegaprotocol/wallet'; import { useVegaWallet } from '@vegaprotocol/wallet';

View File

@ -85,7 +85,7 @@
"uuid": "^8.3.2", "uuid": "^8.3.2",
"web-vitals": "^2.1.4", "web-vitals": "^2.1.4",
"zod": "^3.17.3", "zod": "^3.17.3",
"zustand": "^4.0.0-rc.1" "zustand": "^4.3.2"
}, },
"devDependencies": { "devDependencies": {
"@apollo/react-testing": "^4.0.0", "@apollo/react-testing": "^4.0.0",

View File

@ -23160,13 +23160,20 @@ zod@^3.17.3:
resolved "https://registry.yarnpkg.com/zod/-/zod-3.19.1.tgz#112f074a97b50bfc4772d4ad1576814bd8ac4473" resolved "https://registry.yarnpkg.com/zod/-/zod-3.19.1.tgz#112f074a97b50bfc4772d4ad1576814bd8ac4473"
integrity sha512-LYjZsEDhCdYET9ikFu6dVPGp2YH9DegXjdJToSzD9rO6fy4qiRYFoyEYwps88OseJlPyl2NOe2iJuhEhL7IpEA== integrity sha512-LYjZsEDhCdYET9ikFu6dVPGp2YH9DegXjdJToSzD9rO6fy4qiRYFoyEYwps88OseJlPyl2NOe2iJuhEhL7IpEA==
zustand@^4.0.0-beta.2, zustand@^4.0.0-rc.1: zustand@^4.0.0-beta.2:
version "4.1.2" version "4.1.2"
resolved "https://registry.yarnpkg.com/zustand/-/zustand-4.1.2.tgz#4912b24741662d8a84ed1cb52198471cb369c4b6" resolved "https://registry.yarnpkg.com/zustand/-/zustand-4.1.2.tgz#4912b24741662d8a84ed1cb52198471cb369c4b6"
integrity sha512-gcRaKchcxFPbImrBb/BKgujOhHhik9YhVpIeP87ETT7uokEe2Szu7KkuZ9ghjtD+/KKkcrRNktR2AiLXPIbKIQ== integrity sha512-gcRaKchcxFPbImrBb/BKgujOhHhik9YhVpIeP87ETT7uokEe2Szu7KkuZ9ghjtD+/KKkcrRNktR2AiLXPIbKIQ==
dependencies: dependencies:
use-sync-external-store "1.2.0" use-sync-external-store "1.2.0"
zustand@^4.3.2:
version "4.3.2"
resolved "https://registry.yarnpkg.com/zustand/-/zustand-4.3.2.tgz#bb121fcad84c5a569e94bd1a2695e1a93ba85d39"
integrity sha512-rd4haDmlwMTVWVqwvgy00ny8rtti/klRoZjFbL/MAcDnmD5qSw/RZc+Vddstdv90M5Lv6RPgWvm1Hivyn0QgJw==
dependencies:
use-sync-external-store "1.2.0"
zwitch@^1.0.0: zwitch@^1.0.0:
version "1.0.5" version "1.0.5"
resolved "https://registry.yarnpkg.com/zwitch/-/zwitch-1.0.5.tgz#d11d7381ffed16b742f6af7b3f223d5cd9fe9920" resolved "https://registry.yarnpkg.com/zwitch/-/zwitch-1.0.5.tgz#d11d7381ffed16b742f6af7b3f223d5cd9fe9920"