Break layout into small pieces

master
Tudor Stanciu 2023-03-04 00:37:52 +02:00
parent 735015c516
commit dfcabbe0ce
8 changed files with 312 additions and 270 deletions

View File

@ -1,6 +1,6 @@
import React from "react"; import React from "react";
import PropTypes from "prop-types"; import PropTypes from "prop-types";
import Layout from "./Layout"; import AppLayout from "./layout/AppLayout";
import { BrowserRouter, Switch, Redirect, Route } from "react-router-dom"; import { BrowserRouter, Switch, Redirect, Route } from "react-router-dom";
import { useTuitioToken } from "@flare/tuitio-client-react"; import { useTuitioToken } from "@flare/tuitio-client-react";
import LoginContainer from "../features/login/components/LoginContainer"; import LoginContainer from "../features/login/components/LoginContainer";
@ -63,7 +63,7 @@ const App = () => {
<BrowserRouter basename={process.env.PUBLIC_URL || ""}> <BrowserRouter basename={process.env.PUBLIC_URL || ""}>
<Switch> <Switch>
<PublicRoute path="/login" component={LoginContainer} /> <PublicRoute path="/login" component={LoginContainer} />
<PrivateRoute path="/" component={Layout} /> <PrivateRoute path="/" component={AppLayout} />
</Switch> </Switch>
</BrowserRouter> </BrowserRouter>
); );

View File

@ -1,253 +0,0 @@
import React from "react";
import clsx from "clsx";
import { makeStyles, useTheme } from "@material-ui/core/styles";
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 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 DeleteIcon from "@material-ui/icons/Delete";
import DnsIcon from "@material-ui/icons/Dns";
import MenuItem from "@material-ui/core/MenuItem";
import Menu from "@material-ui/core/Menu";
import AccountCircle from "@material-ui/icons/AccountCircle";
import SettingsIcon from "@material-ui/icons/Settings";
import DashboardIcon from "@material-ui/icons/Dashboard";
import Main from "./layout/Main";
import { useHistory } from "react-router-dom";
import { useTuitioClient } from "@flare/tuitio-client-react";
const drawerWidth = 240;
const useStyles = makeStyles(theme => ({
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
},
title: {
flexGrow: 1
},
content: {
flexGrow: 1,
padding: theme.spacing(2)
}
}));
export default function MiniDrawer() {
const classes = useStyles();
const theme = useTheme();
const [open, setOpen] = React.useState(false);
const history = useHistory();
const { logout } = useTuitioClient();
const handleDrawerOpen = () => {
setOpen(true);
};
const handleDrawerClose = () => {
setOpen(false);
};
const [userAnchorEl, setUserAnchorEl] = React.useState(null);
const openUser = Boolean(userAnchorEl);
const handleMenu = event => {
setUserAnchorEl(event.currentTarget);
};
const handleClose = () => {
setUserAnchorEl(null);
};
return (
<div className={classes.root}>
<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>
<Typography variant="h6" noWrap className={classes.title}>
Network resurrector
</Typography>
<div>
<IconButton
aria-label="account of current user"
aria-controls="menu-appbar"
aria-haspopup="true"
onClick={handleMenu}
color="inherit"
>
<AccountCircle />
</IconButton>
<Menu
id="menu-appbar"
anchorEl={userAnchorEl}
anchorOrigin={{
vertical: "top",
horizontal: "right"
}}
keepMounted
transformOrigin={{
vertical: "top",
horizontal: "right"
}}
open={openUser}
onClose={handleClose}
>
<MenuItem
onClick={() => {
history.push("/user-profile");
handleClose();
}}
>
Profile
</MenuItem>
<MenuItem onClick={() => logout()}>Logout</MenuItem>
</Menu>
</div>
</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>
<Divider />
<List>
<ListItem
button
key="dashboard"
onClick={() => history.push("/dashboard")}
>
<ListItemIcon>
<DashboardIcon />
</ListItemIcon>
<ListItemText primary={"Dashboard"} />
</ListItem>
<ListItem
button
key="machines"
onClick={() => history.push("/machines")}
>
<ListItemIcon>
<DnsIcon />
</ListItemIcon>
<ListItemText primary={"Machines"} />
</ListItem>
</List>
<Divider />
<List>
<ListItem button key="trash" onClick={() => history.push("/trash")}>
<ListItemIcon>
<DeleteIcon />
</ListItemIcon>
<ListItemText primary={"Trash"} />
</ListItem>
<ListItem
button
key="settings"
onClick={() => history.push("/settings")}
>
<ListItemIcon>
<SettingsIcon />
</ListItemIcon>
<ListItemText primary={"Settings"} />
</ListItem>
</List>
</Drawer>
<main className={classes.content}>
<div className={classes.toolbar} />
<Main />
</main>
</div>
);
}

View File

@ -0,0 +1,34 @@
import React, { useState } from "react";
import { makeStyles } from "@material-ui/core/styles";
import AppRoutes from "./AppRoutes";
import TopBar from "./TopBar";
import Sidebar from "./Sidebar";
import styles from "./styles";
const useStyles = makeStyles(styles);
const AppLayout = () => {
const [open, setOpen] = useState(false);
const classes = useStyles();
const handleDrawerOpen = () => {
setOpen(true);
};
const handleDrawerClose = () => {
setOpen(false);
};
return (
<div className={classes.root}>
<TopBar open={open} handleDrawerOpen={handleDrawerOpen} />
<Sidebar open={open} handleDrawerClose={handleDrawerClose} />
<main className={classes.content}>
<div className={classes.toolbar} />
<AppRoutes />
</main>
</div>
);
};
export default AppLayout;

View File

@ -6,7 +6,7 @@ import NetworkContainer from "../../features/network/components/NetworkContainer
import SettingsContainer from "../../features/settings/components/SettingsContainer"; import SettingsContainer from "../../features/settings/components/SettingsContainer";
import DashboardContainer from "../../features/dashboard/components/DashboardContainer"; import DashboardContainer from "../../features/dashboard/components/DashboardContainer";
const Switcher = () => { const AppRoutes = () => {
return ( return (
<Switch> <Switch>
<Route exact path="/dashboard" component={DashboardContainer} /> <Route exact path="/dashboard" component={DashboardContainer} />
@ -18,4 +18,4 @@ const Switcher = () => {
); );
}; };
export default Switcher; export default AppRoutes;

View File

@ -1,13 +0,0 @@
import React from "react";
import Switcher from "./Switcher";
import { useTuitioToken } from "@flare/tuitio-client-react";
import LoginContainer from "../../features/login/components/LoginContainer";
const Main = () => {
const { validate: validateToken } = useTuitioToken();
const tokenIsValid = validateToken();
return <>{tokenIsValid ? <Switcher /> : <LoginContainer />}</>;
};
export default Main;

View File

@ -0,0 +1,102 @@
import React from "react";
import PropTypes from "prop-types";
import clsx from "clsx";
import { makeStyles, useTheme } from "@material-ui/core/styles";
import Drawer from "@material-ui/core/Drawer";
import List from "@material-ui/core/List";
import Divider from "@material-ui/core/Divider";
import IconButton from "@material-ui/core/IconButton";
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 DeleteIcon from "@material-ui/icons/Delete";
import DnsIcon from "@material-ui/icons/Dns";
import SettingsIcon from "@material-ui/icons/Settings";
import DashboardIcon from "@material-ui/icons/Dashboard";
import { useHistory } from "react-router-dom";
import styles from "./styles";
const useStyles = makeStyles(styles);
const Sidebar = ({ open, handleDrawerClose }) => {
const classes = useStyles();
const theme = useTheme();
const history = useHistory();
return (
<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>
<Divider />
<List>
<ListItem
button
key="dashboard"
onClick={() => history.push("/dashboard")}
>
<ListItemIcon>
<DashboardIcon />
</ListItemIcon>
<ListItemText primary={"Dashboard"} />
</ListItem>
<ListItem
button
key="machines"
onClick={() => history.push("/machines")}
>
<ListItemIcon>
<DnsIcon />
</ListItemIcon>
<ListItemText primary={"Machines"} />
</ListItem>
</List>
<Divider />
<List>
<ListItem button key="trash" onClick={() => history.push("/trash")}>
<ListItemIcon>
<DeleteIcon />
</ListItemIcon>
<ListItemText primary={"Trash"} />
</ListItem>
<ListItem
button
key="settings"
onClick={() => history.push("/settings")}
>
<ListItemIcon>
<SettingsIcon />
</ListItemIcon>
<ListItemText primary={"Settings"} />
</ListItem>
</List>
</Drawer>
);
};
Sidebar.propTypes = {
open: PropTypes.bool.isRequired,
handleDrawerClose: PropTypes.func.isRequired
};
export default Sidebar;

View File

@ -0,0 +1,104 @@
import React, { useState } from "react";
import PropTypes from "prop-types";
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 MenuIcon from "@material-ui/icons/Menu";
import MenuItem from "@material-ui/core/MenuItem";
import Menu from "@material-ui/core/Menu";
import AccountCircle from "@material-ui/icons/AccountCircle";
import { useHistory } from "react-router-dom";
import { useTuitioClient } from "@flare/tuitio-client-react";
import styles from "./styles";
const useStyles = makeStyles(styles);
const TopBar = ({ open, handleDrawerOpen }) => {
const classes = useStyles();
const history = useHistory();
const { logout } = useTuitioClient();
const [userAnchorEl, setUserAnchorEl] = useState(null);
const openUserMenu = Boolean(userAnchorEl);
const handleMenu = event => {
setUserAnchorEl(event.currentTarget);
};
const handleClose = () => {
setUserAnchorEl(null);
};
return (
<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>
<Typography variant="h6" noWrap className={classes.title}>
Network resurrector
</Typography>
<div>
<IconButton
aria-label="account of current user"
aria-controls="menu-appbar"
aria-haspopup="true"
onClick={handleMenu}
color="inherit"
>
<AccountCircle />
</IconButton>
<Menu
id="menu-appbar"
anchorEl={userAnchorEl}
anchorOrigin={{
vertical: "top",
horizontal: "right"
}}
keepMounted
transformOrigin={{
vertical: "top",
horizontal: "right"
}}
open={openUserMenu}
onClose={handleClose}
>
<MenuItem
onClick={() => {
history.push("/user-profile");
handleClose();
}}
>
Profile
</MenuItem>
<MenuItem onClick={() => logout()}>Logout</MenuItem>
</Menu>
</div>
</Toolbar>
</AppBar>
);
};
TopBar.propTypes = {
open: PropTypes.bool.isRequired,
handleDrawerOpen: PropTypes.func.isRequired
};
export default TopBar;

View File

@ -0,0 +1,68 @@
const drawerWidth = 240;
const styles = theme => ({
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
},
title: {
flexGrow: 1
},
content: {
flexGrow: 1,
padding: theme.spacing(2)
}
});
export default styles;