React hide sidebar on mobile and show on big screen - javascript

I got a Sidebar from MaterialUI and I want it to hide on mobile screen, but if you click on the menu icon it should be visible and on big screens it should be visible by default, if you click on the menu icon it should close. I would like to use the library "react-responsive" for this, but I don't understand how to use it.
Sidebar.js
// ...imports and styles..
export const SideBar = ({ open }) => {
const history = useHistory();
return (
<StyledSideBar variant="permanent" open={open}>
<ModuleButton onClick={() => history.push('/dashboard')}>
<Tooltip title="Dashdoard" placement="right" arrow >
<FontAwesomeIcon icon={faTachometerAltFast} />
</Tooltip >
</ModuleButton>
<ModuleButton onClick={() => history.push('/chat')}>
<Tooltip title="Chat" placement="right" arrow>
<FontAwesomeIcon icon={faCommentsAlt} />
</Tooltip>
</ModuleButton>
<ModuleButton onClick={() => history.push('/calendar')}>
<Tooltip title="Calendar" placement="right" arrow>
<FontAwesomeIcon icon={faCalendarAlt} />
</Tooltip>
</ModuleButton>
</StyledSideBar>
);
}
export default SideBar;
MainPage.js
...imports and styles...
export const MainPage = () => {
const dispatch = useDispatch();
const onLogout = () => dispatch(logout());
const [showSidebar, setShowSidebar] = useState(false);
const onToggleSidebar = () => {
setShowSidebar(!showSidebar);
};
const isDesktopOrLaptop = useMediaQuery({
query: '(min-device-width: 1224px)'
})
const isTabletOrMobileDevice = useMediaQuery({
query: '(max-device-width: 1224px)'
})
return (
<>
<MainHeader onLogout={onLogout} onToggleSidebar={onToggleSidebar} />
{isDesktopOrLaptop &&
<SideBar open={showSidebar} />
}
{isTabletOrMobileDevice &&
<SmSideBar open={showSidebar} />
}
<Container>
<BrowserRouter>
<Route path="*" exact component={MainContent} />
</BrowserRouter>
</Container>
</>
);
}
export default authGuardFactory(Redirect)(emailGuardFactory(Redirect)(MainPage));
SmSideBar.js
...import and styles...
export const SmSideBar = ({ open }) => {
const history = useHistory();
return (
<StyledSideBar variant="persistent" open={open} >
<ModuleButton onClick={() => history.push('/dashboard')}>
<Tooltip title="Dashdoard" placement="right" arrow >
<FontAwesomeIcon icon={faTachometerAltFast} />
</Tooltip >
</ModuleButton>
<ModuleButton onClick={() => history.push('/chat')}>
<Tooltip title="Chat" placement="right" arrow>
<FontAwesomeIcon icon={faCommentsAlt} />
</Tooltip>
</ModuleButton>
<ModuleButton onClick={() => history.push('/calendar')}>
<Tooltip title="Calendar" placement="right" arrow>
<FontAwesomeIcon icon={faCalendarAlt} />
</Tooltip>
</ModuleButton>
</StyledSideBar>
);
}
export default SmSideBar;
I tried to add another Sidebar only for Tablet and Mobile, but it dont work.
The only difference between the two is the variant.

I solved the Problem with methods by using react-responsive library and js Breakpoints.
MainPage.js
export const MainPage = ( { match }) => {
const dispatch = useDispatch();
const onLogout = () => dispatch(logout());
const onSizeChange = (matches) => {
setShowSidebar(matches);
}
const isDesktopOrLaptop = useMediaQuery(breakpoints.MAndUp, undefined, onSizeChange)
const [showSidebar, setShowSidebar] = useState(isDesktopOrLaptop);
const onToggleSidebar = () => {
setShowSidebar(!showSidebar);
};
Now everything works fine :)

Related

Show modal window without button press in react

I am doing a project and I want to show a modal window to compulsorily accept some Cookies.
I need that cookie window to be launched automatically, without pressing any button, when the application starts, that is, before the dashboard is loaded.
This is my code:
ModalCookie.js
imports ...
const style = {
position: 'absolute',
top: '50%',
left: '50%',
};
export default function CookiesModal() {
const handleOpen = () => setOpen(true);
const [open, setOpen] = React.useState(false);
const handleClickOpen = () => {
setOpen(true);
};
const handleClose = () => {
setCookiesPreview(false);
setOpen(false);
};
const handleNotClose = (event, reason) => {
if (reason && reason == "backdropClick")
return;
}
const [value, setValue] = React.useState('1');
const handleChange = (event, newValue) => {
setValue(newValue);
};
return (
<ThemeProvider theme={theme}>
<div>
<Fade in={open}>
<Box>
<BootstrapDialog
onClose={handleNotClose}
aria-labelledby="customized-dialog-title"
open={open}
closeAfterTransition
BackdropComponent={Backdrop}
BackdropProps={{
timeout: 500,
}}
>
<BootstrapDialogTitle id="customized-dialog-title" onClose={handleClose}>
</BootstrapDialogTitle>
<TabContext value={value}>
<Box sx={{ borderBottom: 1, borderColor: 'divider' }}>
<TabList onChange={handleChange} aria-label="lab API tabs example">
<Tab
label="AAAAA"
value="1" />
</TabList>
</Box>
<TabPanel value="1">
<p>...</p>
</TabPanel>
</TabContext>
<Button
onClick={handleClose}
variant="contained"
color="secondary"
>
Aceptar
</Button>
</BootstrapDialog>
</Box>
</Fade>
</div>
</ThemeProvider>
);
}
Config.js
// COOKIES
export const setCookiesPreview = ( state ) => {
localStorage.setItem('cookiesPreview', state)
}
// --
export const isCookiesPreview = () => {
const active=localStorage.getItem('cookiesPreview') ? localStorage.getItem('cookiesPreview') : true;
setCookiesPreview(false);
return(
active
);
}
And my dashboard:
imports...
// MAIN
export const Dashboard = () => {
const state = useSelector( state => state);
console.log('isCookiesPreview='+isCookiesPreview());
if(isCookiesPreview()){
console.log('CookiesPreview ON ------------------------------------------------')
setTimeout(() => {
CookiesModal.handleOpen();
}, 15000);
}
return (
<>
<ThemeProvider theme={theme}>
<div>
<HeaderBar/>
{(alertMessage != null) && (alertMessage.length>0) ? <Alert severity={alertSeverity}>{alertMessage}</Alert> : <></>}
<Grid container item={true} xs={12}>
<BodyGrid/>
</Grid>
<Grid container item={true} xs={12} pt={4}>
<BottomBar/>
</Grid>
</div>
</ThemeProvider>
</>
)
I am trying to use the handleOpen() constant from ModalCookie.js to open the window from Dashboard.js and save the locale that those cookies have been accepted so as not to show it the following times
I can't get the window to show up, but it does show me the logs I've put on the Dashboard related to cookies.
It tells me that HandleOpen is not a function.

How to toggle Sidebar Component in Header with a Burger Menu using Hooks in React

I am very new in React and maybe someone could help me.
I want to toggle my Sidebar in my Header Component with Hooks.
This is my Code:
Sidebar.js
...imported things
...styles
export const SideBar = () => {
const history = useHistory();
return (
<StyledSideBar>
<Tooltip title="Dashboard" placement="right" arrow >
<StyledButton onClick={() => history.push('/dashboard')}>
<FontAwesomeIcon icon={faTachometerAltFast} />
</StyledButton>
</Tooltip >
<Tooltip title="Chat" placement="right" arrow>
<StyledButton onClick={() => history.push('/chat')}>
<FontAwesomeIcon icon={faCommentsAlt} />
</StyledButton>
</Tooltip>
<Tooltip title="Calendar" placement="right" arrow>
<StyledButton onClick={() => history.push('/calendar')}>
<FontAwesomeIcon icon={faCalendarAlt} />
</StyledButton>
</Tooltip>
</StyledSideBar>
);
}
export default SideBar;
Header.js
...imported things
...styles
import SideBar from '../sidebar';
export const MainHeader = () => {
const [show, setShow] = React.useState(false);
const toggle = () => setShow(!show);
return (
<AppBar elevation={2} position="sticky" color="inherit" >
<FlexToolbar variant="regular">
<StyledMenuIcon open={show} onClick={toggle.{SideBar}>
<FontAwesomeIcon icon={faBars} />
</StyledMenuIcon>
<Logo src="/assets/images/logo.svg" alt="Vetera Sky" />
<BreakpointLogo src="/assets/images/get-started-icon.svg" alt="Vetera Sky" />
<Spacer />
<LogoutButton onClick={onLogout}>
<FontAwesomeIcon icon={faPowerOff} />
<Typography variant="label" color={actionSecondary}>Logout</Typography>
</LogoutButton>
<BreakpointLogoutButton onClick={onLogout}>
<FontAwesomeIcon icon={faPowerOff} />
</BreakpointLogoutButton>
</FlexToolbar>
</AppBar>
)};
export default MainHeader;
I know this is wrong, but i could not find anything in the Web or in here.
If the StyledMenuIcon is clicked once, the Sidebar should open on the left and if clicked again it should close.
Hope someone can help me soon :)
You should move your state higher up in the tree where both MainHeader and SideBar components can use it:
function App() {
const [showSidebar, setShowSidebar] = useState(false);
const onToggleSidebar = () => {
setShowSidebar(!showSidebar);
};
return (
<MainHeader onToggleSidebar={onToggleSidebar} />
<SideBar open={showSidebar}
);
}
If the components aren't available on the same level in the tree, you could use React's context api to use this logic from different places down the tree.
Or if you're already using something like redux or another state management system you could move your app state there.

React Material UI + React Router >>>> I cannot use Redirect inside a onClick function in a button

I am trying to trigger the Redirect React Dom
that is my button component in the handleMenuItemClick() function. But nothing happens.
I have tried a bunch of stuff but but still no success.
How can I make the both work together? My best try was to make a function that return the Redirect component as I saw in one post around, but still no success.
My Code:
import React from 'react';
import { Route, Redirect } from 'react-router-dom';
import { Grid, Button, ButtonGroup, ArrowDropDownIcon, ClickAwayListener, Grow, Paper, Popper, MenuItem, MenuList, Link } from '#material-ui/core/Grid';
const SplitButton = (props) => {
const [open, setOpen] = React.useState(false);
const anchorRef = React.useRef(null);
const [selectedIndex, setSelectedIndex] = React.useState(1);
const myGroups = props.myGroups
const handleMenuItemClick = (event, index) => {
setSelectedIndex(index);
setOpen(false);
return <Redirect to={`/groups/${index}`} />
};
const handleToggle = () => {
setOpen((prevOpen) => !prevOpen);
};
const handleClose = (event) => {
if (anchorRef.current && anchorRef.current.contains(event.target)) {
return;
}
setOpen(false);
};
return (
<>
<ButtonGroup variant="contained" color="primary" ref={anchorRef} aria-label="split button">
<Button onClick={null}>My Groups</Button>
<Button
color="primary"
size="small"
aria-controls={open ? 'split-button-menu' : undefined}
aria-expanded={open ? 'true' : undefined}
aria-label="select merge strategy"
aria-haspopup="menu"
onClick={handleToggle}
>
<ArrowDropDownIcon />
</Button>
</ButtonGroup>
<Popper open={open} anchorEl={anchorRef.current} role={undefined} transition disablePortal>
{({ TransitionProps, placement }) => (
<Grow
{...TransitionProps}
style={{
transformOrigin: placement === 'bottom' ? 'center top' : 'center bottom',
}}
>
<Paper>
<ClickAwayListener onClickAway={handleClose}>
<MenuList id="split-button-menu">
{ myGroups.map((group) => (
<MenuItem
key={group.id}
onClick={(event) => handleMenuItemClick(event, group.id)}
>
{group.title}
</MenuItem>
))}
</MenuList>
</ClickAwayListener>
</Paper>
</Grow>
)}
</Popper>
</>
);
}
export default SplitButton
You can redirect user via 2 methods: useHistory or <Redirect />
useHistory hook
If you want to redirect the user directly on click, you can treat the code imperatively and tell React what to do:
const history = useHistory();
const handleMenuItemClick = (event, index) => {
setSelectedIndex(index);
setOpen(false);
history.push(`/groups/${index}`)
};
More info https://reactrouter.com/web/api/Hooks/usehistory
Redirect component
Or if you feel more comfortable using React's default declarative model, you can say what's changed and allow your code to react to this change:
const [redirectUrl, setRedirectUrl] = useState('')
const handleMenuItemClick = (event, index) => {
setSelectedIndex(index);
setOpen(false);
setRedirectUrl(`/groups/${index}`)
};
if (redirectUrl) {
return <Redirect to={redirectUrl} />
}
return (
<>
<ButtonGroup variant="contained" color="primary" ref={anchorRef} aria-label="split button">
<Button onClick={null}>My Groups</Button>
<Button
...
More info https://reactrouter.com/web/api/Redirect

Close material-ui popper when on clickAway

I have a material ui popper and I am trying to make it close when I click outside of the popper using
ClickAwayListener, but I cannot get this to work. I added the ClickAwayListener around the popper and tried adding it around the content in the popper but nothing seams to work.
I am really new to material-ui so I am a bit lost on how this should be done
This is my code
const Experiences = memo(
(props) => {
const { className } = props;
const classes = useStyles(props);
const [anchorEl, setAnchorEl] = React.useState(null);
const handleClick = (event) => {
setAnchorEl(event.currentTarget);
};
// const open = Boolean(anchorEl);
const handleClickAway = () => {
setAnchorEl(false);
};
const experience = (img, title, id, popoverCategory) => (
<div
className="experience"
aria-describedby={id}
id={id}
onClick={handleClick}
onKeyDown={handleClick}
role="button"
tabIndex="0"
>
<img
data-sizes="auto"
className="lazyload"
data-src={img}
alt={title}
/>
<div className="experience-title">
<Typography
color="textSecondary"
variant="subtitle2"
className="highlight highlight1"
display="inline"
>
{ title }
</Typography>
</div>
<ClickAwayListener onClickAway={handleClickAway}>
<Popper
id={id}
open={anchorEl && anchorEl.id === id}
anchorEl={anchorEl}
className={clsx(classes[id])}
modifiers={{
flip: {
enabled: false,
},
}}
>
<Button >x</Button>
<div className={clsx(classes.paper)}>
{
popoverCategory.map(url => (
<img
key={id}
data-sizes="auto"
className="lazyload"
src={url}
alt={title}
/>
))
}
</div>
</Popper>
</ClickAwayListener>
</div>
);
You may toggle your <Popper /> component visibility using the variable in the local state of the parent component and pass it down as a prop:
//dependencies
const { render } = ReactDOM,
{ useState } = React,
{ Popper, Button, Paper, ClickAwayListener } = MaterialUI
//custom popper
const MyPopper = ({isOpen,clickAwayHandler}) => (
<ClickAwayListener onClickAway={clickAwayHandler}>
<Popper open={isOpen}>
<Paper className="popper">There goes my custom popper</Paper>
</Popper>
</ClickAwayListener>
)
//main page
const MainPage = () => {
const [isOpen, setIsOpen] = useState(true),
clickAwayHandler = () => setIsOpen(false),
clickHandler = () => setIsOpen(true)
return (
<div>
<Button onClick={clickHandler}>Toggle pop-up</Button>
{
isOpen && <MyPopper {...{clickAwayHandler,isOpen}} />
}
</div>
)
}
//render
render (
<MainPage />,
document.getElementById('root')
)
.popper {
display: block;
position: relative;
top: 50px;
left: 100px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.12.0/umd/react.production.min.js"></script><script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.11.0/umd/react-dom.production.min.js"></script><script src="https://unpkg.com/#material-ui/core#latest/umd/material-ui.development.js"></script><div id="root"></div>
It is not working because por the Popper component is a Portal and with portals you have to use de ClickAwayListener in a small different way.
You can check the example at MUI documentation but the short summary is that the button that opens the popper has to be inside the ClickAwayListener too and you have to check if it's open before rendering the Popper.
const Experiences = memo(
(props) => {
const { className } = props;
const classes = useStyles(props);
const [anchorEl, setAnchorEl] = React.useState(null);
const handleClick = (event) => {
setAnchorEl(event.currentTarget);
};
const open = Boolean(anchorEl);
const handleClickAway = () => {
setAnchorEl(false);
};
const experience = (img, title, id, popoverCategory) => (
<ClickAwayListener onClickAway={handleClickAway}> // This wraps all
<div
className="experience"
aria-describedby={id}
id={id}
onClick={handleClick}
onKeyDown={handleClick}
role="button"
tabIndex="0"
>
<img
data-sizes="auto"
className="lazyload"
data-src={img}
alt={title}
/>
<div className="experience-title">
<Typography
color="textSecondary"
variant="subtitle2"
className="highlight highlight1"
display="inline"
>
{ title }
</Typography>
</div>
{open ? ( // You do the check here
<Popper
id={id}
open={anchorEl && anchorEl.id === id}
anchorEl={anchorEl}
className={clsx(classes[id])}
modifiers={{
flip: {
enabled: false,
},
}}
>
<Button >x</Button>
<div className={clsx(classes.paper)}>
{
popoverCategory.map(url => (
<img
key={id}
data-sizes="auto"
className="lazyload"
src={url}
alt={title}
/>
))
}
</div>
</Popper>
) : null}
</div>
</ClickAwayListener>
);
Perhaps MUI has created a new component that handles this for us since the time of this post.
Popover Component: https://mui.com/material-ui/react-popover/
It works similar to the Modal component that handles on click out for you.
Hope this helps.

Temporary Navigation bar not closing after clicking on a icon button reactjs

I created a navigation bar from the material-ui website and I have a onClick that when the user clicks the icon button the navigation will get redirected to a new page and I would like for the navigation to close afterwards. I'v tried different things, but for some reason it will not close.
The only thing that it does now is gets redirected to a new page and the navigation drawer continues to stay open.
I have a a function called handleDrawerClose() that closes the drawer, a const called navigation that creates the text and components and I created a const called handleNavigation that pushes the links, which makes the page redirect. Is there a way to call both of these someway. Thank you.
Below is my code:
const navigation = [
{ to: '/', text: 'Upload', Icon: InboxIcon },
{ to: '/email', text: 'Send', Icon: MailIcon }
]
const NavLinks = ({ links, onClick }) => {
const _onClick = to => () => onClick(to);
return (
<List>
{links.map(({ to, text, Icon }) => (
<ListItem key={to} button onClick={_onClick(to)}>
<ListItemIcon>
<Icon />
</ListItemIcon>
<ListItemText primary={text} />
</ListItem>
))}
</List>
)
}
const IconArrow = ({ onClick }) => {
return (
<IconButton onClick={onClick}>
<ChevronLeftIcon />
</IconButton>
)
}
export default withRouter(({ history }) => {
const classes = useStyles();
const [_, { logout }] = useAppAuth();
const [open, setOpen] = React.useState(false);
const [state, setState] = React.useState({
left: false,
});
function handleDrawerOpen() {
setOpen(true);
}
function handleDrawerClose() {
setOpen(false);
}
const handleNavigation = to => () => history.push(to);
return (
<Fragment>
<AppBar position='static'>
<Toolbar className={classes.toolbar}>
<IconButton
color='inherit'
edge='start'
aria-label='open menu drawer'
onClick={handleDrawerOpen}
>
<MenuIcon />
</IconButton>
<Link to='/'>
<img alt='Logo' src={logo} className={classes.image} />
</Link>
<Typography variant='h6' className={classes.title}>
{process.env.REACT_APP_NAME}
</Typography>
<Tooltip title='Logout'>
<Link to='/login'>
<IconButton onClick={logout} className={classes.logout}>
<LogoutIcon />
</IconButton>
</Link>
</Tooltip>
</Toolbar>
</AppBar>
<Drawer
className={classes.drawer}
variant='temporary'
anchor='left'
open={open}
>
<div className={classes.iconArrow}>
<IconArrow onClick={handleDrawerClose} />
</div>
<Divider />
<NavLinks
links={navigation}
onClick={() => handleNavigation}
/>
</Drawer>
</Fragment>
)
})
Why dont you just close it in the handler?
const handleNavigation = to => {
setOpen(false); // add this
history.push(to);
}

Categories