diff --git a/apps/simple-trading-app-e2e/src/integration/market-list.test.ts b/apps/simple-trading-app-e2e/src/integration/market-list.test.ts index 4aa744942..0c965291c 100644 --- a/apps/simple-trading-app-e2e/src/integration/market-list.test.ts +++ b/apps/simple-trading-app-e2e/src/integration/market-list.test.ts @@ -1,11 +1,14 @@ describe('market list', () => { describe('simple url', () => { - beforeEach(() => cy.visit('/markets')); + beforeEach(() => { + cy.visit('/markets'); + }); it('selects menus', () => { cy.get('.MuiDrawer-root [aria-current]').should('have.text', 'Markets'); - cy.get('select[name="states"]').should('have.value', 'Active'); - cy.get('[data-testid="market-assets-menu"] button.font-bold').should( + cy.getByTestId('state-trigger').should('have.text', 'Active'); + cy.get('[aria-label="Future"]').click(); + cy.get('[data-testid="market-assets-menu"] a.active').should( 'have.text', 'All' ); @@ -14,9 +17,12 @@ describe('market list', () => { it('navigation should make possibly shortest url', () => { cy.location('pathname').should('equal', '/markets'); - cy.get('select[name="states"]').select('All'); + cy.getByTestId('state-trigger').click(); + cy.get('[role=menuitemcheckbox]').contains('All').click(); cy.location('pathname').should('equal', '/markets/all'); + cy.get('[aria-label="Future"]').click(); + cy.location('pathname').should('eq', '/markets/all/Future'); let asset = ''; cy.getByTestId('market-assets-menu') .children() @@ -25,25 +31,18 @@ describe('market list', () => { asset = children[1].innerText; if (asset) { cy.wrap(children[1]).click(); - cy.location('pathname').should('equal', `/markets/all/${asset}`); + cy.location('pathname').should( + 'match', + new RegExp(`/markets/all/Future/${asset}`, 'i') + ); + cy.get('a').contains('All Markets').click(); + cy.location('pathname').should('eq', '/markets/all'); } } }); - if (asset) { - cy.get('button').contains('Future').click(); - cy.location('pathname').should('equal', `/markets/all/${asset}/Future`); - cy.get('button').contains('All Markets').click(); - cy.location('pathname').should('equal', `/markets/all/${asset}`); - } - cy.getByTestId('market-assets-menu') - .children() - .find('button') - .contains('All') - .click(); - cy.location('pathname').should('equal', '/markets/all'); - - cy.get('select[name="states"]').select('Active'); + cy.getByTestId('state-trigger').click(); + cy.get('[role=menuitemcheckbox]').contains('Active').click(); cy.location('pathname').should('equal', '/markets'); }); }); @@ -51,20 +50,29 @@ describe('market list', () => { describe('url params should select filters', () => { it('suspended status', () => { cy.visit('/markets/Suspended'); - cy.get('select[name="states"]').should('have.value', 'Suspended'); + cy.getByTestId('state-trigger').should('have.text', 'Suspended'); }); - it('tBTC asset', () => { - cy.visit('/markets/Suspended/tBTC'); - cy.getByTestId('market-assets-menu') - .find('button.font-bold') - .should('have.text', 'tBTC'); + it('last asset (if exists)', () => { + cy.intercept('POST', '/query').as('Filters'); + cy.visit('/markets'); + cy.wait('@Filters').then((filters) => { + if (filters?.response?.body.data.markets.length) { + const asset = + filters.response.body.data.markets[0].tradableInstrument.instrument + .product.settlementAsset.symbol; + cy.visit(`/markets/Suspended/Future/${asset}`); + cy.getByTestId('market-assets-menu') + .find('a.active') + .should('have.text', asset); + } + }); }); it('Future product', () => { - cy.visit('/markets/Suspended/tBTC/Future'); + cy.visit('/markets/Suspended/Future'); cy.getByTestId('market-products-menu') - .find('button.active') + .find('a.active') .should('have.text', 'Future'); }); }); diff --git a/apps/simple-trading-app/src/app/components/drawer/drawer.tsx b/apps/simple-trading-app/src/app/components/drawer/drawer.tsx index fcf2d9e5d..552098b4b 100644 --- a/apps/simple-trading-app/src/app/components/drawer/drawer.tsx +++ b/apps/simple-trading-app/src/app/components/drawer/drawer.tsx @@ -1,5 +1,5 @@ import * as React from 'react'; -import { theme } from '@vegaprotocol/tailwindcss-config'; +import { themelite as theme } from '@vegaprotocol/tailwindcss-config'; import type { ReactElement } from 'react'; import { useEffect } from 'react'; import Drawer from '@mui/material/Drawer'; diff --git a/apps/simple-trading-app/src/app/components/simple-market-list/simple-market-list.spec.tsx b/apps/simple-trading-app/src/app/components/simple-market-list/simple-market-list.spec.tsx index 03ad76d3b..3268c1f96 100644 --- a/apps/simple-trading-app/src/app/components/simple-market-list/simple-market-list.spec.tsx +++ b/apps/simple-trading-app/src/app/components/simple-market-list/simple-market-list.spec.tsx @@ -3,6 +3,7 @@ import { act } from 'react-dom/test-utils'; import { render, screen, waitFor } from '@testing-library/react'; import { MockedProvider } from '@apollo/client/testing'; import type { MockedResponse } from '@apollo/client/testing'; +import { BrowserRouter } from 'react-router-dom'; import { MarketState } from '@vegaprotocol/types'; import SimpleMarketList from './simple-market-list'; import { FILTERS_QUERY, MARKETS_QUERY } from './data-provider'; @@ -54,7 +55,8 @@ describe('SimpleMarketList', () => { render( - + , + { wrapper: BrowserRouter } ); await new Promise((resolve) => setTimeout(resolve, 0)); }); @@ -122,7 +124,8 @@ describe('SimpleMarketList', () => { render( - + , + { wrapper: BrowserRouter } ); await new Promise((resolve) => setTimeout(resolve, 0)); }); diff --git a/apps/simple-trading-app/src/app/components/simple-market-list/simple-market-list.tsx b/apps/simple-trading-app/src/app/components/simple-market-list/simple-market-list.tsx index 48f81c801..831470e8d 100644 --- a/apps/simple-trading-app/src/app/components/simple-market-list/simple-market-list.tsx +++ b/apps/simple-trading-app/src/app/components/simple-market-list/simple-market-list.tsx @@ -68,7 +68,7 @@ const SimpleMarketList = () => { > {localData?.map((market) => (
  • diff --git a/apps/simple-trading-app/src/app/components/simple-market-list/simple-market-percent-change.spec.tsx b/apps/simple-trading-app/src/app/components/simple-market-list/simple-market-percent-change.spec.tsx index 64db3a61a..0e6d4e733 100644 --- a/apps/simple-trading-app/src/app/components/simple-market-list/simple-market-percent-change.spec.tsx +++ b/apps/simple-trading-app/src/app/components/simple-market-list/simple-market-percent-change.spec.tsx @@ -1,6 +1,6 @@ import React from 'react'; import { render, screen } from '@testing-library/react'; -import { theme } from '@vegaprotocol/tailwindcss-config'; +import { themelite as theme } from '@vegaprotocol/tailwindcss-config'; import { MockedProvider } from '@apollo/react-testing'; import SimpleMarketPercentChange from './simple-market-percent-change'; import type { SimpleMarkets_markets_candles } from './__generated__/SimpleMarkets'; diff --git a/apps/simple-trading-app/src/app/components/simple-market-list/simple-market-percent-change.tsx b/apps/simple-trading-app/src/app/components/simple-market-list/simple-market-percent-change.tsx index ac8efb5f5..e4c094736 100644 --- a/apps/simple-trading-app/src/app/components/simple-market-list/simple-market-percent-change.tsx +++ b/apps/simple-trading-app/src/app/components/simple-market-list/simple-market-percent-change.tsx @@ -1,7 +1,7 @@ import React, { useState } from 'react'; import { InView } from 'react-intersection-observer'; import { useSubscription } from '@apollo/client'; -import { theme } from '@vegaprotocol/tailwindcss-config'; +import { themelite as theme } from '@vegaprotocol/tailwindcss-config'; import type { SimpleMarkets_markets_candles } from './__generated__/SimpleMarkets'; import type { CandleLive, diff --git a/apps/simple-trading-app/src/app/components/simple-market-list/simple-market-toolbar.spec.tsx b/apps/simple-trading-app/src/app/components/simple-market-list/simple-market-toolbar.spec.tsx index 7bcb70b80..bfd803bdb 100644 --- a/apps/simple-trading-app/src/app/components/simple-market-list/simple-market-toolbar.spec.tsx +++ b/apps/simple-trading-app/src/app/components/simple-market-list/simple-market-toolbar.spec.tsx @@ -1,5 +1,5 @@ import React from 'react'; -import { act } from 'react-dom/test-utils'; +import { useLocation, useRoutes, BrowserRouter } from 'react-router-dom'; import { render, screen, fireEvent, waitFor } from '@testing-library/react'; import { MockedProvider } from '@apollo/react-testing'; import SimpleMarketToolbar from './simple-market-toolbar'; @@ -8,14 +8,6 @@ import type { MarketFilters } from './__generated__/MarketFilters'; import { FILTERS_QUERY } from './data-provider'; import filterData from './mocks/market-filters.json'; -const mockedNavigate = jest.fn(); - -jest.mock('react-router-dom', () => ({ - ...jest.requireActual('react-router-dom'), - useNavigate: () => mockedNavigate, - useParams: () => ({}), -})); - describe('SimpleMarketToolbar', () => { const filterMock: MockedResponse = { request: { @@ -26,58 +18,105 @@ describe('SimpleMarketToolbar', () => { }, }; + const WrappedCompForTest = () => { + const routes = useRoutes([ + { + path: '/', + element: , + }, + { + path: 'markets', + children: [ + { + path: `:state`, + element: , + children: [ + { + path: `:product`, + element: , + children: [ + { path: `:asset`, element: }, + ], + }, + ], + }, + ], + element: , + }, + ]); + const location = useLocation(); + return ( + <> + {routes} +
    {location.pathname}
    + + ); + }; + afterEach(() => { jest.resetAllMocks(); }); it('should be properly rendered', async () => { - await act(async () => { - render( - - - - ); - await new Promise((resolve) => setTimeout(resolve, 0)); - }); + render( + + + , + { wrapper: BrowserRouter } + ); await waitFor(() => { - expect(screen.getByTestId('market-assets-menu')).toBeInTheDocument(); + expect(screen.getByText('Future')).toBeInTheDocument(); + }); + fireEvent.click(screen.getByText('Future')); + await waitFor(() => { + expect(screen.getByTestId('market-products-menu').children).toHaveLength( + 3 + ); + expect(screen.getByTestId('market-assets-menu').children).toHaveLength(6); + }); + fireEvent.click(screen.getByTestId('state-trigger')); + waitFor(() => { + expect(screen.getByRole('menu')).toBeInTheDocument(); + expect(screen.getByRole('menu').children).toHaveLength(10); }); - expect(screen.getByTestId('market-products-menu').children).toHaveLength(3); - expect(screen.getByTestId('market-assets-menu').children).toHaveLength(6); - expect(screen.getByRole('combobox').children).toHaveLength(10); }); it('navigation should work well', async () => { - await act(async () => { - render( - - - - ); - await new Promise((resolve) => setTimeout(resolve, 0)); - }); - await waitFor(() => { - expect(screen.getByTestId('market-assets-menu')).toBeInTheDocument(); - }); - fireEvent.click( - screen - .getByTestId('market-products-menu') - .children[1].querySelector('button') as HTMLButtonElement + render( + + + , + { wrapper: BrowserRouter } ); - expect(mockedNavigate).toHaveBeenCalledWith('/markets/Active/all/Future'); + + await waitFor(() => { + expect(screen.getByText('Future')).toBeInTheDocument(); + }); + fireEvent.click(screen.getByText('Future')); + await waitFor(() => { + expect(screen.getByTestId('location-display')).toHaveTextContent( + '/markets/Active/Future' + ); + }); fireEvent.click( screen .getByTestId('market-assets-menu') - .children[5].querySelector('button') as HTMLButtonElement + .children[5].querySelector('a') as HTMLAnchorElement ); - expect(mockedNavigate).toHaveBeenCalledWith('/markets/Active/tEURO/Future'); - - fireEvent.change(screen.getByRole('combobox'), { - target: { value: 'Pending' }, + await waitFor(() => { + expect(screen.getByTestId('location-display')).toHaveTextContent( + '/markets/Active/Future/tEURO' + ); + }); + + fireEvent.click(screen.getByTestId('state-trigger')); + waitFor(() => { + expect(screen.getByRole('menu')).toBeInTheDocument(); + fireEvent.click(screen.getByText('Pending')); + expect(screen.getByTestId('location-display')).toHaveTextContent( + '/markets/Pending/Future/tEURO' + ); }); - expect(mockedNavigate).toHaveBeenCalledWith( - '/markets/Pending/tEURO/Future' - ); }); }); diff --git a/apps/simple-trading-app/src/app/components/simple-market-list/simple-market-toolbar.tsx b/apps/simple-trading-app/src/app/components/simple-market-list/simple-market-toolbar.tsx index 5831f73f3..c250871aa 100644 --- a/apps/simple-trading-app/src/app/components/simple-market-list/simple-market-toolbar.tsx +++ b/apps/simple-trading-app/src/app/components/simple-market-list/simple-market-toolbar.tsx @@ -1,38 +1,41 @@ import React, { useCallback, useEffect, useRef, useState } from 'react'; import classNames from 'classnames'; +import { useNavigate, useParams, Link } from 'react-router-dom'; +import { + DropdownMenu, + DropdownMenuTrigger, +} from '@radix-ui/react-dropdown-menu'; +import { IconNames } from '@blueprintjs/icons'; import { t } from '@vegaprotocol/react-helpers'; -import { theme } from '@vegaprotocol/tailwindcss-config'; -import { useNavigate, useParams } from 'react-router-dom'; -import { Button, Select } from '@vegaprotocol/ui-toolkit'; +import { themelite as theme } from '@vegaprotocol/tailwindcss-config'; +import { + DropdownMenuCheckboxItem, + DropdownMenuContent, + DropdownMenuItemIndicator, + Icon, +} from '@vegaprotocol/ui-toolkit'; import useMarketFiltersData from '../../hooks/use-markets-filter'; import { STATES_FILTER } from './constants'; const SimpleMarketToolbar = () => { const navigate = useNavigate(); const params = useParams(); - const { assets, products, assetsPerProduct } = useMarketFiltersData(); + const { products, assetsPerProduct } = useMarketFiltersData(); + const [isOpen, setOpen] = useState(false); const [activeNumber, setActiveNumber] = useState( products?.length ? products.indexOf(params.product || '') + 1 : -1 ); - const [activeAsset, setActiveAsset] = useState(params.asset || 'all'); - const [activeState, setActiveState] = useState(params.state || 'Active'); + const [sliderStyles, setSliderStyles] = useState>({}); const slideContRef = useRef(null); - const onStateChange = useCallback( - (e: React.ChangeEvent) => { - setActiveState(e.target.value); - }, - [setActiveState] - ); - useEffect(() => { - // handle corner case when there is product - // param, but no products yet - if (activeNumber < 0 && products?.length) { - setActiveNumber(products.indexOf(params.product || '') + 1 || 0); + if (products.length) { + setActiveNumber(products.indexOf(params.product || '') + 1); + } else { + setActiveNumber(-1); } - }, [activeNumber, setActiveNumber, products, params]); + }, [params, products, setActiveNumber]); useEffect(() => { const contStyles = ( @@ -43,7 +46,7 @@ const SimpleMarketToolbar = () => { ]?.getBoundingClientRect(); const styles: Record = selectedStyles ? { - backgroundColor: activeNumber ? '' : theme.colors.coral, + backgroundColor: activeNumber ? '' : theme.colors.pink, width: `${selectedStyles.width}px`, left: `${selectedStyles.left - contStyles.left}px`, } @@ -51,42 +54,55 @@ const SimpleMarketToolbar = () => { setSliderStyles(styles); }, [activeNumber, slideContRef]); - useEffect(() => { - if (activeNumber < 0) { - return; - } - const product = activeNumber ? `/${products[activeNumber - 1]}` : ''; - const asset = activeAsset !== 'all' || product ? `/${activeAsset}` : ''; - const state = activeState !== 'Active' || asset ? `/${activeState}` : ''; - navigate(`/markets${state}${asset}${product}`); - }, [activeNumber, activeAsset, activeState, products, navigate]); + const onStateChange = useCallback( + (activeState: string) => { + const asset = + params.asset && params.asset !== 'all' ? `/${params.asset}` : ''; + const product = params.product ? `/${params.product}` : ''; + const state = + activeState !== 'Active' || product ? `/${activeState}` : ''; + navigate(`/markets${state}${product}${asset}`); + }, + [params, navigate] + ); return ( -
    +
      -
    • - +
    • {products.map((product, i) => (
    • - +
    • ))}
    • { />
    -
    - -
    -
    |
    -
      -
    • - -
    • - {(activeNumber - ? assetsPerProduct[products[activeNumber - 1]] - : assets - )?.map((asset) => ( -
    • -
    +
    + | +
    + {activeNumber > 0 && ( +
      +
    • + - {asset} - + {t('All')} +
    • - ))} -
    + {assetsPerProduct[products[activeNumber - 1]]?.map((asset) => ( +
  • + + {asset} + +
  • + ))} + + )} ); diff --git a/apps/simple-trading-app/src/app/hooks/use-markets-filter.ts b/apps/simple-trading-app/src/app/hooks/use-markets-filter.ts index 2b1bd687b..7b636e1bb 100644 --- a/apps/simple-trading-app/src/app/hooks/use-markets-filter.ts +++ b/apps/simple-trading-app/src/app/hooks/use-markets-filter.ts @@ -4,7 +4,6 @@ import { FILTERS_QUERY } from '../components/simple-market-list/data-provider'; import type { MarketFilters } from '../components/simple-market-list/__generated__/MarketFilters'; const useMarketFilters = () => { - const [assets, setAssets] = useState([]); const [products, setProducts] = useState([]); const [assetsPerProduct, setAssetsPerProduct] = useState< Record @@ -14,7 +13,6 @@ const useMarketFilters = () => { }); useEffect(() => { const localProducts = new Set(); - const localAssets = new Set(); const localAssetPerProduct: Record> = {}; data?.markets?.forEach((item) => { const product = item.tradableInstrument.instrument.product.__typename; @@ -25,9 +23,7 @@ const useMarketFilters = () => { } localAssetPerProduct[product].add(asset); localProducts.add(product); - localAssets.add(asset); }); - setAssets([...localAssets]); setProducts([...localProducts]); setAssetsPerProduct( Object.entries(localAssetPerProduct).reduce( @@ -39,7 +35,7 @@ const useMarketFilters = () => { ) ); }, [data]); - return { assets, products, assetsPerProduct }; + return { products, assetsPerProduct }; }; export default useMarketFilters; diff --git a/apps/simple-trading-app/src/app/routes/router-config.tsx b/apps/simple-trading-app/src/app/routes/router-config.tsx index 59b66b55f..3458cea79 100644 --- a/apps/simple-trading-app/src/app/routes/router-config.tsx +++ b/apps/simple-trading-app/src/app/routes/router-config.tsx @@ -26,9 +26,9 @@ export const routerConfig = [ element: , children: [ { - path: `:asset`, + path: `:product`, element: , - children: [{ path: `:product`, element: }], + children: [{ path: `:asset`, element: }], }, ], }, diff --git a/apps/simple-trading-app/tailwind.config.js b/apps/simple-trading-app/tailwind.config.js index 51ca67ff2..d2fb3eb3d 100644 --- a/apps/simple-trading-app/tailwind.config.js +++ b/apps/simple-trading-app/tailwind.config.js @@ -1,6 +1,6 @@ const { join } = require('path'); const { createGlobPatternsForDependencies } = require('@nrwl/next/tailwind'); -const theme = require('../../libs/tailwindcss-config/src/theme'); +const theme = require('../../libs/tailwindcss-config/src/theme-lite'); const vegaCustomClasses = require('../../libs/tailwindcss-config/src/vega-custom-classes'); module.exports = { diff --git a/apps/token/src/routes/governance/components/vote-details/vote-buttons.tsx b/apps/token/src/routes/governance/components/vote-details/vote-buttons.tsx index 7e9f54682..e8d70992a 100644 --- a/apps/token/src/routes/governance/components/vote-details/vote-buttons.tsx +++ b/apps/token/src/routes/governance/components/vote-details/vote-buttons.tsx @@ -145,7 +145,6 @@ export const VoteButtons = ({ {proposalState === ProposalState.Open ? (