Fix/Default market and tabs navigation (#518)
* fix: dont use localstorage for navigation, remove query params for tabs * chore: lint * fix: revert to using url rather than data test id * chore: lint * chore: remove arrow down ref from markets page object
This commit is contained in:
parent
ca3a2905dd
commit
be3b416176
@ -20,11 +20,10 @@ export default class BasePage {
|
|||||||
.should('be.visible')
|
.should('be.visible')
|
||||||
.click({ force: true });
|
.click({ force: true });
|
||||||
cy.url().should('include', '/portfolio');
|
cy.url().should('include', '/portfolio');
|
||||||
cy.getByTestId('portfolio');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
navigateToMarkets() {
|
navigateToMarkets() {
|
||||||
cy.getByTestId('markets-link').should('be.visible').click({ force: true });
|
cy.get(`a[href='${this.marketsUrl}']`).should('be.visible').click();
|
||||||
cy.url().should('include', '/markets');
|
cy.url().should('include', '/markets');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8,7 +8,6 @@ export default class MarketPage extends BasePage {
|
|||||||
marketRowPrices = 'flash-cell';
|
marketRowPrices = 'flash-cell';
|
||||||
marketRowDescription = 'name';
|
marketRowDescription = 'name';
|
||||||
marketStateColId = 'data';
|
marketStateColId = 'data';
|
||||||
openMarketMenu = 'arrow-down';
|
|
||||||
|
|
||||||
validateMarketsAreDisplayed() {
|
validateMarketsAreDisplayed() {
|
||||||
// We need this to ensure that ag-grid is fully rendered before asserting
|
// We need this to ensure that ag-grid is fully rendered before asserting
|
||||||
@ -57,13 +56,5 @@ export default class MarketPage extends BasePage {
|
|||||||
clickOnMarket(text: string) {
|
clickOnMarket(text: string) {
|
||||||
cy.get(`[col-id=${this.marketStateColId}]`).should('be.visible');
|
cy.get(`[col-id=${this.marketStateColId}]`).should('be.visible');
|
||||||
cy.get(`[col-id=${this.marketStateColId}]`).contains(text).click();
|
cy.get(`[col-id=${this.marketStateColId}]`).contains(text).click();
|
||||||
cy.url({ timeout: 8000 }).should(
|
|
||||||
'contain',
|
|
||||||
'portfolio=orders&trade=orderbook'
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
clickOpenMarketMenu() {
|
|
||||||
cy.getByTestId(this.openMarketMenu).click();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -19,7 +19,6 @@ const mockMarkets = () => {
|
|||||||
Then('I navigate to markets page', () => {
|
Then('I navigate to markets page', () => {
|
||||||
mockMarkets();
|
mockMarkets();
|
||||||
marketsPage.navigateToMarkets();
|
marketsPage.navigateToMarkets();
|
||||||
marketsPage.clickOpenMarketMenu();
|
|
||||||
cy.wait('@Markets');
|
cy.wait('@Markets');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -1,38 +1,17 @@
|
|||||||
import * as Tabs from '@radix-ui/react-tabs';
|
import * as Tabs from '@radix-ui/react-tabs';
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import { useRouter } from 'next/router';
|
|
||||||
import type { ReactElement, ReactNode } from 'react';
|
import type { ReactElement, ReactNode } from 'react';
|
||||||
import { Children, isValidElement, useEffect, useState } from 'react';
|
import { Children, isValidElement, useState } from 'react';
|
||||||
|
|
||||||
interface GridTabsProps {
|
interface GridTabsProps {
|
||||||
children: ReactElement<GridTabProps>[];
|
children: ReactElement<GridTabProps>[];
|
||||||
group: string;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export const GridTabs = ({ children, group }: GridTabsProps) => {
|
export const GridTabs = ({ children }: GridTabsProps) => {
|
||||||
const { query, asPath, replace } = useRouter();
|
|
||||||
const [activeTab, setActiveTab] = useState<string>(() => {
|
const [activeTab, setActiveTab] = useState<string>(() => {
|
||||||
const tab = query[group];
|
|
||||||
|
|
||||||
if (typeof tab === 'string') {
|
|
||||||
return tab;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Default to first tab
|
|
||||||
return children[0].props.id;
|
return children[0].props.id;
|
||||||
});
|
});
|
||||||
|
|
||||||
// Update the query string in the url when the active tab changes
|
|
||||||
// uses group property as the query string key
|
|
||||||
useEffect(() => {
|
|
||||||
const [url, queryString] = asPath.split('?');
|
|
||||||
const searchParams = new URLSearchParams(queryString);
|
|
||||||
searchParams.set(group, activeTab as string);
|
|
||||||
replace(`${url}?${searchParams.toString()}`);
|
|
||||||
// replace and using asPath causes a render loop
|
|
||||||
// eslint-disable-next-line
|
|
||||||
}, [activeTab, group]);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Tabs.Root
|
<Tabs.Root
|
||||||
value={activeTab}
|
value={activeTab}
|
||||||
|
@ -2,38 +2,9 @@ import { useRouter } from 'next/router';
|
|||||||
import { Vega } from '../icons/vega';
|
import { Vega } from '../icons/vega';
|
||||||
import Link from 'next/link';
|
import Link from 'next/link';
|
||||||
import { AnchorButton } from '@vegaprotocol/ui-toolkit';
|
import { AnchorButton } from '@vegaprotocol/ui-toolkit';
|
||||||
import { LocalStorage, t } from '@vegaprotocol/react-helpers';
|
import { t } from '@vegaprotocol/react-helpers';
|
||||||
import { useEffect, useState } from 'react';
|
|
||||||
|
|
||||||
export const Navbar = () => {
|
export const Navbar = () => {
|
||||||
const initNavItemsState = [
|
|
||||||
{
|
|
||||||
name: t('Portfolio'),
|
|
||||||
path: '/portfolio',
|
|
||||||
testId: 'portfolio-link',
|
|
||||||
slug: '',
|
|
||||||
},
|
|
||||||
];
|
|
||||||
const [navItems, setNavItems] = useState(initNavItemsState);
|
|
||||||
const marketId = LocalStorage.getItem('marketId') ?? '';
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
setNavItems([
|
|
||||||
{
|
|
||||||
name: t('Trading'),
|
|
||||||
path: '/markets',
|
|
||||||
testId: 'markets-link',
|
|
||||||
slug: marketId,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: t('Portfolio'),
|
|
||||||
path: '/portfolio',
|
|
||||||
testId: 'portfolio-link',
|
|
||||||
slug: '',
|
|
||||||
},
|
|
||||||
]);
|
|
||||||
}, [marketId]);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<nav className="flex items-center">
|
<nav className="flex items-center">
|
||||||
<Link href="/" passHref={true}>
|
<Link href="/" passHref={true}>
|
||||||
@ -41,7 +12,10 @@ export const Navbar = () => {
|
|||||||
<Vega className="fill-black dark:fill-white" />
|
<Vega className="fill-black dark:fill-white" />
|
||||||
</a>
|
</a>
|
||||||
</Link>
|
</Link>
|
||||||
{navItems.map((route) => (
|
{[
|
||||||
|
{ name: t('Trading'), path: '/markets' },
|
||||||
|
{ name: t('Portfolio'), path: '/portfolio' },
|
||||||
|
].map((route) => (
|
||||||
<NavLink key={route.path} {...route} />
|
<NavLink key={route.path} {...route} />
|
||||||
))}
|
))}
|
||||||
</nav>
|
</nav>
|
||||||
@ -53,30 +27,18 @@ interface NavLinkProps {
|
|||||||
path: string;
|
path: string;
|
||||||
exact?: boolean;
|
exact?: boolean;
|
||||||
testId?: string;
|
testId?: string;
|
||||||
slug?: string;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const NavLink = ({
|
const NavLink = ({ name, path, exact, testId = name }: NavLinkProps) => {
|
||||||
name,
|
|
||||||
path,
|
|
||||||
exact,
|
|
||||||
testId = name,
|
|
||||||
slug = '',
|
|
||||||
}: NavLinkProps) => {
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const isActive =
|
const isActive =
|
||||||
router.asPath === path || (!exact && router.asPath.startsWith(path));
|
router.asPath === path || (!exact && router.asPath.startsWith(path));
|
||||||
const href = slug !== '' ? `${path}/${slug}` : path;
|
|
||||||
return (
|
return (
|
||||||
<AnchorButton
|
<AnchorButton
|
||||||
variant={isActive ? 'accent' : 'inline'}
|
variant={isActive ? 'accent' : 'inline'}
|
||||||
className="px-16 py-6 h-[38px] uppercase border-0 self-end xs:text-ui sm:text-body-large md:text-h5 lg:text-h4"
|
className="px-16 py-6 h-[38px] uppercase border-0 self-end xs:text-ui sm:text-body-large md:text-h5 lg:text-h4"
|
||||||
data-testid={testId}
|
data-testid={testId}
|
||||||
href={href}
|
href={path}
|
||||||
onClick={(e) => {
|
|
||||||
e.preventDefault();
|
|
||||||
router.push(href);
|
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
{name}
|
{name}
|
||||||
</AnchorButton>
|
</AnchorButton>
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import { gql, useQuery } from '@apollo/client';
|
import { gql, useQuery } from '@apollo/client';
|
||||||
import { LocalStorage } from '@vegaprotocol/react-helpers';
|
|
||||||
import { MarketTradingMode } from '@vegaprotocol/types';
|
import { MarketTradingMode } from '@vegaprotocol/types';
|
||||||
import { AsyncRenderer } from '@vegaprotocol/ui-toolkit';
|
import { AsyncRenderer } from '@vegaprotocol/ui-toolkit';
|
||||||
import sortBy from 'lodash/sortBy';
|
import sortBy from 'lodash/sortBy';
|
||||||
@ -36,13 +35,10 @@ export function Index() {
|
|||||||
// should be the oldest market that is currently trading in continuous mode(i.e. not in auction).
|
// should be the oldest market that is currently trading in continuous mode(i.e. not in auction).
|
||||||
const { data, error, loading } = useQuery<MarketsLanding>(MARKETS_QUERY);
|
const { data, error, loading } = useQuery<MarketsLanding>(MARKETS_QUERY);
|
||||||
const setLandingDialog = useGlobalStore((state) => state.setLandingDialog);
|
const setLandingDialog = useGlobalStore((state) => state.setLandingDialog);
|
||||||
const lastSelectedMarketId = LocalStorage.getItem('marketId');
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (data) {
|
if (data) {
|
||||||
const marketId = lastSelectedMarketId
|
const marketId = marketList(data)[0]?.id;
|
||||||
? lastSelectedMarketId
|
|
||||||
: marketList(data)[0]?.id;
|
|
||||||
|
|
||||||
// If a default market is found, go to it with the landing dialog open
|
// If a default market is found, go to it with the landing dialog open
|
||||||
if (marketId) {
|
if (marketId) {
|
||||||
@ -54,7 +50,7 @@ export function Index() {
|
|||||||
replace('/markets');
|
replace('/markets');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, [data, lastSelectedMarketId, replace, setLandingDialog]);
|
}, [data, replace, setLandingDialog]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<AsyncRenderer data={data} loading={loading} error={error}>
|
<AsyncRenderer data={data} loading={loading} error={error}>
|
||||||
|
@ -5,7 +5,7 @@ import React, { useEffect, useState } from 'react';
|
|||||||
import debounce from 'lodash/debounce';
|
import debounce from 'lodash/debounce';
|
||||||
import { PageQueryContainer } from '../../components/page-query-container';
|
import { PageQueryContainer } from '../../components/page-query-container';
|
||||||
import { TradeGrid, TradePanels } from './trade-grid';
|
import { TradeGrid, TradePanels } from './trade-grid';
|
||||||
import { LocalStorage, t } from '@vegaprotocol/react-helpers';
|
import { t } from '@vegaprotocol/react-helpers';
|
||||||
import { useGlobalStore } from '../../stores';
|
import { useGlobalStore } from '../../stores';
|
||||||
import { LandingDialog } from '@vegaprotocol/market-list';
|
import { LandingDialog } from '@vegaprotocol/market-list';
|
||||||
import type { Market, MarketVariables } from './__generated__/Market';
|
import type { Market, MarketVariables } from './__generated__/Market';
|
||||||
@ -74,7 +74,6 @@ const MarketPage = ({ id }: { id?: string }) => {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
LocalStorage.setItem('marketId', marketId);
|
|
||||||
return (
|
return (
|
||||||
<PageQueryContainer<Market, MarketVariables>
|
<PageQueryContainer<Market, MarketVariables>
|
||||||
query={MARKET_QUERY}
|
query={MARKET_QUERY}
|
||||||
|
@ -99,7 +99,7 @@ export const TradeGrid = ({ market }: TradeGridProps) => {
|
|||||||
<TradeMarketHeader market={market} />
|
<TradeMarketHeader market={market} />
|
||||||
<div className={wrapperClasses}>
|
<div className={wrapperClasses}>
|
||||||
<TradeGridChild className="row-start-1 row-end-3">
|
<TradeGridChild className="row-start-1 row-end-3">
|
||||||
<GridTabs group="chart">
|
<GridTabs>
|
||||||
<GridTab id="candles" name={t('Candles')}>
|
<GridTab id="candles" name={t('Candles')}>
|
||||||
<TradingViews.Candles marketId={market.id} />
|
<TradingViews.Candles marketId={market.id} />
|
||||||
</GridTab>
|
</GridTab>
|
||||||
@ -112,7 +112,7 @@ export const TradeGrid = ({ market }: TradeGridProps) => {
|
|||||||
<TradingViews.Ticket marketId={market.id} />
|
<TradingViews.Ticket marketId={market.id} />
|
||||||
</TradeGridChild>
|
</TradeGridChild>
|
||||||
<TradeGridChild className="row-start-1 row-end-3">
|
<TradeGridChild className="row-start-1 row-end-3">
|
||||||
<GridTabs group="trade">
|
<GridTabs>
|
||||||
<GridTab id="trades" name={t('Trades')}>
|
<GridTab id="trades" name={t('Trades')}>
|
||||||
<TradingViews.Trades marketId={market.id} />
|
<TradingViews.Trades marketId={market.id} />
|
||||||
</GridTab>
|
</GridTab>
|
||||||
@ -122,7 +122,7 @@ export const TradeGrid = ({ market }: TradeGridProps) => {
|
|||||||
</GridTabs>
|
</GridTabs>
|
||||||
</TradeGridChild>
|
</TradeGridChild>
|
||||||
<TradeGridChild className="col-span-3">
|
<TradeGridChild className="col-span-3">
|
||||||
<GridTabs group="portfolio">
|
<GridTabs>
|
||||||
<GridTab id="orders" name={t('Orders')}>
|
<GridTab id="orders" name={t('Orders')}>
|
||||||
<TradingViews.Orders />
|
<TradingViews.Orders />
|
||||||
</GridTab>
|
</GridTab>
|
||||||
|
@ -21,7 +21,7 @@ const Portfolio = () => {
|
|||||||
</h2>
|
</h2>
|
||||||
</aside>
|
</aside>
|
||||||
<section>
|
<section>
|
||||||
<GridTabs group="portfolio">
|
<GridTabs>
|
||||||
<GridTab id="positions" name={t('Positions')}>
|
<GridTab id="positions" name={t('Positions')}>
|
||||||
<div className={tabClassName}>
|
<div className={tabClassName}>
|
||||||
<h4 className="text-h4 text-black dark:text-white">
|
<h4 className="text-h4 text-black dark:text-white">
|
||||||
@ -56,7 +56,7 @@ const Portfolio = () => {
|
|||||||
</section>
|
</section>
|
||||||
</main>
|
</main>
|
||||||
<section className="fixed bottom-0 left-0 w-full h-[200px]">
|
<section className="fixed bottom-0 left-0 w-full h-[200px]">
|
||||||
<GridTabs group="collaterals">
|
<GridTabs>
|
||||||
<GridTab id="collateral" name={t('Collateral')}>
|
<GridTab id="collateral" name={t('Collateral')}>
|
||||||
<AccountsContainer />
|
<AccountsContainer />
|
||||||
</GridTab>
|
</GridTab>
|
||||||
|
@ -60,7 +60,7 @@ export const CandlesChartContainer = ({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="h-full flex flex-col">
|
<div className="h-full flex flex-col">
|
||||||
<div className="px-8 flex flex-row flex-wrap gap-8">
|
<div className="p-8 flex flex-row flex-wrap gap-8">
|
||||||
<DropdownMenu>
|
<DropdownMenu>
|
||||||
<DropdownMenuTrigger asChild={true}>
|
<DropdownMenuTrigger asChild={true}>
|
||||||
<Button appendIconName="caret-down" variant="secondary">
|
<Button appendIconName="caret-down" variant="secondary">
|
||||||
|
@ -50,10 +50,7 @@ export const SelectMarketList = ({
|
|||||||
className={`hover:bg-black/20 dark:hover:bg-white/20 cursor-pointer relative`}
|
className={`hover:bg-black/20 dark:hover:bg-white/20 cursor-pointer relative`}
|
||||||
>
|
>
|
||||||
<td className={`${boldUnderlineClassNames} relative`}>
|
<td className={`${boldUnderlineClassNames} relative`}>
|
||||||
<Link
|
<Link href={`/markets/${id}`} passHref={true}>
|
||||||
href={`/markets/${id}?portfolio=orders&trade=orderbook&chart=candles`}
|
|
||||||
passHref={true}
|
|
||||||
>
|
|
||||||
{/* eslint-disable-next-line jsx-a11y/anchor-is-valid */}
|
{/* eslint-disable-next-line jsx-a11y/anchor-is-valid */}
|
||||||
<a
|
<a
|
||||||
onClick={() => onSelect(id)}
|
onClick={() => onSelect(id)}
|
||||||
|
@ -56,9 +56,7 @@ export const MarketsContainer = () => {
|
|||||||
<MarketListTable
|
<MarketListTable
|
||||||
ref={gridRef}
|
ref={gridRef}
|
||||||
data={data}
|
data={data}
|
||||||
onRowClicked={(id) =>
|
onRowClicked={(id) => push(`/markets/${id}`)}
|
||||||
push(`/markets/${id}?portfolio=orders&trade=orderbook`)
|
|
||||||
}
|
|
||||||
/>
|
/>
|
||||||
</AsyncRenderer>
|
</AsyncRenderer>
|
||||||
);
|
);
|
||||||
|
Loading…
Reference in New Issue
Block a user