Commit bb86267b authored by TJHeeringa's avatar TJHeeringa

Massive Routing restructering

parent 2c9c1a00
import "@icon/open-iconic/open-iconic.css";
import MomentUtils from "@date-io/moment";
import { library } from "@fortawesome/fontawesome-svg-core";
import { fab } from "@fortawesome/free-brands-svg-icons";
import {faBars,faCheck,faChevronLeft,faHome,faIgloo,faPlus,faSignOutAlt,faTimes,faUser} from "@fortawesome/free-solid-svg-icons";
import { faBars,faCheck,faChevronLeft,faHome,faIgloo,faPlus,faSignOutAlt,faTimes,faUser } from "@fortawesome/free-solid-svg-icons";
import CssBaseline from "@material-ui/core/CssBaseline";
import { MuiPickersUtilsProvider } from "@material-ui/pickers";
import { BrowserRouter as Router } from "react-router-dom";
import moment from "moment";
import React from "react";
import { BrowserRouter as Router } from "react-router-dom";
import AlertHandlerProvider from "./Contexts/AlertHandler";
import Authenticator from "./Contexts/Authentication";
import LocaleProvider from "./Contexts/Locale";
import PageLayoutProvider from "./Contexts/PageLayout";
import RestProvider from "./Contexts/RestProvider";
import ThemeProvider from "./Contexts/Theme";
import { Routing } from "./Routing/Routing";
import AlertHandlerProvider from "./Contexts/AlertHandler";
import Routing from "./Routing/Routing";
require("bootstrap");
......@@ -30,13 +28,13 @@ const App = (props) => {
<Authenticator>
<ThemeProvider>
<CssBaseline/>
<MuiPickersUtilsProvider libInstance={moment} utils={MomentUtils}>
<LocaleProvider>
<PageLayoutProvider>
<RestProvider>
<Routing/>
</RestProvider>
</PageLayoutProvider>
</MuiPickersUtilsProvider>
</LocaleProvider>
</ThemeProvider>
</Authenticator>
</AlertHandlerProvider>
......
......@@ -105,7 +105,7 @@ const AssociationCard = (props) => {
/>
<Divider/>
<div className={styles.buttonSeparator}>
<Button variant={"contained"} color={"primary"} onClick={()=>history.push("/protected/v/associations/" + slug + "/info")}>Read more</Button>
<Button variant={"contained"} color={"primary"} onClick={()=>history.push("/protected/associations/" + slug + "/info")}>Read more</Button>
{becomeMemberButton && <Button variant={"contained"} color={"primary"} onClick={onBecomeMemberClick}>Become Member</Button>}
</div>
</CardContent>
......
import { makeStyles, useTheme } from "@material-ui/core/styles";
import {KeyboardDatePicker} from "@material-ui/pickers";
import { KeyboardDatePicker } from "@material-ui/pickers";
import PropTypes from "prop-types";
import React from "react";
import {TextValidator} from "react-material-ui-form-validator";
import EmailLists from "../../Pages/Email/EmailLists";
const useStyles = makeStyles(theme => ({
picker: {
......
import MenuItem from "@material-ui/core/MenuItem";
import React from "react";
import { ValidatorForm } from "react-material-ui-form-validator";
import {useLocale} from "../../Contexts/Locale";
import SelectField from "../Fields/SelectField";
const LocaleSwitch = (props) => {
const localer = useLocale();
return (
<ValidatorForm
onSubmit={()=>{}}
onError={errors => console.log(errors)}
>
<SelectField
name={"I18n"}
value={localer.locale}
onChange={event=>localer.setLocale(event.target.value)}
>
<MenuItem value={"en"}>English</MenuItem>
<MenuItem value={"fr"}>French</MenuItem>
</SelectField>
</ValidatorForm>
);
};
LocaleSwitch.propTypes = {
};
export default LocaleSwitch;
\ No newline at end of file
......@@ -5,9 +5,10 @@ import { Helper } from "App/Helper";
import PropTypes from "prop-types";
import React from "react";
import { ValidatorForm } from "react-material-ui-form-validator";
import { Button, Col, Container, Row } from "reactstrap";
import { Button, Col, Row } from "reactstrap";
import { useGet } from "restful-react";
import { v4 as uuidv4 } from "uuid";
import Container from "@material-ui/core/Container";
import { useAlertHandler} from "../../Contexts/AlertHandler";
import DateField from "../Fields/DateField";
......@@ -39,21 +40,20 @@ const ProfileFormWithContainer = (props) => {
return (
<Container>
<Block>
<Row>
<Col sm={"12"}><h4>Profile</h4>
<hr className={"box-title-separator"}/>
{ process.env.REACT_APP_OSIRIS === "true" &&
<div>
<p>Instead of filling in the form, you can also simple sync your profile with the Osiris. This
means that whenever you move, your address will automatically be changed. This is the
recommended option.
</p>
<Osiris/>
</div>
}
<ProfileFormWithoutContainer {...props} />
</Col>
</Row>
<Typography variant={"h4"}>Profile</Typography>
<hr className={"box-title-separator"}/>
{ process.env.REACT_APP_OSIRIS === "true" &&
<div>
<Typography>
Instead of filling in the form, you can also simple
sync your profile with the Osiris. This means that
whenever you move, your address will automatically
be changed. This is the recommended option.
</Typography>
<Osiris/>
</div>
}
<ProfileFormWithoutContainer {...props} />
</Block>
</Container>
);
......@@ -214,13 +214,13 @@ const ProfileFormWithoutContainer = ({ update, profile, onSuccess, disabled, han
<Typography variant={"h5"}>Education</Typography>
<Wrapper>
<SelectField
name={"Master Student"}
name={"Phase"}
value={profile.is_master}
onChange={(event) => handleProfileChange("is_master", event.target.value)}
disabled={disabled}
>
<MenuItem value={true}>Yes</MenuItem>
<MenuItem value={false}>No</MenuItem>
<MenuItem value={true}>Master</MenuItem>
<MenuItem value={false}>Bachelor</MenuItem>
</SelectField>
</Wrapper>
<Wrapper>
......
......@@ -26,7 +26,7 @@ const ProfileInfo = ({ profile }) => {
"BIC": profile.bic_code
};
data["Education"] = {
"Master:": profile.is_master ? "Yes" : "No",
"Phase:": profile.is_master ? "Master" : "Bachelor",
"Study": profile.study
};
return data;
......
import IconButton from "@material-ui/core/IconButton";
import MuiMenu from "@material-ui/core/Menu";
import AccountCircle from "@material-ui/icons/AccountCircle";
import PropTypes from "prop-types";
import React from "react";
import MenuItemButton from "./MenuItemButton";
import MenuItemLink from "./MenuItemLink";
const Menu = ({ children, items }) => {
const [anchorEl, setAnchorEl] = React.useState(null);
const open = Boolean(anchorEl);
const handleClick = (event) => {setAnchorEl(event.currentTarget);};
const handleClose = () => {setAnchorEl(null);};
return (
<div>
<IconButton
aria-label={"account of current user"}
aria-controls={"menu-appbar"}
aria-haspopup={"true"}
onClick={handleClick}
color={"inherit"}
>
{ children }
</IconButton>
<MuiMenu
id={"menu-appbar"}
anchorEl={anchorEl}
anchorOrigin={{
vertical: "top",
horizontal: "right",
}}
keepMounted
transformOrigin={{
vertical: "top",
horizontal: "right",
}}
open={open}
onClose={handleClose}
>
{ items.map((item, id)=>{
if (item.to) {
return <MenuItemLink {...item} key={id}/>;
} else {
return <MenuItemButton {...item} key={id}/>;
}
}) }
</MuiMenu>
</div>
);
};
Menu.propTypes = {
items: PropTypes.array.isRequired
};
export default Menu;
\ No newline at end of file
import React from "react";
import MenuItem from "@material-ui/core/MenuItem";
import ListItemIcon from "@material-ui/core/ListItemIcon";
import ListItemText from "@material-ui/core/ListItemText";
import PropTypes from "prop-types";
const MenuItemButton = React.forwardRef((props, ref) => {
const { onClick, primary, icon } = props;
return (
<MenuItem
ref={ref}
button={true}
onClick={onClick}
primary={primary}
>
<ListItemIcon>{ icon }</ListItemIcon>
<ListItemText primary={primary} />
</MenuItem>
);
});
MenuItemButton.propTypes = {
onClick: PropTypes.func.isRequired,
primary: PropTypes.string.isRequired,
icon: PropTypes.element,
};
export default MenuItemButton;
\ No newline at end of file
import React from "react";
import MenuItem from "@material-ui/core/MenuItem";
import {Link} from "react-router-dom";
import ListItemIcon from "@material-ui/core/ListItemIcon";
import ListItemText from "@material-ui/core/ListItemText";
import PropTypes from "prop-types";
const MenuItemLink = React.forwardRef((props, ref) => {
const { to, primary, icon } = props;
return (
<MenuItem
ref={ref}
component={Link}
to={to}
primary={primary}
>
<ListItemIcon>{ icon }</ListItemIcon>
<ListItemText primary={primary} />
</MenuItem>
);
});
MenuItemLink.propTypes = {
to: PropTypes.string.isRequired,
primary: PropTypes.string.isRequired,
icon: PropTypes.element,
};
export default MenuItemLink;
\ No newline at end of file
import React, { Component } from "react";
import { useLocation,withRouter } from "react-router-dom";
import Header from "./Header/AssociationHeader";
import PageLayout from "./PageLayout";
import AssociationBoardSideBar from "./SideBar/AssociationBoardSideBar";
import AssociationMemberSideBar from "./SideBar/AssociationMemberSideBar";
import EmptySideBar from "./SideBar/EmptySideBar";
import PublicSideBar from "./SideBar/PublicSideBar";
const AssociationPageLayout = (props) => {
const location = useLocation();
const path = location.pathname;
let sidebar;
if (path === "/protected/v/home"){
sidebar = PublicSideBar;
} else {
sidebar = path.search("boardmember") < 0 ? AssociationMemberSideBar: AssociationBoardSideBar ;
sidebar = path.search("add") < 0 ? sidebar : EmptySideBar ;
let current_slug = path.split("/")[4];
let current_membership = props.data.association_memberships.find(membership=>membership.association.slug===current_slug);
if (current_membership !== undefined) {
sidebar = current_membership.status === "Pending" ? EmptySideBar : sidebar;
}
sidebar = path.search("settings") < 0 ? sidebar : EmptySideBar;
}
return (
<PageLayout
sidebar={sidebar}
header={Header}
avatar={true}
{...props.data}
>
{ props.children }
</PageLayout>
);
};
export default AssociationPageLayout;
import Avatar from "@material-ui/core/Avatar";
import Badge from "@material-ui/core/Badge";
import { withStyles } from "@material-ui/core/styles";
import AccountCircleIcon from "@material-ui/icons/AccountCircle";
import AddIcon from "@material-ui/icons/Add";
import StarsIcon from "@material-ui/icons/Stars";
import React, {Component} from "react";
import { FaBolt, FaCheck, FaPause, FaQuestion,FaTimes } from "react-icons/fa";
import { Link , withRouter } from "react-router-dom";
import {NavTab} from "react-router-tabs";
import sizeMe from "react-sizeme";
import { Dropdown, DropdownItem,DropdownMenu, DropdownToggle } from "reactstrap";
import { v4 as uuidv4 } from "uuid";
const AssociationsNavDropdown = (props) => {
const { url, association_memberships } = props;
const [ open, setOpen ] = React.useState(false);
const toggle = () => {setOpen(!open);};
return (
<Dropdown isOpen={open} toggle={toggle}>
<DropdownToggle caret nav>Associations</DropdownToggle>
<DropdownMenu>
{ association_memberships.map((association_membership) => {
let association = association_membership.association;
let path = url+"/associations/"+association.slug+(association.is_board ? "/boardmember" : "/member");
return (
<Link className={"dropdown-link"} to={path} key={uuidv4()}>
<DropdownItem>
{ association_membership.association.name }
</DropdownItem>
</Link>
);
}) }
</DropdownMenu>
</Dropdown>
);
};
const SmallAvatar = withStyles(theme => ({
root: {
width: 22,
height: 22,
border: `2px solid ${theme.palette.background.paper}`,
},
}))(Avatar);
const AssociationsNavTabs = (props) => {
const status_to_dict = {
"Accepted": <AccountCircleIcon/>,
"Disputed": <FaBolt/>,
"Pending": <FaQuestion/>,
"Rejected": <FaTimes/>
};
const getIsActive = (match, location, substring) => {
// console.log(match, location, substring);
return location.pathname.includes(substring);
};
return props.association_memberships.map((association_membership, id) => {
let association = association_membership.association;
let icon;
let subpath = props.url + "/associations/" + association.slug;
let path = subpath + "/member";
if (association.is_board) {
if (props.path.includes(association.slug + "/boardmember")){
path = subpath + "/member";
icon = <AccountCircleIcon/>;
} else {
path = subpath + "/boardmember";
icon = <StarsIcon/>;
}
} else {
icon = status_to_dict[association_membership.status];
}
return (
<NavTab to={path} key={uuidv4()} isActive={(match, location) => getIsActive(match, location, subpath)} allowClickOnActive={true}>
<Badge
overlap={"circle"}
anchorOrigin={{
vertical: "bottom",
horizontal: "right",
}}
badgeContent={<SmallAvatar variant={"circle"} alt={""}>{ icon }</SmallAvatar>}
>
<img onLoad={(image)=>props.onImgLoad(image, id)} className={"associationlogo"} src={association_membership.association.logo} alt={"associationlogo"}/>
</Badge>
</NavTab>
);
});
};
class Header extends Component {
constructor(props){
super(props);
this.state = {
imageWidths: []
};
}
calculateImageWidths = () => {
const arrSum = arr => arr.reduce((a,b) => a + b, 0);
return arrSum(this.state.imageWidths)+this.state.imageWidths.length*30;
}
calculateTotalNavBar = () => {
//the total sum of all the margins and icons
return this.calculateImageWidths()+45;
}
onImgLoad = ({target:img}, id) => {
if(this.state.imageWidths[id] === undefined) {
this.setState(prevState => {
let imageWidths = prevState.imageWidths;
imageWidths[id] = img.offsetWidth;
return {imageWidths: imageWidths};
});
}
}
render() {
let { match: { url } , association_memberships, history: { location: { pathname } } } = this.props;
return (
<div className={"navigation"}>
{ this.props.size.width > this.calculateTotalNavBar()
? (
<AssociationsNavTabs
association_memberships={association_memberships}
url={url}
path={pathname}
onImgLoad={this.onImgLoad}
/>)
: (
<AssociationsNavDropdown
association_memberships={association_memberships}
path={pathname}
url={url}
/>)
}
<NavTab to={url+"/associations/add"}><AddIcon style={{height: "42px"}} fontSize={"large"} color={"inherit"}/></NavTab>
</div>
);
}
}
export default sizeMe({ monitorHeight: true })(withRouter(Header));
\ No newline at end of file
import {Typography} from "@material-ui/core";
import {grey} from "@material-ui/core/colors";
import {makeStyles, useTheme} from "@material-ui/core/styles";
import AddIcon from "@material-ui/icons/Add";
import Menu from "App/Components/Menu/Menu";
import PropTypes from "prop-types";
import React from "react";
import logo from "../../../../img/logo oud.png";
const useStyles = makeStyles(theme=>({
association_logo: {
maxHeight: 42,
height: 42,
maxWidth: null
},
dropdown: {
color: grey[100]
}
}));
const AssociationsNavDropdown = ({ url, association_memberships }) => {
const theme = useTheme();
const classes = useStyles(theme);
let items = association_memberships.map(membership=>({
onClick: ()=>{},
primary: membership.association.name,
icon: <img src={membership.association.logo} className={classes.association_logo}/>
}));
items.unshift({onClick: ()=>{}, primary: "Home", icon: <img src={logo} className={classes.association_logo}/>});
items.push({onClick: ()=>{}, primary: "Add", icon: <AddIcon/>});
return (
<Menu items={items}>
<Typography variant={"h4"} className={classes.dropdown}>Associations</Typography>
</Menu>
);
};
AssociationsNavDropdown.propTypes = {
url: PropTypes.string.isRequired,
association_memberships: PropTypes.array.isRequired
};
export default AssociationsNavDropdown;
\ No newline at end of file
.HeaderBar {
display: flex;
padding-left: 20px;
padding-right: 20px;
justify-content: center; /* align horizontal */
align-items: center; /* align vertical */
height: 66px;
width: 100%;
}
.Header {
width: 100%;
background-color: white;
box-shadow: 1px 1px 5px rgba(0, 0, 0, .15);
position: fixed;
z-index: 300;
margin-top: -66px;
}