feat: page title (660) (#1437)

* feat: page title (660)

* fix: trading-e2e home tests
This commit is contained in:
Art 2022-09-23 16:29:35 +02:00 committed by GitHub
parent 483cf05050
commit d271f28b82
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 131 additions and 26 deletions

View File

@ -63,9 +63,13 @@ describe('home', { tags: '@regression' }, () => {
},
};
aliasQuery(req, 'Markets', data);
aliasQuery(req, 'MarketsDataQuery', data);
aliasQuery(req, 'MarketsCandlesQuery', data);
});
cy.visit('/');
cy.wait('@Markets');
cy.wait('@MarketsDataQuery');
cy.wait('@MarketsCandlesQuery');
cy.url().should('eq', Cypress.config().baseUrl + '/markets');
});
});

View File

@ -3,7 +3,11 @@ import Head from 'next/head';
import { Navbar } from '../components/navbar';
import { t, ThemeContext, useThemeSwitcher } from '@vegaprotocol/react-helpers';
import { VegaConnectDialog, VegaWalletProvider } from '@vegaprotocol/wallet';
import { EnvironmentProvider } from '@vegaprotocol/environment';
import {
EnvironmentProvider,
envTriggerMapping,
useEnvironment,
} from '@vegaprotocol/environment';
import { Connectors } from '../lib/vega-connectors';
import { AppLoader } from '../components/app-loader';
import { RiskNoticeDialog } from '../components/risk-notice-dialog';
@ -14,19 +18,32 @@ import {
useAssetDetailsDialogStore,
} from '@vegaprotocol/assets';
import { Footer } from '../components/footer';
import { useMemo } from 'react';
const DEFAULT_TITLE = t('Welcome to Vega trading!');
function AppBody({ Component, pageProps }: AppProps) {
const { connectDialog, update } = useGlobalStore((store) => ({
const { connectDialog, pageTitle, update } = useGlobalStore((store) => ({
connectDialog: store.connectDialog,
pageTitle: store.pageTitle,
update: store.update,
}));
const { isOpen, symbol, trigger, setOpen } = useAssetDetailsDialogStore();
const [theme, toggleTheme] = useThemeSwitcher();
const { VEGA_ENV } = useEnvironment();
const networkName = envTriggerMapping[VEGA_ENV];
const title = useMemo(() => {
if (!pageTitle) return DEFAULT_TITLE;
if (networkName) return `${pageTitle} [${networkName}]`;
return pageTitle;
}, [pageTitle, networkName]);
return (
<ThemeContext.Provider value={theme}>
<Head>
<title>{t('Welcome to Vega trading!')}</title>
<title>{title}</title>
</Head>
<div className="h-full relative dark:bg-black dark:text-white z-0 grid grid-rows-[min-content,1fr,min-content]">
<AppLoader>

View File

@ -1,5 +1,5 @@
import { activeMarketsProvider } from '@vegaprotocol/market-list';
import { useDataProvider } from '@vegaprotocol/react-helpers';
import { useMarketList } from '@vegaprotocol/market-list';
import { addDecimalsFormatNumber, titlefy } from '@vegaprotocol/react-helpers';
import { AsyncRenderer } from '@vegaprotocol/ui-toolkit';
import { useRouter } from 'next/router';
import { useEffect } from 'react';
@ -9,10 +9,7 @@ export function Index() {
const { replace } = useRouter();
// The default market selected in the platform behind the overlay
// should be the oldest market that is currently trading in continuous mode(i.e. not in auction).
const { data, error, loading } = useDataProvider({
dataProvider: activeMarketsProvider,
noUpdate: true,
});
const { data, error, loading } = useMarketList();
const { riskNoticeDialog, update } = useGlobalStore((store) => ({
riskNoticeDialog: store.riskNoticeDialog,
update: store.update,
@ -22,11 +19,19 @@ export function Index() {
update({ landingDialog: true });
if (data) {
const marketId = data[0]?.id;
const marketId = data.markets[0]?.id;
const marketName = data.markets[0]?.tradableInstrument.instrument.name;
const marketPrice = data.marketsData[0]?.markPrice
? addDecimalsFormatNumber(
data.marketsData[0]?.markPrice,
data.markets[0].decimalPlaces
)
: null;
const pageTitle = titlefy([marketName, marketPrice]);
if (marketId) {
replace(`/markets/${marketId}`);
update({ marketId });
update({ marketId, pageTitle });
}
// Fallback to the markets list page
else {

View File

@ -1,13 +1,16 @@
import { gql } from '@apollo/client';
import { gql, useQuery } from '@apollo/client';
import { useAssetDetailsDialogStore } from '@vegaprotocol/assets';
import { ColumnKind, SelectMarketDialog } from '@vegaprotocol/market-list';
import { t } from '@vegaprotocol/react-helpers';
import {
addDecimalsFormatNumber,
t,
titlefy,
} from '@vegaprotocol/react-helpers';
import { Interval } from '@vegaprotocol/types';
import { Splash } from '@vegaprotocol/ui-toolkit';
import { AsyncRenderer, Splash } from '@vegaprotocol/ui-toolkit';
import debounce from 'lodash/debounce';
import { useRouter } from 'next/router';
import React, { useEffect, useMemo, useState } from 'react';
import { PageQueryContainer } from '../../components/page-query-container';
import { useGlobalStore } from '../../stores';
import { TradeGrid, TradePanels } from './trade-grid';
import type { Market, MarketVariables } from './__generated__/Market';
@ -120,6 +123,30 @@ const MarketPage = ({ id }: { id?: string }) => {
[marketId, yTimestamp]
);
const { data, error, loading } = useQuery<Market, MarketVariables>(
MARKET_QUERY,
{
variables,
fetchPolicy: 'network-only',
errorPolicy: 'ignore',
}
);
useEffect(() => {
const marketName = data?.market?.tradableInstrument.instrument.name;
const marketPrice =
data?.market && data?.market?.data
? addDecimalsFormatNumber(
data.market.data.markPrice,
data.market.decimalPlaces
)
: null;
if (marketName) {
const pageTitle = titlefy([marketName, marketPrice]);
update({ pageTitle });
}
}, [data, update]);
if (!marketId) {
return (
<Splash>
@ -129,18 +156,14 @@ const MarketPage = ({ id }: { id?: string }) => {
}
return (
<PageQueryContainer<Market, MarketVariables>
query={MARKET_QUERY}
data-testid="market"
options={{
variables,
fetchPolicy: 'network-only',
}}
<AsyncRenderer<Market>
loading={loading}
error={error}
data={data}
render={({ market }) => {
if (!market) {
return <Splash>{t('Market not found')}</Splash>;
}
return (
<>
{w > 960 ? (

View File

@ -1,9 +1,15 @@
import { useRouter } from 'next/router';
import { MarketsContainer } from '@vegaprotocol/market-list';
import { useGlobalStore } from '../../stores';
import { useEffect } from 'react';
import { titlefy } from '@vegaprotocol/react-helpers';
const Markets = () => {
const { update } = useGlobalStore((store) => ({ update: store.update }));
useEffect(() => {
update({ pageTitle: titlefy(['Markets']) });
}, [update]);
const router = useRouter();
return (
<MarketsContainer

View File

@ -1,8 +1,17 @@
import { t } from '@vegaprotocol/react-helpers';
import { t, titlefy } from '@vegaprotocol/react-helpers';
import { Web3Container } from '@vegaprotocol/web3';
import { useEffect } from 'react';
import { useGlobalStore } from '../../../stores';
import { DepositContainer } from './deposit-container';
const Deposit = () => {
const { update } = useGlobalStore((store) => ({
update: store.update,
}));
useEffect(() => {
update({ pageTitle: titlefy([t('Deposits')]) });
}, [update]);
return (
<Web3Container>
<div className="max-w-[420px] p-8 mx-auto">

View File

@ -1,4 +1,4 @@
import { t } from '@vegaprotocol/react-helpers';
import { t, titlefy } from '@vegaprotocol/react-helpers';
import { PositionsContainer } from '@vegaprotocol/positions';
import { OrderListContainer } from '@vegaprotocol/orders';
import { AccountsContainer } from '@vegaprotocol/accounts';
@ -6,12 +6,20 @@ import { ResizableGridPanel, Tab, Tabs } from '@vegaprotocol/ui-toolkit';
import { WithdrawalsContainer } from './withdrawals-container';
import { FillsContainer } from '@vegaprotocol/fills';
import type { ReactNode } from 'react';
import { useEffect } from 'react';
import { VegaWalletContainer } from '../../components/vega-wallet-container';
import { DepositsContainer } from './deposits-container';
import { ResizableGrid } from '@vegaprotocol/ui-toolkit';
import { LayoutPriority } from 'allotment';
import { useGlobalStore } from '../../stores';
const Portfolio = () => {
const { update } = useGlobalStore((store) => ({
update: store.update,
}));
useEffect(() => {
update({ pageTitle: titlefy([t('Portfolio')]) });
}, [update]);
const wrapperClasses = 'h-full max-h-full flex flex-col';
const tabContentClassName = 'h-full grid grid-rows-[min-content_1fr]';
return (

View File

@ -6,6 +6,7 @@ interface GlobalStore {
landingDialog: boolean;
riskNoticeDialog: boolean;
marketId: string | null;
pageTitle: string | null;
update: (store: Partial<Omit<GlobalStore, 'update'>>) => void;
}
@ -15,6 +16,7 @@ export const useGlobalStore = create<GlobalStore>((set) => ({
landingDialog: false,
riskNoticeDialog: false,
marketId: null,
pageTitle: null,
update: (state) => {
set(state);
},

View File

@ -1,4 +1,4 @@
import { truncateByChars, ELLIPSIS, shorten } from './strings';
import { truncateByChars, ELLIPSIS, shorten, titlefy } from './strings';
describe('truncateByChars', () => {
it.each([
@ -27,3 +27,25 @@ describe('shorten', () => {
expect(output).toStrictEqual(o);
});
});
describe('titlefy', () => {
it.each([
{ words: [], o: 'Vega' },
{ words: ['one'], o: 'one - Vega' },
{ words: ['one'], o: 'one - Vega' },
{
words: ['one', 'two', 'three'],
o: 'one - two - three - Vega',
},
{
words: ['one', null, undefined, 'two'],
o: 'one - two - Vega',
},
{
words: ['VEGAUSD', '123.22'],
o: 'VEGAUSD - 123.22 - Vega',
},
])('should convert to title-like string', ({ words, o }) => {
expect(titlefy(words)).toEqual(o);
});
});

View File

@ -17,3 +17,12 @@ export function shorten(input: string, limit?: number) {
const suffix = output.length < limit ? ELLIPSIS : '';
return input.substring(0, limit - 1) + suffix;
}
const TITLE_SEPARATOR = ' - ';
const TITLE_SUFFIX = 'Vega';
export function titlefy(words: (string | null | undefined)[]) {
const title = [...words, TITLE_SUFFIX]
.filter((w) => w && w.length > 0)
.join(TITLE_SEPARATOR);
return title;
}