diff --git a/src/nextapp/components/nav-bar/nav-bar.tsx b/src/nextapp/components/nav-bar/nav-bar.tsx index 3858aef4a..1345fa8b0 100644 --- a/src/nextapp/components/nav-bar/nav-bar.tsx +++ b/src/nextapp/components/nav-bar/nav-bar.tsx @@ -4,6 +4,7 @@ import NextLink from 'next/link'; import type { NavLink } from '@/shared/data/links'; import NamespaceMenu from '../namespace-menu'; import { useAuth } from '@/shared/services/auth'; +import { gatewayPages } from '@/shared/data/links'; const linkProps = { px: 4, @@ -48,6 +49,8 @@ const NavBar: React.FC = ({ site, links, pathname }) => { return ''; }, [pathname]); + const requiresNamespace = gatewayPages.includes(pathname); + return ( = ({ site, links, pathname }) => { ))} - {((pathname.startsWith('/manager/') && - pathname !== '/manager/gateways' && - pathname !== '/manager/gateways/get-started' && - pathname !== '/manager/gateways/list') || - pathname === '/devportal/api-directory/your-products') && ( + {requiresNamespace && ( { - const toast = useToast(); - const router = useRouter(); - - React.useEffect(() => { - const handleRouteChange = () => { - const showToast = localStorage.getItem('showNoGatewayToast'); - if (showToast === 'true') { - toast.closeAll(); - toast({ - title: `First select a Gateway to view that page`, - status: 'error', - isClosable: true, - duration: 5000, - }); - localStorage.removeItem('showNoGatewayToast'); - } - }; - - router.events.on('routeChangeComplete', handleRouteChange); - - return () => { - router.events.off('routeChangeComplete', handleRouteChange); - }; - }, [toast, router]); - - return null; -}; - -export default GatewayToastHandler; \ No newline at end of file diff --git a/src/nextapp/components/no-gateway-redirect/index.ts b/src/nextapp/components/no-gateway-redirect/index.ts deleted file mode 100644 index 001eb41b5..000000000 --- a/src/nextapp/components/no-gateway-redirect/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default } from './no-gateway-redirect'; diff --git a/src/nextapp/components/no-gateway-redirect/no-gateway-redirect.tsx b/src/nextapp/components/no-gateway-redirect/no-gateway-redirect.tsx deleted file mode 100644 index 0407a76c7..000000000 --- a/src/nextapp/components/no-gateway-redirect/no-gateway-redirect.tsx +++ /dev/null @@ -1,45 +0,0 @@ -import * as React from 'react'; -import { useRouter } from 'next/router'; -import { useAuth } from '@/shared/services/auth'; - -const NoGatewayRedirect = () => { - const router = useRouter(); - const { user } = useAuth(); - const [isChecking, setIsChecking] = React.useState(true); - - React.useEffect(() => { - const checkNamespaceAndRedirect = async () => { - // Wait for a short period to ensure user data is loaded - await new Promise(resolve => setTimeout(resolve, 2000)); - - setIsChecking(false); - - if (!user?.namespace) { - try { - // Set localStorage item to show toast - await new Promise((resolve, reject) => { - try { - localStorage.setItem('showNoGatewayToast', 'true'); - resolve(); - } catch (error) { - reject(error); - } - }); - await router.push('/manager/gateways/list'); - } catch (error) { - console.error('Error during redirect process:', error); - } - } - }; - - checkNamespaceAndRedirect(); - }, [user, router]); - - if (isChecking) { - return null; // could return a loading indicator - } - - return null; -}; - -export default NoGatewayRedirect; \ No newline at end of file diff --git a/src/nextapp/pages/_app.tsx b/src/nextapp/pages/_app.tsx index 7cf5709b3..f3bb362ba 100644 --- a/src/nextapp/pages/_app.tsx +++ b/src/nextapp/pages/_app.tsx @@ -18,7 +18,7 @@ import Header from '@/components/header'; import NavBar from '@/components/nav-bar'; import MaintenanceBanner from '@/components/maintenance-banner'; import theme from '@/shared/theme'; -import links from '@/shared/data/links'; +import links, { gatewayPages } from '@/shared/data/links'; import AuthAction from '@/components/auth-action'; import { ReactQueryDevtools } from 'react-query/devtools'; import type { AppProps } from 'next/app'; @@ -31,7 +31,6 @@ import '@/shared/styles/global.css'; import { AppWrapper } from './context'; import '../../mocks'; import CompleteProfile from '@/components/complete-profile'; -import GatewayToastHandler from '@/components/no-gateway-redirect/gateway-toast-handler'; const footerItems = [ { href: 'http://www2.gov.bc.ca/gov/content/home', text: 'Home' }, @@ -57,9 +56,6 @@ const App: React.FC = ({ Component, pageProps }) => { const router = useRouter(); const queryClientRef = React.useRef(); const site: string = React.useMemo(() => { - //if (router?.pathname.startsWith('/manager')) { - // return 'manager'; - //} if (router?.pathname.startsWith('/platform')) { return 'platform'; } @@ -71,12 +67,7 @@ const App: React.FC = ({ Component, pageProps }) => { }, [router]); // Temp solution for handing spacing around new gateways dropdown menu - const gatewaysMenu = - (router?.pathname.startsWith('/manager/') && - router?.pathname !== '/manager/gateways' && - router?.pathname !== '/manager/gateways/get-started' && - router?.pathname !== '/manager/gateways/list') || - router?.pathname === '/devportal/api-directory/your-products'; + const requiresNamespace = gatewayPages.includes(router?.pathname); if (!queryClientRef.current) { queryClientRef.current = new QueryClient({ @@ -118,12 +109,11 @@ const App: React.FC = ({ Component, pageProps }) => { as="main" flex={1} mt={{ - base: gatewaysMenu ? '303px' : '65px', - sm: gatewaysMenu ? '163px' : '115px', + base: requiresNamespace ? '303px' : '65px', + sm: requiresNamespace ? '163px' : '115px', }} > - diff --git a/src/nextapp/pages/manager/activity/index.tsx b/src/nextapp/pages/manager/activity/index.tsx index b747d3eb9..73d19a262 100644 --- a/src/nextapp/pages/manager/activity/index.tsx +++ b/src/nextapp/pages/manager/activity/index.tsx @@ -26,7 +26,6 @@ import ActivityFilters from '@/components/activity-filters'; import { FaTimesCircle } from 'react-icons/fa'; import EmptyPane from '@/components/empty-pane'; import ActivityItem from '@/components/activity-item'; -import NoGatewayRedirect from '@/components/no-gateway-redirect'; const timeZone = 'America/Vancouver'; @@ -51,8 +50,6 @@ interface FilterState { } const ActivityPage: React.FC = () => { - // Redirect to My Gateways page if no gateway selected - NoGatewayRedirect(); const breadcrumbs = useNamespaceBreadcrumbs([ { diff --git a/src/nextapp/pages/manager/admin-access/index.tsx b/src/nextapp/pages/manager/admin-access/index.tsx index 0445d0455..9565dca13 100644 --- a/src/nextapp/pages/manager/admin-access/index.tsx +++ b/src/nextapp/pages/manager/admin-access/index.tsx @@ -21,12 +21,8 @@ import { } from '@/components/namespace-access'; import { useAuth } from '@/shared/services/auth'; import { useNamespaceBreadcrumbs } from '@/shared/hooks'; -import NoGatewayRedirect from '@/components/no-gateway-redirect'; const AccessRedirectPage: React.FC = () => { - // Redirect to My Gateways page if no gateway selected - NoGatewayRedirect(); - const { user } = useAuth(); const breadcrumbs = useNamespaceBreadcrumbs([ { href: '/manager/admin-access', text: 'Administration Access' }, diff --git a/src/nextapp/pages/manager/authorization-profiles/index.tsx b/src/nextapp/pages/manager/authorization-profiles/index.tsx index 2fd8dc866..b2c01cf88 100644 --- a/src/nextapp/pages/manager/authorization-profiles/index.tsx +++ b/src/nextapp/pages/manager/authorization-profiles/index.tsx @@ -41,7 +41,6 @@ import type { Mutation, Query, } from '@/shared/types/query.types'; -import NoGatewayRedirect from '@/components/no-gateway-redirect'; export const getServerSideProps: GetServerSideProps = async (context) => { const queryKey = 'authorizationProfiles'; @@ -70,8 +69,6 @@ export const getServerSideProps: GetServerSideProps = async (context) => { const AuthorizationProfiles: React.FC< InferGetServerSidePropsType > = ({ queryKey }) => { - // Redirect to My Gateways page if no gateway selected - NoGatewayRedirect(); const breadcrumbs = useNamespaceBreadcrumbs([ { diff --git a/src/nextapp/pages/manager/consumers/index.tsx b/src/nextapp/pages/manager/consumers/index.tsx index 466f4d7ac..2908a6266 100644 --- a/src/nextapp/pages/manager/consumers/index.tsx +++ b/src/nextapp/pages/manager/consumers/index.tsx @@ -36,7 +36,6 @@ import GrantAccessDialog from '@/components/access-request/grant-access-dialog'; import ConsumerFilters from '@/components/consumer-filters'; import AccessRequestsList from '@/components/access-request/access-requests-list'; import { useNamespaceBreadcrumbs } from '@/shared/hooks'; -import NoGatewayRedirect from '@/components/no-gateway-redirect'; const sortDate = new Intl.DateTimeFormat('en-ca', { dateStyle: 'short' }); @@ -77,8 +76,6 @@ export const getServerSideProps: GetServerSideProps = async (context) => { const ConsumersPage: React.FC< InferGetServerSidePropsType > = ({ queryKey }) => { - // Redirect to My Gateways page if no gateway selected - NoGatewayRedirect(); const toast = useToast(); const breadcrumbs = useNamespaceBreadcrumbs([{ text: 'Consumers' }]); diff --git a/src/nextapp/pages/manager/gateways/detail.tsx b/src/nextapp/pages/manager/gateways/detail.tsx index 4a93ca708..a4d597d9d 100644 --- a/src/nextapp/pages/manager/gateways/detail.tsx +++ b/src/nextapp/pages/manager/gateways/detail.tsx @@ -60,7 +60,6 @@ import useCurrentNamespace from '@/shared/hooks/use-current-namespace'; import { useGlobal } from '@/shared/services/global'; import EditNamespaceDisplayName from '@/components/edit-display-name'; import { useNamespaceBreadcrumbs } from '@/shared/hooks'; -import NoGatewayRedirect from '@/components/no-gateway-redirect'; const actions = [ { @@ -120,9 +119,6 @@ const secondaryActions = [ ]; const NamespacesPage: React.FC = () => { - // Redirect to My Gateways page if no gateway selected - NoGatewayRedirect(); - const { user } = useAuth(); const breadcrumbs = useNamespaceBreadcrumbs(); const hasNamespace = !!user?.namespace; diff --git a/src/nextapp/pages/manager/gateways/list.tsx b/src/nextapp/pages/manager/gateways/list.tsx index 6e9389835..64b2f14d4 100644 --- a/src/nextapp/pages/manager/gateways/list.tsx +++ b/src/nextapp/pages/manager/gateways/list.tsx @@ -289,6 +289,10 @@ const MyGatewaysPage: React.FC = () => { py={2} mb={4} data-testid={`ns-list-item-${namespace.name}`} + onClick={handleNamespaceChange(namespace)} + cursor="pointer" + transition="background-color 0.2s" + _hover={{ backgroundColor: "#f0f0f0" }} > @@ -298,16 +302,15 @@ const MyGatewaysPage: React.FC = () => { mr={4} boxSize={4} /> - {namespace.displayName} - + {namespace.name} diff --git a/src/nextapp/pages/manager/products/index.tsx b/src/nextapp/pages/manager/products/index.tsx index 6018ab425..26a4eaed2 100644 --- a/src/nextapp/pages/manager/products/index.tsx +++ b/src/nextapp/pages/manager/products/index.tsx @@ -23,11 +23,8 @@ import useCurrentNamespace, { import { useRestMutationApi } from '@/shared/services/api'; import { gql } from 'graphql-request'; import { useAuth } from '@/shared/services/auth'; -import NoGatewayRedirect from '@/components/no-gateway-redirect'; const ProductsPage: React.FC = () => { - // Redirect to My Gateways page if no gateway selected - NoGatewayRedirect(); const { user } = useAuth(); const breadcrumbs = useNamespaceBreadcrumbs([{ text: 'Products' }]); diff --git a/src/nextapp/pages/manager/service-accounts/index.tsx b/src/nextapp/pages/manager/service-accounts/index.tsx index fcd65ed39..751244760 100644 --- a/src/nextapp/pages/manager/service-accounts/index.tsx +++ b/src/nextapp/pages/manager/service-accounts/index.tsx @@ -35,7 +35,6 @@ import { FaCheckCircle } from 'react-icons/fa'; import ServiceAccountCreate from '@/components/service-account-create'; import { useNamespaceBreadcrumbs } from '@/shared/hooks'; import EmptyPane from '@/components/empty-pane'; -import NoGatewayRedirect from '@/components/no-gateway-redirect'; export const getServerSideProps: GetServerSideProps = async (context) => { const queryKey = 'getServiceAccounts'; @@ -64,8 +63,6 @@ export const getServerSideProps: GetServerSideProps = async (context) => { const ServiceAccountsPage: React.FC< InferGetServerSidePropsType > = ({ queryKey }) => { - // Redirect to My Gateways page if no gateway selected - NoGatewayRedirect(); const breadcrumbs = useNamespaceBreadcrumbs([{ text: 'Service Accounts' }]); const client = useQueryClient(); diff --git a/src/nextapp/pages/manager/services/index.tsx b/src/nextapp/pages/manager/services/index.tsx index bc3199cdd..af9c718db 100644 --- a/src/nextapp/pages/manager/services/index.tsx +++ b/src/nextapp/pages/manager/services/index.tsx @@ -12,7 +12,6 @@ import ServicesFilters from '@/components/services-list/services-filters'; import { useAuth } from '@/shared/services/auth'; import { useNamespaceBreadcrumbs } from '@/shared/hooks'; import { GetServerSideProps, InferGetServerSidePropsType } from 'next'; -import NoGatewayRedirect from '@/components/no-gateway-redirect'; import { FilterState } from '@/components/services-list/types'; @@ -27,8 +26,6 @@ export const getServerSideProps: GetServerSideProps = async () => { const ServicesPage: React.FC< InferGetServerSidePropsType > = ({ metricsUrl }) => { - // Redirect to My Gateways page if no gateway selected - NoGatewayRedirect(); const title = 'Gateway Services'; const breadcrumb = useNamespaceBreadcrumbs([{ text: title }]); diff --git a/src/nextapp/shared/data/links.ts b/src/nextapp/shared/data/links.ts index e3191da12..1c7ef23b7 100644 --- a/src/nextapp/shared/data/links.ts +++ b/src/nextapp/shared/data/links.ts @@ -10,6 +10,24 @@ export interface NavLink { access: string[]; } +export const gatewayPages = [ + '/manager/gateways/detail', + '/manager/services', + '/manager/services/[id]', + '/manager/products', + '/manager/products/[id]', + '/manager/consumers', + '/manager/consumers/[id]', + '/manager/requests/[id]', + '/manager/authorization-profiles', + '/manager/authorization-profiles/new', + '/manager/authorization-profiles/[id]', + '/manager/admin-access', + '/manager/service-accounts', + '/manager/activity', + '/devportal/api-directory/your-products', +]; + const links: NavLink[] = [ // { name: 'Home', url: '/manager', access: [], sites: ['manager'] }, // { name: 'Home', url: '/devportal', access: [], sites: ['devportal'] }, @@ -52,20 +70,8 @@ const links: NavLink[] = [ access: ['idir-user'], altUrls: [ '/manager/gateways/get-started', - '/manager/gateways/detail', '/manager/gateways/list', - '/manager/services', - '/manager/services/[id]', - '/manager/products', - '/manager/products/[id]', - '/manager/consumers', - '/manager/consumers/[id]', - '/manager/requests/[id]', - '/manager/authorization-profiles', - '/manager/authorization-profiles/new', - '/manager/authorization-profiles/[id]', - '/manager/admin-access', - '/manager/service-accounts', + ...gatewayPages.filter(page => !page.startsWith('/devportal')), ], sites: ['devportal'], }, diff --git a/src/nextapp/shared/services/auth/auth-context.tsx b/src/nextapp/shared/services/auth/auth-context.tsx index b2b9a1d3e..d8b6776eb 100644 --- a/src/nextapp/shared/services/auth/auth-context.tsx +++ b/src/nextapp/shared/services/auth/auth-context.tsx @@ -3,6 +3,8 @@ import { Box, Center, Heading, Text } from '@chakra-ui/react'; import Button from '@/components/button'; import links from '@/shared/data/links'; import { useRouter } from 'next/router'; +import { gatewayPages } from '@/shared/data/links'; +import { useToast } from '@chakra-ui/react'; import { useSession, UserSessionResult } from './use-session'; @@ -19,6 +21,7 @@ interface AuthProviderProps { export const AuthProvider: React.FC = ({ children }) => { const session = useSession(); + const toast = useToast(); const router = useRouter(); const route = links.find( (d) => d.url === router?.pathname || d.altUrls?.includes(router?.pathname) @@ -38,16 +41,22 @@ export const AuthProvider: React.FC = ({ children }) => { // A logged in user trying to access a Namespace'd page (page that is not protected with "portal-user" role) // and no namespace set, then redirect to Gateways page + const requiresNamespace = gatewayPages.includes(router?.pathname); + const noNamespace = session.user && - route?.access && - route?.access.length > 0 && - route?.access.indexOf('portal-user') == -1 && - route?.access.indexOf('idir-user') == -1 && + requiresNamespace && !session.user.namespace; if (noNamespace) { - router?.push('/manager/gateways'); + router?.push('/manager/gateways/list').then(() => { + toast({ + title: `First select a Gateway to view that page`, + status: 'error', + isClosable: true, + duration: 5000, + }); + }); return <>; }