diff --git a/apps/trading/client-pages/assets/assets.tsx b/apps/trading/client-pages/assets/assets.tsx new file mode 100644 index 000000000..b60b89e04 --- /dev/null +++ b/apps/trading/client-pages/assets/assets.tsx @@ -0,0 +1,31 @@ +import { t } from '@vegaprotocol/i18n'; +import { Links } from '../../lib/links'; +import classNames from 'classnames'; +import { NavLink, Outlet } from 'react-router-dom'; + +export const Assets = () => { + const linkClasses = ({ isActive }: { isActive: boolean }) => { + return classNames('border-b-2 border-transparent', { + 'border-vega-yellow': isActive, + }); + }; + + return ( +
+ +
+ +
+
+ ); +}; diff --git a/apps/trading/client-pages/assets/index.ts b/apps/trading/client-pages/assets/index.ts new file mode 100644 index 000000000..1cd127066 --- /dev/null +++ b/apps/trading/client-pages/assets/index.ts @@ -0,0 +1 @@ +export { Assets } from './assets'; diff --git a/apps/trading/client-pages/deposit/deposit-get-started.tsx b/apps/trading/client-pages/deposit/deposit-get-started.tsx new file mode 100644 index 000000000..86983e8b5 --- /dev/null +++ b/apps/trading/client-pages/deposit/deposit-get-started.tsx @@ -0,0 +1,44 @@ +import { t } from '@vegaprotocol/i18n'; +import { Intent, TradingAnchorButton } from '@vegaprotocol/ui-toolkit'; +import { GetStartedCheckList } from '../../components/welcome-dialog'; +import { + useGetOnboardingStep, + useOnboardingStore, + OnboardingStep, +} from '../../components/welcome-dialog/use-get-onboarding-step'; +import { Links } from '../../lib/links'; +import classNames from 'classnames'; + +export const DepositGetStarted = () => { + const onboardingDismissed = useOnboardingStore((store) => store.dismissed); + const dismiss = useOnboardingStore((store) => store.dismiss); + const step = useGetOnboardingStep(); + const wrapperClasses = classNames( + 'flex flex-col py-4 px-6 gap-4 rounded', + 'bg-vega-blue-300 dark:bg-vega-blue-700', + 'border border-vega-blue-350 dark:border-vega-blue-650' + ); + + // Dont show unless still onboarding + if (onboardingDismissed) { + return null; + } + + return ( +
+
+

{t('Get started')}

+ + {step > OnboardingStep.ONBOARDING_DEPOSIT_STEP && ( + dismiss()} + intent={Intent.Info} + > + {t('Start trading')} + + )} +
+
+ ); +}; diff --git a/apps/trading/client-pages/deposit/deposit.spec.tsx b/apps/trading/client-pages/deposit/deposit.spec.tsx new file mode 100644 index 000000000..fb61fff51 --- /dev/null +++ b/apps/trading/client-pages/deposit/deposit.spec.tsx @@ -0,0 +1,30 @@ +import { render, screen } from '@testing-library/react'; +import { MemoryRouter } from 'react-router-dom'; +import { Deposit } from './deposit'; + +jest.mock('@vegaprotocol/deposits', () => ({ + DepositContainer: ({ assetId }: { assetId?: string }) => ( +
{assetId}
+ ), +})); + +jest.mock('./deposit-get-started', () => ({ + DepositGetStarted: () =>
DepositGetStarted
, +})); + +const renderJsx = (route = '/deposit') => { + render( + + + + ); +}; + +describe('Deposit page', () => { + it('assetId should be passed down', () => { + const assetId = 'foo'; + const route = '/deposit?assetId=' + assetId; + renderJsx(route); + expect(screen.getByTestId('assetId')).toHaveTextContent(assetId); + }); +}); diff --git a/apps/trading/client-pages/deposit/deposit.tsx b/apps/trading/client-pages/deposit/deposit.tsx index f9c961ec8..33dc8570a 100644 --- a/apps/trading/client-pages/deposit/deposit.tsx +++ b/apps/trading/client-pages/deposit/deposit.tsx @@ -1,59 +1,14 @@ import { DepositContainer } from '@vegaprotocol/deposits'; -import { t } from '@vegaprotocol/i18n'; -import { Intent, TradingAnchorButton } from '@vegaprotocol/ui-toolkit'; -import { GetStartedCheckList } from '../../components/welcome-dialog'; -import { - useGetOnboardingStep, - useOnboardingStore, - OnboardingStep, -} from '../../components/welcome-dialog/use-get-onboarding-step'; -import { Links, Routes } from '../../pages/client-router'; -import classNames from 'classnames'; +import { useSearchParams } from 'react-router-dom'; +import { DepositGetStarted } from './deposit-get-started'; export const Deposit = () => { + const [searchParams] = useSearchParams(); + const assetId = searchParams.get('assetId') || undefined; return ( -
-

- {t('Deposit')} -

-
- - -
-
- ); -}; - -const DepositGetStarted = () => { - const onboardingDismissed = useOnboardingStore((store) => store.dismissed); - const dismiss = useOnboardingStore((store) => store.dismiss); - const step = useGetOnboardingStep(); - const wrapperClasses = classNames( - 'flex flex-col py-4 px-6 gap-4 rounded', - 'bg-vega-blue-300 dark:bg-vega-blue-700', - 'border border-vega-blue-350 dark:border-vega-blue-650' - ); - - // Dont show unless still onboarding - if (onboardingDismissed) { - return null; - } - - return ( -
-
-

{t('Get started')}

- - {step > OnboardingStep.ONBOARDING_DEPOSIT_STEP && ( - dismiss()} - intent={Intent.Info} - > - {t('Start trading')} - - )} -
+
+ +
); }; diff --git a/apps/trading/client-pages/disclaimer/disclaimer.tsx b/apps/trading/client-pages/disclaimer/disclaimer.tsx index 22abcc58f..9a7195ba3 100644 --- a/apps/trading/client-pages/disclaimer/disclaimer.tsx +++ b/apps/trading/client-pages/disclaimer/disclaimer.tsx @@ -2,47 +2,45 @@ import { t } from '@vegaprotocol/i18n'; export const Disclaimer = () => { return ( -
-
-

- {t('Disclaimer')} -

-

- {t( - 'Vega is a decentralised peer-to-peer protocol that can be used to trade derivatives with cryptoassets. The Vega Protocol is an implementation layer (layer one) protocol made of free, public, open-source or source-available software. Use of the Vega Protocol involves various risks, including but not limited to, losses while digital assets are supplied to the Vega Protocol and losses due to the fluctuation of prices of assets.' - )} -

-

- {t( - 'Before using the Vega Protocol, review the relevant documentation at docs.vega.xyz to make sure that you understand how it works. Conduct your own due diligence and consult your financial advisor before making any investment decisions.' - )} -

-

- {t( - 'As described in the Vega Protocol core license, the Vega Protocol is provided “as is”, at your own risk, and without warranties of any kind. Although Gobalsky Labs Limited developed much of the initial code for the Vega Protocol, it does not provide or control the Vega Protocol, which is run by third parties deploying it on a bespoke blockchain. Upgrades and modifications to the Vega Protocol are managed in a community-driven way by holders of the VEGA governance token.' - )} -

-

- {t( - 'No developer or entity involved in creating the Vega Protocol will be liable for any claims or damages whatsoever associated with your use, inability to use, or your interaction with other users of the Vega Protocol, including any direct, indirect, incidental, special, exemplary, punitive or consequential damages, or legal costs, or loss of profits, cryptoassets, tokens or anything else of value.' - )} -

-

- {t( - 'This website is hosted on a decentralised network, the Interplanetary File System (“IPFS”). The IPFS decentralised web is made up of all the computers (nodes) connected to it. Data is therefore stored on many different computers.' - )} -

-

- {t( - "The information provided on this website does not constitute investment advice, financial advice, trading advice, or any other sort of advice and you should not treat any of the website's content as such. No party recommends that any cryptoasset should be bought, sold, or held by you via this website. No party ensures the accuracy of information listed on this website or holds any responsibility for any missing or wrong information. You understand that you are using any and all information available here at your own risk." - )} -

-

- {t( - 'Additionally, just as you can access email protocols such as SMTP through multiple email clients, you can potentially access the Vega Protocol through many web or mobile interfaces. You are responsible for doing your own diligence on those interfaces to understand the associated risks and any fees.' - )} -

-
-
+ <> +

+ {t('Disclaimer')} +

+

+ {t( + 'Vega is a decentralised peer-to-peer protocol that can be used to trade derivatives with cryptoassets. The Vega Protocol is an implementation layer (layer one) protocol made of free, public, open-source or source-available software. Use of the Vega Protocol involves various risks, including but not limited to, losses while digital assets are supplied to the Vega Protocol and losses due to the fluctuation of prices of assets.' + )} +

+

+ {t( + 'Before using the Vega Protocol, review the relevant documentation at docs.vega.xyz to make sure that you understand how it works. Conduct your own due diligence and consult your financial advisor before making any investment decisions.' + )} +

+

+ {t( + 'As described in the Vega Protocol core license, the Vega Protocol is provided “as is”, at your own risk, and without warranties of any kind. Although Gobalsky Labs Limited developed much of the initial code for the Vega Protocol, it does not provide or control the Vega Protocol, which is run by third parties deploying it on a bespoke blockchain. Upgrades and modifications to the Vega Protocol are managed in a community-driven way by holders of the VEGA governance token.' + )} +

+

+ {t( + 'No developer or entity involved in creating the Vega Protocol will be liable for any claims or damages whatsoever associated with your use, inability to use, or your interaction with other users of the Vega Protocol, including any direct, indirect, incidental, special, exemplary, punitive or consequential damages, or legal costs, or loss of profits, cryptoassets, tokens or anything else of value.' + )} +

+

+ {t( + 'This website is hosted on a decentralised network, the Interplanetary File System (“IPFS”). The IPFS decentralised web is made up of all the computers (nodes) connected to it. Data is therefore stored on many different computers.' + )} +

+

+ {t( + "The information provided on this website does not constitute investment advice, financial advice, trading advice, or any other sort of advice and you should not treat any of the website's content as such. No party recommends that any cryptoasset should be bought, sold, or held by you via this website. No party ensures the accuracy of information listed on this website or holds any responsibility for any missing or wrong information. You understand that you are using any and all information available here at your own risk." + )} +

+

+ {t( + 'Additionally, just as you can access email protocols such as SMTP through multiple email clients, you can potentially access the Vega Protocol through many web or mobile interfaces. You are responsible for doing your own diligence on those interfaces to understand the associated risks and any fees.' + )} +

+ ); }; diff --git a/apps/trading/client-pages/disclaimer/index.ts b/apps/trading/client-pages/disclaimer/index.ts index c47c92bfc..a5a11f6cd 100644 --- a/apps/trading/client-pages/disclaimer/index.ts +++ b/apps/trading/client-pages/disclaimer/index.ts @@ -1,3 +1 @@ -import { Disclaimer } from './disclaimer'; - -export default Disclaimer; +export { Disclaimer } from './disclaimer'; diff --git a/apps/trading/client-pages/home/home.tsx b/apps/trading/client-pages/home/home.tsx index c4974bc99..76be931cb 100644 --- a/apps/trading/client-pages/home/home.tsx +++ b/apps/trading/client-pages/home/home.tsx @@ -1,9 +1,9 @@ import { useEffect } from 'react'; import { useNavigate } from 'react-router-dom'; import { Loader, Splash } from '@vegaprotocol/ui-toolkit'; -import { Links, Routes } from '../../pages/client-router'; import { useGlobalStore } from '../../stores'; import { useTopTradedMarkets } from '../../lib/hooks/use-top-traded-markets'; +import { Links } from '../../lib/links'; // The home pages only purpose is to redirect to the users last market, // the top traded if they are new, or fall back to the list of markets. @@ -15,17 +15,17 @@ export const Home = () => { useEffect(() => { if (marketId) { - navigate(Links[Routes.MARKET](marketId), { + navigate(Links.MARKET(marketId), { replace: true, }); } else if (data) { const marketDataId = data[0]?.id; if (marketDataId) { - navigate(Links[Routes.MARKET](marketDataId), { + navigate(Links.MARKET(marketDataId), { replace: true, }); } else { - navigate(Links[Routes.MARKETS]()); + navigate(Links.MARKETS()); } } }, [marketId, data, navigate]); diff --git a/apps/trading/client-pages/home/index.ts b/apps/trading/client-pages/home/index.ts index 64a0ba43f..e331f58c5 100644 --- a/apps/trading/client-pages/home/index.ts +++ b/apps/trading/client-pages/home/index.ts @@ -1,3 +1 @@ -import { Home } from './home'; - -export default Home; +export { Home } from './home'; diff --git a/apps/trading/client-pages/liquidity/index.ts b/apps/trading/client-pages/liquidity/index.ts index 2b2228473..15a9df50e 100644 --- a/apps/trading/client-pages/liquidity/index.ts +++ b/apps/trading/client-pages/liquidity/index.ts @@ -1,3 +1 @@ -import { Liquidity } from './liquidity'; - -export default Liquidity; +export { Liquidity } from './liquidity'; diff --git a/apps/trading/client-pages/market/index.ts b/apps/trading/client-pages/market/index.ts index 22af22088..20f2a87f3 100644 --- a/apps/trading/client-pages/market/index.ts +++ b/apps/trading/client-pages/market/index.ts @@ -1,3 +1 @@ -import { MarketPage } from './market'; - -export default MarketPage; +export { MarketPage as default } from './market'; diff --git a/apps/trading/client-pages/market/market.tsx b/apps/trading/client-pages/market/market.tsx index c9014878f..fd29cdec0 100644 --- a/apps/trading/client-pages/market/market.tsx +++ b/apps/trading/client-pages/market/market.tsx @@ -9,7 +9,7 @@ import { useGlobalStore, usePageTitleStore } from '../../stores'; import { TradeGrid } from './trade-grid'; import { TradePanels } from './trade-panels'; import { useNavigate, useParams } from 'react-router-dom'; -import { Links, Routes } from '../../pages/client-router'; +import { Links } from '../../lib/links'; import { ViewType, useSidebar } from '../../components/sidebar'; import { useGetCurrentRouteId } from '../../lib/hooks/use-get-current-route-id'; @@ -96,12 +96,12 @@ export const MarketPage = () => { return ( -

+

{t('This market URL is not available any more.')}

-

+

{t(`Please choose another market from the`)}{' '} - navigate(Links[Routes.MARKETS]())}> + navigate(Links.MARKETS())}> market list

diff --git a/apps/trading/client-pages/markets/index.ts b/apps/trading/client-pages/markets/index.ts index 6141f6f03..64f1859fa 100644 --- a/apps/trading/client-pages/markets/index.ts +++ b/apps/trading/client-pages/markets/index.ts @@ -1,3 +1 @@ -import { MarketsPage } from './markets-page'; - -export default MarketsPage; +export { MarketsPage } from './markets-page'; diff --git a/apps/trading/client-pages/markets/market-table-actions.tsx b/apps/trading/client-pages/markets/market-table-actions.tsx index 01db1d70f..e239ff7f8 100644 --- a/apps/trading/client-pages/markets/market-table-actions.tsx +++ b/apps/trading/client-pages/markets/market-table-actions.tsx @@ -10,7 +10,7 @@ import { import { DApp, EXPLORER_MARKET, useLinks } from '@vegaprotocol/environment'; import { useAssetDetailsDialogStore } from '@vegaprotocol/assets'; import { useNavigate } from 'react-router-dom'; -import { Links, Routes } from '../../pages/client-router'; +import { Links } from '../../lib/links'; export const MarketActionsDropdown = ({ marketId, @@ -52,7 +52,7 @@ export const MarketActionsDropdown = ({ {parentMarketID && ( { - navigate(Links[Routes.MARKET](parentMarketID)); + navigate(Links.MARKET(parentMarketID)); }} > @@ -62,7 +62,7 @@ export const MarketActionsDropdown = ({ {successorMarketID && ( { - navigate(Links[Routes.MARKET](successorMarketID)); + navigate(Links.MARKET(successorMarketID)); }} > diff --git a/apps/trading/client-pages/portfolio/index.ts b/apps/trading/client-pages/portfolio/index.ts index 7ae87c170..aab6c3eff 100644 --- a/apps/trading/client-pages/portfolio/index.ts +++ b/apps/trading/client-pages/portfolio/index.ts @@ -1,3 +1 @@ -import { Portfolio } from './portfolio'; - -export default Portfolio; +export { Portfolio as default } from './portfolio'; diff --git a/apps/trading/client-pages/transfer/transfer.spec.tsx b/apps/trading/client-pages/transfer/transfer.spec.tsx index b756b448e..3315432a7 100644 --- a/apps/trading/client-pages/transfer/transfer.spec.tsx +++ b/apps/trading/client-pages/transfer/transfer.spec.tsx @@ -21,14 +21,6 @@ const renderJsx = (route = '/transfer') => { }; describe('Transfer page', () => { - it('properly rendered', () => { - renderJsx(); - expect( - screen.getByRole('heading', { level: 1, name: 'Transfer' }) - ).toBeInTheDocument(); - expect(screen.getByTestId('assetId')).toBeEmptyDOMElement(); - }); - it('assetId should be passed down', () => { const assetId = 'foo'; const route = '/transfer?assetId=' + assetId; diff --git a/apps/trading/client-pages/transfer/transfer.tsx b/apps/trading/client-pages/transfer/transfer.tsx index 073513fef..62134d565 100644 --- a/apps/trading/client-pages/transfer/transfer.tsx +++ b/apps/trading/client-pages/transfer/transfer.tsx @@ -1,5 +1,4 @@ import { useSearchParams } from 'react-router-dom'; -import { t } from '@vegaprotocol/i18n'; import { TransferContainer } from '@vegaprotocol/accounts'; import { GetStarted } from '../../components/welcome-dialog'; @@ -8,16 +7,9 @@ export const Transfer = () => { const assetId = searchParams.get('assetId') || undefined; return ( -
-
-

- {t('Transfer')} -

-
- - -
-
-
+ <> + + + ); }; diff --git a/apps/trading/client-pages/withdraw/withdraw.spec.tsx b/apps/trading/client-pages/withdraw/withdraw.spec.tsx index d102e0a1c..8253fcdf7 100644 --- a/apps/trading/client-pages/withdraw/withdraw.spec.tsx +++ b/apps/trading/client-pages/withdraw/withdraw.spec.tsx @@ -21,21 +21,10 @@ const renderJsx = (route = '/withdraw') => { }; describe('Withdraw page', () => { - it('should be properly rendered', () => { - renderJsx(); - expect( - screen.getByRole('heading', { level: 1, name: 'Withdraw' }) - ).toBeInTheDocument(); - expect(screen.getByTestId('assetId')).toBeEmptyDOMElement(); - }); - it('assetId should be passed down', () => { const assetId = 'foo'; const route = '/withdraw?assetId=' + assetId; renderJsx(route); - expect( - screen.getByRole('heading', { level: 1, name: 'Withdraw' }) - ).toBeInTheDocument(); expect(screen.getByTestId('assetId')).toHaveTextContent(assetId); }); }); diff --git a/apps/trading/client-pages/withdraw/withdraw.tsx b/apps/trading/client-pages/withdraw/withdraw.tsx index f513077f7..3e0686362 100644 --- a/apps/trading/client-pages/withdraw/withdraw.tsx +++ b/apps/trading/client-pages/withdraw/withdraw.tsx @@ -1,5 +1,4 @@ import { useSearchParams } from 'react-router-dom'; -import { t } from '@vegaprotocol/i18n'; import { GetStarted } from '../../components/welcome-dialog'; import { WithdrawContainer } from '../../components/withdraw-container'; @@ -7,16 +6,9 @@ export const Withdraw = () => { const [searchParams] = useSearchParams(); const assetId = searchParams.get('assetId') || undefined; return ( -
-
-

- {t('Withdraw')} -

-
- - -
-
-
+ <> + + + ); }; diff --git a/apps/trading/components/layouts/layout-centered.tsx b/apps/trading/components/layouts/layout-centered.tsx new file mode 100644 index 000000000..7ea9afffd --- /dev/null +++ b/apps/trading/components/layouts/layout-centered.tsx @@ -0,0 +1,9 @@ +import { Outlet } from 'react-router-dom'; + +export const LayoutCentered = () => { + return ( +
+ +
+ ); +}; diff --git a/apps/trading/components/layouts/layout-with-sidebar.tsx b/apps/trading/components/layouts/layout-with-sidebar.tsx index 0e777b993..a3391f42d 100644 --- a/apps/trading/components/layouts/layout-with-sidebar.tsx +++ b/apps/trading/components/layouts/layout-with-sidebar.tsx @@ -1,7 +1,6 @@ import { Outlet, Routes, Route } from 'react-router-dom'; import { Sidebar, SidebarContent, useSidebar } from '../sidebar'; import classNames from 'classnames'; -import { Routes as AppRoutes } from '../../pages/client-router'; import { MarketHeader } from '../market-header'; import { LiquidityHeader } from '../liquidity-header'; import { useGetCurrentRouteId } from '../../lib/hooks/use-get-current-route-id'; @@ -23,8 +22,8 @@ export const LayoutWithSidebar = () => {
- } /> - } /> + } /> + } />
- - - {t('Supplied stake')} - - {market?.suppliedStake - ? addDecimalsFormatNumber( - new BigNumber(market?.suppliedStake).toString(), - assetDecimals - ) - : '-'} - - - - {t('Target stake')} - - {market?.targetStake - ? addDecimalsFormatNumber( - new BigNumber(market?.targetStake).toString(), - assetDecimals - ) - : '-'} - - - -
-
- - {t('View liquidity provision table')} - - {DocsLinks && ( - - {t('Learn about providing liquidity')} - - )} +
+ + + {t('Supplied stake')} + + {market?.suppliedStake + ? addDecimalsFormatNumber( + new BigNumber(market?.suppliedStake).toString(), + assetDecimals + ) + : '-'} + + + + {t('Target stake')} + + {market?.targetStake + ? addDecimalsFormatNumber( + new BigNumber(market?.targetStake).toString(), + assetDecimals + ) + : '-'} + + +
{showMessage && ( -

+

{t( 'The market has sufficient liquidity but there are not enough priced limit orders in the order book, which are required to deploy liquidity commitment pegged orders.' )}

)} +
+ + {t('View liquidity provision table')} + +
+ {DocsLinks && ( +
+ + {t('Learn about providing liquidity')} + +
+ )} ) : ( '-' diff --git a/apps/trading/components/market-selector/product-selector.tsx b/apps/trading/components/market-selector/product-selector.tsx index 15077c7f6..b80361d37 100644 --- a/apps/trading/components/market-selector/product-selector.tsx +++ b/apps/trading/components/market-selector/product-selector.tsx @@ -1,8 +1,8 @@ import classNames from 'classnames'; import { Link } from 'react-router-dom'; -import { Routes } from '../../pages/client-router'; import { t } from '@vegaprotocol/i18n'; import { VegaIcon, VegaIconNames } from '@vegaprotocol/ui-toolkit'; +import { Links } from '../../lib/links'; // Make sure these match the available __typename properties on product export const Product = { @@ -55,7 +55,7 @@ export const ProductSelector = ({ ); })} diff --git a/apps/trading/components/navbar/navbar.tsx b/apps/trading/components/navbar/navbar.tsx index 4cc0f1281..e2b8b05cc 100644 --- a/apps/trading/components/navbar/navbar.tsx +++ b/apps/trading/components/navbar/navbar.tsx @@ -15,7 +15,7 @@ import * as N from '@radix-ui/react-navigation-menu'; import * as D from '@radix-ui/react-dialog'; import { NavLink } from 'react-router-dom'; -import { Links, Routes } from '../../pages/client-router'; +import { Links } from '../../lib/links'; import classNames from 'classnames'; import { VegaWalletMenu } from '../vega-wallet'; import { useVegaWallet, useVegaWalletDialogStore } from '@vegaprotocol/wallet'; @@ -142,9 +142,7 @@ const NavbarMenu = ({ onClick }: { onClick: () => void }) => { // If we have a stored marketId make Trade link go to that market // otherwise always go to /markets/all - const tradingPath = marketId - ? Links[Routes.MARKET](marketId) - : Links[Routes.MARKET](''); + const tradingPath = marketId ? Links.MARKET(marketId) : Links.MARKETS(); return (
@@ -171,7 +169,7 @@ const NavbarMenu = ({ onClick }: { onClick: () => void }) => { - + {t('Markets')} @@ -181,7 +179,7 @@ const NavbarMenu = ({ onClick }: { onClick: () => void }) => { - + {t('Portfolio')} @@ -209,7 +207,7 @@ const NavbarMenu = ({ onClick }: { onClick: () => void }) => { )} - + {t('Disclaimer')} diff --git a/apps/trading/components/sidebar/sidebar.spec.tsx b/apps/trading/components/sidebar/sidebar.spec.tsx index 5a78360c3..e55d9fe4f 100644 --- a/apps/trading/components/sidebar/sidebar.spec.tsx +++ b/apps/trading/components/sidebar/sidebar.spec.tsx @@ -11,7 +11,7 @@ import { MemoryRouter, Route, Routes } from 'react-router-dom'; import { VegaIconNames } from '@vegaprotocol/ui-toolkit'; import type { VegaWalletContextShape } from '@vegaprotocol/wallet'; import { VegaWalletContext } from '@vegaprotocol/wallet'; -import { Routes as AppRoutes } from '../../pages/client-router'; +import { Routes as AppRoutes } from '../../lib/links'; jest.mock('../node-health', () => ({ NodeHealthContainer: () => , diff --git a/apps/trading/components/sidebar/sidebar.tsx b/apps/trading/components/sidebar/sidebar.tsx index 6eb66a593..b09a5517d 100644 --- a/apps/trading/components/sidebar/sidebar.tsx +++ b/apps/trading/components/sidebar/sidebar.tsx @@ -13,10 +13,9 @@ import { NodeHealthContainer } from '../node-health'; import { Settings } from '../settings'; import { Tooltip } from '../../components/tooltip'; import { WithdrawContainer } from '../withdraw-container'; -import { Routes as AppRoutes } from '../../pages/client-router'; +import { GetStarted } from '../welcome-dialog'; import { useVegaWallet, useViewAsDialog } from '@vegaprotocol/wallet'; import { useGetCurrentRouteId } from '../../lib/hooks/use-get-current-route-id'; -import { GetStarted } from '../welcome-dialog'; export enum ViewType { Order = 'Order', @@ -51,6 +50,28 @@ type SidebarView = type: ViewType.Settings; }; +const MarketSidebarButtons = () => { + const currentRouteId = useGetCurrentRouteId(); + + return ( + <> + + + + + ); +}; + export const Sidebar = () => { const currentRouteId = useGetCurrentRouteId(); const navClasses = 'flex lg:flex-col items-center gap-2 lg:gap-4 p-1'; @@ -81,34 +102,19 @@ export const Sidebar = () => { {/* buttons for specific routes */} + } /> - - - - - } + path="liquidity/:marketId" + element={} /> diff --git a/apps/trading/components/welcome-dialog/get-started.tsx b/apps/trading/components/welcome-dialog/get-started.tsx index faa825cf2..14b0cfdbb 100644 --- a/apps/trading/components/welcome-dialog/get-started.tsx +++ b/apps/trading/components/welcome-dialog/get-started.tsx @@ -15,7 +15,7 @@ import { useGetOnboardingStep, useOnboardingStore, } from './use-get-onboarding-step'; -import { Links, Routes } from '../../pages/client-router'; +import { Links, Routes } from '../../lib/links'; import { useGlobalStore } from '../../stores'; import { useSidebar, ViewType } from '../sidebar'; @@ -48,17 +48,18 @@ const GetStartedButton = ({ step }: { step: OnboardingStep }) => { return ( setDialogOpen(false)} > {t('Deposit')} ); } else if (step >= OnboardingStep.ONBOARDING_ORDER_STEP) { + const link = marketId ? Links.MARKET(marketId) : Links.HOME(); return ( { setViews({ type: ViewType.Order }, Routes.MARKET); dismiss(); diff --git a/apps/trading/components/welcome-dialog/risk-message.tsx b/apps/trading/components/welcome-dialog/risk-message.tsx index 8168e405f..29ed85ead 100644 --- a/apps/trading/components/welcome-dialog/risk-message.tsx +++ b/apps/trading/components/welcome-dialog/risk-message.tsx @@ -1,12 +1,12 @@ import { t } from '@vegaprotocol/i18n'; import { VegaIcon, VegaIconNames } from '@vegaprotocol/ui-toolkit'; -import { Routes } from '../../pages/client-router'; import { Link } from 'react-router-dom'; +import { Links } from '../../lib/links'; export const RiskMessage = () => { return ( <> -
+
  • {t( @@ -27,7 +27,7 @@ export const RiskMessage = () => { {t( 'By using the Vega Console, you acknowledge that you have read and understood the' )}{' '} - + {t('Vega Console Disclaimer')} diff --git a/apps/trading/components/welcome-dialog/welcome-dialog-content.tsx b/apps/trading/components/welcome-dialog/welcome-dialog-content.tsx index f15471cff..b47147812 100644 --- a/apps/trading/components/welcome-dialog/welcome-dialog-content.tsx +++ b/apps/trading/components/welcome-dialog/welcome-dialog-content.tsx @@ -1,7 +1,7 @@ import { t } from '@vegaprotocol/i18n'; import { GetStarted } from './get-started'; import { TradingAnchorButton } from '@vegaprotocol/ui-toolkit'; -import { Links, Routes } from '../../pages/client-router'; +import { Links } from '../../lib/links'; import { Networks, useEnvironment } from '@vegaprotocol/environment'; import type { ReactNode } from 'react'; import { useTopTradedMarkets } from '../../lib/hooks/use-top-traded-markets'; @@ -15,9 +15,7 @@ export const WelcomeDialogContent = () => { const { data } = useTopTradedMarkets(); const marketId = data && data[0]?.id; - const link = marketId - ? Links[Routes.MARKET](marketId) - : Links[Routes.MARKETS](); + const link = marketId ? Links.MARKET(marketId) : Links.MARKETS(); const lead = VEGA_ENV === Networks.MAINNET diff --git a/apps/trading/lib/hooks/use-get-current-route-id.ts b/apps/trading/lib/hooks/use-get-current-route-id.ts index d99c757c7..5adb812bd 100644 --- a/apps/trading/lib/hooks/use-get-current-route-id.ts +++ b/apps/trading/lib/hooks/use-get-current-route-id.ts @@ -3,12 +3,10 @@ import { matchRoutes, useLocation } from 'react-router-dom'; export const useGetCurrentRouteId = () => { const location = useLocation(); - const currentRoute = matchRoutes(routerConfig, location); - const lastRoute = currentRoute?.pop(); + const matches = matchRoutes(routerConfig, location); + const lastRoute = matches ? matches[matches.length - 1] : undefined; if (lastRoute) { - const { - route: { id }, - } = lastRoute; + const id = lastRoute.route.id; return id || ''; } return ''; diff --git a/apps/trading/lib/hooks/use-market-click-handler.ts b/apps/trading/lib/hooks/use-market-click-handler.ts index 2fef70d08..4fd3c883a 100644 --- a/apps/trading/lib/hooks/use-market-click-handler.ts +++ b/apps/trading/lib/hooks/use-market-click-handler.ts @@ -1,12 +1,12 @@ import { useNavigate } from 'react-router-dom'; import { useCallback } from 'react'; -import { Links, Routes } from '../../pages/client-router'; +import { Links } from '../../lib/links'; export const useMarketClickHandler = (replace = false) => { const navigate = useNavigate(); return (selectedId: string, metaKey?: boolean) => { - const link = Links[Routes.MARKET](selectedId); + const link = Links.MARKET(selectedId); if (metaKey) { window.open(`/#${link}`, '_blank'); } else { diff --git a/apps/trading/lib/links.ts b/apps/trading/lib/links.ts new file mode 100644 index 000000000..283347b90 --- /dev/null +++ b/apps/trading/lib/links.ts @@ -0,0 +1,35 @@ +import trimEnd from 'lodash/trimEnd'; + +// Make all route paths 'absolute' for easier +// href creation +export const Routes = { + HOME: '/', + MARKETS: '/markets/all', + MARKET: '/markets/:marketId', + LIQUIDITY: '/liquidity/:marketId', + PORTFOLIO: '/portfolio', + DISCLAIMER: '/disclaimer', + ASSETS: '/portfolio/assets', + DEPOSIT: '/portfolio/assets/deposit', + WITHDRAW: '/portfolio/assets/withdraw', + TRANSFER: '/portfolio/assets/transfer', +} as const; + +type ConsoleLinks = { + [R in keyof typeof Routes]: (...args: string[]) => string; +}; + +export const Links: ConsoleLinks = { + HOME: () => Routes.HOME, + MARKET: (marketId: string) => + trimEnd(Routes.MARKET.replace(':marketId', marketId)), + MARKETS: () => Routes.MARKETS, + PORTFOLIO: () => Routes.PORTFOLIO, + LIQUIDITY: (marketId: string) => + trimEnd(Routes.LIQUIDITY.replace(':marketId', marketId)), + DISCLAIMER: () => Routes.DISCLAIMER, + ASSETS: () => Routes.ASSETS, + DEPOSIT: () => Routes.DEPOSIT, + WITHDRAW: () => Routes.WITHDRAW, + TRANSFER: () => Routes.TRANSFER, +}; diff --git a/apps/trading/pages/_app.page.tsx b/apps/trading/pages/_app.page.tsx index 188c9f889..eca47a271 100644 --- a/apps/trading/pages/_app.page.tsx +++ b/apps/trading/pages/_app.page.tsx @@ -48,8 +48,8 @@ import { } from '@vegaprotocol/proposals'; import { ViewingBanner } from '../components/viewing-banner'; import { NavHeader } from '../components/navbar/nav-header'; -import { Routes as AppRoutes } from './client-router'; import { Telemetry } from '../components/telemetry'; +import { Routes as AppRoutes } from '../lib/links'; const DEFAULT_TITLE = t('Welcome to Vega trading!'); diff --git a/apps/trading/pages/client-router.tsx b/apps/trading/pages/client-router.tsx index 7932db72a..880ef8732 100644 --- a/apps/trading/pages/client-router.tsx +++ b/apps/trading/pages/client-router.tsx @@ -1,127 +1,106 @@ -import { Suspense } from 'react'; import type { RouteObject } from 'react-router-dom'; -import { Outlet, useRoutes } from 'react-router-dom'; -import dynamic from 'next/dynamic'; +import { Navigate, Outlet, useRoutes } from 'react-router-dom'; +import { lazy, Suspense } from 'react'; import { t } from '@vegaprotocol/i18n'; import { Loader, Splash } from '@vegaprotocol/ui-toolkit'; -import trimEnd from 'lodash/trimEnd'; import { LayoutWithSidebar } from '../components/layouts'; +import { LayoutCentered } from '../components/layouts/layout-centered'; +import { Home } from '../client-pages/home'; +import { Liquidity } from '../client-pages/liquidity'; +import { MarketsPage } from '../client-pages/markets'; +import { Disclaimer } from '../client-pages/disclaimer'; +import { Assets } from '../client-pages/assets'; import { Deposit } from '../client-pages/deposit'; import { Withdraw } from '../client-pages/withdraw'; import { Transfer } from '../client-pages/transfer'; +import { Routes } from '../lib/links'; -const LazyHome = dynamic(() => import('../client-pages/home'), { - ssr: false, -}); +// These must remain dynamically imported as pennant cannot be compiled by nextjs due to ESM +// Using dynamic imports is a workaround for this until pennant is published as ESM +const MarketPage = lazy(() => import('../client-pages/market')); +const Portfolio = lazy(() => import('../client-pages/portfolio')); -const LazyLiquidity = dynamic(() => import('../client-pages/liquidity'), { - ssr: false, -}); - -const LazyMarkets = dynamic(() => import('../client-pages/markets'), { - ssr: false, -}); - -const LazyMarket = dynamic(() => import('../client-pages/market'), { - ssr: false, -}); - -const LazyPortfolio = dynamic(() => import('../client-pages/portfolio'), { - ssr: false, -}); - -const LazyDisclaimer = dynamic(() => import('../client-pages/disclaimer'), { - ssr: false, -}); - -export enum Routes { - HOME = '/', - MARKET = '/markets/:marketId', - MARKETS = '/markets/all', - PORTFOLIO = '/portfolio', - LIQUIDITY = '/liquidity/:marketId', - DISCLAIMER = '/disclaimer', - DEPOSIT = '/deposit', - WITHDRAW = '/withdraw', - TRANSFER = '/transfer', -} - -type ConsoleLinks = { [r in Routes]: (...args: string[]) => string }; - -export const Links: ConsoleLinks = { - [Routes.HOME]: () => Routes.HOME, - [Routes.MARKET]: (marketId: string) => - trimEnd(Routes.MARKET.replace(':marketId', marketId)), - [Routes.MARKETS]: () => Routes.MARKETS, - [Routes.PORTFOLIO]: () => Routes.PORTFOLIO, - [Routes.LIQUIDITY]: (marketId: string) => - trimEnd(Routes.LIQUIDITY.replace(':marketId', marketId)), - [Routes.DISCLAIMER]: () => Routes.DISCLAIMER, - [Routes.DEPOSIT]: () => Routes.DEPOSIT, - [Routes.WITHDRAW]: () => Routes.WITHDRAW, - [Routes.TRANSFER]: () => Routes.TRANSFER, -}; +const NotFound = () => ( + +

    {t('Page not found')}

    +
    +); export const routerConfig: RouteObject[] = [ + // Pages that dont use the LayoutWithSidebar must come first + // to ensure they are matched before the catch all route '/*' + { + path: 'disclaimer', + element: , + id: Routes.DISCLAIMER, + children: [{ index: true, element: }], + }, + + // All other pages will use the sidebar { path: '/*', element: , children: [ - // all pages that require the Layout component (Sidebar) { index: true, - element: , + element: , id: Routes.HOME, }, { path: 'markets', element: , children: [ + { + index: true, + element: , + }, { path: 'all', - element: , + element: , id: Routes.MARKETS, }, { path: ':marketId', - element: , + element: , id: Routes.MARKET, }, ], }, { path: 'portfolio', - element: , - id: Routes.PORTFOLIO, - }, - { - path: 'liquidity', element: , children: [ { - path: ':marketId', - element: , - id: Routes.LIQUIDITY, + index: true, + element: , + id: Routes.PORTFOLIO, + }, + { + path: 'assets', + element: , + id: Routes.ASSETS, + children: [ + { index: true, element: }, + { path: 'deposit', element: , id: Routes.DEPOSIT }, + { path: 'withdraw', element: , id: Routes.WITHDRAW }, + { path: 'transfer', element: , id: Routes.TRANSFER }, + ], }, ], }, + { + path: 'liquidity/:marketId', + element: , + id: Routes.LIQUIDITY, + }, + + // NotFound page is here so its caught within parent '/*' route + { + path: '*', + element: , + }, ], }, - { - path: Routes.DISCLAIMER, - element: , - }, - { path: Routes.DEPOSIT, element: }, - { path: Routes.WITHDRAW, element: }, - { path: Routes.TRANSFER, element: }, - { - path: '*', - element: ( - -

    {t('Not found')}

    -
    - ), - }, ]; export const ClientRouter = () => { @@ -129,9 +108,9 @@ export const ClientRouter = () => { return ( + -
+ } > {routes} diff --git a/apps/trading/pages/toasts-manager.tsx b/apps/trading/pages/toasts-manager.tsx index 4d06ca160..7620f6d70 100644 --- a/apps/trading/pages/toasts-manager.tsx +++ b/apps/trading/pages/toasts-manager.tsx @@ -3,8 +3,8 @@ import { useUpdateNetworkParametersToasts } from '@vegaprotocol/proposals'; import { useVegaTransactionToasts } from '@vegaprotocol/web3'; import { useEthereumTransactionToasts } from '@vegaprotocol/web3'; import { useEthereumWithdrawApprovalsToasts } from '@vegaprotocol/web3'; -import { Routes } from './client-router'; import { useReadyToWithdrawalToasts } from '@vegaprotocol/withdraws'; +import { Links } from '../lib/links'; export const ToastsManager = () => { useUpdateNetworkParametersToasts(); @@ -12,7 +12,7 @@ export const ToastsManager = () => { useEthereumTransactionToasts(); useEthereumWithdrawApprovalsToasts(); useReadyToWithdrawalToasts({ - withdrawalsLink: `${Routes.PORTFOLIO}`, + withdrawalsLink: Links.PORTFOLIO(), }); const toasts = useToasts((store) => store.toasts); diff --git a/libs/ui-toolkit/src/components/link/link.tsx b/libs/ui-toolkit/src/components/link/link.tsx index 524ba3fd6..172907214 100644 --- a/libs/ui-toolkit/src/components/link/link.tsx +++ b/libs/ui-toolkit/src/components/link/link.tsx @@ -11,7 +11,7 @@ type LinkProps = AnchorHTMLAttributes & { */ export const Link = ({ className, children, ...props }: LinkProps) => { const anchorClassName = classNames(className, { - underline: typeof children === 'string', + 'underline underline-offset-4': typeof children === 'string', 'cursor-pointer': props['aria-disabled'] !== true, 'opacity-50 pointer-events-none': props['aria-disabled'] === true, });