From 470b98814319164775d83bfc811ea7236c521e76 Mon Sep 17 00:00:00 2001 From: Tusharjamdade Date: Wed, 8 Jan 2025 23:04:27 +0530 Subject: [PATCH] Implement notification icon with badge for warnings and its test --- cypress/component/Navbar.cy.tsx | 11 +++- src/App.tsx | 32 +++++----- src/components/Navbar.tsx | 101 +++++++++++++++++++++++++++++++- 3 files changed, 127 insertions(+), 17 deletions(-) diff --git a/cypress/component/Navbar.cy.tsx b/cypress/component/Navbar.cy.tsx index e048bddc..9f429d0a 100644 --- a/cypress/component/Navbar.cy.tsx +++ b/cypress/component/Navbar.cy.tsx @@ -3,11 +3,18 @@ import Navbar from '../../src/components/Navbar'; const props = { isLoggedIn: true, onLogin: () => {}, + warnings: ['Warning 1', 'Warning 2', 'Warning n'], }; describe('Navbar', () => { it('Displays a MUI Toolbar with logo, title, subtitle, documentation link, and GitHub link', () => { - cy.mount(); + cy.mount( + + ); cy.get("[data-cy='navbar']").should('be.visible'); cy.get("[data-cy='navbar'] img").should('exist'); cy.get("[data-cy='navbar'] h5").should('contain', 'Neurobagel Query'); @@ -24,5 +31,7 @@ describe('Navbar', () => { cy.get("[data-cy='navbar'] a") .eq(1) .should('have.attr', 'href', 'https://github.com/neurobagel/query-tool/'); + // Test for Notification Icon and Badge + cy.get("[data-cy='navbar'] button").eq(1).find('svg').should('be.visible'); // Check if the notification icon exists }); }); diff --git a/src/App.tsx b/src/App.tsx index 936178f3..5c1ffb13 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -61,6 +61,7 @@ function App() { const [openAuthDialog, setOpenAuthDialog] = useState(false); const [IDToken, setIDToken] = useState(''); const { isAuthenticated, isLoading, getIdTokenClaims } = useAuth0(); + const [warnings, setWarnings] = useState([]); // Extract the raw OIDC ID token from the Auth0 SDK useEffect(() => { @@ -116,10 +117,10 @@ function App() { } else { // If any errors occurred, report them response.data.errors.forEach((error) => { - enqueueSnackbar(`Failed to retrieve ${NBResource} options from ${error.node_name}`, { - variant: 'warning', - action, - }); + setWarnings((prev) => [ + ...(prev ?? []), + `Failed to retrieve ${NBResource} options from ${error.node_name}`, + ]); }); // If the results are empty, report that if (Object.keys(response.data.responses[dataElementURI]).length === 0) { @@ -132,10 +133,10 @@ function App() { response.data.responses[dataElementURI].some((item) => item.Label === null) && NBResource !== 'pipelines' ) { - enqueueSnackbar(`Warning: Missing labels were removed for ${NBResource} `, { - variant: 'warning', - action, - }); + setWarnings((prev) => [ + ...(prev ?? []), + `Warning: Missing labels were removed for ${NBResource}`, + ]); response.data.responses[dataElementURI] = response.data.responses[ dataElementURI ].filter((item) => item.Label !== null); @@ -201,13 +202,10 @@ function App() { } else { // If any errors occurred, report them response.data.errors.forEach((error) => { - enqueueSnackbar( + setWarnings((prev) => [ + ...(prev ?? []), `Failed to retrieve ${pipelineURI.label} versions from ${error.node_name}`, - { - variant: 'warning', - action, - } - ); + ]); }); // If the results are empty, report that if (Object.keys(response.data.responses[pipelineURI.id]).length === 0) { @@ -439,7 +437,11 @@ function App() { anchorOrigin={{ vertical: 'top', horizontal: 'right' }} maxSnack={7} /> - setOpenAuthDialog(true)} /> + setOpenAuthDialog(true)} + notifications={warnings} + /> {showAlert() && ( <> diff --git a/src/components/Navbar.tsx b/src/components/Navbar.tsx index ef2c35df..29a76c85 100644 --- a/src/components/Navbar.tsx +++ b/src/components/Navbar.tsx @@ -8,6 +8,11 @@ import { MenuItem, ListItemIcon, Tooltip, + Popover, + List, + ListItem, + ListItemText, + ListItemSecondaryAction, } from '@mui/material'; import GitHub from '@mui/icons-material/GitHub'; import Article from '@mui/icons-material/Article'; @@ -15,23 +20,43 @@ import Logout from '@mui/icons-material/Logout'; import Login from '@mui/icons-material/Login'; import Avatar from '@mui/material/Avatar'; import { useAuth0 } from '@auth0/auth0-react'; +import NotificationsIcon from '@mui/icons-material/Notifications'; import { enableAuth } from '../utils/constants'; import packageJson from '../../package.json'; import logo from '../assets/logo.png'; -function Navbar({ isLoggedIn, onLogin }: { isLoggedIn: boolean; onLogin: () => void }) { +function Navbar({ + isLoggedIn, + onLogin, + notifications, +}: { + isLoggedIn: boolean; + onLogin: () => void; + notifications: string[]; +}) { const [anchorEl, setAnchorEl] = useState(null); const openAccountMenu = Boolean(anchorEl); const { user, logout } = useAuth0(); + const [anchorMailEl, setAnchorMailEl] = useState(null); + const openMailMenu = Boolean(anchorMailEl); const handleClick = (event: React.MouseEvent) => { setAnchorEl(event.currentTarget); }; + const handleClose = () => { setAnchorEl(null); }; + const handleMailClick = (event: React.MouseEvent) => { + setAnchorMailEl(event.currentTarget); + }; + + const handleMailClose = () => { + setAnchorMailEl(null); + }; + return (
@@ -56,9 +81,83 @@ function Navbar({ isLoggedIn, onLogin }: { isLoggedIn: boolean; onLogin: () => v
+ + + + + + + + + + {notifications.length > 0 ? ( + notifications.map((notification) => ( + + + {/* Add the appropriate title for the notification if any */} + + } + secondary={ + + {notification} + + } + /> + + + + + )) + ) : ( + + + No notifications + + } + /> + + )} + + + + {enableAuth && ( <>