diff --git a/.gitignore b/.gitignore index 763a38d8..ee49cd3f 100644 --- a/.gitignore +++ b/.gitignore @@ -23,3 +23,4 @@ npm-debug.log* yarn-debug.log* yarn-error.log* +.idea/ diff --git a/src/components/Breadcrumbs/FFBreadcrumb.tsx b/src/components/Breadcrumbs/FFBreadcrumb.tsx index 9bbe2331..8759d6d1 100644 --- a/src/components/Breadcrumbs/FFBreadcrumb.tsx +++ b/src/components/Breadcrumbs/FFBreadcrumb.tsx @@ -1,5 +1,5 @@ import { Breadcrumbs, Link, Typography } from '@mui/material'; -import { useNavigate } from 'react-router-dom'; +import { Link as RouterLink } from 'react-router-dom'; import { IFFBreadcrumb } from '../../interfaces'; interface Props { @@ -7,31 +7,55 @@ interface Props { } export const FFBreadcrumb: React.FC = ({ breadcrumbs }) => { - const navigate = useNavigate(); - return ( - {breadcrumbs.map((b, idx) => ( - navigate(b.link ?? '') : undefined} - > - { + const isLast = idx === breadcrumbs.length - 1; + const link = b.link; + if (link && !isLast) { + return ( + + + {b.content} + + + ); + } + + return ( + - {b.content} - - - ))} + + {b.content} + + + ); + })} ); }; diff --git a/src/components/Navigation/ActivityNav.tsx b/src/components/Navigation/ActivityNav.tsx index 8ad05a38..21b8e437 100644 --- a/src/components/Navigation/ActivityNav.tsx +++ b/src/components/Navigation/ActivityNav.tsx @@ -17,14 +17,13 @@ import { InsertChartOutlined } from '@mui/icons-material'; import React, { useContext } from 'react'; import { useTranslation } from 'react-i18next'; -import { useLocation, useNavigate } from 'react-router-dom'; +import { useLocation } from 'react-router-dom'; import { ApplicationContext } from '../../contexts/ApplicationContext'; import { FF_NAV_PATHS, INavItem } from '../../interfaces'; import { NavSection } from './NavSection'; export const ActivityNav = () => { const { t } = useTranslation(); - const navigate = useNavigate(); const { selectedNamespace } = useContext(ApplicationContext); const { pathname } = useLocation(); @@ -36,22 +35,22 @@ export const ActivityNav = () => { const navItems: INavItem[] = [ { name: t('timeline'), - action: () => navigate(timelinePath), + to: timelinePath, itemIsActive: pathname === timelinePath, }, { name: t('events'), - action: () => navigate(eventsPath), + to: eventsPath, itemIsActive: pathname === eventsPath, }, { name: t('transactions'), - action: () => navigate(txPath), + to: txPath, itemIsActive: pathname.startsWith(txPath), }, { name: t('operations'), - action: () => navigate(opsPath), + to: opsPath, itemIsActive: pathname === opsPath, }, ]; diff --git a/src/components/Navigation/BlockchainNav.tsx b/src/components/Navigation/BlockchainNav.tsx index 330b17a2..2ddaf248 100644 --- a/src/components/Navigation/BlockchainNav.tsx +++ b/src/components/Navigation/BlockchainNav.tsx @@ -17,14 +17,13 @@ import ViewInArIcon from '@mui/icons-material/ViewInAr'; import React, { useContext } from 'react'; import { useTranslation } from 'react-i18next'; -import { useLocation, useNavigate } from 'react-router-dom'; +import { useLocation } from 'react-router-dom'; import { ApplicationContext } from '../../contexts/ApplicationContext'; import { FF_NAV_PATHS, INavItem } from '../../interfaces'; import { NavSection } from './NavSection'; export const BlockchainNav = () => { const { t } = useTranslation(); - const navigate = useNavigate(); const { selectedNamespace } = useContext(ApplicationContext); const { pathname } = useLocation(); @@ -38,27 +37,27 @@ export const BlockchainNav = () => { const navItems: INavItem[] = [ { name: t('dashboard'), - action: () => navigate(blockchainPath), + to: blockchainPath, itemIsActive: pathname === blockchainPath, }, { name: t('events'), - action: () => navigate(eventsPath), + to: eventsPath, itemIsActive: pathname === eventsPath, }, { name: t('apis'), - action: () => navigate(apiPath), + to: apiPath, itemIsActive: pathname === apiPath, }, { name: t('interfaces'), - action: () => navigate(interfacesPath), + to: interfacesPath, itemIsActive: pathname === interfacesPath, }, { name: t('listeners'), - action: () => navigate(listenersPath), + to: listenersPath, itemIsActive: pathname === listenersPath, }, ]; diff --git a/src/components/Navigation/MyNodeNav.tsx b/src/components/Navigation/MyNodeNav.tsx index 9e9d0070..45f2a2d4 100644 --- a/src/components/Navigation/MyNodeNav.tsx +++ b/src/components/Navigation/MyNodeNav.tsx @@ -17,14 +17,13 @@ import HexagonIcon from '@mui/icons-material/Hexagon'; import React, { useContext } from 'react'; import { useTranslation } from 'react-i18next'; -import { useLocation, useNavigate } from 'react-router-dom'; +import { useLocation } from 'react-router-dom'; import { ApplicationContext } from '../../contexts/ApplicationContext'; import { FF_NAV_PATHS, INavItem } from '../../interfaces'; import { NavSection } from './NavSection'; export const MyNodeNav = () => { const { t } = useTranslation(); - const navigate = useNavigate(); const { selectedNamespace } = useContext(ApplicationContext); const { pathname } = useLocation(); @@ -37,17 +36,17 @@ export const MyNodeNav = () => { const navItems: INavItem[] = [ { name: t('dashboard'), - action: () => navigate(myNodePath), + to: myNodePath, itemIsActive: pathname === myNodePath, }, { name: t('subscriptions'), - action: () => navigate(myNodeSubscriptionsPath), + to: myNodeSubscriptionsPath, itemIsActive: pathname === myNodeSubscriptionsPath, }, { name: t('websockets'), - action: () => navigate(myNodeWebsocketsPath), + to: myNodeWebsocketsPath, itemIsActive: pathname === myNodeWebsocketsPath, }, ]; diff --git a/src/components/Navigation/NavItem.tsx b/src/components/Navigation/NavItem.tsx index aa045174..6f5c6358 100644 --- a/src/components/Navigation/NavItem.tsx +++ b/src/components/Navigation/NavItem.tsx @@ -21,16 +21,18 @@ import { ListItemText, Typography, } from '@mui/material'; +import { Link as RouterLink } from 'react-router-dom'; interface Props { name: string; - action: () => void; - icon?: JSX.Element; itemIsActive: boolean; + icon?: JSX.Element; rightIcon?: JSX.Element; isRoot?: boolean; + to?: string; // internal route (React Router) + href?: string; // external link + action?: () => void; // fallback click handler (legacy) } - export const NavItem = ({ name, action, @@ -38,9 +40,23 @@ export const NavItem = ({ itemIsActive, rightIcon, isRoot = false, + to, + href, }: Props) => { + const linkProps = + to != null + ? { component: RouterLink, to } + : href != null + ? { + component: 'a' as const, + href, + target: '_blank', + rel: 'noopener noreferrer', + } + : {}; return ( { {navItems.map((item) => ( ))} diff --git a/src/components/Navigation/Navigation.tsx b/src/components/Navigation/Navigation.tsx index 0eabab85..4260ecf6 100644 --- a/src/components/Navigation/Navigation.tsx +++ b/src/components/Navigation/Navigation.tsx @@ -4,7 +4,7 @@ import MenuBookIcon from '@mui/icons-material/MenuBook'; import { Drawer, List } from '@mui/material'; import { default as React, useContext } from 'react'; import { useTranslation } from 'react-i18next'; -import { useLocation, useNavigate } from 'react-router-dom'; +import { useLocation } from 'react-router-dom'; import { ApplicationContext } from '../../contexts/ApplicationContext'; import { FF_NAV_PATHS } from '../../interfaces'; import { MenuLogo } from '../MenuLogo'; @@ -23,14 +23,13 @@ export const Navigation: React.FC = () => { const { selectedNamespace } = useContext(ApplicationContext); const { t } = useTranslation(); const { pathname } = useLocation(); - const navigate = useNavigate(); const makeDrawerContents = ( <> } - action={() => navigate(FF_NAV_PATHS.homePath(selectedNamespace))} + to={FF_NAV_PATHS.homePath(selectedNamespace)} // ← use `to` instead of action itemIsActive={pathname === FF_NAV_PATHS.homePath(selectedNamespace)} isRoot /> @@ -43,7 +42,7 @@ export const Navigation: React.FC = () => { } - action={() => window.open(FF_NAV_PATHS.docsPath, '_blank')} + href={FF_NAV_PATHS.docsPath} // ← external URL itemIsActive={false} rightIcon={} isRoot diff --git a/src/components/Navigation/NetworkNav.tsx b/src/components/Navigation/NetworkNav.tsx index a242d7c8..194e3f47 100644 --- a/src/components/Navigation/NetworkNav.tsx +++ b/src/components/Navigation/NetworkNav.tsx @@ -17,14 +17,13 @@ import LanguageIcon from '@mui/icons-material/Language'; import React, { useContext } from 'react'; import { useTranslation } from 'react-i18next'; -import { useLocation, useNavigate } from 'react-router-dom'; +import { useLocation } from 'react-router-dom'; import { ApplicationContext } from '../../contexts/ApplicationContext'; import { FF_NAV_PATHS, INavItem } from '../../interfaces'; import { NavSection } from './NavSection'; export const NetworkNav = () => { const { t } = useTranslation(); - const navigate = useNavigate(); const { selectedNamespace } = useContext(ApplicationContext); const { pathname } = useLocation(); @@ -37,27 +36,27 @@ export const NetworkNav = () => { const navItems: INavItem[] = [ { name: t('dashboard'), - action: () => navigate(networkPath), + to: networkPath, itemIsActive: pathname === networkPath, }, { name: t('organizations'), - action: () => navigate(orgPath), + to: orgPath, itemIsActive: pathname === orgPath, }, { name: t('nodes'), - action: () => navigate(nodePath), + to: nodePath, itemIsActive: pathname === nodePath, }, { name: t('identities'), - action: () => navigate(identitiesPath), + to: identitiesPath, itemIsActive: pathname === identitiesPath, }, { name: t('namespaces'), - action: () => navigate(namespacesPath), + to: namespacesPath, itemIsActive: pathname === namespacesPath, }, ]; diff --git a/src/components/Navigation/OffChainNav.tsx b/src/components/Navigation/OffChainNav.tsx index 9ca5925a..203b3482 100644 --- a/src/components/Navigation/OffChainNav.tsx +++ b/src/components/Navigation/OffChainNav.tsx @@ -17,14 +17,13 @@ import InventoryIcon from '@mui/icons-material/Inventory'; import React, { useContext } from 'react'; import { useTranslation } from 'react-i18next'; -import { useLocation, useNavigate } from 'react-router-dom'; +import { useLocation } from 'react-router-dom'; import { ApplicationContext } from '../../contexts/ApplicationContext'; import { FF_NAV_PATHS, INavItem } from '../../interfaces'; import { NavSection } from './NavSection'; export const OffChainNav = () => { const { t } = useTranslation(); - const navigate = useNavigate(); const { pathname } = useLocation(); const { selectedNamespace } = useContext(ApplicationContext); @@ -38,32 +37,32 @@ export const OffChainNav = () => { const navItems: INavItem[] = [ { name: t('dashboard'), - action: () => navigate(offchainPath), + to: offchainPath, itemIsActive: pathname === offchainPath, }, { name: t('messages'), - action: () => navigate(messagesPath), + to: messagesPath, itemIsActive: pathname === messagesPath, }, { name: t('data'), - action: () => navigate(dataPath), + to: dataPath, itemIsActive: pathname === dataPath, }, { name: t('batches'), - action: () => navigate(batchesPath), + to: batchesPath, itemIsActive: pathname === batchesPath, }, { name: t('datatypes'), - action: () => navigate(datatypesPath), + to: datatypesPath, itemIsActive: pathname === datatypesPath, }, { name: t('groups'), - action: () => navigate(groupsPath), + to: groupsPath, itemIsActive: pathname === groupsPath, }, ]; diff --git a/src/components/Navigation/TokensNav.tsx b/src/components/Navigation/TokensNav.tsx index 0aac4d94..dbd19b99 100644 --- a/src/components/Navigation/TokensNav.tsx +++ b/src/components/Navigation/TokensNav.tsx @@ -17,14 +17,13 @@ import AdjustIcon from '@mui/icons-material/Adjust'; import React, { useContext } from 'react'; import { useTranslation } from 'react-i18next'; -import { useLocation, useNavigate } from 'react-router-dom'; +import { useLocation } from 'react-router-dom'; import { ApplicationContext } from '../../contexts/ApplicationContext'; import { FF_NAV_PATHS, INavItem } from '../../interfaces'; import { NavSection } from './NavSection'; export const TokensNav = () => { const { t } = useTranslation(); - const navigate = useNavigate(); const { pathname } = useLocation(); const { selectedNamespace } = useContext(ApplicationContext); @@ -37,27 +36,27 @@ export const TokensNav = () => { const navItems: INavItem[] = [ { name: t('dashboard'), - action: () => navigate(blockchainPath), + to: blockchainPath, itemIsActive: pathname === blockchainPath, }, { name: t('transfers'), - action: () => navigate(transfersPath), + to: transfersPath, itemIsActive: pathname === transfersPath, }, { name: t('pools'), - action: () => navigate(poolsPath), + to: poolsPath, itemIsActive: pathname.startsWith(poolsPath), }, { name: t('balances'), - action: () => navigate(balancesPath), + to: balancesPath, itemIsActive: pathname === balancesPath, }, { name: t('approvals'), - action: () => navigate(approvalsPath), + to: approvalsPath, itemIsActive: pathname === approvalsPath, }, ]; diff --git a/src/interfaces/navigation.ts b/src/interfaces/navigation.ts index 97f7c652..dd6b5f18 100644 --- a/src/interfaces/navigation.ts +++ b/src/interfaces/navigation.ts @@ -18,9 +18,16 @@ import { FF_OPS } from './enums'; export interface INavItem { name: string; - action: () => void; - icon?: JSX.Element; itemIsActive: boolean; + icon?: JSX.Element; + + // Preferred props for link/navigation behavior + to?: string; // internal React Router path + href?: string; // external URL + + // DEPRECATED: legacy click handler (prefer `to` or `href`) + /** @deprecated use `to` or `href` instead */ + action?: () => void; } export const ACTIVITY_PATH = 'activity';