️ 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 27f3cbd7 authored by TJHeeringa's avatar TJHeeringa

Massive expansion of store; package upgrades

parent c5fa4003
This diff is collapsed.
......@@ -13,8 +13,8 @@
"@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/free-brands-svg-icons": "^5.15.4",
"@fortawesome/free-solid-svg-icons": "^5.15.4",
"@fortawesome/react-fontawesome": "^0.1.15",
"@icon/open-iconic": "^1.1.4",
"@material-ui/core": "^4.12.3",
......@@ -22,57 +22,54 @@
"@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/components": "^1.10.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",
"@react-hook/size": "^2.1.2",
"@reduxjs/toolkit": "^1.6.2",
"bic-from-iban": "^1.0.0",
"bootstrap": "^4.5.2",
"change-case": "^4.1.2",
"clsx": "^1.1.1",
"env-cmd": "^10.1.0",
"file-saver": "^2.0.2",
"eslint-plugin-jsx-a11y": "^6.4.1",
"file-saver": "^2.0.5",
"i": "^0.3.6",
"iban": "0.0.14",
"jquery": "^3.5.1",
"jquery": "^3.6.0",
"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",
"moment": "^2.29.0",
"moment": "^2.29.1",
"mui-numpad": "^0.1.4-alpha",
"node-sass": "^4.14.1",
"npm": "^6.14.8",
"papaparse": "^5.3.0",
"node-sass": "^6.0.1",
"npm": "^8.0.0",
"papaparse": "^5.3.1",
"prop-types": "^15.7.2",
"query-string": "^6.13.1",
"react": "^16.13.1",
"query-string": "^7.0.1",
"react": "^17.0.2",
"react-big-calendar": "^0.31.0",
"react-cookie": "^3.1.2",
"react-csv": "^2.0.3",
"react-datepicker": "^2.16.0",
"react-dom": "^16.13.1",
"react-dom": "^17.0.2",
"react-icons": "^3.11.0",
"react-lines-ellipsis": "^0.14.1",
"react-lorem-ipsum": "^1.4.5",
"react-lines-ellipsis": "^0.15.0",
"react-lorem-ipsum": "^1.4.9",
"react-material-ui-form-validator": "^2.1.1",
"react-modal": "^3.11.1",
"react-redux": "^7.2.4",
"react-router-dom": "^5.2.0",
"react-scripts": "^3.4.3",
"react-redux": "^7.2.5",
"react-router-dom": "^5.3.0",
"react-simple-tree-menu": "^1.1.18",
"react-sizeme": "^3.0.2",
"react-table": "^6.11.5",
"reactstrap": "^8.5.1",
"recharts": "^2.1.0",
"restful-react": "^14.4.0",
"reactstrap": "^8.10.0",
"recharts": "^2.1.4",
"typescript": "^3.9.7",
"universal-cookie": "^3.1.0",
"use-light-switch": "^1.0.1",
"uuid": "^8.3.0"
"uuid": "^8.3.2"
},
"scripts": {
"start": "react-scripts start",
......@@ -92,17 +89,18 @@
"not op_mini all"
],
"devDependencies": {
"babel-plugin-root-import": "^6.5.0",
"eslint": "^6.8.0",
"eslint-config-react-app": "^5.2.1",
"eslint-plugin-import": "^2.22.0",
"babel-plugin-root-import": "^6.6.0",
"eslint": "^7.32.0",
"eslint-config-react-app": "^6.0.0",
"eslint-plugin-import": "^2.25.2",
"eslint-plugin-node": "^11.1.0",
"eslint-plugin-react": "^7.20.6",
"eslint-plugin-react-hooks": "^4.1.0",
"eslint-plugin-simple-import-sort": "^5.0.3",
"husky": "^4.2.5",
"eslint-plugin-react": "^7.26.1",
"eslint-plugin-react-hooks": "^4.2.0",
"eslint-plugin-simple-import-sort": "^7.0.0",
"husky": "^7.0.2",
"react-form-validator-core": "^1.1.1",
"react-image-webp": "^0.7.0",
"react-scripts": "^4.0.3",
"redux-devtools-extension": "^2.13.9"
},
"husky": {
......
......@@ -9,13 +9,13 @@ import TextInfoContent from "@mui-treasury/components/content/textInfo";
import { useOverShadowStyles } from "@mui-treasury/styles/shadow/over";
import { useBlogTextInfoContentStyles } from "@mui-treasury/styles/textInfoContent/blog";
import cx from "clsx";
import Image from "img/default_photo.jpg"; // Import using relative path
import PropTypes from "prop-types";
import React from "react";
import LinesEllipsis from "react-lines-ellipsis";
import { loremIpsum } from "react-lorem-ipsum";
import { useHistory } from "react-router-dom";
import Image from "../../../img/default_photo.jpg";
import Info from "../Info/Info";
......
......@@ -2,7 +2,6 @@ import PropTypes from "prop-types";
import React from "react";
import { Link } from "react-router-dom";
import { Button, Card, CardBody, CardSubtitle, CardText,CardTitle } from "reactstrap";
import Poll from "restful-react";
const SUNCard = (props) => {
......@@ -12,15 +11,6 @@ const SUNCard = (props) => {
<CardBody>
<CardTitle><h5>{ title }</h5></CardTitle>
{ subtitle && <CardSubtitle>{ subtitle }
{ poll && <Poll path={poll.url} >
{ (data, response) =>
response.loading ? (
<x-fragment>{ poll.loading }</x-fragment>
) : (
data && <x-fragment>{ poll.render(data) }</x-fragment>
)
}
</Poll> }
</CardSubtitle> }
{ text && <CardText>{ text }</CardText> }
{ link && <Link to={link}><Button>View</Button></Link> }
......
......@@ -6,10 +6,10 @@ import Typography from "@material-ui/core/Typography";
import { useOverShadowStyles } from "@mui-treasury/styles/shadow/over";
import { useBlogTextInfoContentStyles } from "@mui-treasury/styles/textInfoContent/blog";
import cx from "clsx";
import Image from "img/default_photo.jpg"; // Import using relative path
import PropTypes from "prop-types";
import React from "react";
import Image from "../../../img/default_photo.jpg";
import Info from "../Info/Info";
......
......@@ -10,7 +10,8 @@ import cx from "clsx";
import PropTypes from "prop-types";
import React from "react";
import {Link} from "react-router-dom";
import Image from "img/default_photo.jpg"; // Import using relative path
import Image from "../../../img/default_photo.jpg";
const useStyles = makeStyles(theme => ({
root: {
......
import Button from "@material-ui/core/Button";
import Card from "@material-ui/core/Card";
import CardMedia from "@material-ui/core/CardMedia";
import { makeStyles, useTheme } from "@material-ui/core/styles";
import Typography from "@material-ui/core/Typography";
import { useOverShadowStyles } from "@mui-treasury/styles/shadow/over";
import cx from "clsx";
import Image from "img/default_photo.jpg"; // Import using relative path
import PropTypes from "prop-types";
import React from "react";
import Button from "@material-ui/core/Button";
import Image from "../../../img/default_photo.jpg";
const useStyles = makeStyles(theme => ({
root: {
......
......@@ -3,6 +3,9 @@ import { DatePicker } from "@material-ui/pickers";
import moment from "moment";
import PropTypes from "prop-types";
import React from "react";
import {ValidatorComponent} from "react-material-ui-form-validator";
import useFieldStyles from "./fieldStyles";
const useStyles = makeStyles(theme => ({
......@@ -66,5 +69,46 @@ const DateFieldV2 = (props) => {
);
};
export { DateFieldV2 };
export default DateTimeField;
\ No newline at end of file
class DateValidator extends ValidatorComponent {
renderValidatorComponent() {
const {
errorMessages,
validators,
requiredError,
helperText,
validatorListener,
...rest
} = this.props;
const { isValid } = this.state;
return (
<DateFieldV2
{...rest}
error={!isValid}
helperText={(!isValid && this.getErrorMessage()) || helperText}
/>
);
}
}
const DateFieldV3 = (props) => {
const fieldClasses = useFieldStyles();
const classes = useStyles();
return (
<DateValidator
inputVariant={"outlined"}
className={classes.picker}
ampm={false}
format={"L"}
containerProps={{className: fieldClasses.field}}
{...props}
/>
);
};
export { DateFieldV2, DateFieldV3 };
export default DateTimeField;
......@@ -2,6 +2,7 @@ import { makeStyles } from "@material-ui/core/styles";
import TextField from "@material-ui/core/TextField";
import Autocomplete from "@material-ui/lab/Autocomplete";
import React, {useMemo} from "react";
import {useLoadedMembers} from "../../Contexts/Members";
const useStyles = makeStyles({
......
......@@ -2,6 +2,7 @@ import {makeStyles} from "@material-ui/core/styles";
import MuiPhoneInput from "material-ui-phone-number";
import React from "react";
import { ValidatorComponent } from "react-form-validator-core";
import useFieldStyles from "./fieldStyles";
......
......@@ -11,10 +11,10 @@ import PropTypes from "prop-types";
import React from "react";
import { ValidatorForm } from "react-material-ui-form-validator";
import {useHistory} from "react-router-dom";
import {useGet} from "restful-react";
import { useAlertHandler } from "../../Contexts/AlertHandler";
import {useAPI} from "../../Contexts/API";
import {useGetEventTypesByAssociationQuery} from "../../Store/services/eventTypes";
import DateTimeField from "../Fields/DateTimeField";
import IconHolder from "../Fields/IconHolder";
import NumberField from "../Fields/NumberField";
......@@ -28,11 +28,7 @@ export const EventForm = ({ association, event, handleEventChange, update, onSuc
const alerthandler = useAlertHandler();
const history = useHistory();
let { data: event_types, loading: loadingStudies, refetch } = useGet({
path: "/event_types",
queryParams: {limit: 100, association__slug: association.slug},
resolve: data => data && data.results
});
const { data: eventTypes } = useGetEventTypesByAssociationQuery(association.slug);
const handleSubmit = () => {
// make a copy of the event so that the null key operation don't accidentally change the event prop
......@@ -146,7 +142,7 @@ export const EventForm = ({ association, event, handleEventChange, update, onSuc
onChange={(event) => handleEventChange("type", event.target.value)}
required
>
{ event_types && event_types.map(event_type => (
{ eventTypes && eventTypes.map(event_type => (
<MenuItem key={event_type.slug} value={event_type.url}>
{ event_type.type }
</MenuItem>
......
......@@ -7,17 +7,17 @@ import EventAvailableIcon from "@material-ui/icons/EventAvailable";
import EventBusyIcon from "@material-ui/icons/EventBusy";
import FormatListNumberedIcon from "@material-ui/icons/FormatListNumbered";
import GradeIcon from "@material-ui/icons/Grade";
import Wrapper from "../Fields/Wrapper";
import PropTypes from "prop-types";
import React, {useEffect, useMemo, useState} from "react";
import React, {useState} from "react";
import { ValidatorForm } from "react-material-ui-form-validator";
import IconHolder from "../Fields/IconHolder";
import TextField from "../Fields/TextField";
import { useAlertHandler } from "../../Contexts/AlertHandler";
import {useAPI} from "../../Contexts/API";
import BooleanField from "../Fields/BooleanField";
import IconHolder from "../Fields/IconHolder";
import NumberField from "../Fields/NumberField";
import TextField from "../Fields/TextField";
import Wrapper from "../Fields/Wrapper";
import YearlessDateField from "../Fields/YearlessDateField";
......
......@@ -4,29 +4,43 @@ import CalendarToday from "@material-ui/icons/CalendarToday";
import DirectionsWalkIcon from "@material-ui/icons/DirectionsWalk";
import TransferWithinAStationIcon from "@material-ui/icons/TransferWithinAStation";
import { pick } from "lodash";
import * as moment from "moment";
import PropTypes from "prop-types";
import React, {useMemo} from "react";
import React, {useEffect, useMemo} from "react";
import {ValidatorForm} from "react-material-ui-form-validator";
import {useAlertHandler} from "../../Contexts/AlertHandler";
import {useAPI} from "../../Contexts/API";
import {useMemberTypes} from "../../Contexts/Members";
import DateField from "../Fields/DateField";
import {useGetMemberTypesByAssociationQuery} from "../../Store/services/memberTypes";
import {DateFieldV2, DateFieldV3} from "../Fields/DateField";
import IconHolder from "../Fields/IconHolder";
import SelectField from "../Fields/SelectField";
import Wrapper from "../Fields/Wrapper";
import useAddValidationRule from "../Hooks/useAddValidationRule";
import isAfterDate from "../ValidatorRules/isAfterDate";
const dataFields = ["date_joined", "date_left", "type", "new_type"];
const membershipWithDatesToApi = (membership) => pick({
...membership,
date_joined: membership.date_joined && moment(membership.date_joined).format("YYYY-MM-DD"),
date_left: membership.date_left && moment(membership.date_left).format("YYYY-MM-DD"),
}, dataFields);
export const MembershipForm = ({ association, membership, handleMembershipChange, onCancel, afterAPIcall }) => {
const alerthandler = useAlertHandler();
const API = useAPI();
const MembertypesAPI = useMemberTypes();
const membertypes = MembertypesAPI.collection;
// const MembertypesAPI = useMemberTypes();
// const membertypes = MembertypesAPI.collection;
const { data: membertypes } = useGetMemberTypesByAssociationQuery(association.slug);
useAddValidationRule(ValidatorForm, isAfterDate.name, isAfterDate.validate(membership.date_joined));
const handleSubmit = () => {
const toBePatchedMembership = pick(membership, dataFields);
const toBePatchedMembership = membershipWithDatesToApi(membership, dataFields);
API.callv4({
url: membership.url,
queryParams: {expand: "type,new_type"},
......@@ -67,8 +81,9 @@ export const MembershipForm = ({ association, membership, handleMembershipChange
>
<Wrapper>
<IconHolder Icon={CalendarToday}/>
<DateField
name={"Date joined"}
<DateFieldV2
name={"date_joined"}
label={"Date joined"}
value={membership.date_joined}
onChange={date=>handleMembershipChange("date_joined", date)}
disabled
......@@ -76,12 +91,15 @@ export const MembershipForm = ({ association, membership, handleMembershipChange
</Wrapper>
<Wrapper>
<IconHolder Icon={CalendarToday}/>
<DateField
name={"Date left"}
<DateFieldV3
label={"Date left"}
name={"date_left"}
value={membership.date_left}
onChange={date=>handleMembershipChange("date_left", date)}
disabled={!association.is_board}
helperText={dateLeftHelperText}
validators={[isAfterDate.name]}
errorMessages={["Must be a later date than the date the member joined"]}
/>
</Wrapper>
<Wrapper>
......@@ -112,18 +130,18 @@ export const MembershipForm = ({ association, membership, handleMembershipChange
)) }
</SelectField>
</Wrapper>
{/*<Wrapper>*/}
{/* <IconHolder Icon={VisibilityIcon}/>*/}
{/* <SelectField*/}
{/* name={"Data after end of membership"}*/}
{/* value={membership.visible_after_date_left}*/}
{/* onChange={event=>handleMembershipChange("visible_after_date_left", event.target.value)}*/}
{/* helperText={"What should happen to your data after your membership has ended?"}*/}
{/* >*/}
{/* <MenuItem value={true}>visible</MenuItem>*/}
{/* <MenuItem value={false}>gone</MenuItem>*/}
{/* </SelectField>*/}
{/*</Wrapper>*/}
{ /*<Wrapper>*/ }
{ /* <IconHolder Icon={VisibilityIcon}/>*/ }
{ /* <SelectField*/ }
{ /* name={"Data after end of membership"}*/ }
{ /* value={membership.visible_after_date_left}*/ }
{ /* onChange={event=>handleMembershipChange("visible_after_date_left", event.target.value)}*/ }
{ /* helperText={"What should happen to your data after your membership has ended?"}*/ }
{ /* >*/ }
{ /* <MenuItem value={true}>visible</MenuItem>*/ }
{ /* <MenuItem value={false}>gone</MenuItem>*/ }
{ /* </SelectField>*/ }
{ /*</Wrapper>*/ }
<Wrapper>
<div/>
<div>
......
......@@ -5,10 +5,10 @@ import Typography from "@material-ui/core/Typography";
import PropTypes from "prop-types";
import React, {useEffect, useMemo} from "react";
import { ValidatorForm } from "react-material-ui-form-validator";
import { useGet } from "restful-react";
import { useAlertHandler} from "../../Contexts/AlertHandler";
import {useAPI} from "../../Contexts/API";
import { useGetStudiesQuery } from "../../Store/services/studies";
import CountryField, { countries } from "../Fields/CountryField";
import DateField from "../Fields/DateField";
import PhoneNumberField from "../Fields/PhoneNumberField";
......@@ -65,11 +65,7 @@ const ProfileFormWithoutContainer = ({ update, profile, onSuccess, disabled, han
const alerthandler = useAlertHandler();
const API = useAPI();
let { data: studies, loading: loadingStudies, refetch } = useGet({
path: "/studies",
queryParams: {limit: 10000},
resolve: data => data && data.results
});
const { data: studies } = useGetStudiesQuery();
useEffect(()=>{
// called when component is mounted
......@@ -191,19 +187,19 @@ const ProfileFormWithoutContainer = ({ update, profile, onSuccess, disabled, han
}
required
/>
{/*<PhoneNumberField*/}
{/* label={"Phone number"}*/}
{/* value={profile.phone_number}*/}
{/* onChange={phone => handleProfileChange("phone_number", phone)}*/}
{/* disabled={disabled}*/}
{/* helperText={*/}
{/* <>*/}
{/* Please enter your phone number with country code, i.e. +31 06 12345678 instead of 0612345678.<br/>*/}
{/* NB: Dutch mobile phone numbers start with +31 06, not +31 6.*/}
{/* </>*/}
{/* }*/}
{/* required*/}
{/*/>*/}
{ /*<PhoneNumberField*/ }
{ /* label={"Phone number"}*/ }
{ /* value={profile.phone_number}*/ }
{ /* onChange={phone => handleProfileChange("phone_number", phone)}*/ }
{ /* disabled={disabled}*/ }
{ /* helperText={*/ }
{ /* <>*/ }
{ /* Please enter your phone number with country code, i.e. +31 06 12345678 instead of 0612345678.<br/>*/ }
{ /* NB: Dutch mobile phone numbers start with +31 06, not +31 6.*/ }
{ /* </>*/ }
{ /* }*/ }
{ /* required*/ }
{ /*/>*/ }
</Wrapper>
<Wrapper>
<TextField
......
import {useEffect} from "react";
const useAddValidationRule = (ValidatorForm, validationRuleName, validateFunction) => {
useEffect(() => {
if (!ValidatorForm.hasValidationRule(validationRuleName)) {
ValidatorForm.addValidationRule(validationRuleName, validateFunction);
}
return function cleanPasswordMatchRule() {
if (ValidatorForm.hasValidationRule(validationRuleName)) {
ValidatorForm.removeValidationRule(validationRuleName);
}
};
});
};
export default useAddValidationRule;
\ No newline at end of file
......@@ -3,22 +3,22 @@ import PropTypes from "prop-types";
import React, {useMemo} from "react";
import {useMemberTypes} from "../../Contexts/Members";
import {useGetMemberTypesByAssociationQuery} from "../../Store/services/memberTypes";
import Info from "./Info";
const MembershipInfo = ({ membership }) => {
const MembertypesAPI = useMemberTypes();
const membertypes = MembertypesAPI.list();
const MembershipInfo = ({ association, membership }) => {
const { data: membertypes, loading } = useGetMemberTypesByAssociationQuery(association.slug);
const morphMembershipToData = (membership) => {
let data = {
"Date Joined:": membership.date_joined
"Date Joined:": moment(membership.date_joined).format("L")
};
if (membership.date_left) {
const date_left_or_leaving_text = moment(membership.date_left) <= moment() ? "Date Left:" : "Date Leaving";
data[date_left_or_leaving_text] = membership.date_left;
data[date_left_or_leaving_text] = moment(membership.date_left).format("L");
}
data["Status"] = membership.status;
if (MembertypesAPI.loaded) {
if (!loading) {
if (membership.new_type !== null) {
data = {...data,
"Current Membertype:": membertypes.find(membertype=>membertype.url === membership.type).type || "",
......@@ -33,7 +33,7 @@ const MembershipInfo = ({ membership }) => {
return data;
};