From 6c84153cdb5d180a2b44b167c503adbd8a5b66f1 Mon Sep 17 00:00:00 2001 From: macqbat Date: Mon, 2 Jan 2023 17:01:06 +0100 Subject: [PATCH] chore: redirect to last visited market instead first from the list (#2489) * chore: redirect to last visited market instead first from the list * chore: redirect to last visited market instead first from the list - add int tests * feat: redirect to last visited market instead first from the list - refactor solution * feat: redirect to last visited market instead first from the list - fix failing int test * feat: redirect to last visited market instead first from the list - fix failing int test * feat: redirect to last visited market instead first from the list - fix failing int test * feat: redirect to last visited market instead first from the list - use immer in globalStore * chore: redirect to last visited market - improve use of zustand --- apps/trading-e2e/src/integration/global.cy.ts | 1 + apps/trading-e2e/src/integration/home.cy.ts | 30 +++++++ apps/trading/client-pages/home/home.tsx | 52 ++++-------- apps/trading/client-pages/market/market.tsx | 41 +++++----- apps/trading/client-pages/markets/markets.tsx | 5 +- .../welcome-dialog/welcome-dialog.tsx | 79 ++++++++----------- .../welcome-dialog/welcome-landing-dialog.tsx | 8 +- apps/trading/pages/client-router.tsx | 4 +- apps/trading/stores/global.ts | 15 +++- 9 files changed, 118 insertions(+), 117 deletions(-) diff --git a/apps/trading-e2e/src/integration/global.cy.ts b/apps/trading-e2e/src/integration/global.cy.ts index 6780e7a97..d52c4096c 100644 --- a/apps/trading-e2e/src/integration/global.cy.ts +++ b/apps/trading-e2e/src/integration/global.cy.ts @@ -133,6 +133,7 @@ describe('Navbar', { tags: '@smoke' }, () => { cy.mockTradingPage(); cy.mockSubscription(); cy.visit('/'); + cy.wait('@Market'); cy.getByTestId('dialog-close').click(); }); diff --git a/apps/trading-e2e/src/integration/home.cy.ts b/apps/trading-e2e/src/integration/home.cy.ts index 60751eb98..1e6802296 100644 --- a/apps/trading-e2e/src/integration/home.cy.ts +++ b/apps/trading-e2e/src/integration/home.cy.ts @@ -224,4 +224,34 @@ describe('home', { tags: '@regression' }, () => { .should('exist'); }); }); + + describe('redirect should take last visited market into consideration', () => { + beforeEach(() => { + cy.window().then((window) => { + window.localStorage.removeItem('marketId'); + }); + }); + it('marketId comes from existing market', () => { + cy.window().then((window) => { + window.localStorage.setItem('marketId', 'market-1'); + cy.visit('/'); + cy.wait('@Market'); + cy.location('hash').should('equal', '#/markets/market-1'); + cy.get('[role="dialog"]').should('not.exist'); + }); + }); + + it('marketId comes from not-existing market', () => { + cy.window().then((window) => { + window.localStorage.setItem('marketId', 'market-not-existing'); + cy.mockGQL((req) => { + aliasGQLQuery(req, 'Market', null); + }); + cy.visit('/'); + cy.wait('@Market'); + cy.location('hash').should('equal', '#/markets/market-not-existing'); + cy.get('[role="dialog"]').should('not.exist'); + }); + }); + }); }); diff --git a/apps/trading/client-pages/home/home.tsx b/apps/trading/client-pages/home/home.tsx index e49cbcae2..8fb31c879 100644 --- a/apps/trading/client-pages/home/home.tsx +++ b/apps/trading/client-pages/home/home.tsx @@ -1,14 +1,10 @@ -import { marketsWithDataProvider } from '@vegaprotocol/market-list'; -import { - addDecimalsFormatNumber, - titlefy, - useDataProvider, -} from '@vegaprotocol/react-helpers'; -import { AsyncRenderer } from '@vegaprotocol/ui-toolkit'; -import { Links, Routes } from '../../pages/client-router'; import { useEffect } from 'react'; import { useNavigate } from 'react-router-dom'; -import { useGlobalStore, usePageTitleStore } from '../../stores'; +import { marketsWithDataProvider } from '@vegaprotocol/market-list'; +import { useDataProvider } from '@vegaprotocol/react-helpers'; +import { AsyncRenderer } from '@vegaprotocol/ui-toolkit'; +import { Links, Routes } from '../../pages/client-router'; +import { useGlobalStore } from '../../stores'; export const Home = () => { const navigate = useNavigate(); @@ -17,40 +13,26 @@ export const Home = () => { const { data, error, loading } = useDataProvider({ dataProvider: marketsWithDataProvider, }); - const { update } = useGlobalStore((store) => ({ - update: store.update, - })); - - const { pageTitle, updateTitle } = usePageTitleStore((store) => ({ - pageTitle: store.pageTitle, - updateTitle: store.updateTitle, - })); + const update = useGlobalStore((store) => store.update); + const marketId = useGlobalStore((store) => store.marketId); useEffect(() => { - if (data) { - const marketId = data[0]?.id; - const marketName = data[0]?.tradableInstrument.instrument.name; - const marketPrice = data[0]?.data?.markPrice - ? addDecimalsFormatNumber( - data[0]?.data?.markPrice, - data[0]?.decimalPlaces - ) - : null; - const newPageTitle = titlefy([marketName, marketPrice]); - - if (marketId) { - navigate(Links[Routes.MARKET](marketId), { + if (marketId) { + navigate(Links[Routes.MARKET](marketId), { + replace: true, + }); + } else if (data) { + const marketDataId = data[0]?.id; + if (marketDataId) { + navigate(Links[Routes.MARKET](marketDataId), { replace: true, }); - update({ marketId }); - if (pageTitle !== newPageTitle) { - updateTitle(newPageTitle); - } } else { navigate(Links[Routes.MARKET]()); } + update({ shouldDisplayWelcomeDialog: true }); } - }, [data, navigate, update, pageTitle, updateTitle]); + }, [marketId, data, navigate, update]); return ( diff --git a/apps/trading/client-pages/market/market.tsx b/apps/trading/client-pages/market/market.tsx index f3feeff88..0fad3d26c 100644 --- a/apps/trading/client-pages/market/market.tsx +++ b/apps/trading/client-pages/market/market.tsx @@ -32,29 +32,23 @@ export interface SingleMarketData extends SingleMarketFieldsFragment { } export const Market = () => { - const params = useParams(); + const { marketId } = useParams(); const navigate = useNavigate(); - const marketId = params.marketId; - const { w } = useWindowSize(); - const { update } = useGlobalStore((store) => ({ - update: store.update, - })); + const update = useGlobalStore((store) => store.update); + const lastMarketId = useGlobalStore((store) => store.marketId); - const { pageTitle, updateTitle } = usePageTitleStore((store) => ({ - pageTitle: store.pageTitle, - updateTitle: store.updateTitle, - })); + const pageTitle = usePageTitleStore((store) => store.pageTitle); + const updateTitle = usePageTitleStore((store) => store.updateTitle); const onSelect = useCallback( (id: string) => { if (id && id !== marketId) { - update({ marketId: id }); navigate(Links[Routes.MARKET](id)); } }, - [marketId, update, navigate] + [marketId, navigate] ); const variables = useMemo( @@ -64,12 +58,22 @@ export const Market = () => { [marketId] ); + const updateMarketId = useCallback( + ({ data }: { data: { id?: string } | null }) => { + if (data?.id && data.id !== lastMarketId) { + update({ marketId: data.id }); + } + return true; + }, + [update, lastMarketId] + ); const { data, error, loading } = useDataProvider< SingleMarketFieldsFragment, never >({ dataProvider: marketProvider, variables, + update: updateMarketId, skip: !marketId, }); @@ -104,11 +108,10 @@ export const Market = () => { } return ; }, [w, data, onSelect]); - if (!data && marketId) { return ( -

{t('Not found')}

+

{t('Market not found')}

); } @@ -119,13 +122,9 @@ export const Market = () => { error={error} data={data || undefined} noDataCondition={(data) => false} - render={(data) => { - if (!data && marketId) { - return {t('Market not found')}; - } - return <>{tradeView}; - }} - /> + > + {tradeView} +
); }; diff --git a/apps/trading/client-pages/markets/markets.tsx b/apps/trading/client-pages/markets/markets.tsx index 04aab70b9..ffdf3eb94 100644 --- a/apps/trading/client-pages/markets/markets.tsx +++ b/apps/trading/client-pages/markets/markets.tsx @@ -1,18 +1,15 @@ import { useCallback } from 'react'; import { MarketsContainer } from '@vegaprotocol/market-list'; -import { useGlobalStore } from '../../stores'; import { useNavigate } from 'react-router-dom'; import { Links, Routes } from '../../pages/client-router'; export const Markets = () => { const navigate = useNavigate(); - const { update } = useGlobalStore((store) => ({ update: store.update })); const handleOnSelect = useCallback( (marketId: string) => { - update({ marketId }); navigate(Links[Routes.MARKET](marketId)); }, - [update, navigate] + [navigate] ); return ; diff --git a/apps/trading/components/welcome-dialog/welcome-dialog.tsx b/apps/trading/components/welcome-dialog/welcome-dialog.tsx index 97be3da40..bdeac4a63 100644 --- a/apps/trading/components/welcome-dialog/welcome-dialog.tsx +++ b/apps/trading/components/welcome-dialog/welcome-dialog.tsx @@ -1,4 +1,4 @@ -import React, { useMemo, useState, useCallback } from 'react'; +import React, { useCallback } from 'react'; import { useLocation } from 'react-router-dom'; import { Dialog } from '@vegaprotocol/ui-toolkit'; import { @@ -12,59 +12,50 @@ import * as constants from '../constants'; import { RiskNoticeDialog } from './risk-notice-dialog'; import { WelcomeNoticeDialog } from './welcome-notice-dialog'; import { WelcomeLandingDialog } from './welcome-landing-dialog'; +import { useGlobalStore } from '../../stores'; -interface DialogConfig { - open?: boolean; - content: React.ReactNode; - title?: string; - size?: 'small' | 'medium'; - onClose: () => void; -} export const WelcomeDialog = () => { const { pathname } = useLocation(); const { VEGA_ENV } = useEnvironment(); - const [dialog, setDialog] = useState(null); - const onClose = useCallback(() => { - setDialog(null); - }, [setDialog]); + let dialogContent: React.ReactNode = null; + let title = ''; + let size: 'small' | 'medium' = 'small'; const [riskAccepted] = useLocalStorage(constants.RISK_ACCEPTED_KEY); - const { data } = useDataProvider({ dataProvider: activeMarketsProvider, }); - useMemo(() => { - switch (true) { - case riskAccepted !== 'true' && VEGA_ENV === Networks.MAINNET: - setDialog({ - content: , - title: t('WARNING'), - size: 'medium', - onClose, - }); - break; - case pathname === '/' && data?.length === 0: - setDialog({ - content: , - onClose, - }); - break; - case pathname === '/' && (data?.length || 0) > 0: - setDialog({ - content: , - onClose, - }); - break; - } - }, [onClose, data?.length, riskAccepted, pathname, VEGA_ENV, setDialog]); - return dialog ? ( + const { update, shouldDisplayWelcomeDialog } = useGlobalStore((store) => ({ + update: store.update, + shouldDisplayWelcomeDialog: store.shouldDisplayWelcomeDialog, + })); + const isRiskDialogNeeded = + riskAccepted !== 'true' && VEGA_ENV === Networks.MAINNET; + const isWelcomeDialogNeeded = pathname === '/' || shouldDisplayWelcomeDialog; + const onClose = useCallback(() => { + update({ shouldDisplayWelcomeDialog: isRiskDialogNeeded }); + // eslint-disable-next-line react-hooks/exhaustive-deps + dialogContent = null; + }, [update, isRiskDialogNeeded]); + + if (isRiskDialogNeeded) { + dialogContent = ; + title = t('WARNING'); + size = 'medium'; + } else if (isWelcomeDialogNeeded && data?.length === 0) { + dialogContent = ; + } else if (isWelcomeDialogNeeded && (data?.length || 0) > 0) { + dialogContent = ; + } + + return ( - {dialog.content} + {dialogContent} - ) : null; + ); }; diff --git a/apps/trading/components/welcome-dialog/welcome-landing-dialog.tsx b/apps/trading/components/welcome-dialog/welcome-landing-dialog.tsx index 02d5c3540..ecac87f0f 100644 --- a/apps/trading/components/welcome-dialog/welcome-landing-dialog.tsx +++ b/apps/trading/components/welcome-dialog/welcome-landing-dialog.tsx @@ -12,7 +12,6 @@ import { } from '../select-market'; import { WelcomeDialogHeader } from './welcome-dialog-header'; import { Link, useNavigate, useParams } from 'react-router-dom'; -import { useGlobalStore } from '../../stores'; import { ProposedMarkets } from './proposed-markets'; import { Links, Routes } from '../../pages/client-router'; @@ -27,18 +26,13 @@ export const SelectMarketLandingTable = ({ const navigate = useNavigate(); const marketId = params.marketId; - const { update } = useGlobalStore((store) => ({ - update: store.update, - })); - const onSelect = useCallback( (id: string) => { if (id && id !== marketId) { - update({ marketId: id }); navigate(Links[Routes.MARKET](id)); } }, - [marketId, update, navigate] + [marketId, navigate] ); const onSelectMarket = useCallback( diff --git a/apps/trading/pages/client-router.tsx b/apps/trading/pages/client-router.tsx index 78bcee9b3..7fa7c15ed 100644 --- a/apps/trading/pages/client-router.tsx +++ b/apps/trading/pages/client-router.tsx @@ -3,7 +3,7 @@ import type { RouteObject } from 'react-router-dom'; import { useRoutes } from 'react-router-dom'; import dynamic from 'next/dynamic'; import { t } from '@vegaprotocol/react-helpers'; -import { Splash } from '@vegaprotocol/ui-toolkit'; +import { Loader, Splash } from '@vegaprotocol/ui-toolkit'; import trimEnd from 'lodash/trimEnd'; const LazyHome = dynamic(() => import('../client-pages/home'), { @@ -91,7 +91,7 @@ export const ClientRouter = () => { - {t('Loading...')} + } > diff --git a/apps/trading/stores/global.ts b/apps/trading/stores/global.ts index 493f53efd..ee88e768b 100644 --- a/apps/trading/stores/global.ts +++ b/apps/trading/stores/global.ts @@ -1,10 +1,12 @@ import { LocalStorage } from '@vegaprotocol/react-helpers'; import create from 'zustand'; +import produce from 'immer'; interface GlobalStore { networkSwitcherDialog: boolean; marketId: string | null; update: (store: Partial>) => void; + shouldDisplayWelcomeDialog: boolean; } interface PageTitleStore { @@ -15,10 +17,15 @@ interface PageTitleStore { export const useGlobalStore = create((set) => ({ networkSwitcherDialog: false, marketId: LocalStorage.getItem('marketId') || null, - update: (state) => { - set(state); - if (state.marketId) { - LocalStorage.setItem('marketId', state.marketId); + shouldDisplayWelcomeDialog: false, + update: (newState) => { + set( + produce((state: GlobalStore) => { + Object.assign(state, newState); + }) + ); + if (newState.marketId) { + LocalStorage.setItem('marketId', newState.marketId); } }, }));