From 346af6118d2f5562ca28571201a33dd6386a07da Mon Sep 17 00:00:00 2001 From: Art Date: Tue, 24 Jan 2023 14:56:12 +0100 Subject: [PATCH] chore: consolidate persisted order entries (#2673) --- .../deal-ticket/deal-ticket.spec.tsx | 68 ++++++++++--------- .../components/deal-ticket/deal-ticket.tsx | 12 +++- .../src/hooks/use-persisted-order.ts | 53 +++++++++++---- 3 files changed, 82 insertions(+), 51 deletions(-) diff --git a/libs/deal-ticket/src/components/deal-ticket/deal-ticket.spec.tsx b/libs/deal-ticket/src/components/deal-ticket/deal-ticket.spec.tsx index 8170b3fe8..99d3b46f9 100644 --- a/libs/deal-ticket/src/components/deal-ticket/deal-ticket.spec.tsx +++ b/libs/deal-ticket/src/components/deal-ticket/deal-ticket.spec.tsx @@ -52,7 +52,9 @@ function generateJsx(order?: OrderSubmissionBody['orderSubmission']) { } describe('DealTicket', () => { - beforeEach(() => window.localStorage.clear()); + beforeEach(() => { + window.localStorage.clear(); + }); afterEach(() => { window.localStorage.clear(); jest.clearAllMocks(); @@ -87,38 +89,6 @@ describe('DealTicket', () => { ); }); - it('can edit deal ticket', async () => { - render(generateJsx()); - - // BUY is selected by default - expect( - screen.getByTestId('order-side-SIDE_BUY')?.querySelector('input') - ).toBeChecked(); - - await act(async () => { - fireEvent.change(screen.getByTestId('order-size'), { - target: { value: '200' }, - }); - }); - - expect(screen.getByTestId('order-size')).toHaveDisplayValue('200'); - - fireEvent.change(screen.getByTestId('order-tif'), { - target: { value: Schema.OrderTimeInForce.TIME_IN_FORCE_IOC }, - }); - expect(screen.getByTestId('order-tif')).toHaveValue( - Schema.OrderTimeInForce.TIME_IN_FORCE_IOC - ); - - // Switch to limit order - fireEvent.click(screen.getByTestId('order-type-TYPE_LIMIT')); - - // Check all TIF options shown - expect(screen.getByTestId('order-tif').children).toHaveLength( - Object.keys(Schema.OrderTimeInForce).length - ); - }); - it('handles TIF select box dependent on order type', () => { render(generateJsx()); @@ -221,4 +191,36 @@ describe('DealTicket', () => { ).toHaveTextContent('Wrong trading mode'); }); }); + + it('can edit deal ticket', async () => { + render(generateJsx()); + + // BUY is selected by default + expect( + screen.getByTestId('order-side-SIDE_BUY')?.querySelector('input') + ).toBeChecked(); + + await act(async () => { + fireEvent.change(screen.getByTestId('order-size'), { + target: { value: '200' }, + }); + }); + + expect(screen.getByTestId('order-size')).toHaveDisplayValue('200'); + + fireEvent.change(screen.getByTestId('order-tif'), { + target: { value: Schema.OrderTimeInForce.TIME_IN_FORCE_IOC }, + }); + expect(screen.getByTestId('order-tif')).toHaveValue( + Schema.OrderTimeInForce.TIME_IN_FORCE_IOC + ); + + // Switch to limit order + fireEvent.click(screen.getByTestId('order-type-TYPE_LIMIT')); + + // Check all TIF options shown + expect(screen.getByTestId('order-tif').children).toHaveLength( + Object.keys(Schema.OrderTimeInForce).length + ); + }); }); diff --git a/libs/deal-ticket/src/components/deal-ticket/deal-ticket.tsx b/libs/deal-ticket/src/components/deal-ticket/deal-ticket.tsx index 76e3d678d..76cfa8a63 100644 --- a/libs/deal-ticket/src/components/deal-ticket/deal-ticket.tsx +++ b/libs/deal-ticket/src/components/deal-ticket/deal-ticket.tsx @@ -15,7 +15,7 @@ import { useVegaWallet } from '@vegaprotocol/wallet'; import { InputError } from '@vegaprotocol/ui-toolkit'; import { useOrderMarginValidation } from '../../hooks/use-order-margin-validation'; import { MarginWarning } from '../deal-ticket-validation/margin-warning'; -import { usePersistedOrder } from '../../hooks/use-persisted-order'; +import { usePersistedOrderStore } from '../../hooks/use-persisted-order'; import { getDefaultOrder, validateMarketState, @@ -43,7 +43,13 @@ export type DealTicketFormFields = OrderSubmissionBody['orderSubmission'] & { export const DealTicket = ({ market, submit }: DealTicketProps) => { const { pubKey } = useVegaWallet(); - const [persistedOrder, setPersistedOrder] = usePersistedOrder(market); + // const [persistedOrder, setPersistedOrder] = usePersistedOrder(market); + const { getPersistedOrder, setPersistedOrder } = usePersistedOrderStore( + (store) => ({ + getPersistedOrder: store.getOrder, + setPersistedOrder: store.setOrder, + }) + ); const { register, control, @@ -53,7 +59,7 @@ export const DealTicket = ({ market, submit }: DealTicketProps) => { clearErrors, formState: { errors }, } = useForm({ - defaultValues: persistedOrder || getDefaultOrder(market), + defaultValues: getPersistedOrder(market.id) || getDefaultOrder(market), }); const order = watch(); diff --git a/libs/deal-ticket/src/hooks/use-persisted-order.ts b/libs/deal-ticket/src/hooks/use-persisted-order.ts index a4591bb60..3cfda54d9 100644 --- a/libs/deal-ticket/src/hooks/use-persisted-order.ts +++ b/libs/deal-ticket/src/hooks/use-persisted-order.ts @@ -1,20 +1,43 @@ -import { useLocalStorage } from '@vegaprotocol/react-helpers'; import type { OrderSubmissionBody } from '@vegaprotocol/wallet'; -import { useCallback, useMemo } from 'react'; +import produce from 'immer'; +import create from 'zustand'; +import { persist } from 'zustand/middleware'; type OrderData = OrderSubmissionBody['orderSubmission'] | null; -export const usePersistedOrder = (market: { - id: string; -}): [OrderData, (value: OrderData) => void] => { - const [value, setValue] = useLocalStorage(`deal-ticket-order-${market.id}`); - const order = value != null ? (JSON.parse(value) as OrderData) : null; - const setOrder = useCallback( - (order: OrderData) => setValue(JSON.stringify(order)), - [setValue] - ); - return useMemo<[OrderData, (value: OrderData) => void]>( - () => [order, setOrder], - [order, setOrder] - ); +type PersistedOrderStore = { + orders: OrderData[]; + getOrder: (marketId: string) => OrderData | undefined; + setOrder: (order: OrderData) => void; + clear: () => void; }; + +export const usePersistedOrderStore = create( + persist( + (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', + } + ) +);