React.js - Drawer covers page conent - reactjs

I decided to implement Drawer component to my react project from material-ui library, like so:
class RightDrawer extends React.Component {
state = {
open: false,
};
handleDrawerOpen = () => {
this.setState({ open: true });
};
handleDrawerClose = () => {
this.setState({ open: false });
};
render() {
const { classes, children, theme } = this.props;
return (
<div className={classes.root}>
<AppBar
position="absolute"
className={classNames(classes.appBar, this.state.open && classes.appBarShift)}
>
<Toolbar disableGutters={!this.state.open}>
<IconButton
color="inherit"
aria-label="Open drawer"
onClick={this.handleDrawerOpen}
className={classNames(classes.menuButton, this.state.open && classes.hide)}
>
<MenuIcon />
</IconButton>
<Typography variant="title" color="inherit" noWrap>
Mini variant drawer
</Typography>
</Toolbar>
</AppBar>
<Drawer
variant="permanent"
classes={{
paper: classNames(classes.drawerPaper, !this.state.open && classes.drawerPaperClose),
}}
open={this.state.open}
>
<div className={classes.toolbar}>
<IconButton onClick={this.handleDrawerClose}>
{theme.direction === 'rtl' ? <ChevronRightIcon /> : <ChevronLeftIcon />}
</IconButton>
</div>
<Divider />
<List>{mailFolderListItems}</List>
</Drawer>
<main className={classes.content}>
<div className={classes.toolbar} />
{children}
</main>
</div>
);
}
}
RightDrawer.propTypes = {
classes: PropTypes.object.isRequired,
theme: PropTypes.object.isRequired,
};
export default withStyles(styles, { withTheme: true })(RightDrawer);
So I am wrapping all my components in RightDrawer component and simply inject them via {children}.
Final result is:
So it is cropped to like 1/3 of a page and when the table is filled:
Should I insert Drawer directly to App.js rather than wrapping every component inside? Maybe it is cause by className={classes.root} ?

The question description and code that you provide is not enough to answer this question.
As I found so far, If you want to have a full height drawer you might add height to your root class.
For example:
root: {
height: '100vh',
}

Related

Navigating to routes does not render page component in Next.js

I am very new to Next.js, and am trying to create a basic app where we have a header, and the header has 3 buttons clicking which the users should be redirected to the required route. The header should be present in all the pages, hence have put it in _app.js itself. Clicking on either of the 3 buttons does show a change in URL, but the component doesn't get rendered, and I am struggling to understand why that's happening. All the 3 files which we need to route to have been created under the 'pages' folder, and have their names set as expected.
The _app.js:
import Head from "next/head";
import Header from "./components/header";
function MyApp({ Component, pageProps }) {
return (
<>
<Head>
<title>GameZop Assignment</title>
<link rel="icon" href="/favicon.ico" />
</Head>
<Header />
</>
);
}
export default MyApp;
The header.js(from MUI):
const drawerWidth = 240;
const navItems = [
{ value: "users", label: "Users" },
{ value: "news", label: "News" },
{ value: "topUsers", label: "Top Users" },
];
function Header(props) {
const { window } = props;
const router = useRouter();
const [mobileOpen, setMobileOpen] = React.useState(false);
const showComponent = (comp) => {
router.push(`/${comp}`)
}
const handleDrawerToggle = () => {
setMobileOpen(!mobileOpen);
};
const drawer = (
<Box onClick={handleDrawerToggle} sx={{ textAlign: "center" }}>
<Typography variant="h6" sx={{ my: 2 }}>
MUI
</Typography>
<Divider />
<List>
{navItems.map((item) => (
<ListItem key={item.value} disablePadding>
<ListItemButton sx={{ textAlign: "center" }}>
<ListItemText primary={item.label} />
</ListItemButton>
</ListItem>
))}
</List>
</Box>
);
const container =
window !== undefined ? () => window().document.body : undefined;
return (
<Box sx={{ display: "flex" }}>
<AppBar component="nav">
<Toolbar>
<IconButton
color="inherit"
aria-label="open drawer"
edge="start"
onClick={handleDrawerToggle}
sx={{ mr: 2, display: { sm: "none" } }}
>
<MenuIcon />
</IconButton>
<Typography
variant="h6"
component="div"
sx={{ flexGrow: 1, display: { xs: "none", sm: "block" } }}
>
Assignment
</Typography>
<Box sx={{ display: { xs: "none", sm: "block" } }}>
{navItems.map((item) => (
<Button
key={item}
sx={{ color: "#fff" }}
onClick={() => showComponent(item.value)}
>
{item.label}
</Button>
))}
</Box>
</Toolbar>
</AppBar>
<Box component="nav">
<Drawer
container={container}
variant="temporary"
open={mobileOpen}
onClose={handleDrawerToggle}
ModalProps={{
keepMounted: true, // Better open performance on mobile.
}}
sx={{
display: { xs: "block", sm: "none" },
"& .MuiDrawer-paper": {
boxSizing: "border-box",
width: drawerWidth,
},
}}
>
{drawer}
</Drawer>
</Box>
</Box>
);
}
Header.propTypes = {
window: PropTypes.func,
};
export default Header;
Finally, the users.js, which I want to load below this header:
function Users(){
return (
<>
<h2>Hello from users</h2>
</>
)
}
export default Users;
I found the mistake, I had removed the rendering of 'Component' from _app.js, hence the components weren't loading. The _app.js now becomes:
import Head from "next/head";
import Header from "./components/header";
function MyApp({ Component, pageProps }) {
return (
<>
<Head>
<title>GameZop Assignment</title>
<link rel="icon" href="/favicon.ico" />
</Head>
<Header />
<Component {...pageProps} />
</>
);
}
export default MyApp;

How do I link to another page in my MUI mini drawer sidebar?

I've tried to encapsulate my ListItem component with <Link to"/create> but it doesn't work, i've also tried using the history option but that confused me.
My codesandbox:
codesandbox.io/s/funny-einstein-deuqhi?file=/src/App.js
This is my sidebar.js (without all the imports and the creation of mixin&drawerheader and co, the link on the appbar to my createsite works, i want the same for my sidebar listitems. i want my listitem with the text ."add to-do" to link to the "\create" page):
const openedMixin = (theme) => (...);
const closedMixin = (theme) => (...);
const DrawerHeader = styled(...);
const AppBar = styled(...);
const Drawer = styled(...);
export default function MiniDrawer() {
const theme = useTheme();
const [open, setOpen] = React.useState(false);
const handleDrawerOpen = () => {
setOpen(true);
};
const handleDrawerClose = () => {
setOpen(false);
};
const itemsList = [
{
text: "Calendar",
icon: <EventAvailableOutlinedIcon style={{ fill: 'white' }} />,
},
{
text: "Add To-do",
icon: <AddBoxTwoToneIcon style={{ fill: 'white' }} />
}
]
return (
<Router>
<Box sx={{ display: 'flex' }}>
<CssBaseline />
<AppBar position="fixed" open={open} style={{ background: 'white' }}>
<Toolbar>
<IconButton
color="inherit"
aria-label="open drawer"
onClick={handleDrawerOpen}
edge="start"
sx={{
marginRight: 5,
...(open && { display: 'none' }),
}}
>
<MenuIcon style={{ fill: '#85CEE9' }} />
</IconButton>
<Link to="/create">create</Link>
<Typography variant="h6" noWrap component="div" style={{ color: "#85CEE9" }}>
project
</Typography>
</Toolbar>
</AppBar>
<Drawer variant="permanent" open={open}>
<DrawerHeader>
<IconButton onClick={handleDrawerClose}>
{theme.direction === 'rtl' ? <ChevronRightIcon style={{ fill: 'white' }} /> : <ChevronLeftIcon style={{ fill: 'white' }} />}
</IconButton>
</DrawerHeader>
<Divider />
<List>
{itemsList.map((item, index) => {
const { text, icon } = item;
return (
// <Link to="/create">
<Link to="/create">
<ListItem button component={Link} to="/create" onClick={onItemClick('Page 2')} key={text}>
{icon && <ListItemIcon >{icon}</ListItemIcon>}
// <ListItemText primary={text} style={{ color: "white" }} />
<Link to="/create">create</Link>
</ListItem>
</Link>
// </Link>
);
})}
</List>
</Drawer>
</Box>
</Router>
);
}```
In the sandbox you linked you weren't using the Link component at all in the drawer, so nothing was being linked to.
Render the ListItem component as a Link component and pass the appropriate link props.
Example:
const itemsList = [
{
text: "Calendar",
icon: <EventAvailableOutlinedIcon style={{ fill: "white" }} />,
to: "/create" // <-- add link targets
},
{
text: "Add To-do",
icon: <AddBoxTwoToneIcon style={{ fill: "white" }} />,
to: "/add-todo"
}
];
To the ListItem component, specify the Link component to be the component to render the list item as, and pass the current mapped item's to property.
<List>
{itemsList.map((item, index) => {
const { text, icon } = item;
return (
<ListItem component={Link} to={item.to} button key={text}>
{icon && <ListItemIcon>{icon}</ListItemIcon>}
<ListItemText primary={text} style={{ color: "white" }} />
</ListItem>
);
})}
</List>
Instead of using Link within your List component, use ListItem, ListItemButton, and ListItemText:
<List>
{['Inbox', 'Starred', 'Send email', 'Drafts'].map((text, index) => (
<ListItem key = {text} disablePadding>
<ListItemButton onClick = {handleNav} >
<ListItemIcon>
{index % 2 === 0 ? <InboxIcon /> : <MailIcon />}
</ListItemIcon>
<ListItemText primary={text} />
</ListItemButton>
</ListItem>
))}
</List>
Create the method to pass to each ListItemButton's onClick:
import { useHistory } from 'react-router-dom'
const history = useHistory()
const handleNav = (event) =>
{
// Do whatever you need to do then push to the new page
history.push('/create')
}
Depending on what version of react-router you're using, your actual method to push to a new page may vary (useHistory for v5, useNavigate for v6, etc.).

Drawer Material-ui Close Drawer Function Issue

I'm using Material-UI at my React Project and Im trying create a component that render a drawer and some other components inside it. But I'm having a lot of issues with the open drawer function... I tried passing simply as a state props but then my drawer won't close...
interface Props {
cartOpen: boolean;
}
const CartDrawer: React.FunctionComponent<Props> = ({ cartOpen }) => {
const classes = useStyles();
return (
<Drawer anchor="right" open={cartOpen}>
<div className={classes.cartDrawerDiv}>
<div className={classes.cartTitle}>
<List>
<ListItem>
<ShoppingCartIcon className={classes.icon} />
<Typography
style={{
fontFamily: "Montserrat, sans-serif",
fontSize: "15px",
fontWeight: 800,
marginLeft: "8px",
}}
>
1 Item
</Typography>
</ListItem>
</List>
</div>
<Divider />
</div>
</Drawer>
);
};
export default CartDrawer;
Example of a component using it...
...
<Button
color="secondary"
size="large"
variant="contained"
className={classes.buyButton}
style={{ fontWeight: 600 }}
onClick={() => setCartOpen(true)}
>
COMPRAR
</Button>
</div>
</div>
</div>
<CartDrawer cartOpen={cartOpen} />
You should add onClose to close Drawer
<CartDrawer cartOpen={cartOpen} onClose={() => setCartOpen(false)} />
interface Props {
cartOpen: boolean;
onClose: () => void
}
const CartDrawer: React.FunctionComponent<Props> = ({ cartOpen, onClose }) => {
const classes = useStyles();
return (
<Drawer anchor="right" open={cartOpen} onClose={onClose}>
...

How to pass state between these 2 components

I am trying to conditionally render a functional component. I have another component for the layout of the page. It contains a list item which the user will click to show this other component. Ideally, I'm hoping to have a few of these.
I have tried just about every example I can find online. Callback functions, using the React docs etc. I'm only trying to toggle a Boolean value to show a component or not. So using Redux seems a bit extreme for what I'm trying to do. I'm not sure if it has to do with this being a next, or typescript project.
Here is the parent component - index.tsx
const Index: React.FC = ({flagHelper}: any) => {
const handleOpenLink = (href: string) => {
window.open(href);
return false;
};
const classes = useStyles();
return (
<Layout>
<div className={classes.root}>
<div className={classes.background}>
</div>
<Head>
<title>Countryball Creator</title>
</Head>
<div className={classes.strip}>
{flagHelper && (<div>hello</div>)}
</div>
</div>
</Layout>
);
};
export default Index;
And here is the layout/child component.
export const Layout: React.FC<LayoutProps> = (props) => {
const { container } = props;
const classes = useStyles();
const theme = useTheme();
const [mobileOpen, setMobileOpen] = React.useState(false);
function handleDrawerToggle() {
setMobileOpen(!mobileOpen);
}
// Set state for component
const [flagHelper, setFlagHelper] = useState(false); // Flag tool
const drawer = (
<div>
<div className={classes.toolbar} />
<Divider />
<List>
{['Pick Flag'].map((text) => (
<ListItem button key={text} onClick={() => setFlagHelper(!flagHelper)} className={classes.menuItem}>
<ListItemIcon className={classes.menuItem}><DashboardIcon /></ListItemIcon>
<ListItemText primary={text} />
</ListItem>
))}
</List>
</div>
);
return (
<div className={classes.root}>
<CssBaseline />
<AppBar position="fixed" className={classes.appBar}>
<Toolbar>
<IconButton
color="inherit"
aria-label="open drawer"
edge="start"
onClick={handleDrawerToggle}
className={classes.menuButton}
>
<MenuIcon />
</IconButton>
<Typography variant="h6" noWrap>
Countryball Creator 🌎
</Typography>
<User/>
</Toolbar>
</AppBar>
<nav className={classes.drawer} aria-label="mailbox folders">
{/* The implementation can be swapped with js to avoid SEO duplication of links. */}
<Hidden smUp implementation="css">
<Drawer // this one is for mobile
container={container}
variant="temporary"
anchor={theme.direction === 'rtl' ? 'right' : 'left'}
open={mobileOpen}
onClose={handleDrawerToggle}
classes={{
paper: classes.drawerPaper,
}}
ModalProps={{
keepMounted: true, // Better open performance on mobile.
}}
>
{drawer}
</Drawer>
</Hidden>
<Hidden xsDown implementation="css">
<Drawer // This one is for desktop
classes={{
paper: classes.drawerPaper,
}}
variant="permanent"
open
>
{drawer}
</Drawer>
</Hidden>
</nav>
<main className={classes.content}>
<div className={classes.toolbar} />
{props.children}
</main>
</div>
);
}

Changing background Image based on Route in React

Hey I have a background image for Home component. I've placed the background image in Header Component. In my Header component there is a navbar and the background image. I've place the Header component outside switch inside React Router so that some pages can access the navbar. Now what I want to do is when I go to a food description page I want to keep the navbar but I want to change/remove the background Image . How can I achieve that ?
App.js
function App() {
return (
<div>
<DataContextProvider>
<LoginContextProvider>
<Router>
<Header></Header>
<Switch>
<Route exact path="/" component={Home} />
<Route path="/login" component={Login} />
<Route path="/food/:id" component={FoodDetail} />
</Switch>
</Router>
</LoginContextProvider>
</DataContextProvider>
</div>
);
}
Header.js
<div className={classes.grow}>
<AppBar position="fixed" style={{ backgroundColor: "white" }}>
<Container>
<Toolbar>
<Link to="/">
<Typography className={classes.title} variant="h6" noWrap>
Material-UI
</Typography>
</Link>
<div className={classes.grow} />
<div className={classes.sectionDesktop}>
{loggedInUser.email ? (
<MenuItem onClick={handleProfileMenuOpen}>
<IconButton
aria-label="account of current user"
aria-controls="primary-search-account-menu"
aria-haspopup="true"
color="inherit"
>
<AccountCircleIcon style={{ fill: "black" }} />
</IconButton>
<p className={classes.textColor}>{loggedInUser.name}</p>
</MenuItem>
) : (
<MenuItem onClick={handleLogin}>
<IconButton
aria-label="account of current user"
aria-controls="primary-search-account-menu"
aria-haspopup="true"
color="inherit"
>
<AccountCircleIcon style={{ fill: "black" }} />
</IconButton>
<p className={classes.textColor}>Login</p>
</MenuItem>
)}
<IconButton
aria-label="show 11 new notifications"
color="inherit"
>
<Badge badgeContent={0} color="secondary">
<ShoppingCart style={{ fill: "black" }}></ShoppingCart>
</Badge>
</IconButton>
</div>
<div className={classes.sectionMobile}>
<IconButton
aria-label="show more"
aria-controls={mobileMenuId}
aria-haspopup="true"
onClick={handleMobileMenuOpen}
color="inherit"
>
<MenuIcon style={{ fill: "black" }} />
</IconButton>
</div>
</Toolbar>
</Container>
</AppBar>
{renderMobileMenu}
{renderMenu}
<div style={{ backgroundImage: `url(${bg})` }} className="header">
<h2>Whatever you need, we will deliver it to you!</h2>
<Paper component="form" className="search">
<InputBase
className={classes.input}
placeholder="Search Keywords"
inputProps={{ "aria-label": "search google maps" }}
onChange={(e) => setSearch(e.target.value)}
/>
<IconButton
type="submit"
className={classes.iconButton}
aria-label="search"
>
<SearchIcon />
</IconButton>
</Paper>
</div>
</div>
);
};
FoodDetail.js
const FoodDetail = () => {
const { id } = useParams();
const [foodDetails, setFoodDetails] = useState({});
useEffect(() => {
fetch(`http://localhost:5000/api/foods/${id}`)
.then((res) => res.json())
.then((data) => {
setFoodDetails(data);
console.log(data);
});
}, [id]);
return (
<div>
<h1>Details</h1>
<h1>Name: {foodDetails.name} </h1>
</div>
);
};
You need to use 'useLocation' to get the page path and then add it in a className.
Header.js
import React from "react";
import { useLocation } from "react-router-dom";
import "./Header.css";
import Navigation from "../Navigation/Navigation";
export default function Header() {
const path = useLocation().pathname;
const location = path.split("/")[1];
return (
<div className={"header " + location}>
<Navigation />
</div>
);
}
Header.css
.header {
height: 300px;
}
.header.home {
background: grey
}
.header.about {
background: red
}
.header.contact {
background: yellow
}
Check my complete demo : Stackblitz

Resources