From 9c8485da6ddbda1665f4375f6519dfed952499e4 Mon Sep 17 00:00:00 2001
From: Karel Hala <khala@redhat.com>
Date: Mon, 23 Mar 2020 00:09:00 +0100
Subject: [PATCH] Add dashboard layout

---
 package.json                 |   2 +
 src/App.js                   | 123 ++++++++++++++++++++++++---
 src/bordel/form-input.js     |  20 -----
 src/bordel/form.js           |  36 --------
 src/components/NavBar.js     | 155 +++++++++++++++++++++++++++++------
 src/components/Navigation.js |  36 ++++++++
 src/views/Home.js            |   1 -
 src/views/bordel.js          |  11 ---
 yarn.lock                    |   9 +-
 9 files changed, 286 insertions(+), 107 deletions(-)
 delete mode 100644 src/bordel/form-input.js
 delete mode 100644 src/bordel/form.js
 create mode 100644 src/components/Navigation.js
 delete mode 100644 src/views/bordel.js

diff --git a/package.json b/package.json
index 8eac39e..cae8988 100644
--- a/package.json
+++ b/package.json
@@ -12,7 +12,9 @@
   "dependencies": {
     "@auth0/auth0-spa-js": "^1.0.2",
     "@material-ui/core": "^4.9.5",
+    "@material-ui/icons": "^4.9.1",
     "axios": "^0.19.0",
+    "clsx": "^1.1.0",
     "react": "^16.8.6",
     "react-dom": "^16.8.6",
     "react-router-dom": "^5.0.0",
diff --git a/src/App.js b/src/App.js
index a218e0f..09498bc 100644
--- a/src/App.js
+++ b/src/App.js
@@ -1,5 +1,5 @@
-import React from "react";
-import { Router, Route, Switch, Link } from "react-router-dom";
+import React, { useState } from "react";
+import { Router, Route, Switch } from "react-router-dom";
 
 import PrivateRoute from "./components/PrivateRoute";
 import Loading from "./components/Loading";
@@ -8,26 +8,123 @@ import Home from "./views/Home";
 import Profile from "./views/Profile";
 import { useAuth0 } from "./react-auth0-spa";
 import history from "./utils/history";
+import clsx from "clsx";
+import { makeStyles } from "@material-ui/core/styles";
+import CssBaseline from "@material-ui/core/CssBaseline";
+import Drawer from "@material-ui/core/Drawer";
+import Divider from "@material-ui/core/Divider";
+import IconButton from "@material-ui/core/IconButton";
+import Container from "@material-ui/core/Container";
+import ChevronLeftIcon from "@material-ui/icons/ChevronLeft";
+import Navigation from "./components/Navigation";
 
-import Bordel from './views/bordel';
+const drawerWidth = 240;
+
+const useStyles = makeStyles((theme) => ({
+  root: {
+    display: "flex"
+  },
+  toolbarIcon: {
+    display: "flex",
+    alignItems: "center",
+    justifyContent: "flex-end",
+    padding: "0 8px",
+    ...theme.mixins.toolbar
+  },
+  title: {
+    flexGrow: 1
+  },
+  drawerPaper: {
+    position: "relative",
+    whiteSpace: "nowrap",
+    width: drawerWidth,
+    transition: theme.transitions.create("width", {
+      easing: theme.transitions.easing.sharp,
+      duration: theme.transitions.duration.enteringScreen
+    })
+  },
+  drawerPaperClose: {
+    overflowX: "hidden",
+    transition: theme.transitions.create("width", {
+      easing: theme.transitions.easing.sharp,
+      duration: theme.transitions.duration.leavingScreen
+    }),
+    width: theme.spacing(7),
+    [theme.breakpoints.up("sm")]: {
+      width: theme.spacing(9)
+    }
+  },
+  appBarSpacer: theme.mixins.toolbar,
+  content: {
+    flexGrow: 1,
+    height: "100vh",
+    overflow: "auto"
+  },
+  container: {
+    paddingTop: theme.spacing(4),
+    paddingBottom: theme.spacing(4)
+  },
+  paper: {
+    padding: theme.spacing(2),
+    display: "flex",
+    overflow: "auto",
+    flexDirection: "column"
+  },
+  fixedHeight: {
+    height: 240
+  }
+}));
 
 const App = () => {
-  const { loading } = useAuth0();
+  const { loading, isAuthenticated } = useAuth0();
+  const classes = useStyles();
+  const [open, setOpen] = useState(true);
 
   if (loading) {
     return <Loading />;
   }
 
+  const handleDrawerOpen = () => {
+    setOpen(true);
+  };
+  const handleDrawerClose = () => {
+    setOpen(false);
+  };
+
   return (
-    <Router history={history}>
-      <NavBar />
-      <Link to="/testing">Take me to tests</Link>
-      <Switch>
-        <Route path="/" exact component={Home} />
-        <PrivateRoute path="/profile" component={Profile} />
-        <Route path="/testing" component={Bordel} />
-      </Switch>
-    </Router>
+    <div className={classes.root}>
+      <Router history={history}>
+        <CssBaseline />
+        <NavBar open={open} handleOpen={handleDrawerOpen} />
+        {isAuthenticated && (
+          <Drawer
+            variant="permanent"
+            classes={{
+              paper: clsx(classes.drawerPaper, !open && classes.drawerPaperClose)
+            }}
+            open={open}
+          >
+            <div className={classes.toolbarIcon}>
+              <IconButton onClick={handleDrawerClose}>
+                <ChevronLeftIcon />
+              </IconButton>
+            </div>
+            <Divider />
+            <Navigation />
+            <Divider />
+          </Drawer>
+        )}
+        <main className={classes.content}>
+          <div className={classes.appBarSpacer} />
+          <Container maxWidth="lg" className={classes.container}>
+            <Switch>
+              <Route path="/" exact component={Home} />
+              <PrivateRoute path="/profile" component={Profile} />
+            </Switch>
+          </Container>
+        </main>
+      </Router>
+    </div>
   );
 };
 
diff --git a/src/bordel/form-input.js b/src/bordel/form-input.js
deleted file mode 100644
index 1666cd1..0000000
--- a/src/bordel/form-input.js
+++ /dev/null
@@ -1,20 +0,0 @@
-import React, { useContext } from "react";
-import PropTypes from "prop-types";
-import { FormContext } from "./form";
-
-const FormInput = ({ name, label, ...rest }) => {
-  const { onChange, values } = useContext(FormContext);
-  return (
-    <div>
-      <label htmlFor={name}>{label}</label>
-      <input id={name} name={name} {...rest} value={values[name] || ''} onChange={({ target: { value } }) => onChange(value, name)} />
-    </div>
-  );
-};
-
-FormInput.propTypes = {
-  name: PropTypes.string.isRequired,
-  label: PropTypes.string
-};
-
-export default FormInput;
diff --git a/src/bordel/form.js b/src/bordel/form.js
deleted file mode 100644
index d42997e..0000000
--- a/src/bordel/form.js
+++ /dev/null
@@ -1,36 +0,0 @@
-import React, { useState, createContext } from "react";
-import FormInput from "./form-input";
-
-export const FormContext = createContext({});
-
-const Form = () => {
-  const [values, setValues] = useState({
-    "first-name": "Martin",
-    "last-name": "Hura"
-  });
-
-  const onChange = (value, name) =>
-    setValues((prevValues) => ({
-      ...prevValues,
-      [name]: value
-    }));
-  return (
-    <FormContext.Provider
-      value={{
-        values,
-        onChange
-      }}
-    >
-      <form>
-        <FormInput name="first-name" label="First name" />
-        <FormInput name="last-name" label="Last name" />
-        <FormInput name="age" label="Age" type="number" />
-        <button type="button" onClick={() => console.log(values)}>
-          Submit
-        </button>
-      </form>
-    </FormContext.Provider>
-  );
-};
-
-export default Form;
diff --git a/src/components/NavBar.js b/src/components/NavBar.js
index 29151f3..46951d4 100644
--- a/src/components/NavBar.js
+++ b/src/components/NavBar.js
@@ -1,10 +1,75 @@
-import React from "react";
-import { NavLink as RouterNavLink } from "react-router-dom";
-
+import React, { useState } from "react";
+import PropTypes from "prop-types";
 import { useAuth0 } from "../react-auth0-spa";
+import clsx from "clsx";
+import { makeStyles } from "@material-ui/core/styles";
+import AppBar from "@material-ui/core/AppBar";
+import Toolbar from "@material-ui/core/Toolbar";
+import Typography from "@material-ui/core/Typography";
+import IconButton from "@material-ui/core/IconButton";
+import Badge from "@material-ui/core/Badge";
+import NotificationsIcon from "@material-ui/icons/Notifications";
+import MenuIcon from "@material-ui/icons/Menu";
+import Button from "@material-ui/core/Button";
+import Avatar from "@material-ui/core/Avatar";
+import Menu from "@material-ui/core/Menu";
+import MenuItem from "@material-ui/core/MenuItem";
+import { useHistory } from "react-router-dom";
+
+const drawerWidth = 240;
 
-const NavBar = () => {
+const useStyles = makeStyles((theme) => {
+  console.log(theme);
+  return {
+    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
+      })
+    },
+    toolbar: {
+      paddingRight: 24 // keep right padding when drawer closed
+    },
+    menuButton: {
+      marginRight: 36
+    },
+    menuButtonHidden: {
+      display: "none"
+    },
+    title: {
+      flexGrow: 1
+    },
+    avatar: {
+      color: theme.palette.common.white
+    },
+    avatarCircle: {
+      marginRight: theme.spacing(2)
+    }
+  };
+});
+
+const NavBar = ({ open, handleOpen }) => {
   const { user, isAuthenticated, loginWithRedirect, logout } = useAuth0();
+  const classes = useStyles();
+  const [anchorEl, setAnchorEl] = useState(null);
+  const history = useHistory();
+
+  const handleClick = (event) => {
+    setAnchorEl(event.currentTarget);
+  };
+
+  const handleClose = () => {
+    setAnchorEl(null);
+  };
 
   const logoutWithRedirect = () =>
     logout({
@@ -12,28 +77,68 @@ const NavBar = () => {
     });
 
   return (
-    <div className="nav-container">
-      {!isAuthenticated && (
-        <button id="qsLoginBtn" type="button" onClick={() => loginWithRedirect({})}>
-          Log in
-        </button>
-      )}
-      {isAuthenticated && (
-        <ul>
-          <li>
-            <img src={user.picture} alt="Profile" className="nav-user-profile rounded-circle" width="50" />
-            {user.name}
-          </li>
-          <li>
-            <RouterNavLink to="/profile">Profile</RouterNavLink>
-          </li>
-          <li>
-            <button onClick={() => logoutWithRedirect()}>Log out</button>
-          </li>
-        </ul>
-      )}
-    </div>
+    <AppBar position="absolute" className={clsx(classes.appBar, isAuthenticated && open && classes.appBarShift)}>
+      <Toolbar className={classes.toolbar}>
+        {isAuthenticated && (
+          <IconButton
+            edge="start"
+            color="inherit"
+            aria-label="open drawer"
+            onClick={handleOpen}
+            className={clsx(classes.menuButton, open && classes.menuButtonHidden)}
+          >
+            <MenuIcon />
+          </IconButton>
+        )}
+        <Typography component="h1" variant="h6" color="inherit" noWrap className={classes.title}>
+          Dashboard
+        </Typography>
+        {isAuthenticated && (
+          <IconButton color="inherit">
+            <Badge badgeContent={4} color="secondary">
+              <NotificationsIcon />
+            </Badge>
+          </IconButton>
+        )}
+        {!isAuthenticated && (
+          <Button id="qsLoginBtn" variant="contained" type="button" onClick={() => loginWithRedirect({})}>
+            Log in
+          </Button>
+        )}
+        {isAuthenticated && (
+          <div>
+            <Button className={clsx(classes.avatar)} aria-controls="simple-menu" aria-haspopup="true" onClick={handleClick}>
+              <Avatar src={user.picture} alt="Profile" className={clsx(classes.avatarCircle)} />
+              {user.name}
+            </Button>
+            <Menu id="simple-menu" anchorEl={anchorEl} keepMounted open={Boolean(anchorEl)} onClose={handleClose}>
+              <MenuItem
+                onClick={() => {
+                  handleClose();
+                  history.push("/profile");
+                }}
+              >
+                Profile
+              </MenuItem>
+              <MenuItem
+                onClick={() => {
+                  handleClose();
+                  logoutWithRedirect();
+                }}
+              >
+                Log out
+              </MenuItem>
+            </Menu>
+          </div>
+        )}
+      </Toolbar>
+    </AppBar>
   );
 };
 
+NavBar.propTypes = {
+  open: PropTypes.bool,
+  handleOpen: PropTypes.func
+};
+
 export default NavBar;
diff --git a/src/components/Navigation.js b/src/components/Navigation.js
new file mode 100644
index 0000000..1ec233f
--- /dev/null
+++ b/src/components/Navigation.js
@@ -0,0 +1,36 @@
+import React from "react";
+import clsx from "clsx";
+import ListItem from "@material-ui/core/ListItem";
+import ListItemIcon from "@material-ui/core/ListItemIcon";
+import ListItemText from "@material-ui/core/ListItemText";
+import DashboardIcon from "@material-ui/icons/Dashboard";
+import { NavLink as RouterNavLink } from "react-router-dom";
+import { makeStyles } from "@material-ui/core/styles";
+
+const useStyles = makeStyles((theme) => ({
+  link: {
+    textDecoration: "none",
+    color: theme.palette.text.primary,
+    "&:hover": {
+      textDecoration: "none"
+    }
+  }
+}));
+
+const Navigation = () => {
+  const styles = useStyles();
+  return (
+    <div>
+      <RouterNavLink to="/" className={clsx(styles.link)} activeClassName="selected">
+        <ListItem button>
+          <ListItemIcon>
+            <DashboardIcon />
+          </ListItemIcon>
+          <ListItemText primary="Dashboard" />
+        </ListItem>
+      </RouterNavLink>
+    </div>
+  );
+};
+
+export default Navigation;
diff --git a/src/views/Home.js b/src/views/Home.js
index 517df01..f89852c 100644
--- a/src/views/Home.js
+++ b/src/views/Home.js
@@ -35,7 +35,6 @@ const headerTemplate = {
 
 const DataTable = ({ rows }) => {
   const classes = useStyles();
-  console.log(classes);
   return (
     <TableContainer className={classes.tableContainer} component={Paper}>
       <Table className={classes.table} aria-label="simple table">
diff --git a/src/views/bordel.js b/src/views/bordel.js
deleted file mode 100644
index 1426a96..0000000
--- a/src/views/bordel.js
+++ /dev/null
@@ -1,11 +0,0 @@
-import React from 'react';
-import Form from '../bordel/form';
-
-const Bordel = () => (
-  <div>
-    <h1>There is a form</h1>
-    <Form />
-  </div>
-)
-
-export default Bordel;
diff --git a/yarn.lock b/yarn.lock
index 40dcee5..bd23de3 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -1213,6 +1213,13 @@
     react-is "^16.8.0"
     react-transition-group "^4.3.0"
 
+"@material-ui/icons@^4.9.1":
+  version "4.9.1"
+  resolved "https://registry.yarnpkg.com/@material-ui/icons/-/icons-4.9.1.tgz#fdeadf8cb3d89208945b33dbc50c7c616d0bd665"
+  integrity sha512-GBitL3oBWO0hzBhvA9KxqcowRUsA0qzwKkURyC8nppnC3fw54KPKZ+d4V1Eeg/UnDRSzDaI9nGCdel/eh9AQMg==
+  dependencies:
+    "@babel/runtime" "^7.4.4"
+
 "@material-ui/styles@^4.9.0":
   version "4.9.0"
   resolved "https://registry.yarnpkg.com/@material-ui/styles/-/styles-4.9.0.tgz#10c31859f6868cfa9d3adf6b6c3e32c9d676bc76"
@@ -2668,7 +2675,7 @@ clone-deep@^2.0.1:
     kind-of "^6.0.0"
     shallow-clone "^1.0.0"
 
-clsx@^1.0.2:
+clsx@^1.0.2, clsx@^1.1.0:
   version "1.1.0"
   resolved "https://registry.yarnpkg.com/clsx/-/clsx-1.1.0.tgz#62937c6adfea771247c34b54d320fb99624f5702"
   integrity sha512-3avwM37fSK5oP6M5rQ9CNe99lwxhXDOeSWVPAOYF6OazUTgZCMb0yWlJpmdD74REy1gkEaFiub2ULv4fq9GUhA==
-- 
GitLab