I'm currently trying to build a website using react for my web development class, which is my first foray into JS and React. I'm using a Material UI appbar for my header. I've used react router in one of my class examples so I've set that up and my app bar is displaying as intended. My question is, how do I set the buttons on the appbar/header to link to my pages? The default code (minus imports) provided by Material UI is below with my placeholder page names added.
const pages = ['Utility List', 'Register', 'Login'];
const settings = ['Profile', 'Account', 'Logout'];
const Header = () => {
const [anchorElNav, setAnchorElNav] = React.useState(null);
const [anchorElUser, setAnchorElUser] = React.useState(null);
const handleOpenNavMenu = (event) => {
setAnchorElNav(event.currentTarget);
};
const handleOpenUserMenu = (event) => {
setAnchorElUser(event.currentTarget);
};
const handleCloseNavMenu = () => {
setAnchorElNav(null);
};
const handleCloseUserMenu = () => {
setAnchorElUser(null);
};
return (
<AppBar position="static">
<Container maxWidth="xl">
<Toolbar disableGutters>
<Typography
variant="h6"
noWrap
component="div"
sx={{ mr: 2, display: { xs: 'none', md: 'flex' } }}
>
LOGO
</Typography>
<Box sx={{ flexGrow: 1, display: { xs: 'flex', md: 'none' } }}>
<IconButton
size="large"
aria-label="account of current user"
aria-controls="menu-appbar"
aria-haspopup="true"
onClick={handleOpenNavMenu}
color="inherit"
>
<MenuIcon />
</IconButton>
<Menu
id="menu-appbar"
anchorEl={anchorElNav}
anchorOrigin={{
vertical: 'bottom',
horizontal: 'left',
}}
keepMounted
transformOrigin={{
vertical: 'top',
horizontal: 'left',
}}
open={Boolean(anchorElNav)}
onClose={handleCloseNavMenu}
sx={{
display: { xs: 'block', md: 'none' },
}}
>
{pages.map((page) => (
<MenuItem key={page} onClick={handleCloseNavMenu}>
<Typography textAlign="center">{page}</Typography>
</MenuItem>
))}
</Menu>
</Box>
<Typography
variant="h6"
noWrap
component="div"
sx={{ flexGrow: 1, display: { xs: 'flex', md: 'none' } }}
>
LOGO
</Typography>
<Box sx={{ flexGrow: 1, display: { xs: 'none', md: 'flex' } }}>
{pages.map((page) => (
<Button
key={page}
onClick={handleCloseNavMenu}
sx={{ my: 2, color: 'white', display: 'block' }}
>
{page}
</Button>
))}
</Box>
<Box sx={{ flexGrow: 0 }}>
<Tooltip title="Open settings">
<IconButton onClick={handleOpenUserMenu} sx={{ p: 0 }}>
<Avatar alt="Remy Sharp" src="/static/images/avatar/2.jpg" />
</IconButton>
</Tooltip>
<Menu
sx={{ mt: '45px' }}
id="menu-appbar"
anchorEl={anchorElUser}
anchorOrigin={{
vertical: 'top',
horizontal: 'right',
}}
keepMounted
transformOrigin={{
vertical: 'top',
horizontal: 'right',
}}
open={Boolean(anchorElUser)}
onClose={handleCloseUserMenu}
>
{settings.map((setting) => (
<MenuItem key={setting} onClick={handleCloseUserMenu}>
<Typography textAlign="center">{setting}</Typography>
</MenuItem>
))}
</Menu>
</Box>
</Toolbar>
</Container>
</AppBar>
);
};
export default Header;
Find the place in your code where your navbar links are added to JSX. Wrap each link in Link component from react-router
const yourPages = [
{ text: 'Home', href: '/' },
{ text: 'About', href: '/about' }
]
// inside return statement
{yourPages.map((page) => (
<Link href={page.href}>{page.text}</Link
)}
...
Related
I was wondering if anyone could tell me the best way to dyamically change the button title I'm using in the PopUp component to change the title to 'login' or 'signup' depending on what component I'm passing into the NavBar?
I'm returning a and form into each PopUp component in the navbar as children but have gotten a bit stuck on how to get the title to change. Any help would be much appreciated.
const BootstrapDialog = styled(Dialog)(({ theme }) => ({
"& .MuiDialogContent-root": {
padding: theme.spacing(2),
},
"& .MuiDialogActions-root": {
padding: theme.spacing(1),
},
}));
const BootstrapDialogTitle = (props) => {
const { children, onClose, ...other } = props;
return (
<DialogTitle sx={{ m: 0, p: 2 }} {...other}>
{children}
{onClose ? (
<IconButton
aria-label="close"
onClick={onClose}
sx={{
position: "absolute",
right: 8,
top: 8,
color: (theme) => theme.palette.grey[500],
}}
>
<CloseIcon />
</IconButton>
) : null}
</DialogTitle>
);
};
BootstrapDialogTitle.propTypes = {
children: PropTypes.node,
onClose: PropTypes.func.isRequired,
};
export function PopUp(props) {
const [open, setOpen] = React.useState(false);
const handleClickOpen = () => {
setOpen(true);
};
const handleClose = () => {
setOpen(false);
};
return (
<div>
<Button color="inherit" onClick={handleClickOpen}>
SignUp
</Button>
<BootstrapDialog
onClose={handleClose}
aria-labelledby="customized-dialog-title"
open={open}
>
<BootstrapDialogTitle
id="customized-dialog-title"
onClose={handleClose}
>
<Logo />
</BootstrapDialogTitle>
<DialogContent dividers>{props.children}</DialogContent>
</BootstrapDialog>
</div>
);
}
export default function NavBar() {
return (
<Box sx={{ flexGrow: 1 }}>
<AppBar position="fixed">
<Toolbar>
<IconButton
size="large"
edge="start"
color="inherit"
aria-label="menu"
sx={{ mr: 2 }}
>
<MenuIcon />
</IconButton>
<Typography variant="h6" component="div" sx={{ flexGrow: 1 }}>
<Logo />
</Typography>
<PopUp>
<Login />
</PopUp>
<PopUp>
<SignUp />
</PopUp>
<Button color="inherit">About</Button>
</Toolbar>
</AppBar>
</Box>
);
}
I need to pass the state value to a different component and I want to use it in the different component.
Code in the first component:
const handleFormSubmit = async (event) => {
event.preventDefault()
console.log(formData)
try {
await axios
.post(`http://localhost:4000/accounts/register`, formData)
.then(function (response) {
console.log(response)
console.log(response.data)
setServerMessage(response.data)
})
} catch (error) {
console.log(error)
}
history({
pathname: '/session/verifyotp',
state: { serverMessage: serverMessage.message },
})
}
The second component where I am trying to access the state.
const navigate = useNavigate()
let data = useLocation()
console.log(data)
I have tried to log the current state value in the console using this:
useEffect(() => {
console.log(serverMessage)
}, [serverMessage])
I have tried to set the state in useffect like this:
useEffect(() => {
setServerMessage(serverMessage)
}, [serverMessage])
The output I am getting in the browser console is:
Object { pathname: "/session/verifyotp", search: "", hash: "", state: null, key: "n1jhatdj" }
This is the complete code in the page :
import React, { useEffect, useState } from 'react'
import { Box, styled } from '#mui/system'
import { Grid, Button } from '#mui/material'
import { ValidatorForm, TextValidator } from 'react-material-ui-form-validator'
import Typography from '#mui/material/Typography'
import { FormLabel } from '#mui/material'
import Link from '#mui/material/Link'
import axios from 'axios'
import Appbar from '../Appbar'
import Alert from '#mui/material/Alert'
import Snackbar from '#mui/material/Snackbar'
import { useNavigate } from 'react-router-dom'
const FlexBox = styled(Box)(() => ({
display: 'flex',
alignItems: 'center',
}))
const JustifyBox = styled(FlexBox)(() => ({
justifyContent: 'center',
}))
const IMG = styled('img')(() => ({
width: '100%',
}))
const JWTRegister = styled(JustifyBox)(() => ({
background: '#ffffff',
minHeight: '100vh !important',
input: {
background: 'white',
borderRadius: 25,
},
}))
const JwtRegister = (props) => {
const [serverMessage, setServerMessage] = useState('')
const [open, setOpen] = useState(false)
const history = useNavigate()
const [formData, setFormData] = useState({
name: '',
mobile: '',
email: '',
password: '',
})
const handleClick = () => {
setOpen(true)
}
const handleClose = (event, reason) => {
if (reason === 'clickaway') {
return
}
setOpen(false)
}
const { name, mobile, email, password } = formData
const handleChange = (event) => {
setFormData({
...formData,
[event.target.name]: event.target.value,
})
}
const handleFormSubmit = async (event) => {
event.preventDefault()
console.log(formData)
try {
await axios
.post(`http://localhost:4000/accounts/register`, formData)
.then(function (response) {
console.log(response)
console.log(response.data)
const newValue = response.data
setServerMessage(newValue)
})
} catch (error) {
console.log(error)
}
history({
pathname: '/session/verifyotp',
state: { serverMessage: serverMessage },
})
}
useEffect(() => {
console.log(serverMessage)
setServerMessage(serverMessage)
console.log(serverMessage)
}, [serverMessage])
return (
<JWTRegister>
<Grid container>
<Appbar />
<Grid
pt={0}
pl={10}
pr={10}
item
lg={6}
md={6}
sm={6}
xs={12}
sx={{ height: '100vh', backgroundColor: '#3E8BFF' }}
>
<Typography
component="h1"
variant="h3"
sx={{ textTransform: 'none', color: '#000' }}
>
Sign up
</Typography>
<Typography component="h1" variant="h5">
Register now to get 100 free credits
</Typography>
{serverMessage ? (
<>
<Alert
variant="filled"
autohideduration={6000}
severity="success"
>
{serverMessage.message}
</Alert>
<Snackbar
open={open}
autoHideDuration={3000}
onClose={handleClose}
>
<Alert
onClose={handleClose}
severity="success"
sx={{ width: '100%' }}
>
{serverMessage.message}
</Alert>
</Snackbar>
</>
) : null}
<ValidatorForm id="Register" onSubmit={handleFormSubmit}>
<Grid container spacing={2}>
<Grid
item
lg={6}
md={6}
sm={12}
xs={12}
sx={{ mt: 2 }}
>
<FormLabel sx={{ color: '#000000' }}>
Name
</FormLabel>
<TextValidator
sx={{ mb: 3, width: '100%' }}
size="small"
type="text"
name="name"
value={name}
autoFocus
onChange={handleChange}
validators={['required']}
errorMessages={['Name field is required']}
inputProps={{
style: {
borderRadius: 25,
backgroundColor: 'white',
disableUnderline: true,
},
}}
/>
</Grid>
<Grid
item
lg={6}
md={6}
sm={12}
xs={12}
sx={{ mt: 2 }}
>
<FormLabel sx={{ color: '#000000' }}>
Mobile
</FormLabel>
<TextValidator
sx={{ mb: 3, width: '100%' }}
size="small"
type="text"
name="mobile"
value={mobile}
onChange={handleChange}
validators={['required']}
errorMessages={[
'Mobile Number field is required',
]}
inputProps={{
style: {
borderRadius: 25,
backgroundColor: 'white',
disableUnderline: true,
},
}}
/>
</Grid>
</Grid>
<FormLabel sx={{ color: '#000000' }}>Email</FormLabel>
<TextValidator
sx={{ mb: 3, width: '100%' }}
size="small"
type="email"
name="email"
value={email}
onChange={handleChange}
validators={['required', 'isEmail']}
inputProps={{
style: {
borderRadius: 25,
backgroundColor: 'white',
disableUnderline: true,
},
}}
errorMessages={[
'Email field is required',
'Email is not valid',
]}
/>
<FormLabel sx={{ color: '#000000' }}>
Password
</FormLabel>
<TextValidator
sx={{ mb: '16px', width: '100%' }}
size="small"
name="password"
type="password"
value={password}
onChange={handleChange}
validators={['required']}
errorMessages={['Password field is required']}
inputProps={{
style: {
borderRadius: 25,
disableUnderline: true,
backgroundColor: 'white',
},
}}
/>
<FlexBox pb={2}>
<Button
type="submit"
variant="contained"
sx={{
borderRadius: 25,
textTransform: 'none',
background: '#C7FF80',
color: '#000000',
}}
onClick={handleClick}
>
Verify OTP
</Button>
</FlexBox>
</ValidatorForm>
<Typography
variant="subtitle1"
display="inline"
sx={{
textTransform: 'none',
color: '#000000',
}}
>
Already a member?
<Link
href="/session/signin"
sx={{
textTransform: 'none',
color: '#FFFFFF',
}}
>
Sign in
</Link>
instead.
</Typography>
</Grid>
<Grid
pt={1}
pl={10}
item
lg={6}
md={6}
sm={6}
xs={12}
sx={{ height: '100vh', backgroundColor: '#3E8BFF' }}
>
<Typography pb={3} variant="body">
or sign up with
</Typography>
<Grid
pb={3}
pt={3}
container
alignItems="center"
spacing={2}
>
<Grid item>
<IMG
src="/assets/images/signup-linkedin.svg"
height={55}
width={55}
/>
</Grid>
<Grid item>
<Typography pb={1} component="h6" variant="h6">
Linkedin
</Typography>
</Grid>
</Grid>
<Grid pb={3} container alignItems="center" spacing={2}>
<Grid item>
<IMG
src="/assets/images/signup-google.svg"
height={55}
width={55}
/>
</Grid>
<Grid item>
<Typography pb={1} component="h6" variant="h6">
Google
</Typography>
</Grid>
</Grid>
<Grid pb={3} container alignItems="center" spacing={2}>
<Grid item>
<IMG
src="/assets/images/signup-facebook.svg"
height={55}
width={55}
/>
</Grid>
<Grid item>
<Typography pb={1} component="h6" variant="h6">
Facebook
</Typography>
</Grid>
</Grid>
<Grid pb={3} container alignItems="center" spacing={2}>
<Grid item>
<IMG
src="/assets/images/signup-email.svg"
height={55}
width={55}
/>
</Grid>
<Grid item>
<Typography component="h6" variant="h6">
Corporate Email ID
</Typography>
<span pb={1} component="h6" variant="h6">
(Use only Business email)
</span>
</Grid>
</Grid>
</Grid>
</Grid>
</JWTRegister>
)
}
export default JwtRegister
No matter what I try I am not able to pass the state to the different component. I have followed this question but does not solve my problem.
How can I access the state value? Why is it coming as null?
I have found the answer to this question. react-router v6 In You need to use your history like this for react-router v6.
This is not the right way to pass state:
history({
pathname: '/session/verifyotp',
state: { serverMessage: serverMessage.message },
})
Correct way to pass state in react-router v6 is the following:
history("/session/verifyotp", {
state: { serverMessage: serverMessage },
});
Hello I want to know how do you change the zAxis of a paper from MUI
As you can see the carousel overlaps my menu and I would like my menu to be on top of everything.
This is how I have it wrapped:
<Box sx={{ background: '#272A31', flexGrow: 0, display: { xs: 'none', md: 'flex' } }}>
<StyledIconButton size="small" edge="start" color="inherit" aria-label="menu" sx={{ mr: 2 }} onClick={handleToggle} ref={anchorRef} >
<GamesIcon />
<Typography variant="h6" component="div" sx={{ flexGrow: 1 }}> GAMES </Typography>
<Popper open={open} anchorEl={anchorRef.current} role={undefined} placement="bottom-start" transition disablePortal >
{({ TransitionProps, placement }) => (
<Grow {...TransitionProps}
style={{
transformOrigin: placement === 'bottom-start' ? 'left top' : 'left bottom',
}}
>
<StyledPaper sx = {{zIndex: 1600}} >
<ClickAwayListener onClickAway={handleClose}>
<MenuList autoFocusItem={open} id="composition-menu" aria-labelledby="composition-button" onKeyDown={handleListKeyDown}>
<StyledMenuItem onClick={handleClose}>JUNGLE RAIDER</StyledMenuItem>
<StyledMenuItem onClick={handleClose}>MEGAMAN TEMPLATE</StyledMenuItem>
<StyledMenuItem onClick={handleClose}>TOWER DEFENSE</StyledMenuItem>
<StyledMenuItem onClick={handleClose}>BLADES AND DUNGEON</StyledMenuItem>
<StyledMenuItem onClick={handleClose}>FIXSPACE</StyledMenuItem>
</MenuList>
</ClickAwayListener>
</StyledPaper>
</Grow>
)}
</Popper>
</StyledIconButton>
</Box>
While my Carousel is wraped in the following way:
<Box mb = {2} mt = {2} sx={{display: 'flex', justifyContent: 'center', alignItems: 'center', zIndex: -1}}>
<Card sx={{ width: 1500, backgroundColor: "transparent"}} >
<Carousel fullHeightHover={false} navButtonsAlwaysVisible={true} duration={500} animation="slide"
navButtonsProps={{
style: {
backgroundColor: '#FF5917',
borderRadius: 0,
}
}} >
{items.map( (item, i) => <Item key={i} item={item} />)}
</Carousel>
</Card>
</Box>
Even though the paper is at z-(1600) and the carousel box at z-(-1) it still overlaps the paper for some reason
https://mui.com/customization/z-index/ check this link. tooptip has highest zindex value. you can add it to your popper
I want to render Material UI Elements like MenuItem of a AppBar Conditionally if some conditions are true. In my example menu items should only be rendered for specific users. But it doesnt work like the way it would work with normal html in react.
{context.token && context.userRole === "USER" && (
<MenuItem key="submission" onClick={handleCloseNavMenu}>
<Typography textAlign="center">Submission</Typography>
</MenuItem>
)}
{context.token && context.userRole === "JUDGE" && (
<MenuItem key="submissions" onClick={handleCloseNavMenu}>
<Typography textAlign="center">Submissions</Typography>
</MenuItem>
)}
Its rendering this Items all the time anyways and seems to ignoring the conditions.
The full code:
import React from "react";
import { NavLink } from "react-router-dom";
import AuthContext from "../context/auth-context.js";
import AppBar from "#mui/material/AppBar";
import Box from "#mui/material/Box";
import Toolbar from "#mui/material/Toolbar";
import IconButton from "#mui/material/IconButton";
import Typography from "#mui/material/Typography";
import Menu from "#mui/material/Menu";
import MenuIcon from "#mui/icons-material/Menu";
import Container from "#mui/material/Container";
import Avatar from "#mui/material/Avatar";
import Button from "#mui/material/Button";
import Tooltip from "#mui/material/Tooltip";
import MenuItem from "#mui/material/MenuItem";
import ComputerIcon from "#mui/icons-material/Computer";
const ResponsiveAppBar = (props) => {
const pages = ["Conditions", "Winner", "Submission", "Submissions", "Login"];
const settings = ["Profile", "Settings", "Logout"];
const [anchorElNav, setAnchorElNav] = React.useState(null);
const [anchorElUser, setAnchorElUser] = React.useState(null);
const handleOpenNavMenu = (event) => {
setAnchorElNav(event.currentTarget);
};
const handleOpenUserMenu = (event) => {
setAnchorElUser(event.currentTarget);
};
const handleCloseNavMenu = () => {
setAnchorElNav(null);
};
const handleCloseUserMenu = () => {
setAnchorElUser(null);
};
return (
<AuthContext.Consumer>
{(context) => (
<AppBar position="static">
<Container maxWidth="xl">
<Toolbar disableGutters>
<Typography
variant="h6"
noWrap
component="div"
sx={{ mr: 2, display: { xs: "none", md: "flex" } }}
>
<ComputerIcon />
</Typography>
<Box sx={{ flexGrow: 1, display: { xs: "flex", md: "none" } }}>
<IconButton
size="large"
aria-label="account of current user"
aria-controls="menu-appbar"
aria-haspopup="true"
onClick={handleOpenNavMenu}
color="inherit"
>
<MenuIcon />
</IconButton>
<Menu
id="menu-appbar"
anchorEl={anchorElNav}
anchorOrigin={{
vertical: "bottom",
horizontal: "left",
}}
keepMounted
transformOrigin={{
vertical: "top",
horizontal: "left",
}}
open={Boolean(anchorElNav)}
onClose={handleCloseNavMenu}
sx={{
display: { xs: "block", md: "none" },
}}
>
{context.token && context.userRole === "USER" && (
<MenuItem key="submission" onClick={handleCloseNavMenu}>
<Typography textAlign="center">Submission</Typography>
</MenuItem>
)}
{context.token && context.userRole === "JUDGE" && (
<MenuItem key="submissions" onClick={handleCloseNavMenu}>
<Typography textAlign="center">Submissions</Typography>
</MenuItem>
)}
<MenuItem key="conditions" onClick={handleCloseNavMenu}>
<Typography textAlign="center">Conditions</Typography>
</MenuItem>
<MenuItem key="winner" onClick={handleCloseNavMenu}>
<Typography textAlign="center">Winner</Typography>
</MenuItem>
</Menu>
</Box>
<Typography
variant="h6"
noWrap
component="div"
sx={{ flexGrow: 1, display: { xs: "flex", md: "none" } }}
>
LOGO
</Typography>
<Box sx={{ flexGrow: 1, display: { xs: "none", md: "flex" } }}>
{pages.map((page) => (
<Button
key={page}
onClick={handleCloseNavMenu}
sx={{ my: 2, color: "white", display: "block" }}
>
{page}
</Button>
))}
</Box>
<Box sx={{ flexGrow: 0 }}>
<Tooltip title="Open settings">
<IconButton onClick={handleOpenUserMenu} sx={{ p: 0 }}>
<Avatar
alt="Remy Sharp"
src="/static/images/avatar/2.jpg"
/>
</IconButton>
</Tooltip>
<Menu
sx={{ mt: "45px" }}
id="menu-appbar"
anchorEl={anchorElUser}
anchorOrigin={{
vertical: "top",
horizontal: "right",
}}
keepMounted
transformOrigin={{
vertical: "top",
horizontal: "right",
}}
open={Boolean(anchorElUser)}
onClose={handleCloseUserMenu}
>
{settings.map((setting) => (
<MenuItem key={setting} onClick={handleCloseNavMenu}>
<Typography textAlign="center">{setting}</Typography>
</MenuItem>
))}
</Menu>
</Box>
</Toolbar>
</Container>
</AppBar>
)}
</AuthContext.Consumer>
);
};
export default ResponsiveAppBar;
How to split material-ui toolbar into left and right part. For example, this is my toolbar
let EnhancedTableToolbar = props => {
const { numSelected, classes ,deletefunc} = props;
return (
<Toolbar
className={classNames(classes.root, {
[classes.highlight]: numSelected > 0,
})}
>
<div className={classes.title}>
{numSelected > 0 ? (
<Typography color="inherit" variant="subtitle1">
{numSelected} selected
</Typography>
) : (
<Typography variant="h6" id="tableTitle">
User List
</Typography>
)}
</div>
<div className={classes.actions}>
{numSelected > 0 ? (
<div >
<div style={{ display: 'inline-block' }}>
<Tooltip title="Delete">
<IconButton aria-label="Delete">
<DeleteIcon onClick={() => { if (window.confirm('Are you sure you wish to delete '+numSelected +' item?')) {deletefunc()} } }>
</DeleteIcon>
</IconButton>
</Tooltip>
</div>
<div style={{ display: 'inline-block' }}>
<Tooltip title="Edit">
<IconButton aria-label="Edit">
<EditIcon>
</EditIcon>
</IconButton>
</Tooltip>
</div>
</div>
) : (
<Tooltip title="Filter list">
<IconButton aria-label="Filter list">
<FilterListIcon />
</IconButton>
</Tooltip>
)}
</div>
</Toolbar>
);
};
I want to show the numSelected in my left side of toolbar and the delete button and edit button at my right side of toolbar. However, my example output show the delete button and edit button just beside the numSelected. Anyone has any solution regarding this issue?
The solution is add
flex: '0 0 auto'
in my actions class and a
<div className={classes.spacer}>
between title class and action class.
This is how I setup spacer, title and action classes.
const toolbarStyles = theme => ({
root: {
paddingRight: theme.spacing.unit,
},
highlight:
theme.palette.type === 'light'
? {
color: theme.palette.secondary.main,
backgroundColor: lighten(theme.palette.secondary.light, 0.85),
}
: {
color: theme.palette.text.primary,
backgroundColor: theme.palette.secondary.dark,
},
spacer: {
flex: '1 1 100%',
},
actions: {
color: theme.palette.text.secondary,
flex: '0 0 auto',
},
title: {
flex: '0 0 auto',
},
});