Conditionally Rendering Material UI Elements in React - javascript

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;

Related

i wan to get timely divided number of slot in reactjs

i just create this timepicker using mui and momentjs. 2 timepicker, one input, and one button, when user selects particular time like in first picker 8:am and in second one is 9:00am, and enter the slot like 6 so output will be 8:00-8:10, 8:10-8:20, 8:20 - 8:30, 8:40 - 8:50, 8:50 - 9:00. i am done with this to think about logic.
import * as React from "react";
import TextField from "#mui/material/TextField";
import { AdapterDateFns } from "#mui/x-date-pickers/AdapterDateFns";
import { LocalizationProvider } from "#mui/x-date-pickers/LocalizationProvider";
import { TimePicker } from "#mui/x-date-pickers/TimePicker";
import { Box } from "#mui/system";
import moment from "moment";
import { Button, Grid } from "#mui/material";
import Paper from "#mui/material/Paper";
export default function BasicDatePicker() {
const [startTime, setStartTime] = React.useState([]);
const [endTime, setEndTime] = React.useState([]);
return (
<Box
component="main"
sx={{ flexGrow: 1, p: 3 }}
style={{ marginTop: "100px" }}
>
<LocalizationProvider
dateAdapter={AdapterDateFns}
sx={{ flexGrow: 1, p: 3 }}
>
<Box
sx={{
display: "flex",
flexWrap: "wrap",
"& > :not(style)": {
m: "0 auto",
width: 300,
height: 350,
},
}}
>
<Paper elevation={3}>
<Grid container>
<Grid item xs={12} style={{ margin: "25px" }}>
<TimePicker
label="Start Time"
value={startTime}
onChange={(newValue) => {
setStartTime(newValue);
// setStartTime(moment(newValue).add(1, "days"));
// console.log(newValue)
}}
renderInput={(params) => <TextField {...params} />}
/>
</Grid>
<Grid item xs={12} style={{ margin: "25px" }}>
<TimePicker label="End Time"
// disabled
value={endTime}
onChange={(newValue) => {
setEndTime(newValue);
}}
renderInput={(params) => <TextField {...params} />}
/>
</Grid>
<Grid item xs={12} style={{ textAlign: "center" , }}>
{" "}
<TextField id="outlined-basic" label="Slot" variant="outlined"/>
</Grid>
<Grid item xs={12} style={{ textAlign: "center", margin: "10px" }}>
{" "}
<Button variant="contained">Action</Button>
</Grid>
</Grid>
</Paper>
</Box>
</LocalizationProvider>
</Box>
);
}
Here you can use this function, pass the moment objects to the function.
const today = moment();
const someday = moment().add(1,"h");
function getSlots(one, two){
const slots = [];
while(one.unix() < two.unix()){
const tmp = one;
const slot = `${tmp.format("h:mm")}-${one.add(10,"m").format("h:mm")}`;
}
return slots;
}
console.log(getSlots(today, someday,"10 min"));

How to declare one button in a react component and update the title of it in another?

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>
);
}

Using the Material UI App Bar and React Router

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
)}
...

How to align Material-UI Menu items?

I use the menu and menu item of material-ui to build a select dropdown menu, but I found one thing strange: the dropdown menu always expand to the left side of the box, as the image shown below:
I've tried to use the alignItems property inside my <MenuItem> but it didn't work.
My code is shown below. Can anybody help me to fix this problem? I really appreciate your help!
<Menu
id="order-menu"
anchorEl={anchorEl}
keepMounted
open={Boolean(anchorEl)}
onClose={() => setAnchorEl(null)}
>
{options.map((option, index) => (
<MenuItem
key={option}
selected={index === selectedIndex}
onClick={(event) => handleMenuItemClick(event, index)}
>
{option}
</MenuItem>
))}
</Menu>
The default styles controlling this are in ListItem where it specifies justifyContent: 'flex-start'.
You can change this to be right aligned with:
const MenuItem = withStyles({
root: {
justifyContent: "flex-end"
}
})(MuiMenuItem);
Here's a full working example:
import React from "react";
import Button from "#material-ui/core/Button";
import Menu from "#material-ui/core/Menu";
import MuiMenuItem from "#material-ui/core/MenuItem";
import { withStyles } from "#material-ui/core/styles";
const MenuItem = withStyles({
root: {
justifyContent: "flex-end"
}
})(MuiMenuItem);
export default function SimpleMenu() {
const [anchorEl, setAnchorEl] = React.useState(null);
const handleClick = event => {
setAnchorEl(event.currentTarget);
};
const handleClose = () => {
setAnchorEl(null);
};
return (
<div>
<Button
aria-controls="simple-menu"
aria-haspopup="true"
onClick={handleClick}
>
Open Menu
</Button>
<Menu
id="simple-menu"
anchorEl={anchorEl}
keepMounted
open={Boolean(anchorEl)}
onClose={handleClose}
>
<MenuItem onClick={handleClose}>1</MenuItem>
<MenuItem onClick={handleClose}>2</MenuItem>
<MenuItem onClick={handleClose}>3</MenuItem>
<MenuItem onClick={handleClose}>10</MenuItem>
<MenuItem onClick={handleClose}>20</MenuItem>
<MenuItem onClick={handleClose}>300</MenuItem>
</Menu>
</div>
);
}
Related documentation:
https://developer.mozilla.org/en-US/docs/Web/CSS/justify-content
https://css-tricks.com/snippets/css/a-guide-to-flexbox/
A more flexible solution to your problem,
use <ListItemText> inside <MenuItem>
In this way you can style parts of the element.
<MenuItem onClick={handleClose}>
<ListItemText style={{ paddingRight: 50 }}>undo</ListItemText>
<ListItemText style={{ textAlign: "right" }}>ctrl+z</ListItemText>
</MenuItem>
example : shortcut hint on the right.
You can use this code to align the menu
anchorOrigin={{
vertical: 'bottom',
horizontal: 'center',
}}
transformOrigin={{
vertical: 'bottom',
horizontal: 'center',
}}
Example
<Menu
id="order-menu"
anchorEl={anchorEl}
keepMounted
open={Boolean(anchorEl)}
onClose={() => setAnchorEl(null)}
anchorOrigin={{
vertical: 'bottom',
horizontal: 'center',
}}
transformOrigin={{
vertical: 'bottom',
horizontal: 'center',
}}
style={{top: 170}} // you can set top position so that it will show under the selection
>
{options.map((option, index) => (
<MenuItem
key={option}
selected={index === selectedIndex}
onClick={(event) => handleMenuItemClick(event, index)}
>
{option}
</MenuItem>
))}
mui 5 could use sx.
<MenuItem sx={{ justifyContent: 'flex-end' }}>

How to position content perfectly within the left center of Paper component and remain that way on smaller devices?

I am putting together a component for my Goal Sharing social media app. This is what I have so far:
I'm trying to position the Avatar component as well as the two typography components beneath the Avatar component within the center of the left section of this Paper component. I have tried doing this by altering marginLeft and marginTop as you can see in the code below, but the issue when I do this is the components in this Goal component jumble on top of each other when I switch over to smaller devices. So, what's the best way to position these components in the center of the left section, and to ensure they remain that way on smaller devices?
This is the parent component file:
import React, { useEffect } from "react";
import Moment from "react-moment";
import PropTypes from "prop-types";
import { Link } from "react-router-dom";
import { connect } from "react-redux";
import { getGoals } from "../../actions/goal";
import Spinner from "../layout/Spinner";
import Navbar from "../dashboard/Navbar";
import ThumbUpAltIcon from "#material-ui/icons/ThumbUpAlt";
import ThumbDownAltIcon from "#material-ui/icons/ThumbDownAlt";
import ChatIcon from "#material-ui/icons/Chat";
import DeleteIcon from "#material-ui/icons/Delete";
import DoneIcon from "#material-ui/icons/Done";
import {
Typography,
Container,
CssBaseline,
makeStyles,
Grid,
Card,
Avatar,
CardContent,
CardActions
} from "#material-ui/core";
const useStyles = makeStyles(theme => ({
paper: {
marginTop: theme.spacing(8),
display: "flex",
flexDirection: "column",
alignItems: "center"
},
submit: {
margin: theme.spacing(2, 0, 2)
},
form: {
marginTop: theme.spacing(5)
},
cardGrid: {
paddingTop: theme.spacing(4),
paddingBottom: theme.spacing(4)
},
card: {
height: "100%",
display: "flex",
flexDirection: "column",
alignItems: "center"
},
cardContent: {
flexGrow: 1
},
profileHeader: {
textAlign: "center",
marginBottom: 10
},
avatar: {
width: theme.spacing(10),
height: theme.spacing(10),
marginLeft: "2.5vw",
marginTop: "5vh"
},
name: {
textAlign: "center",
marginLeft: "2vw"
},
goalText: {
marginTop: "5vh",
marginLeft: "3vw"
},
postedOn: {
marginLeft: "2vw"
}
}));
const Goals = ({ getGoals, auth, goal: { goals, user, loading } }) => {
useEffect(() => {
getGoals();
}, [getGoals]);
const classes = useStyles();
return loading ? (
<>
<Navbar />
<Container component="main" maxWidth="xs">
<CssBaseline />
<div className={classes.paper}>
<Spinner />
</div>
</Container>
</>
) : (
<>
<CssBaseline />
<Navbar />
<main>
<Container className={classes.cardGrid} maxWidth="md">
<Typography variant="h2" className={classes.profileHeader}>
Goals
</Typography>
<Grid container spacing={4}>
{goals.map(singleGoal => (
<Grid item key={singleGoal._id} xs={12}>
<Card fullwidth="true" className={classes.card}>
<Grid container spacing={2}>
<Grid item>
<Avatar
className={classes.avatar}
src={singleGoal.avatar}
/>
<Typography variant="subtitle2" className={classes.name}>
{singleGoal.first_name} {singleGoal.last_name}
</Typography>
<Typography
variant="caption"
className={classes.postedOn}
>
Posted on{" "}
<Moment format="MM/DD/YYYY">{singleGoal.date}</Moment>
</Typography>
</Grid>
<Grid item xs={12} sm container>
<Grid item xs container direction="column" spacing={2}>
<Grid item xs>
<Typography
className={classes.goalText}
variant="body1"
gutterBottom
>
{singleGoal.text}
</Typography>
<Typography variant="h5"></Typography>
</Grid>
</Grid>
</Grid>
</Grid>
<CardContent className={classes.cardContent}></CardContent>
<CardActions>
<ThumbUpAltIcon />
<Typography variant="caption">
{singleGoal.likes.length}
</Typography>
<ThumbDownAltIcon />
<Link to={`/goal/${singleGoal.user}`}>
<ChatIcon />
</Link>
<Typography variant="caption">
{singleGoal.comments.length}
</Typography>
{!auth.loading && singleGoal.user === auth.user._id && (
<DoneIcon />
)}
{!auth.loading && singleGoal.user === auth.user._id && (
<DeleteIcon />
)}
</CardActions>
</Card>
</Grid>
))}
</Grid>
</Container>
</main>
</>
);
};
Goals.propTypes = {
getGoals: PropTypes.func.isRequired,
goal: PropTypes.object.isRequired
};
const mapStateToProps = state => ({
goal: state.goal,
auth: state.auth
});
export default connect(mapStateToProps, { getGoals })(Goals);
Try this
card: {
height: "100%",
display: "flex",
flexDirection: "column",
alignItems: "center",
justifyContent: "center"
},

Categories

Resources