Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -63,3 +63,4 @@ typings/

# generate output
dist
*.mp4
2 changes: 1 addition & 1 deletion src/components/Loading/Loading.cy.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ describe('<Loading />', () => {
cy.mount(<Loading loading />)
cy.get('.MuiCircularProgress-root').should('exist')
})
it('Show data only when loading and containing data', () => {
it('Show data when loading and containing data', () => {
cy.mount(
<Loading
loading
Expand Down
61 changes: 61 additions & 0 deletions src/components/Navigation.cy.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import React from 'react'
import Navigation from './Navigation'
import { MemoryRouter } from 'react-router-dom'

interface Props {
children: React.ReactNode
}
function Wrapper({ children }: Props) {
return <MemoryRouter>{children}</MemoryRouter>
}

const protectedPage = {
name: 'protected-route',
path: '/protected',
protected: true
}
const publicPage = {
name: 'public-route',
path: '/public'
}

describe('<Navigation />', () => {
describe('Show only non-protected pages', () => {
;[true, false].forEach((drawer) => {
it(`drawer=${drawer}`, () => {
cy.mount(
<Wrapper>
<Navigation
drawer={drawer}
pages={[protectedPage, publicPage]}
/>
</Wrapper>
)
cy.get('[data-cy=navbar-menu-button]').click()

cy.get('[data-cy=navbar-menu-item]').should('have.length', 1)
cy.get('[data-cy=navbar-menu-item]').should('contain.text', 'public-route')
})
})
})

describe('Show protected pages when logged in', () => {
;[true, false].forEach((drawer) => {
it(`drawer=${drawer}`, () => {
cy.mount(
<Wrapper>
<Navigation
drawer={drawer}
isLoggedIn
pages={[protectedPage, publicPage]}
/>
</Wrapper>
)
cy.get('[data-cy=navbar-menu-button]').click()

cy.get('[data-cy=navbar-menu-item]').should('have.length', 2)
cy.get('[data-cy=navbar-menu-item]').should('contain.text', 'protected-route')
})
})
})
})
158 changes: 84 additions & 74 deletions src/components/Navigation.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@ import {
SxProps,
Theme,
Toolbar,
Typography
Typography,
useMediaQuery,
useTheme
} from '@mui/material'
import { useState } from 'react'
import { Link } from 'react-router-dom'
Expand Down Expand Up @@ -70,6 +72,8 @@ function NavigationBar({ title, Icon, pages, avatarOptions, user, isLoggedIn, dr
const [anchorElNav, setAnchorElNav] = useState<null | HTMLElement>(null)
const [anchorElUser, setAnchorElUser] = useState<null | HTMLElement>(null)
const [showDrawer, setShowDrawer] = useState(false)
const theme = useTheme()
const isLargeScreen = useMediaQuery(theme.breakpoints.up('sm'))

const handleOpenNavMenu = (event: React.MouseEvent<HTMLElement>) => {
if (drawer) {
Expand All @@ -90,8 +94,10 @@ function NavigationBar({ title, Icon, pages, avatarOptions, user, isLoggedIn, dr
setAnchorElUser(null)
}

const showMenu = !!(pages && pages.length)
const filteredPages = (pages || []).filter((x) => !x.protected || isLoggedIn)
const showMenu = !!filteredPages.length
const showAvatarOptions = !!(avatarOptions && avatarOptions.length)

return (
<>
<AppBar position="static">
Expand All @@ -101,29 +107,32 @@ function NavigationBar({ title, Icon, pages, avatarOptions, user, isLoggedIn, dr
>
<Toolbar disableGutters>
{/* show on large screen */}
{Icon && <Icon sx={{ display: { xs: 'none', sm: 'flex' }, mr: 1, ml: 2 }} />}
<Typography
variant="h6"
noWrap
component={Link}
to="/"
sx={{
mr: 2,
ml: 1,
display: { xs: 'none', sm: 'flex' },
fontWeight: 700,
letterSpacing: '.3rem',
color: 'inherit',
textDecoration: 'none'
}}
>
{title}
</Typography>
{Icon && isLargeScreen && <Icon sx={{ display: 'flex', mr: 1, ml: 2 }} />}
{isLargeScreen && (
<Typography
variant="h6"
noWrap
component={Link}
to="/"
sx={{
mr: 2,
ml: 1,
display: 'flex',
fontWeight: 700,
letterSpacing: '.3rem',
color: 'inherit',
textDecoration: 'none'
}}
>
{title}
</Typography>
)}

{/* Navigation menu (burger menu) show on small screen */}
{showMenu && (
<Box sx={{ flexGrow: 1, display: { xs: 'flex', sm: 'none' } }}>
{showMenu && !isLargeScreen && (
<Box sx={{ flexGrow: 1, display: 'flex' }}>
<IconButton
data-cy="navbar-menu-button"
size="large"
aria-label="account of current user"
aria-controls="menu-appbar"
Expand All @@ -149,67 +158,68 @@ function NavigationBar({ title, Icon, pages, avatarOptions, user, isLoggedIn, dr
open={Boolean(anchorElNav)}
onClose={handleCloseNavMenu}
sx={{
display: { xs: 'block', sm: 'none' }
display: 'block'
}}
>
{(pages || [])
.filter((x) => isLoggedIn || !x.protected)
.map((page) => (
<MenuItem
key={page.name}
component={Link}
to={page.path}
onClick={handleCloseNavMenu}
>
<Typography textAlign="center">{page.name}</Typography>
</MenuItem>
))}
{filteredPages.map((page) => (
<MenuItem
data-cy="navbar-menu-item"
key={page.name}
component={Link}
to={page.path}
onClick={handleCloseNavMenu}
>
<Typography textAlign="center">{page.name}</Typography>
</MenuItem>
))}
</Menu>
</Box>
)}
{/* show on small screen */}
{Icon && <Icon sx={{ display: { xs: 'flex', sm: 'none' }, mr: 1 }} />}

{/* title - show on small screen */}
<Typography
variant="h6"
noWrap
component="a"
href=""
sx={{
mr: 2,
display: { xs: 'flex', sm: 'none' },
flexGrow: 1,
fontFamily: 'monospace',
fontWeight: 700,
letterSpacing: '.2rem',
color: 'inherit',
textDecoration: 'none'
}}
>
{title}
</Typography>
{!isLargeScreen && (
<>
{Icon && <Icon sx={{ display: 'flex', mr: 1 }} />}

{/* title - show on small screen */}
<Typography
variant="h6"
noWrap
component="a"
href=""
sx={{
mr: 2,
display: 'flex',
flexGrow: 1,
fontFamily: 'monospace',
fontWeight: 700,
letterSpacing: '.2rem',
color: 'inherit',
textDecoration: 'none'
}}
>
{title}
</Typography>
</>
)}
{/* pages link - show on large screens */}
{!drawer && (
<Box sx={{ flexGrow: 1, display: { xs: 'none', sm: 'flex' } }}>
{(pages || [])
.filter((x) => isLoggedIn || !x.protected)
.map((page) => (
<Button
key={page.name}
onClick={handleCloseNavMenu}
component={Link}
to={page.path}
variant="text"
sx={{ my: 2, color: 'white', display: 'block' }}
>
{page.name}
</Button>
))}
{!drawer && isLargeScreen && (
<Box sx={{ flexGrow: 1, display: 'flex' }}>
{filteredPages.map((page) => (
<Button
key={page.name}
data-cy="navbar-menu-item"
onClick={handleCloseNavMenu}
component={Link}
to={page.path}
variant="text"
sx={{ my: 2, color: 'white', display: 'block' }}
>
{page.name}
</Button>
))}
</Box>
)}
{/* avatar if logged - show on large AND small screens */}
{/* avatar if logged in - show on large AND small screens */}
{isLoggedIn && (
<Box sx={{ flexGrow: 0 }}>
<IconButton
Expand Down Expand Up @@ -261,7 +271,7 @@ function NavigationBar({ title, Icon, pages, avatarOptions, user, isLoggedIn, dr
drawerWidth={drawerWidth || defaultDrawerWidth}
mobileOpen={showDrawer}
onMobileClose={() => setShowDrawer(false)}
items={pages}
items={filteredPages}
>
{children}
</ResponsiveDrawer>
Expand Down