️ This Gitlab will be shut down at 2021-12-31 23:59:59.
Students and staff can migrate to gitlab.utwente.nl.
SNT members can migrate to gitlab.snt.utwente.nl.
Contact bestuur@snt.utwente.nl for more information.

Migrate your projects today!
Export your project using the webinterface or use a script.

Commit c5fa4003 authored by TJHeeringa's avatar TJHeeringa

Massive rewrite to include RTK Query

parent 4555d156
This diff is collapsed.
......@@ -5,30 +5,30 @@
"dependencies": {
"@date-io/core": "^1.3.13",
"@date-io/moment": "^1.3.13",
"@devexpress/dx-core": "^2.7.4",
"@devexpress/dx-react-core": "^2.7.1",
"@devexpress/dx-react-grid": "^2.7.1",
"@devexpress/dx-react-grid-export": "^2.7.1",
"@devexpress/dx-react-grid-material-ui": "^2.7.1",
"@devexpress/dx-react-scheduler": "^2.7.1",
"@devexpress/dx-react-scheduler-material-ui": "^2.7.1",
"@devexpress/dx-core": "^2.7.6",
"@devexpress/dx-react-core": "^2.7.6",
"@devexpress/dx-react-grid": "^2.7.6",
"@devexpress/dx-react-grid-export": "^2.7.6",
"@devexpress/dx-react-grid-material-ui": "^2.7.6",
"@devexpress/dx-react-scheduler": "^2.7.6",
"@devexpress/dx-react-scheduler-material-ui": "^2.7.6",
"@fortawesome/fontawesome-svg-core": "^1.2.30",
"@fortawesome/free-brands-svg-icons": "^5.15.0",
"@fortawesome/free-solid-svg-icons": "^5.14.0",
"@fortawesome/react-fontawesome": "^0.1.11",
"@fortawesome/react-fontawesome": "^0.1.15",
"@icon/open-iconic": "^1.1.4",
"@material-ui/core": "^4.11.0",
"@material-ui/icons": "^4.9.1",
"@material-ui/lab": "^4.0.0-alpha.56",
"@material-ui/pickers": "^3.2.10",
"@material-ui/core": "^4.12.3",
"@material-ui/icons": "^4.11.2",
"@material-ui/lab": "^4.0.0-alpha.60",
"@material-ui/pickers": "^3.3.10",
"@material-ui/styles": "^4.11.4",
"@mui-treasury/components": "^1.9.1",
"@mui-treasury/styling": "^0.2.8",
"@n8tb1t/use-scroll-position": "^2.0.3",
"@react-hook/size": "^2.1.1",
"@reduxjs/toolkit": "^1.6.1",
"availity-reactstrap-validation": "^2.6.1",
"bic-from-iban": "^1.0.0",
"bootstrap": "^4.5.2",
"bootstrap-switch-button-react": "^1.2.0",
"change-case": "^4.1.2",
"clsx": "^1.1.1",
"env-cmd": "^10.1.0",
......@@ -39,8 +39,9 @@
"js-cookie": "^2.2.1",
"json-loader": "^0.5.7",
"lodash": "^4.17.21",
"material-react-toastify": "^1.0.1",
"material-ui-phone-number": "^2.2.6",
"material-ui-search-bar": "^1.0.0-beta.14",
"material-ui-search-bar": "^1.0.0",
"moment": "^2.29.0",
"mui-numpad": "^0.1.4-alpha",
"node-sass": "^4.14.1",
......@@ -50,8 +51,6 @@
"query-string": "^6.13.1",
"react": "^16.13.1",
"react-big-calendar": "^0.31.0",
"react-bootstrap": "^1.3.0",
"react-bootstrap-switch": "^15.5.3",
"react-cookie": "^3.1.2",
"react-csv": "^2.0.3",
"react-datepicker": "^2.16.0",
......@@ -65,7 +64,7 @@
"react-router-dom": "^5.2.0",
"react-scripts": "^3.4.3",
"react-simple-tree-menu": "^1.1.18",
"react-sizeme": "^2.6.12",
"react-sizeme": "^3.0.2",
"react-table": "^6.11.5",
"reactstrap": "^8.5.1",
"recharts": "^2.1.0",
......
import "@icon/open-iconic/open-iconic.css";
import "material-react-toastify/dist/ReactToastify.css";
import { library } from "@fortawesome/fontawesome-svg-core";
import {fab, faDiscord, faSnapchat} from "@fortawesome/free-brands-svg-icons";
......@@ -16,6 +17,7 @@ import {
faWarehouse
} from "@fortawesome/free-solid-svg-icons";
import CssBaseline from "@material-ui/core/CssBaseline";
import {ToastContainer} from "material-react-toastify";
import React from "react";
import { Provider } from "react-redux";
import { BrowserRouter as Router } from "react-router-dom";
......@@ -37,6 +39,18 @@ library.add(faSignOutAlt, faUser, faIgloo, faBars, faCheck, faTimes, faHome,
const App = () => {
return (
<AlertHandlerProvider>
<ToastContainer
position={"bottom-center"}
autoClose={7000}
limit={3}
hideProgressBar={false}
newestOnTop
closeOnClick={false}
rtl={false}
pauseOnFocusLoss
draggable
pauseOnHover
/>
<Provider store={store}>
<Router>
<API>
......
......@@ -2,8 +2,7 @@ import PropTypes from "prop-types";
import React from "react";
import {Alert} from "reactstrap";
export const AlertHandler = (props) => {
const {color, message, visible} = props;
export const AlertHandler = ({color, message, visible}) => {
let color_message;
if (color) {
switch (color) {
......
import Box from "@material-ui/core/Box";
import Button from "@material-ui/core/Button";
import Card from "@material-ui/core/Card";
import CardContent from "@material-ui/core/CardContent";
import CardMedia from "@material-ui/core/CardMedia";
......
.react-datepicker-wrapper {
display: inline-block;
width:100%;
}
.react-datepicker__input-container {
width:100%;
position: relative;
display: inline-block;
}
import { makeStyles } from "@material-ui/core/styles";
import { KeyboardDatePicker } from "@material-ui/pickers";
import { DatePicker } from "@material-ui/pickers";
import moment from "moment";
import PropTypes from "prop-types";
import React from "react";
......@@ -30,7 +30,7 @@ const DateTimeField = ({name, value, onChange, apiFormat, ...remaining_props}) =
};
return (
<KeyboardDatePicker
<DatePicker
{...pickerEditorProps(name)}
{...remaining_props}
onChange={handleChange}
......@@ -52,4 +52,19 @@ DateTimeField.defaultProps = {
format: "YYYY-MM-DD"
};
const DateFieldV2 = (props) => {
const classes = useStyles();
return (
<DatePicker
inputVariant={"outlined"}
className={classes.picker}
ampm={false}
format={"L"}
{...props}
/>
);
};
export { DateFieldV2 };
export default DateTimeField;
\ No newline at end of file
import { makeStyles } from "@material-ui/core/styles";
import { KeyboardDateTimePicker } from "@material-ui/pickers";
import { DateTimePicker } from "@material-ui/pickers";
import moment from "moment";
import PropTypes from "prop-types";
import React from "react";
......@@ -30,7 +30,7 @@ const DateTimeField = ({name, value, onChange, apiFormat, ...remaining_props}) =
};
return (
<KeyboardDateTimePicker
<DateTimePicker
{...pickerEditorProps(name)}
{...remaining_props}
onChange={handleChange}
......@@ -52,4 +52,20 @@ DateTimeField.defaultProps = {
format: "YYYY-MM-DD HH:mm"
};
const DateTimeFieldV2 = (props) => {
const classes = useStyles();
return (
<DateTimePicker
inputVariant={"outlined"}
className={classes.picker}
ampm={false}
format={"L"}
{...props}
/>
);
};
export { DateTimeFieldV2 };
export default DateTimeField;
\ No newline at end of file
......@@ -41,7 +41,7 @@ const SpecificDataField = (props) =>{
<CheckboxField
validators={["required"]}
errorMessages={["This field is required"]}
label={field.name}
label={field.name + " *"}
value={value !== "False"}
checked={value !== "False"}
onChange={(event)=>onChange(field.url, event.target.checked ? "True" : "False")}
......
......@@ -130,7 +130,7 @@ const ProfileFormWithoutContainer = ({ update, profile, onSuccess, disabled, han
<Wrapper>
<TextField
name={"Given name"}
helperText={"This is the name you are commonly addressed with; in Dutch: roepnaam"}
helperText={"This is the name you are commonly addressed with; in Dutch: roepnaam. Example: People adres Henk Jan Boudewijn with Henk, so his given name is Henk."}
value={profile.given_name}
onChange={(event) => handleProfileChange("given_name", event.target.value)}
disabled={disabled}
......@@ -228,6 +228,7 @@ const ProfileFormWithoutContainer = ({ update, profile, onSuccess, disabled, han
<Wrapper>
<TextField
name={"Zip code"}
helperText={"Dutch: postcode"}
value={profile.zip_code}
onChange={(event) => handleProfileChange("zip_code", event.target.value)}
disabled={disabled}
......
import PropTypes from "prop-types";
import React from "react";
const withExtraProps = (WrappedComponent, extraProps) => props => {
return <WrappedComponent {...props} {...extraProps}/>;
};
withExtraProps.propTypes = {
WrappedComponent: PropTypes.elementType.isRequired,
extraProps: PropTypes.func.isRequired
};
export default withExtraProps;
\ No newline at end of file
import PropTypes from "prop-types";
import React from "react";
const withPropMap = (WrappedComponent, propMap) => props => {
return <WrappedComponent {...propMap(props)}/>;
};
withPropMap.propTypes = {
WrappedComponent: PropTypes.elementType.isRequired,
propMap: PropTypes.func.isRequired
};
export default withPropMap;
\ No newline at end of file
import PropTypes from "prop-types";
import React from "react";
import Info from "./Info";
const GroupInfo = ({ group }) => {
const morphGroupToData = (group) => {
return {
"Full Name": group.full_name,
"Short Name": group.short_name,
"Number": group.number,
"Creed": group.creed,
"Founding Date": group.founding_date,
"Dissolution Date": group.dissolution_date,
"Email": group.email,
"Description": group.description
};
};
return (
<Info
headerless={true}
data={morphGroupToData(group)}
/>
);
};
GroupInfo.propTypes = {
group: PropTypes.object.isRequired
};
export default GroupInfo;
\ No newline at end of file
......@@ -2,10 +2,10 @@ import React from "react";
import {useAlertHandler} from "../../Contexts/AlertHandler";
import {useAPI} from "../../Contexts/API";
import InfoForm from "../../InfoForms/InfoForm";
import AssociationForm from "../Forms/AssociationForm";
import AssociationInfo from "../Info/AssociationInfo";
import AssociationType from "../Types/Association";
import InfoForm from "./InfoForm";
const AssociationInfoWrapper = ({ info }) => <AssociationInfo association={info}/>;
......
import PropTypes from "prop-types";
import React, {useState} from "react";
import {GroupForm} from "../Forms/GroupForm";
import GroupInfo from "../Info/GroupInfo";
const Group = ({association, group: propGroup, parentable_groups, infoOrForm, ...props}) => {
const [group, setGroup] = useState(propGroup.association ? propGroup : {...propGroup, association: association.url});
const handleGroupChange = (field, value) => {
setGroup(prevState => ({...prevState, [field]:value}));
};
if (infoOrForm === "info") {
return (
<GroupInfo
group={group}
/>
);
} else {
return (
<GroupForm
group={group}
handleGroupChange={handleGroupChange}
parentable_groups={parentable_groups}
{...props}
/>
);
}
};
Group.propTypes = {
infoOrForm: PropTypes.string.isRequired,
parentable_groups: PropTypes.arrayOf(PropTypes.object),
group: PropTypes.object
};
Group.defaultProps = {
group: {
association: "",
full_name: "",
short_name: "",
description: "",
number: "",
creed: "",
email: "",
founding_date: "",
dissolution_date: "",
photo: "",
parent_group: ""
}
};
export default Group;
......@@ -2,7 +2,7 @@ import Collapse from "@material-ui/core/Collapse";
import List from "@material-ui/core/List";
import ListItem from "@material-ui/core/ListItem";
import ListItemText from "@material-ui/core/ListItemText";
import {fade, makeStyles} from "@material-ui/core/styles";
import { alpha, makeStyles} from "@material-ui/core/styles";
import ExpandLess from "@material-ui/icons/ExpandLess";
import ExpandMore from "@material-ui/icons/ExpandMore";
import PropTypes from "prop-types";
......@@ -10,7 +10,7 @@ import React from "react";
const useStyles = makeStyles(theme => ({
tableStriped: {
backgroundColor: fade(theme.palette.primary.main, 0.35),
backgroundColor: alpha(theme.palette.primary.main, 0.35),
},
}));
......
import Collapse from "@material-ui/core/Collapse";
import ListItem from "@material-ui/core/ListItem";
import ListItemText from "@material-ui/core/ListItemText";
import {fade, makeStyles} from "@material-ui/core/styles";
import {alpha, makeStyles} from "@material-ui/core/styles";
import ExpandLess from "@material-ui/icons/ExpandLess";
import ExpandMore from "@material-ui/icons/ExpandMore";
import PropTypes from "prop-types";
......@@ -9,7 +9,7 @@ import React from "react";
const useStyles = makeStyles(theme => ({
tableStriped: {
backgroundColor: fade(theme.palette.primary.main, 0.35),
backgroundColor: alpha(theme.palette.primary.main, 0.35),
},
}));
......
......@@ -26,13 +26,16 @@ import AssociationBoardSideBar from "./SideBar/AssociationBoardSideBar";
import AssociationMemberSideBar from "./SideBar/AssociationMemberSideBar";
import EmptySideBar from "./SideBar/EmptySideBar";
import PublicSideBar from "./SideBar/PublicSideBar";
import StudentUnionChannels from "./StudentUnionChannels";
import {useScrollPosition} from "@n8tb1t/use-scroll-position";
const drawerHeaderHeight = 90;
const drawerWidth = 240;
const styles = theme => ({
root: {
display: "flex",
marginTop: 90
// marginTop: 90
// overflow: "auto",
// msOverflowStyle: "none",
// scrollbarWidth: "none"
......@@ -71,7 +74,10 @@ const styles = theme => ({
padding: theme.spacing(0, 1),
...theme.mixins.toolbar,
justifyContent: "flex-end",
height: 90
height: drawerHeaderHeight
},
drawerHeaderTopOfScreen: {
height: 126
},
content: {
width: `calc(100% - ${drawerWidth}px)`,
......@@ -120,6 +126,8 @@ const PageLayout = ({ children }) => {
const { pathname } = useLocation();
const alerthandler = useAlertHandler();
const [topOfScreen, setTopOfScreen] = useState(126);
const mobile = useMediaQuery(theme.breakpoints.down("xs"));
const [openDrawer, setOpenDrawer] = useState(false);
......@@ -158,82 +166,103 @@ const PageLayout = ({ children }) => {
}
}, [authenticated]);
useScrollPosition(
({ currPos }) => {
const isTopOfScreen = currPos.y > -36;
if (isTopOfScreen) {
const height = drawerHeaderHeight + 36 + currPos.y;
if (topOfScreen !== height) {
setTopOfScreen(height);
}
} else {
if (topOfScreen !== drawerHeaderHeight) {
setTopOfScreen(drawerHeaderHeight);
}
}
},
[topOfScreen]
);
return (
<div className={classes.root}>
<nav className={classes.drawer}>
<AppBar
position={"fixed"}
className={classes.appBar}
>
<Toolbar>
<Burger open={openDrawer} onClick={toggleDrawer}/>
<SizeMe>{ ({ size }) =>
<div style={{width: "100%"}}>
<div className={classes.headerBar}>
<div className={classes.navigation}>
<Header size={size}/>
</div>
<div className={classes.navigation}>
{ /*<NotificationMenu/>*/ }
<AvatarMenu>
<MoreVertIcon fontSize={"large"} />
</AvatarMenu>
</div>
</div>
</div> }
</SizeMe>
</Toolbar>
</AppBar>
<Hidden smUp implementation={"js"}>
<Drawer
variant={"temporary"}
anchor={"left"}
open={openDrawer}
onClose={handleDrawerClose}
classes={{
paper: classes.drawerPaper,
}}
ModalProps={{
keepMounted: true, // Better open performance on mobile.
}}
>
<div className={classes.drawerHeader}>
<IconButton
color={"inherit"}
onClick={handleDrawerClose}
edge={"start"}
className={clsx(classes.menuButton, openDrawer || classes.hide)}
>
<ChevronLeftIcon/>
</IconButton>
</div>
<Divider/>
<Sidebar/>
</Drawer>
</Hidden>
<Hidden xsDown implementation={"js"}>
<Drawer
classes={{
paper: classes.drawerPaper,
}}
variant={"persistent"}
open={openDrawer}
>
<div className={classes.drawerHeader}/>
<Divider/>
<Sidebar/>
</Drawer>
</Hidden>
</nav>
<main
className={clsx(classes.content, {
[classes.contentShift]: openDrawer,
})}
<>
<StudentUnionChannels/>
<AppBar
position={"sticky"}
className={classes.appBar}
>
<AlertHandler {...alerthandler}/>
{ children }
</main>
</div>
<Toolbar>
<Burger open={openDrawer} onClick={toggleDrawer}/>
<SizeMe>{ ({ size }) =>
<div style={{width: "100%"}}>
<div className={classes.headerBar}>
<div className={classes.navigation}>
<Header size={size}/>
</div>
<div className={classes.navigation}>
{ /*<NotificationMenu/>*/ }
<AvatarMenu>
<MoreVertIcon fontSize={"large"} />
</AvatarMenu>
</div>
</div>
</div> }
</SizeMe>
</Toolbar>