I am trying to create a page that contains a list of cards. I designed the Header of the page but as a beginner, but I created it in my own way.
Problem is that when I am trying to display the card in the new Grid container its will not showing the desired result.
Here the Image with the head I created
Here the I the problem picture when I try to put Grid container
My Style and Code :
import { AppBar, Avatar, Button, Card, CardActionArea, CardActions, CardContent, CardMedia, Grid, IconButton, makeStyles, Toolbar, Typography } from '#material-ui/core';
import React from 'react';
import MenuIcon from '#material-ui/icons/Menu';
import { Link } from 'react-router-dom';
const useStyles = makeStyles((theme) => ({
blackBox: {
backgroundColor: 'black',
height: '350px'
},
AppBar: {
'&.MuiAppBar-positionFixed': {
top: '60px',
right: '126px',
'#media (max-width: 576px)': {
right: '42px'
}
},
width: '85%',
},
large: {
width: theme.spacing(10),
height: theme.spacing(10),
},
link: {
color: 'white',
textDecoration: 'none',
marginLeft: '30px',
fontFamily: 'Times new roman'
},
headText: {
marginTop: '130px',
'#media (max-width: 576px)': {
marginTop: '170px',
}
},
title: {
color: 'white',
'#media (max-width: 576px)': {
fontSize: '30px'
}
},
titleDesc: {
color: 'white',
'#media (max-width: 576px)': {
width: '235px'
}
}
}))
export default function CoursesView() {
const classes = useStyles();
return (
<>
<Grid container
direction="column"
// justify="space-evenly"
alignItems="center"
className={classes.blackBox}
>
<Grid item >
<AppBar className={classes.AppBar} color='transparent'>
<Toolbar>
{/* <IconButton edge="start" className={classes.menuButton} color="inherit" aria-label="menu">
<MenuIcon />
</IconButton> */}
<div style={{ flexGrow: '1' }}>
<Avatar alt="Remy Sharp" src="https://seeklogo.com/images/F/forex-logo-6B4D0AB43E-seeklogo.com.png" className={classes.large} />
</div>
<Link to='/play' className={classes.link}>Home</Link>
<Link to='/play' className={classes.link}>Courses</Link>
<Link to='/play' className={classes.link}>The Trade Signal</Link>
<Link to='/play' className={classes.link}>About</Link>
<Link to='/play' className={classes.link}>My Account</Link>
<Link to='/play' className={classes.link}>My Crat</Link>
</Toolbar>
</AppBar>
</Grid>
<Grid item container className={classes.headText} direction="column"
justify="center"
alignItems="center">
<Typography variant="h2" className={classes.title}>
Courses
</Typography>
<Typography variant="p" className={classes.titleDesc}>
our uniqly designed courses will help you in your specific areas of needs
</Typography>
</Grid>
</Grid>
<Grid container>
<h1>The cards wil display Here</h1>
</Grid>
</>
)
}
enter code here
The main app file that renders this app
import React from "react";
import CourseListView from "./components/pages/CourseListView";
import VideoPlayView from "./components/pages/VideoPlayView";
import { Route, Switch } from "react-router-dom";
import { makeStyles, ThemeProvider } from "#material-ui/core/styles";
import { createMuiTheme } from '#material-ui/core';
import CoursesView from "./components/pages/CoursesView";
const useStyles = makeStyles({
container: {
display: "flex"
}
});
const theme = createMuiTheme({
palette: {
primary: {
main: "#333996",
light: "#3c44b126"
},
secondary: {
main: "#f83245",
light: "#f8324526"
},
background: {
default: "#f4f5fd"
},
},
overrides: {
MuiAppBar: {
root: {
transform: 'translateZ(0)',
}
}
}
})
export default function App() {
const classes = useStyles();
return (
<ThemeProvider theme={theme}>
<div className={classes.container}>
<Switch>
<Route exact from="/" render={props => <CourseListView {...props} />} />
<Route exact from="/play" render={props => <VideoPlayView {...props} />} />
<Route exact from="/Home" render={props => <CoursesView {...props} />} />
</Switch>
</div>
</ThemeProvider>
);
}
try this :
container: {
display: "flex",
flexDirection: column
}
Related
So I'm a newbie when it comes to React and thought to get familiar with the concepts utilizing mui. I'm creating a nav bar and one of the features is to have a search bar that is initially collapsed and expand once the search icon is pressed. This will also hide the typography element. My issue seems that no matter if I set flexgrow for both collapse or the text input that's being encapsulated the element doesn't seem to grow despite the extra space. I also observed when I set the width of the element using vw it adjusts but the right icons and search bar begin to overlap after minimizing it to a certain point. I wonder if this is a styling issue or whether if transition is incapable of doing this, if it's a styling issue how do I get the text input to expand the needed space?
Navbar.js
import React, { useState } from "react";
import {
AppBar,
Drawer,
Box,
IconButton,
List,
ListItemButton,
ListItemText,
Toolbar,
TextField,
Typography,
Collapse,
} from "#mui/material";
import MenuIcon from "#mui/icons-material/Menu";
import PersonOutlineOutlinedIcon from "#mui/icons-material/PersonOutlineOutlined";
import SearchOutlinedIcon from "#mui/icons-material/SearchOutlined";
import ShoppingBagOutlinedIcon from "#mui/icons-material/ShoppingBagOutlined";
import { createTheme } from "#mui/material";
const Navbar = () => {
const [drawer, setDrawer] = useState(false);
const [drawer2, setDrawer2] = useState(false);
const [clicked, setClicked] = useState(false);
const theme = createTheme({
typography: {
fontFamily: ["Abril Fatface", "cursive"].join(","),
},
});
return (
<AppBar position="fixed" sx={{ height: 70 }} className="navbar">
<Toolbar>
<IconButton onClick={() => setDrawer(!drawer)} className="id">
<MenuIcon fontSize="large"></MenuIcon>
</IconButton>
<Drawer open={drawer} onClose={() => setDrawer(!drawer)}>
<Box sx={{ width: 400, backgroundColor: "red" }}>
<List>
<ListItemButton>
<ListItemText primary="HI" />
</ListItemButton>
</List>
</Box>
</Drawer>
<Collapse orientation="horizontal" in={clicked} timeout={100} unmountOnExit>
<TextField sx={{ flexGrow: 2 }} />
</Collapse>
<Typography
component="a"
variant="h4"
theme={theme}
className="item"
sx={{
color: "black",
flexGrow: 2,
textAlign: "center",
display: clicked ? "none" : "block",
}}
>
APPSTUFF
</Typography>
<IconButton className="id">
<PersonOutlineOutlinedIcon fontSize="large"></PersonOutlineOutlinedIcon>
</IconButton>
<IconButton className="id" onClick={() => setClicked(!clicked)}>
<SearchOutlinedIcon fontSize="large"></SearchOutlinedIcon>
</IconButton>
<IconButton className="id" onClick={() => setDrawer2(!drawer2)}>
<ShoppingBagOutlinedIcon fontSize="large"></ShoppingBagOutlinedIcon>
</IconButton>
<Drawer
open={drawer2}
onClose={() => setDrawer2(!drawer2)}
anchor="right"
>
<Box sx={{ width: 400, backgroundColor: "red" }}>
<List>
<ListItemButton>
<ListItemText primary="HI" />
</ListItemButton>
</List>
</Box>
</Drawer>
</Toolbar>
</AppBar>
);
};
export default Navbar;
NavbarStyle.css
.id {
color: black;
margin-top: 0.5%;
display: flex;
flex-grow: 0;
}
.navbar {
width: 100vw;
box-shadow: none;
background-color: white;
}
Hey Guys I have an irritating problem with my code. I am rendering the user name and logout button in the navbar based on whether the user is not null and if it is null then I am rendering sign-in and sign-up links. But the problem arises it keeps saying that Cannot read properties of null (reading 'user') so if it is null it should render the navbar with sign-in and sign-up but it is giving an error can anybody solve my problem.
App.js
import { Switch, Route } from "react-router-dom";
import Home from "./pages/Home";
import SignInSide from "./pages/SignIn";
import SignUpSide from "./pages/SignUp";
import SignUpUser from "./pages/SignUpUser";
import AddAdmin from "./pages/AddAdmin";
import Dashboard from "./pages/Dashboard";
import AppAppBar from "./components/AppAppBar";
import withRoot from "./withRoot";
import { UsersContextProvider } from "./global/UsersContext";
import { SellersContextProvider } from "./global/SellersContext";
import { VerifySellersContextProvider } from "./global/VerifySellersContext";
import { RejectSellersContextProvider } from "./global/RejectSellersContext";
import { useEffect, useState } from "react";
import { auth, db } from "../src/config/Config";
function App() {
//create a state to store user data
const [userData, setuserData] = useState(null);
useEffect(() => {
//check if any change in auth state change
auth.onAuthStateChanged((user) => {
if (user !== null) {
console.log(user);
db.collection("SignedUpUsersData")
.doc(user.uid)
.get()
.then((snapshot) => {
//set teh userData STATE
setuserData({
user: snapshot.data().Name,
});
});
} else {
setuserData({
user: null,
});
}
});
}, []);
return (
<div>
<RejectSellersContextProvider>
<VerifySellersContextProvider>
<SellersContextProvider>
<UsersContextProvider>
{/* This is where the user object have been passed and it is navbar */}
<AppAppBar user={userData} />
<Switch>
<Route path="/" exact>
<Home />
</Route>
<Route path="/dashboard">
<Dashboard />
</Route>
<Route path="/signin">
<SignInSide />
</Route>
<Route path="/signup">
<SignUpSide />
</Route>
<Route path="/signupuser">
<SignUpUser />
</Route>
<Route path="/addadmin">
<AddAdmin />
</Route>
</Switch>
</UsersContextProvider>
</SellersContextProvider>
</VerifySellersContextProvider>
</RejectSellersContextProvider>
</div>
);
}
export default withRoot(App);
AppAppBar.js
import * as React from "react";
import Box from "#mui/material/Box";
import Link from "#mui/material/Link";
import AppBar from "../subcomponents/AppBar";
import Toolbar from "../subcomponents/Toolbar";
import Button from "#mui/material/Button";
import Stack from "#mui/material/Stack";
import { Link as RouterLink } from "react-router-dom";
import { auth } from "../config/Config";
import { useHistory } from "react-router-dom";
const rightLink = {
fontSize: 16,
color: "common.white",
ml: 3,
};
const button = {
fontSize: 16,
color: "red",
ml: 3,
cursor: "pointer",
};
function AppAppBar({ user }) {
const history = useHistory();
const logut = () => {
auth.signOut().then(() => {
history.push("/signin");
console.log("user has singned out");
});
};
console.log(user);
return (
<div>
<AppBar position="fixed">
<Toolbar
sx={{ justifyContent: "space-between", backgroundColor: "black" }}
>
<Box sx={{ flex: 1, display: "flex", justifyContent: "flex-start" }}>
<Link
component={RouterLink}
to="/"
variant="h6"
underline="none"
color="inherit"
sx={{ fontSize: 24, color: "white" }}
>
{"tenderdash"}
</Link>
</Box>
<Box sx={{ flex: 1, display: "flex", justifyContent: "flex-end" }}>
<Link
color="inherit"
variant="h6"
underline="none"
href="/premium-themes/onepirate/sign-in/"
sx={rightLink}
>
{"Products"}
</Link>
<Link
color="inherit"
variant="h6"
underline="none"
href="/premium-themes/onepirate/sign-in/"
sx={rightLink}
>
{"List Equipments"}
</Link>
<Link
color="inherit"
variant="h6"
underline="none"
href="/premium-themes/onepirate/sign-in/"
sx={rightLink}
>
{"Contact Us"}
</Link>
{/* if there is not a user */}
{user.user === null && (
<div>
<Link
component={RouterLink}
to="/signin"
color="inherit"
variant="h6"
underline="none"
sx={rightLink}
>
{"SignIn"}
</Link>
<Link
component={RouterLink}
to="/signup"
variant="h6"
underline="none"
sx={rightLink}
>
{"Sign Up"}
</Link>
</div>
)}
{/* if there is a user */}
{user.user && (
<>
<Link variant="h6" underline="none" sx={rightLink}>
{user.user}
</Link>
<Link onClick={logut} sx={button} variant="h6">
Logout
</Link>
</>
)}
{/* if the user is admin */}
{/* <Link
component={RouterLink}
to="/dashboard"
variant="h6"
underline="none"
sx={{ ...rightLink, color: "secondary.main" }}
>
{"Admin Console"}
</Link> */}
</Box>
</Toolbar>
</AppBar>
<Toolbar />
</div>
);
}
export default AppAppBar;
When you initialize userData , you are initializing with null, then in your component AppAppBar in the line user.user is the same than null.user, this is the error.
You should replace this:
const [userData, setuserData] = useState(null)
by:
const [userData, setuserData] = useState({user: null})
Using ReactJS, I am trying to make a second (smaller) navbar the same way Airtable has done on their product page. My first navbar is at the top, and turns dark from transparent once I scroll. The second bar (colored purple in the screenshot to easily see) is currently behind the first navbar when I would like it to sit right underneath the header background image.
First (main) Navbar - "Header.js"
import React, { useEffect, useState } from 'react';
import { makeStyles } from '#material-ui/core/styles';
import { AppBar, IconButton, Toolbar, Collapse } from '#material-ui/core';
import SortIcon from '#material-ui/icons/Sort';
import ExpandMoreIcon from '#material-ui/icons/ExpandMore';
import { Link as Scroll } from 'react-scroll';
import ScrollToColor from './ColorChangeOnScroll';
const useStyles = makeStyles((theme) => ({
root: {
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
height: '100vh',
fontFamily: 'Nunito',
},
appbar: {
background: 'none',
},
appbarTitle:{
flexGrow: '1',
},
appbarWrapper:{
width: '80%',
margin: '0 auto',
},
icon: {
color: '#fff',
fontSize: '2rem',
},
colorText: {
color: '#34cbc2',
},
container: {
textAlign: 'center',
},
title: {
color: '#fff',
fontSize: '4rem',
},
goDown: {
color: '#34cbc2',
fontSize: '4rem',
},
}));
export default function Header() {
const classes = useStyles();
const [checked, setChecked] = useState(false);
useEffect(() => {
setChecked(true);
}, []);
return (
<section>
<div className={classes.root} id="header">
<ScrollToColor>
<AppBar className={classes.appbar} elevation={0}>
<Toolbar className={classes.appbarWrapper}>
<h1 className={classes.appbarTitle}>
Logo <span className={classes.colorText}>Colored</span>
</h1>
<IconButton>
<SortIcon className={classes.icon} />
</IconButton>
</Toolbar>
</AppBar>
</ScrollToColor>
<Collapse
in={checked}
{...(checked ? { timeout: 1000 } : {})}
collapsedHeight={50}>
<div className={classes.container}>
<h1 className={classes.title}>
Main header <br />
at <span className={classes.colorText}>title.</span>
</h1>
<Scroll to="info-card" smooth={true}>
<IconButton>
<ExpandMoreIcon className={classes.goDown} />
</IconButton>
</Scroll>
</div>
</Collapse>
</div>
</section>
);
}
Second Navbar - "StickyHeader.js"
import React, { useEffect, useState } from 'react';
import { makeStyles } from '#material-ui/core/styles';
import { AppBar, IconButton, Toolbar, Collapse } from '#material-ui/core';
import SortIcon from '#material-ui/icons/Sort';
const useStyles = makeStyles((theme) => ({
root: {
top: '1000px',
display: 'flex',
position: 'sticky',
justifyContent: 'center',
alignItems: 'center',
fontFamily: 'Nunito',
},
appbar: {
background: 'purple',
},
list: {
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
},
}));
export default function Header() {
const classes = useStyles();
const [checked, setChecked] = useState(false);
useEffect(() => {
setChecked(true);
}, []);
return (
<section>
<div className={classes.root} style={{ top: "72px" }} id="stickyheader">
<AppBar className={classes.appbar} elevation={4}>
<Toolbar className={classes.appbarWrapper}>
<ul className={classes.list} style={{ listStyleType: "none" }}>
<li>
Database
</li>
</ul>
</Toolbar>
</AppBar>
</div>
</section>
);
}
Landing Page snippet
export default function Landing() {
const classes = useStyles();
return (
<div className={classes.root}>
<CssBaseline />
<Header />
<StickyHeader />
<InfoCards />
</div>
);
}
Tried adjusting:
Separating each component into their own files to act as 'sections,' so one would sit on top of the other
Adjusting margin, marginTop in useStyles with position: relative
Same as above with position: sticky
Added style={{ top: "##px" }} to the navbar's div to see if that pushed it downwards
Images
2nd navbar behind 1st at top
2nd navbar behind 1st, scrolled
Photoshopped view of the desired outcome (where 2nd navbar is sticky and 'joins' the 1st navbar when scrolled past)
I'm not sure if I am missing something simple in the styling for these navbars, or if this needs something more complex. Any advice is appreciated in advance.
Note
The logo and header titles are a part of the first navbar. The second (purple) navbar has a very small 'Database' clickable text that is difficult to see in the first couple screenshots, right on top of 'Logo colored.'
Update
Resulting screenshot from MB_'s answer
EDIT
This is the only solution I have found...
PS:
1/ Use position: "fixed" instead of position: "sticky"
2/ There are other modifications to do... (add scroll listener,...)
Header.js
import React, { useEffect, useState } from "react";
import { makeStyles } from "#material-ui/core/styles";
import { AppBar, IconButton, Toolbar, Collapse } from "#material-ui/core";
import SortIcon from "#material-ui/icons/Sort";
import ExpandMoreIcon from "#material-ui/icons/ExpandMore";
import { Link as Scroll } from "react-scroll";
const useStyles = makeStyles(theme => ({
root: {
fontFamily: "Nunito"
},
appbar: {
position: "fixed",
zIndex: "9999",
background: "black"
},
appbarTitle: {
flexGrow: "1"
},
appbarWrapper: {
width: "80%",
margin: "0 auto"
},
icon: {
color: "#fff",
fontSize: "2rem"
},
colorText: {
color: "#34cbc2"
},
container: {
textAlign: "center",
height: "100vh",
marginTop: "80px",
display: "flex",
flexDirection: "column",
justifyContent: "center",
alignItems: "center"
},
title: {
color: "#333",
fontSize: "4rem"
},
goDown: {
color: "#34cbc2",
fontSize: "4rem"
}
}));
export default function Header() {
const classes = useStyles();
const [checked, setChecked] = useState(false);
useEffect(() => {
setChecked(true);
}, []);
return (
<div className={classes.root} id="header">
<AppBar className={classes.appbar} elevation={0}>
<Toolbar className={classes.appbarWrapper}>
<h1 className={classes.appbarTitle}>
Logo <span className={classes.colorText}>Colored</span>
</h1>
<IconButton>
<SortIcon className={classes.icon} />
</IconButton>
</Toolbar>
</AppBar>
<Collapse
in={checked}
{...(checked ? { timeout: 1000 } : {})}
collapsedHeight={50}
>
<div id="mainheader" className={classes.container}>
<h1 className={classes.title}>
Main header <br />
at <span className={classes.colorText}>title.</span>
</h1>
<Scroll to="info-card" smooth={true}>
<IconButton>
<ExpandMoreIcon className={classes.goDown} />
</IconButton>
</Scroll>
</div>
</Collapse>
</div>
);
}
StickyHeader.js
import React, { useEffect, useState } from "react";
import { makeStyles } from "#material-ui/core/styles";
import { AppBar, IconButton, Toolbar, Collapse } from "#material-ui/core";
const useStyles = makeStyles(theme => ({
root: {
fontFamily: "Nunito"
},
appbar: {
background: "purple"
},
list: {
display: "flex",
justifyContent: "center",
alignItems: "center"
}
}));
export default function StickyHeader() {
const classes = useStyles();
const [checked, setChecked] = useState(false);
const [scrollY, setScrollY] = useState({ position: "relative" });
useEffect(() => {
window.addEventListener("scroll", () => {
const heightVh = document.querySelector("#mainheader").offsetHeight / 100;
if (window.scrollY > heightVh * 100) {
setScrollY({ position: "fixed", top: "80px" });
} else {
setScrollY({ position: "relative" });
}
});
return () => {
window.removeEventListener("scroll");
};
}, [scroll]);
useEffect(() => {
setChecked(true);
}, []);
return (
<>
{console.log(scrollY)}
<div className={classes.root} id="stickyheader">
<AppBar className={classes.appbar} style={scrollY} elevation={4}>
<Toolbar className={classes.appbarWrapper}>
<ul className={classes.list} style={{ listStyleType: "none" }}>
<li>
<a href="#product" data-id="product" data-is-active="true">
Database
</a>
</li>
</ul>
</Toolbar>
</AppBar>
</div>
</>
);
}
Demo : stackblitz
I'm completely new in MaterialUI. I'm working on my first project right now and trying to make use of templates form its page. I've loaded two .tsx files with log in view and main dashboard view. I'd like to show main dashboard view after clicking Login button on log in view. Both files have its own export default function FnName() function with const classes = useStyles(); and it seems to cause my problems. The way of using hooks is the issue here I guess. But how to pass this function to onClick handler event button? You can see my project here:
https://codesandbox.io/s/adoring-leftpad-6nwv2?file=/src/SignIn.tsx
Somebody can help?
Please check this example:
App Component
import React, {useEffect, useState} from 'react';
import SignIn from "./material-ui/signin-template/SignIn";
import {BrowserRouter as Router, Switch, Route} from "react-router-dom";
import { createBrowserHistory as history} from 'history';
import MiniDrawer from "./material-ui/signin-template/Dashboard";
class App extends React.Component {
render() {
return (
<div>
<Router history={history}>
<Switch>
<Route path="/" exact component={SignIn}/>
<Route path="/dashboard" component={MiniDrawer}/>
</Switch>
</Router>
</div>
)
}
}
export default App;
SingIn Component
import React from "react";
import Avatar from "#material-ui/core/Avatar";
import Button from "#material-ui/core/Button";
import CssBaseline from "#material-ui/core/CssBaseline";
import TextField from "#material-ui/core/TextField";
import FormControlLabel from "#material-ui/core/FormControlLabel";
import Checkbox from "#material-ui/core/Checkbox";
import Link from "#material-ui/core/Link";
import Grid from "#material-ui/core/Grid";
import Box from "#material-ui/core/Box";
import LockOutlinedIcon from "#material-ui/icons/LockOutlined";
import Typography from "#material-ui/core/Typography";
import {makeStyles} from "#material-ui/core/styles";
import Container from "#material-ui/core/Container";
import {Redirect, useHistory} from "react-router-dom";
function Copyright() {
return (
<Typography variant="body2" color="textSecondary" align="center">
{"Copyright © "}
<Link color="inherit" href="https://material-ui.com/">
Your Website
</Link>{" "}
{new Date().getFullYear()}
{"."}
</Typography>
);
}
const useStyles = makeStyles(theme => ({
paper: {
marginTop: theme.spacing(8),
display: "flex",
flexDirection: "column",
alignItems: "center"
},
avatar: {
margin: theme.spacing(1),
backgroundColor: theme.palette.secondary.main
},
form: {
width: "100%", // Fix IE 11 issue.
marginTop: theme.spacing(1)
},
submit: {
margin: theme.spacing(3, 0, 2)
}
}));
export default function SignIn() {
const classes = useStyles();
let history = useHistory();
return (
<Container component="main" maxWidth="xs">
<CssBaseline/>
<div className={classes.paper}>
<Avatar className={classes.avatar}>
<LockOutlinedIcon/>
</Avatar>
<Typography component="h1" variant="h5">
Sign in
</Typography>
<form className={classes.form} noValidate>
<TextField
variant="outlined"
margin="normal"
required
fullWidth
id="email"
label="Email Address"
name="email"
autoComplete="email"
autoFocus
/>
<TextField
variant="outlined"
margin="normal"
required
fullWidth
name="password"
label="Password"
type="password"
id="password"
autoComplete="current-password"
/>
<FormControlLabel
control={<Checkbox value="remember" color="primary"/>}
label="Remember me"
/>
<Button
onClick={()=>{
history.push('/dashboard')
}}
fullWidth
variant="contained"
color="primary"
className={classes.submit}
>
Sign In
</Button>
<Grid container>
<Grid item xs>
<Link href="#" variant="body2">
Forgot password?
</Link>
</Grid>
<Grid item>
<Link href="#" variant="body2">
{"Don't have an account? Sign Up"}
</Link>
</Grid>
</Grid>
</form>
</div>
<Box mt={8}>
<Copyright/>
</Box>
</Container>
);
}
Dashboard Component
import React from "react";
import clsx from "clsx";
import {
createStyles,
makeStyles,
useTheme,
Theme
} from "#material-ui/core/styles";
import Button from "#material-ui/core/Button";
import Drawer from "#material-ui/core/Drawer";
import AppBar from "#material-ui/core/AppBar";
import Toolbar from "#material-ui/core/Toolbar";
import List from "#material-ui/core/List";
import CssBaseline from "#material-ui/core/CssBaseline";
import Typography from "#material-ui/core/Typography";
import Divider from "#material-ui/core/Divider";
import IconButton from "#material-ui/core/IconButton";
import MenuIcon from "#material-ui/icons/Menu";
import ChevronLeftIcon from "#material-ui/icons/ChevronLeft";
import ChevronRightIcon from "#material-ui/icons/ChevronRight";
import ListItem from "#material-ui/core/ListItem";
import ListItemIcon from "#material-ui/core/ListItemIcon";
import ListItemText from "#material-ui/core/ListItemText";
import InboxIcon from "#material-ui/icons/MoveToInbox";
import MailIcon from "#material-ui/icons/Mail";
import MapOutlinedIcon from "#material-ui/icons/MapOutlined";
import DriveEtaOutlinedIcon from "#material-ui/icons/DriveEtaOutlined";
import PeopleAltOutlinedIcon from "#material-ui/icons/PeopleAltOutlined";
import DirectionsOutlinedIcon from "#material-ui/icons/DirectionsOutlined";
import AssessmentOutlinedIcon from "#material-ui/icons/AssessmentOutlined";
import ReportProblemOutlinedIcon from "#material-ui/icons/ReportProblemOutlined";
import AccountCircleOutlinedIcon from "#material-ui/icons/AccountCircleOutlined";
import { Redirect, useHistory } from "react-router-dom";
import ExitToAppIcon from "#material-ui/icons/ExitToApp";
const drawerWidth = 240;
const useStyles = makeStyles((theme: Theme) =>
createStyles({
root: {
display: "flex"
},
appBar: {
zIndex: theme.zIndex.drawer + 1,
transition: theme.transitions.create(["width", "margin"], {
easing: theme.transitions.easing.sharp,
duration: theme.transitions.duration.leavingScreen
})
},
appBarShift: {
marginLeft: drawerWidth,
width: `calc(100% - ${drawerWidth}px)`,
transition: theme.transitions.create(["width", "margin"], {
easing: theme.transitions.easing.sharp,
duration: theme.transitions.duration.enteringScreen
})
},
menuButton: {
marginRight: 36
},
hide: {
display: "none"
},
drawer: {
width: drawerWidth,
flexShrink: 0,
whiteSpace: "nowrap"
},
drawerOpen: {
width: drawerWidth,
transition: theme.transitions.create("width", {
easing: theme.transitions.easing.sharp,
duration: theme.transitions.duration.enteringScreen
})
},
drawerClose: {
transition: theme.transitions.create("width", {
easing: theme.transitions.easing.sharp,
duration: theme.transitions.duration.leavingScreen
}),
overflowX: "hidden",
width: theme.spacing(7) + 1,
[theme.breakpoints.up("sm")]: {
width: theme.spacing(9) + 1
}
},
toolbar: {
display: "flex",
alignItems: "center",
justifyContent: "flex-end",
padding: theme.spacing(0, 1),
// necessary for content to be below app bar
...theme.mixins.toolbar
},
content: {
flexGrow: 1,
padding: theme.spacing(3)
}
})
);
function MiniDrawer() {
const classes = useStyles();
let history = useHistory();
const theme = useTheme();
const [open, setOpen] = React.useState(false);
const handleDrawerOpen = () => {
setOpen(true);
};
const handleDrawerClose = () => {
setOpen(false);
};
return (
<div className={classes.root}>
<CssBaseline />
<AppBar
position="fixed"
className={clsx(classes.appBar, {
[classes.appBarShift]: open
})}
>
<Toolbar>
<IconButton
color="inherit"
aria-label="open drawer"
onClick={handleDrawerOpen}
edge="start"
className={clsx(classes.menuButton, {
[classes.hide]: open
})}
>
<MenuIcon />
</IconButton>
</Toolbar>
</AppBar>
<Drawer
variant="permanent"
className={clsx(classes.drawer, {
[classes.drawerOpen]: open,
[classes.drawerClose]: !open
})}
classes={{
paper: clsx({
[classes.drawerOpen]: open,
[classes.drawerClose]: !open
})
}}
>
<div className={classes.toolbar}>
<IconButton onClick={handleDrawerClose}>
{theme.direction === "rtl" ? (
<ChevronRightIcon />
) : (
<ChevronLeftIcon />
)}
</IconButton>
</div>
<div className={classes.toolbar} />
<div className={classes.toolbar} />
<div className={classes.toolbar} />
<IconButton
onClick={() => {
history.push("/");
}}
>
<ExitToAppIcon />
</IconButton>
<Divider />
<List>
{["Mapa", "Pojazdy", "Kierowcy", "Trasy", "Raporty", "Alerty"].map(
(text, index) => (
<ListItem
button
key={text}
onClick={event => {
console.log(event.currentTarget);
history.push("/");
}}
>
<ListItemIcon>
{index === 0 && <MapOutlinedIcon />}
{index === 1 && <DriveEtaOutlinedIcon />}
{index === 2 && <PeopleAltOutlinedIcon />}
{index === 3 && <DirectionsOutlinedIcon />}
{index === 4 && <AssessmentOutlinedIcon />}
{index === 5 && <ReportProblemOutlinedIcon />}
</ListItemIcon>
<ListItemText primary={text} />
</ListItem>
)
)}
</List>
</Drawer>
<main className={classes.content}>
<div className={classes.toolbar} />
<Typography paragraph />
</main>
</div>
);
}
export default MiniDrawer;
Here is the Code Sandbox
I'm using the nivo charting library and am struggling to get my pie charts to render. I really don't understand why the pie chart isn't showing up.
Here is my core component code for the dashboard:
import React, { useState, useEffect } from "react";
import Amplify, { Storage } from "aws-amplify";
import Paper from "#material-ui/core/Paper";
import Box from "#material-ui/core/Box";
import Grid from "#material-ui/core/Grid";
import awsmobile from "./aws-exports";
import * as d3 from "d3";
import CircularProgress from "#material-ui/core/CircularProgress";
import MyResponsivePie from "./pieConfig";
import useStyles from "./useStyles";
import AppBar from "#material-ui/core/AppBar";
import Toolbar from "#material-ui/core/Toolbar";
import IconButton from "#material-ui/core/IconButton";
import CloudDownloadIcon from "#material-ui/icons/CloudDownload";
import Typography from "#material-ui/core/Typography";
Amplify.configure(awsmobile);
Storage.configure({ level: "private" });
export default function Dashboard() {
useEffect(() => {
getFile();
}, []);
const classes = useStyles();
const [dashboard, showDashboard] = useState(false);
const [dashboardfile, setFile] = useState();
const getFile = async () => {
const url = await get_url().catch(err => getFile());
const file = await d3.csv(url);
if (file) {
console.log(file);
setFile(file);
showDashboard(true);
}
};
const get_url = () => {
var url = Storage.get("output.csv", { level: "private" }, { expires: 60 });
console.log(url);
return url;
};
const countColumnValues = (file, column) => {
var data_count = d3
.nest()
.key(function(d) {
return d[column];
})
.rollup(function(leaves) {
return leaves.length;
})
.entries(file);
console.log(data_count);
return data_count;
};
const generatePie = (file, column) => {
var data = countColumnValues(file, column);
return data;
};
return (
<Box className={classes.root}>
<AppBar position="static">
<Toolbar>
<IconButton
edge="start"
className={classes.menuButton}
color="inherit"
>
<CloudDownloadIcon onClick={get_url}></CloudDownloadIcon>
</IconButton>
<Typography variant="h6" className={classes.title}>
Atreides Controls NLP Dashboard
</Typography>
</Toolbar>
</AppBar>
{dashboard === false && (
<div className={classes.circle}>
<CircularProgress />
</div>
)}
{dashboard && (
<div className={classes.root}>
<Grid container direction="row" space={3}>
<Grid item xs>
<Paper className={classes.paper}>
<div className={classes.pie}>
<MyResponsivePie
id="contains_who_pie"
data={generatePie(dashboardfile, "contains_whos")}
/>{" "}
</div>
</Paper>
</Grid>
<Grid item xs>
<Paper className={classes.paper}>
<div className={classes.pie}>
<MyResponsivePie
id="contains_what_pie"
data={generatePie(dashboardfile, "contains_whats")}
/>
</div>
</Paper>
</Grid>
<Grid item xs>
<Paper className={classes.paper}>
<div className={classes.pie}>
<MyResponsivePie
id="contains_how_pie"
data={generatePie(dashboardfile, "contains_hows")}
/>
</div>
</Paper>
</Grid>
</Grid>
<Grid container direction="row" space={3}>
<Grid item xs>
<Paper className={classes.paper}>
<div className={classes.pie}>
<MyResponsivePie
id="multiple_who_pie"
data={generatePie(dashboardfile, "multiple_whos")}
/>
</div>
</Paper>
</Grid>
<Grid item xs>
<Paper className={classes.paper}>
<div className={classes.pie}>
<MyResponsivePie
id="multiple_what_pie"
data={generatePie(dashboardfile, "multiple_whats")}
/>{" "}
</div>
</Paper>
</Grid>
<Grid item xs>
<Paper className={classes.paper}>
<div className={classes.pie}>
<MyResponsivePie
id="multiple_how_pie"
data={generatePie(dashboardfile, "multiple_hows")}
/>
</div>
</Paper>
</Grid>
</Grid>
<Grid container direction="row" space={3}>
<Grid item xs>
<Paper className={classes.paper}>
<div className={classes.pie}>
<MyResponsivePie
id="risk_relevance_pie"
data={generatePie(
dashboardfile,
"control_relevance_to_risk"
)}
/>
</div>
</Paper>
</Grid>
<Grid item xs>
<Paper className={classes.paper}>
<div className={classes.pie}>
<MyResponsivePie
id="automated_manual_pie"
data={generatePie(dashboardfile, "")}
/>
</div>
</Paper>
</Grid>
<Grid item xs>
<Paper className={classes.paper}>
<div className={classes.pie}>
<MyResponsivePie
id="preventative_detective_pie"
data={generatePie(dashboardfile, "")}
/>
</div>
</Paper>
</Grid>
</Grid>
</div>
)}
</Box>
);
}
The pie chart component is configured using this component that I am importing:
import React from "react";
import { ResponsivePie } from "#nivo/pie";
const MyResponsivePie = ({ data }) => (
<ResponsivePie
data={data}
margin={{ top: 40, right: 80, bottom: 80, left: 80 }}
startAngle={-180}
innerRadius={0.5}
padAngle={0.7}
cornerRadius={3}
colors={{ scheme: "nivo" }}
borderWidth={1}
borderColor={{ theme: "grid.line.stroke" }}
radialLabelsSkipAngle={10}
radialLabelsTextXOffset={6}
radialLabelsTextColor="#333333"
radialLabelsLinkOffset={0}
radialLabelsLinkDiagonalLength={16}
radialLabelsLinkHorizontalLength={24}
radialLabelsLinkStrokeWidth={3}
radialLabelsLinkColor={{ from: "color", modifiers: [] }}
slicesLabelsSkipAngle={10}
slicesLabelsTextColor="#333333"
animate={true}
motionStiffness={90}
motionDamping={15}
legends={[
{
anchor: "bottom",
direction: "row",
translateY: 56,
itemWidth: 100,
itemHeight: 18,
itemTextColor: "#999",
symbolSize: 18,
symbolShape: "circle",
effects: [
{
on: "hover",
style: {
itemTextColor: "#000"
}
}
]
}
]}
/>
);
export default MyResponsivePie;
and my styles file looks like this
import { green } from "#material-ui/core/colors";
import { makeStyles } from "#material-ui/core/styles";
import { forceCenter } from "d3";
const useStyles = makeStyles(theme => ({
root: {
height: "100vh"
},
success: {
backgroundColor: green[600]
},
error: {
backgroundColor: theme.palette.error.dark
},
icon: {
fontSize: 20
},
iconVariant: {
opacity: 0.9,
marginRight: theme.spacing(1)
},
message: {
display: "flex",
alignItems: "center"
},
image: {
backgroundImage: "url(https://source.unsplash.com/8WFnEehJWso)",
backgroundRepeat: "no-repeat",
backgroundColor:
theme.palette.type === "dark"
? theme.palette.grey[900]
: theme.palette.grey[50],
backgroundSize: "cover",
backgroundPosition: "center"
},
paper: {
margin: theme.spacing(1.5, 3),
display: "flex",
flexDirection: "column",
alignItems: "center"
},
form: {
width: "100%", // Fix IE 11 issue.
marginTop: theme.spacing(1)
},
submit: {
margin: theme.spacing(3, 0, 2)
},
card: {
maxWidth: 600
},
media: {
height: 500
},
circle: {
display: "flex",
"& > * + *": {
marginLeft: theme.spacing(2)
}
},
menuButton: {
marginRight: theme.spacing(2)
},
title: {
flexGrow: 1,
alignContent: "center"
},
pie: {
height: 250
}
}));
export default useStyles;
Lastly an example of my data that is coming back from the generate pie function is like this:
[
{key: "True", value: 7981},
{key: "False", value: 950}
]
The issue I had was rather daft, the container object did not have a specified size.