From 780e85913fdbf4f6d85ae3056bdcf901d15422d9 Mon Sep 17 00:00:00 2001 From: michalsmiarowski Date: Tue, 25 Jul 2023 16:34:51 +0200 Subject: [PATCH] Use parentPath property to fix the issue I've manage to resolve the issue using `resolvePath` and `matchPath` functions instead of `useMatch` and `useResolvedPath` hooks. For that I had to introduce a new property - `parentPath` - that is passed to `SubNavigationPills` component and will be used as a `pathnaemBase` for the `resolvePath` function. If more than one pill is active then the one with the longest `pathnameBase` from the `matchPath` function will be active. This will happen when there are two paths with asterisk, for example: `tBTC/*`, `tBTC/how-it-work/*`. For the path `tBTC/how-it-work/overview` we want only the second one to be active so we are picking the one with the longest `pathnameBase`. In the first case the pathnameBase is `tBTC` and in the second one it's `tBTC/how-it-works`. --- src/App.tsx | 22 ++++- src/components/SubNavigationPills/index.tsx | 93 ++++++++++++++------- src/pages/Feedback/index.tsx | 8 +- src/pages/PageLayout.tsx | 7 +- src/pages/Staking/index.tsx | 8 +- src/pages/Upgrade/index.tsx | 8 +- src/pages/tBTC/index.tsx | 8 +- src/types/page.ts | 9 +- 8 files changed, 121 insertions(+), 42 deletions(-) diff --git a/src/App.tsx b/src/App.tsx index 7181b77e0..f703524e7 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -197,15 +197,22 @@ const Routing = () => { }> } /> - {pages.map(renderPageComponent)} + {pages.map((page) => renderPageComponent(page))} } /> ) } -const renderPageComponent = (PageComponent: PageComponent) => { +const renderPageComponent = ( + PageComponent: PageComponent, + /** @see PageComponent type */ + parentPathBase: string = "" +) => { if (!PageComponent.route.isPageEnabled) return null + const updatedParentPathBase = PageComponent.route.path + ? `${parentPathBase}/${PageComponent.route.path}` + : parentPathBase return ( @@ -217,9 +224,16 @@ const renderPageComponent = (PageComponent: PageComponent) => { )} } + element={ + + } > - {PageComponent.route.pages?.map(renderPageComponent)} + {PageComponent.route.pages?.map((page) => + renderPageComponent(page, updatedParentPathBase) + )} ) diff --git a/src/components/SubNavigationPills/index.tsx b/src/components/SubNavigationPills/index.tsx index 047e6b81f..43210d007 100644 --- a/src/components/SubNavigationPills/index.tsx +++ b/src/components/SubNavigationPills/index.tsx @@ -7,27 +7,33 @@ import { Stack, useColorModeValue, } from "@threshold-network/components" -import { - matchPath, - resolvePath, - useLocation, - useMatch, - useResolvedPath, -} from "react-router-dom" +import { matchPath, resolvePath } from "react-router-dom" import { RouteProps } from "../../types" import Link from "../Link" interface SubNavigationPillsProps { links: RouteProps[] + /** @see PageComponent type */ + parentPathBase: string } +interface PathMatchResult { + index: number + path: string + pathOverride?: string + resolvedPath: string + match: any +} interface NavPill extends RouteProps { - resolvedPaths: string[] + isActive?: boolean } -const SubNavigationPills: FC = ({ links }) => { +const SubNavigationPills: FC = ({ + links, + parentPathBase, +}) => { const linksWithTitle = links.filter((link) => !!link.title) - const resolvedPaths = getResolvedPathsFromPills(linksWithTitle) + const activePillIndex = getActivePillIndex(linksWithTitle, parentPathBase) const wrapperBorderColor = useColorModeValue("gray.100", "gray.700") return ( @@ -49,27 +55,17 @@ const SubNavigationPills: FC = ({ links }) => { height="28px" as="ul" > - {linksWithTitle.map((linkWithTitle) => - renderPill(linkWithTitle, resolvedPaths) - )} + {linksWithTitle.map((linkWithTitle, index) => { + const isActive = index === activePillIndex + return renderPill(linkWithTitle, isActive) + })} ) } -const NavPill: FC = ({ path, pathOverride, title, resolvedPaths }) => { - let isActive = false - const resolved = useResolvedPath(pathOverride || path) - const match = useMatch({ path: resolved.pathname, end: true }) - if (match) { - if (match.params["*"]) { - const lastPieceOfPath = match.pathname.replace(match.pathnameBase, "") - if (!resolvedPaths.includes(lastPieceOfPath)) isActive = true - } else { - isActive = true - } - } +const NavPill: FC = ({ path, title, isActive = false }) => { const activeColor = useColorModeValue("brand.500", "gray.100") const underlineColor = useColorModeValue("brand.500", "white") @@ -103,18 +99,51 @@ const NavPill: FC = ({ path, pathOverride, title, resolvedPaths }) => { ) } -const renderPill = (pill: RouteProps, resolvedPaths: string[]) => ( - +const renderPill = (pill: RouteProps, isActive = false) => ( + ) -const getResolvedPathsFromPills = (pills: RouteProps[]) => { - const resolvedPaths: string[] = [] +const getPathMatches = (pills: RouteProps[], parentPathBase: string = "") => { + const pathMatches: PathMatchResult[] = [] for (let i = 0; i < pills.length; i++) { const { path, pathOverride } = pills[i] - const resolved = resolvePath(pathOverride || path) - resolvedPaths.push(resolved.pathname) + const location = window.location.pathname + const resolved = resolvePath( + pathOverride + ? `${parentPathBase}/${pathOverride}` + : `${parentPathBase}/${path}` + ) + const match = matchPath({ path: resolved.pathname, end: true }, location) + pathMatches.push({ + index: i, + path, + pathOverride, + resolvedPath: resolved.pathname, + match, + }) } - return resolvedPaths + return pathMatches +} + +const getActivePillIndex = (pills: RouteProps[], parentPathBase: string) => { + const pathMatches = getPathMatches(pills, parentPathBase) + const matchedPaths = pathMatches.filter((_) => { + return !!_.match + }) + + if (matchedPaths.length === 0) return undefined + if (matchedPaths.length === 1) return matchedPaths[0].index + + const matchedElementWithLongestPathnameBase = matchedPaths.reduce( + (maxElement, currentElement) => { + return currentElement.match.pathnameBase.length > + maxElement.match.pathnameBase.length + ? currentElement + : maxElement + } + ) + + return matchedElementWithLongestPathnameBase.index } export default SubNavigationPills diff --git a/src/pages/Feedback/index.tsx b/src/pages/Feedback/index.tsx index 9e1f36fbf..4bacc3967 100644 --- a/src/pages/Feedback/index.tsx +++ b/src/pages/Feedback/index.tsx @@ -7,7 +7,13 @@ import Settings from "./Settings" import { featureFlags } from "../../constants" const FeedbackPage: PageComponent = (props) => { - return + return ( + + ) } FeedbackPage.route = { diff --git a/src/pages/PageLayout.tsx b/src/pages/PageLayout.tsx index 9d87ba2b9..0bbbb6496 100644 --- a/src/pages/PageLayout.tsx +++ b/src/pages/PageLayout.tsx @@ -8,12 +8,15 @@ import useDocumentTitle from "../hooks/useDocumentTitle" export interface PageLayoutProps extends ContainerProps { pages?: PageComponent[] title?: string + /** @see PageComponent type */ + parentPathBase: string } const PageLayout: FC = ({ pages, title, children, + parentPathBase, ...restProps }) => { useDocumentTitle(`Threshold - ${title}`) @@ -23,7 +26,9 @@ const PageLayout: FC = ({ return ( <> - {links.length > 0 && } + {links.length > 0 && ( + + )} { } = useAppSelector((state) => state.account) return ( - + { pages={props.pages} title={props.title} maxW={{ base: "2xl", lg: "4xl", xl: "6xl" }} + parentPathBase={props.parentPathBase} /> ) } diff --git a/src/pages/Upgrade/index.tsx b/src/pages/Upgrade/index.tsx index 1f541023b..753ddf891 100644 --- a/src/pages/Upgrade/index.tsx +++ b/src/pages/Upgrade/index.tsx @@ -4,7 +4,13 @@ import PageLayout from "../PageLayout" import { PageComponent } from "../../types" const UpgradePage: PageComponent = (props) => { - return + return ( + + ) } UpgradePage.route = { diff --git a/src/pages/tBTC/index.tsx b/src/pages/tBTC/index.tsx index 84c04d242..8224a3c44 100644 --- a/src/pages/tBTC/index.tsx +++ b/src/pages/tBTC/index.tsx @@ -6,7 +6,13 @@ import { featureFlags } from "../../constants" import { ExplorerPage } from "./Explorer" const MainTBTCPage: PageComponent = (props) => { - return + return ( + + ) } MainTBTCPage.route = { diff --git a/src/types/page.ts b/src/types/page.ts index 00cbc8458..764838f1c 100644 --- a/src/types/page.ts +++ b/src/types/page.ts @@ -10,4 +10,11 @@ export type RouteProps = { isPageEnabled: boolean } -export type PageComponent = FC & { route: RouteProps } +export type PageComponent = FC< + RouteProps & { + // Paths combined from all Route parents of the current Route + parentPathBase: string + } +> & { + route: RouteProps +}