Commit 8cb617b8 authored by Florent Chehab's avatar Florent Chehab Committed by Florent Chehab
Browse files

refacto(Front): more hookification

parent 57ce7f17
......@@ -17,65 +17,80 @@ import {
settingsMenuItems
} from "./menuItems";
class DrawerMenu extends React.Component {
toListItem(items, inset = false) {
const { closeDrawer } = this.props;
const ListItemHeading = ({ label, Icon }) => (
<ListItem>
<ListItemIcon>
<Icon />
</ListItemIcon>
<ListItemText primary={label} />
</ListItem>
);
return items.map(({ label, route, Icon }, idx) => (
ListItemHeading.propTypes = {
label: PropTypes.node.isRequired,
Icon: PropTypes.object.isRequired
};
const ListItemsTmp = ({ items, onClick, inset }) => (
<>
{items.map(({ label, route, Icon }, idx) => (
// eslint-disable-next-line react/no-array-index-key
<CustomNavLink key={idx} to={route} onClick={() => closeDrawer()}>
<ListItem button onClick={() => closeDrawer()}>
{Icon !== null ? (
<CustomNavLink key={idx} to={route} onClick={onClick}>
<ListItem button onClick={onClick}>
{Icon !== null && (
<ListItemIcon>
<Icon />
</ListItemIcon>
) : (
<></>
)}
<ListItemText primary={label} inset={inset} />
</ListItem>
</CustomNavLink>
));
}
))}
</>
);
ListItemsTmp.propTypes = {
items: PropTypes.array.isRequired,
onClick: PropTypes.func.isRequired,
inset: PropTypes.bool
};
toListItemBasic(label, Icon) {
return (
<ListItem>
<ListItemIcon>
<Icon />
</ListItemIcon>
<ListItemText primary={label} />
</ListItem>
);
}
ListItemsTmp.defaultProps = {
inset: false
};
render() {
const { closeDrawer, open } = this.props;
function DrawerMenu({ open, closeDrawer }) {
const ListItems = props => <ListItemsTmp {...props} onClick={closeDrawer} />;
return (
<div style={{ zIndex: 200000 }}>
<Drawer open={open} onClose={() => closeDrawer()}>
<List>{this.toListItem([mainMenuHome])}</List>
<Divider />
<List>{this.toListItem(mainMenuItems)}</List>
<Divider />
<List>{this.toListItem(secondaryMenuItems)}</List>
<Divider />
<List>
{this.toListItemBasic(<em>Informations</em>, InfoIcon)}
<Divider variant="inset" />
{this.toListItem(infoMenuItems, true)}
</List>
return (
<div style={{ zIndex: 200000 }}>
<Drawer open={open} onClose={closeDrawer}>
<List>
<ListItems items={[mainMenuHome]} />
</List>
<Divider />
<List>
<ListItems items={mainMenuItems} />
</List>
<Divider />
<List>
<ListItems items={secondaryMenuItems} />
<Divider />
<List>
{this.toListItemBasic(<em>Paramètres</em>, SettingsIcon)}
<Divider variant="inset" />
{this.toListItem(settingsMenuItems, true)}
</List>
</Drawer>
</div>
);
}
</List>
<List>
<ListItemHeading label={<em>Informations</em>} Icon={InfoIcon} />
<Divider variant="inset" />
<ListItems items={infoMenuItems} inset />
</List>
<Divider />
<List>
<ListItemHeading label={<em>Paramètres</em>} Icon={SettingsIcon} />
<Divider variant="inset" />
<ListItems items={settingsMenuItems} inset />
</List>
</Drawer>
</div>
);
}
DrawerMenu.propTypes = {
......@@ -83,4 +98,4 @@ DrawerMenu.propTypes = {
closeDrawer: PropTypes.func.isRequired
};
export default DrawerMenu;
export default React.memo(DrawerMenu);
......@@ -4,9 +4,9 @@ import MenuIcon from "@material-ui/icons/Menu";
import SettingsIcon from "@material-ui/icons/Settings";
import InfoIcon from "@material-ui/icons/Info";
import Button from "@material-ui/core/Button";
import withStyles from "@material-ui/core/styles/withStyles";
import PropTypes from "prop-types";
import Fab from "@material-ui/core/Fab";
import { makeStyles } from "@material-ui/styles";
import {
infoMenuItems,
mainMenuItems,
......@@ -20,8 +20,9 @@ import CustomNavLink from "../common/CustomNavLink";
import classNames from "../../utils/classNames";
import Logo from "./Logo";
import BaseTemplate from "./BaseTemplate";
import useOpenClose from "../../hooks/useOpenClose";
const styles = theme => {
const useStyles = makeStyles(theme => {
const onDesktops = "@media (min-width:1375px)";
const onMobiles = "@media (max-width:1375px)";
......@@ -110,195 +111,195 @@ const styles = theme => {
width: "100%"
}
};
};
});
class MainAppFrame extends React.Component {
state = {
drawerOpened: false
};
function SecondaryIcons() {
const classes = useStyles();
return (
<div className={classes.ifNotTooSmallAndInlined}>
<IconWithMenu
Icon={InfoIcon}
iconProps={{ className: classes.mobileIcon }}
fabProps={{
color: "primary",
className: classes.mobileIconContainer,
classes: { primary: classes.primaryDark }
}}
menuItems={infoMenuItems}
/>
openDrawer() {
this.setState({ drawerOpened: true });
}
<IconWithMenu
Icon={SettingsIcon}
iconProps={{ className: classes.mobileIcon }}
fabProps={{
color: "primary",
className: classes.mobileIconContainer,
classes: { primary: classes.primaryDark }
}}
menuItems={settingsMenuItems}
/>
</div>
);
}
closeDrawer() {
this.setState({ drawerOpened: false });
}
/**
* Helper to render the full size versions of the menu items
*
* @param items
* @returns {*}
* @constructor
*/
function MenuItems({ items }) {
const classes = useStyles();
return (
<div
className={classNames(
classes.desktopOnly,
classes.centered,
classes.widthFitContent
)}
>
{items.map(({ label, Icon, route }, idx) => (
// eslint-disable-next-line react/no-array-index-key
<CustomNavLink to={route} key={idx}>
<Button
color="default"
className={classNames(
classes.mainMenuButton,
classes.contrastTextPrimary
)}
>
{label}
{<Icon className={classes.mainMenuButtonIcon} />}
</Button>
</CustomNavLink>
))}
</div>
);
}
/**
* Helper to render the full size versions of the menu items
* @param items
*/
renderMenuItems(items) {
const { classes } = this.props;
return (
<div
className={classNames(
classes.desktopOnly,
classes.centered,
classes.widthFitContent
)}
>
{items.map(({ label, Icon, route }, idx) => (
// eslint-disable-next-line react/no-array-index-key
<CustomNavLink to={route} key={idx}>
<Button
color="default"
className={classNames(
classes.mainMenuButton,
classes.contrastTextPrimary
)}
>
{label}
{<Icon className={classes.mainMenuButtonIcon} />}
</Button>
</CustomNavLink>
))}
</div>
);
}
MenuItems.propTypes = {
items: PropTypes.array.isRequired
};
/**
* Helper to render simplified versions (icon based) of menu
* @param items
*/
renderSimplified(items) {
const { classes } = this.props;
return (
<div className={classes.ifNotTooSmallAndInlined}>
{items.map(({ label, Icon, route }, idx) => (
// eslint-disable-next-line react/no-array-index-key
<CustomNavLink to={route} key={idx}>
<Fab
size="medium"
color="primary"
classes={{ primary: classes.primaryDark }}
aria-label={label}
className={classes.mobileIconContainer}
>
{
<Icon
className={classNames(
classes.mobileIcon,
classes.contrastTextSecondary
)}
/>
}
</Fab>
</CustomNavLink>
))}
</div>
);
}
/**
* Helper to render simplified versions (icon based) of menu
* @param items
*/
function SimplifiedItems({ items }) {
const classes = useStyles();
return (
<div className={classes.ifNotTooSmallAndInlined}>
{items.map(({ label, Icon, route }, idx) => (
// eslint-disable-next-line react/no-array-index-key
<CustomNavLink to={route} key={idx}>
<Fab
size="medium"
color="primary"
classes={{ primary: classes.primaryDark }}
aria-label={label}
className={classes.mobileIconContainer}
>
{
<Icon
className={classNames(
classes.mobileIcon,
classes.contrastTextSecondary
)}
/>
}
</Fab>
</CustomNavLink>
))}
</div>
);
}
renderSimplifiedLeft() {
const { classes } = this.props;
return (
<div className={classes.mobileOnly}>
<IconButton
className={classes.menuButton}
color="inherit"
aria-label="Menu"
onClick={() => this.openDrawer()}
>
<MenuIcon className={classes.menuButtonIcon} />
</IconButton>
{this.renderSimplified(mainMenuItems)}
</div>
);
}
SimplifiedItems.propTypes = {
items: PropTypes.array.isRequired
};
renderSimplifiedRight() {
const { classes } = this.props;
return (
<div className={classes.mobileOnly}>
{this.renderSimplified(secondaryMenuItems)}
</div>
);
}
function SimplifiedLeft({ openDrawer }) {
const classes = useStyles();
return (
<div className={classes.mobileOnly}>
<IconButton
className={classes.menuButton}
color="inherit"
aria-label="Menu"
onClick={openDrawer}
>
<MenuIcon className={classes.menuButtonIcon} />
</IconButton>
<SimplifiedItems items={mainMenuItems} />
</div>
);
}
renderSecondaryIcons() {
const { classes } = this.props;
return (
<div className={classes.ifNotTooSmallAndInlined}>
<IconWithMenu
Icon={InfoIcon}
iconProps={{ className: classes.mobileIcon }}
fabProps={{
color: "primary",
className: classes.mobileIconContainer,
classes: { primary: classes.primaryDark }
}}
menuItems={infoMenuItems}
/>
SimplifiedLeft.propTypes = {
openDrawer: PropTypes.func.isRequired
};
<IconWithMenu
Icon={SettingsIcon}
iconProps={{ className: classes.mobileIcon }}
fabProps={{
color: "primary",
className: classes.mobileIconContainer,
classes: { primary: classes.primaryDark }
}}
menuItems={settingsMenuItems}
/>
</div>
);
}
function SimplifiedRight() {
const classes = useStyles();
return (
<div className={classes.mobileOnly}>
<SimplifiedItems items={secondaryMenuItems} />
</div>
);
}
render() {
const { classes, children } = this.props;
const { drawerOpened } = this.state;
function MainAppFrame({ children }) {
const classes = useStyles();
const [drawerOpened, openDrawer, closeDrawer] = useOpenClose(false);
const inBetween = (
<DrawerMenu open={drawerOpened} closeDrawer={() => this.closeDrawer()} />
);
const inBetween = (
<DrawerMenu open={drawerOpened} closeDrawer={closeDrawer} />
);
const toolbarContent = (
<>
<div className={classes.leftBlock}>
{this.renderMenuItems(mainMenuItems)}
{this.renderSimplifiedLeft()}
</div>
const toolbarContent = (
<>
<div className={classes.leftBlock}>
<MenuItems items={mainMenuItems} />
<SimplifiedLeft openDrawer={openDrawer} />
</div>
<div className={classes.middleBlock}>
<Logo linkTo={APP_ROUTES.base} />
</div>
<div className={classes.middleBlock}>
<Logo linkTo={APP_ROUTES.base} />
</div>
<div className={classes.rightBlock}>
<div style={{ flex: 2 }} />
<div
style={{
flex: 3,
flexBasis: "auto"
}}
>
{this.renderMenuItems(secondaryMenuItems)}
{this.renderSimplifiedRight()}
</div>
<div
style={{
flex: 4,
flexBasis: "auto"
}}
>
{this.renderSecondaryIcons()}
</div>
<div className={classes.rightBlock}>
<div style={{ flex: 2 }} />
<div
style={{
flex: 3,
flexBasis: "auto"
}}
>
<MenuItems items={secondaryMenuItems} />
<SimplifiedRight />
</div>
</>
);
<div
style={{
flex: 4,
flexBasis: "auto"
}}
>
<SecondaryIcons />
</div>
</div>
</>
);
return (
<BaseTemplate toolbarContent={toolbarContent} inBetween={inBetween}>
{children}
</BaseTemplate>
);
}
return (
<BaseTemplate toolbarContent={toolbarContent} inBetween={inBetween}>
{children}
</BaseTemplate>
);
}
MainAppFrame.propTypes = {
classes: PropTypes.object.isRequired,
children: PropTypes.node.isRequired
};
export default withStyles(styles, { withTheme: true })(MainAppFrame);
export default MainAppFrame;
import React from "react";
import PropTypes from "prop-types";
import { compose } from "recompose";
import { connect } from "react-redux";
import Alert from "./Alert";
import getActions from "../../redux/api/getActions";
import RequestParams from "../../redux/api/RequestParams";
import useDeleteOne from "../../hooks/useDeleteOne";
class DeleteHandler extends React.Component {
handleDelete() {
const { route, id, performDelete, performClose } = this.props;
performDelete(route, id, () => performClose());
}
function DeleteHandler({ performClose, route, id }) {
const performDelete = useDeleteOne(route);
render() {
const { performClose } = this.props;
return (
<Alert
open
info={false}
title="Confirmer la suppression de l'object."
description="Ếtes-vous sûr⋅e ?"
agreeText="Oui"
disagreeText="Non"
handleClose={() => performClose()}
handleResponse={confirmed => {
if (confirmed) this.handleDelete();
else performClose();
}}
/>
);
}
return (
<Alert
open
info={false}
title="Confirmer la suppression de l'object."
description="Ếtes-vous sûr⋅e ?"
agreeText="Oui"
disagreeText="Non"
handleClose={performClose}
handleResponse={confirmed => {
if (confirmed) performDelete(id, () => performClose());
else performClose();
}}
/>
);
}
DeleteHandler.propTypes = {
......@@ -39,24 +29,7 @@ DeleteHandler.propTypes = {
PropTypes.string.isRequired,
PropTypes.number.isRequired
]).isRequired,
performClose: PropTypes.func.isRequired,
performDelete: PropTypes.func.isRequired
performClose: PropTypes.func.isRequired
};
const mapDispatchToProps = dispatch => ({
performDelete: (route, id, onSuccess) =>
dispatch(
getActions(route).delete(
RequestParams.Builder.withId(id)
.withOnSuccessCallback(onSuccess)
.build()
)
)