️ 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 59070d6b authored by TJHeeringa's avatar TJHeeringa

Buttload of changes

parent 8143c9dc
......@@ -8,10 +8,9 @@ import React from "react";
import { BrowserRouter as Router } from "react-router-dom";
import AlertHandlerProvider from "./Contexts/AlertHandler";
import Authenticator from "./Contexts/Authentication";
import API from "./Contexts/API";
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";
......@@ -25,18 +24,16 @@ const App = (props) => {
<div className={"App"}>
<Router>
<AlertHandlerProvider>
<Authenticator>
<API>
<ThemeProvider>
<CssBaseline/>
<LocaleProvider>
<PageLayoutProvider>
<RestProvider>
<Routing/>
</RestProvider>
<Routing/>
</PageLayoutProvider>
</LocaleProvider>
</ThemeProvider>
</Authenticator>
</API>
</AlertHandlerProvider>
</Router>
</div>
......
import Button from "@material-ui/core/Button";
import PropTypes from "prop-types";
import React from "react";
const EventAgenda = ({ event, handleEventSelect }) => {
return (
<span>
<b>{ event.name }</b>
<p>{ event.description }</p>
<Button color={"primary"} onClick={()=>handleEventSelect(event)}>Read More</Button>
</span>
);
};
EventAgenda.propTypes = {
handleEventSelect: PropTypes.func.isRequired,
event: PropTypes.object.isRequired,
};
export default EventAgenda;
\ No newline at end of file
import PropTypes from "prop-types";
import React from "react";
const Event = ({ event }) => {
return (
<span>
<strong>{ event.name }</strong>
</span>
);
};
Event.propTypes = {
event: PropTypes.object.isRequired
};
export default Event;
\ No newline at end of file
import PropTypes from "prop-types";
import React, { Component } from "react";
import React from "react";
import { Link } from "react-router-dom";
import { Button, Card, CardBody, CardSubtitle, CardText,CardTitle } from "reactstrap";
import Poll from "restful-react";
......
......@@ -2,6 +2,15 @@ import React from "react";
import DateTimeField from "./DateTimeField";
export const DateField = (props) => {return <DateTimeField format={"YYYY/MM/DD"} {...props}/>;};
const DateField = (props) => {
return <DateTimeField
apiFormat={"YYYY-MM-DD"}
format={"YYYY-MM-DD"}
{...props}
/>;
};
DateField.propTypes = {
};
export default DateField;
\ No newline at end of file
import { makeStyles, useTheme } from "@material-ui/core/styles";
import { KeyboardDatePicker } from "@material-ui/pickers";
import moment from "moment";
import PropTypes from "prop-types";
import React from "react";
......@@ -14,33 +15,41 @@ const useStyles = makeStyles(theme => ({
},
}));
export const DateTimeField = (props) => {
const DateTimeField = ({name, value, onChange, apiFormat, ...remaining_props}) => {
const theme = useTheme();
const classes = useStyles(theme);
const {name, format, ...remaining_props} = props;
const pickerEditorProps = field => ({
className: classes.picker,
ampm: false,
inputVariant: "outlined",
format: format,
label: field[0].toUpperCase() + field.slice(1).replaceAll("_", " "),
});
const handleChange = (datetime_util_object) => {
onChange(datetime_util_object.format(apiFormat));
};
return (
<KeyboardDatePicker
{...pickerEditorProps(name)}
{...remaining_props}
onChange={handleChange}
value={value && moment(value)}
/>
);
};
DateTimeField.propTypes = {
name: PropTypes.string.isRequired,
format: PropTypes.string
value: PropTypes.string,
onChange: PropTypes.func.isRequired,
apiFormat: PropTypes.string,
format: PropTypes.string,
};
DateTimeField.defaultProps = {
apiFormat: "YYYY/MM/DD HH:mm",
format: "YYYY/MM/DD HH:mm"
};
......
import MenuItem from "@material-ui/core/MenuItem";
import { makeStyles, useTheme } from "@material-ui/core/styles";
import PropTypes from "prop-types";
import React from "react";
......@@ -9,10 +10,9 @@ const useStyles = makeStyles(theme => ({
},
}));
const SelectField = (props) => {
const SelectField = ({name, children, value, ...remaining_props}) => {
const theme = useTheme();
const classes = useStyles(theme);
const {name, children, ...remaining_props} = props;
const selectEditorProps = field => ({
variant: "outlined",
......@@ -24,15 +24,18 @@ const SelectField = (props) => {
return (
<SelectValidator
{...selectEditorProps(name)}
value={value === null ? "" : value}
{...remaining_props}
>
{ props.children }
{ children || <MenuItem/> }
</SelectValidator>
);
};
SelectField.propTypes = {
name: PropTypes.string
name: PropTypes.string.isRequired,
value: PropTypes.any,
children: PropTypes.node
};
export default SelectField;
\ No newline at end of file
......@@ -56,8 +56,8 @@ const SpecificDataField = (props) =>{
onChange={(event)=>onChange(field.url, event.target.value)}
{...rest_props}
>
<MenuItem value={true}>Yes</MenuItem>
<MenuItem value={false}>No</MenuItem>
<MenuItem value={"True"}>Yes</MenuItem>
<MenuItem value={"False"}>No</MenuItem>
</SelectField>
);
}
......
import { makeStyles, useTheme } from "@material-ui/core/styles";
import PropTypes from "prop-types";
import React from "react";
import {TextValidator} from "react-material-ui-form-validator";
import {SelectValidator, TextValidator} from "react-material-ui-form-validator";
const useStyles = makeStyles(theme => ({
textField: {
......@@ -9,10 +9,9 @@ const useStyles = makeStyles(theme => ({
},
}));
const TextField = (props) => {
const TextField = ({name, value, ...remaining_props}) => {
const theme = useTheme();
const classes = useStyles(theme);
const {name, ...remaining_props} = props;
const textEditorProps = field => ({
variant: "outlined",
......@@ -24,13 +23,15 @@ const TextField = (props) => {
return (
<TextValidator
{...textEditorProps(name)}
value={value === null ? "" : value}
{...remaining_props}
/>
);
};
TextField.propTypes = {
name: PropTypes.string
name: PropTypes.string.isRequired,
value: PropTypes.any
};
export default TextField;
\ No newline at end of file
......@@ -20,9 +20,9 @@ import PhotoSizeSelectLargeIcon from "@material-ui/icons/PhotoSizeSelectLarge";
import RoomServiceIcon from "@material-ui/icons/RoomService";
import DateField from "App/Components/Fields/DateField";
import FileField from "App/Components/Fields/FileField";
import IconHolder from "App/Components/Fields/IconHolder";
import TextField from "App/Components/Fields/TextField";
import Wrapper from "App/Components/Fields/Wrapper";
import IconHolder from "App/Components/Fields/IconHolder";
import YearlessDateField from "App/Components/Fields/YearlessDateField";
import { useAlertHandler } from "App/Contexts/AlertHandler";
import { Helper } from "App/Helper";
......@@ -57,9 +57,6 @@ export const AssociationForm = (props) => {
(props.association.terms_of_service === association.terms_of_service) && delete to_be_patched_association.terms_of_service;
Helper.api_call(props.association.url, "PATCH", to_be_patched_association, "form-data",
(patched_association)=>{
delete patched_association.membership;
delete patched_association.board;
delete patched_association.committees;
props.handleAssociationChange(patched_association);
alertHandler.handleAlertHandler("green", "Save successful");
},
......@@ -175,8 +172,8 @@ export const AssociationForm = (props) => {
<DateField
name={"founding_date"}
value={association.founding_date}
onChange={datetime_util_object => handleAssociationChange("founding_date", datetime_util_object.toDate())}
helperText={"This is the date you are planning on collection the debt collection."}
onChange={date => handleAssociationChange("founding_date", date)}
helperText={""}
disableFuture
/>
</Wrapper>
......@@ -185,7 +182,7 @@ export const AssociationForm = (props) => {
<DateField
name={"dissolution_date"}
value={association.dissolution_date}
onChange={datetime_util_object => handleAssociationChange("dissolution_date", datetime_util_object.toDate())}
onChange={date => handleAssociationChange("dissolution_date", date)}
disabled
helperText={"Connect the SU if you want to dissolve your association."}
/>
......@@ -196,7 +193,7 @@ export const AssociationForm = (props) => {
<Wrapper>
<IconHolder Icon={AssignmentLateIcon}/>
<FileField
onChange={(event)=>handleAssociationChange("privacy_statement",event.target.files[0])}
onChange={(event)=>handleAssociationChange("privacy_statement", event.target.files[0])}
name={"Privacy Statement"}
/>
</Wrapper>
......@@ -204,7 +201,7 @@ export const AssociationForm = (props) => {
<IconHolder Icon={RoomServiceIcon}/>
<FileField
name={"Terms of Service"}
onChange={(event)=>handleAssociationChange("terms_of_service",event.target.files[0])}
onChange={(event)=>handleAssociationChange("terms_of_service", event.target.files[0])}
/>
</Wrapper>
......
.membership_form_label_narrow {
font-size: 1rem !important;
}
.membership_form_col_narrow {
padding-left: 0px !important;
}
\ No newline at end of file
import "./MembershipForm.css";
import Button from "@material-ui/core/Button";
import MenuItem from "@material-ui/core/MenuItem";
import CalendarToday from "@material-ui/icons/CalendarToday";
import DirectionsWalkIcon from "@material-ui/icons/DirectionsWalk";
import TransferWithinAStationIcon from "@material-ui/icons/TransferWithinAStation";
import VisibilityIcon from "@material-ui/icons/Visibility";
import PropTypes from "prop-types";
import React, { useState } from "react";
import {ValidatorForm} from "react-material-ui-form-validator";
import {useGet} from "restful-react";
import {AvCheckbox, AvFeedback,AvField, AvForm, AvGroup, AvInput} from "availity-reactstrap-validation";
import React, { Component } from "react";
import {Button,Col, Label, Row} from "reactstrap";
import { v4 as uuidv4 } from "uuid";
import {useAlertHandler} from "../../Contexts/AlertHandler";
import {useAPI} from "../../Contexts/API";
import DateField from "../Fields/DateField";
import IconHolder from "../Fields/IconHolder";
import SelectField from "../Fields/SelectField";
import Wrapper from "../Fields/Wrapper";
import {Helper} from "../../Helper";
export class MembershipForm extends Component {
constructor(props){
super(props);
let membership = this.props.membership;
membership.type_url = membership.type.url;
this.state = {
membership: this.props.membership
};
}
export const MembershipForm = ({ membership: propMembership, association }) => {
// We change the types on propMembership to the types url, since we need it
// to have that shape for the form. Type is guaranteed to have a value,
// so we don't need to check for existance, but new_type can be null.
const [membership, setMembership] = useState({
...propMembership,
type: propMembership.type.url,
// TODO: uncomment line below when API passes new_type
// new_type: propMembership.new_type === null ? null : propMembership.new_type.url
});
handleValidSubmit = (event, values) => {
let membership = this.state.membership;
membership.type_url = membership.type.url;
return Helper.api_call(this.state.membership.url, "PATCH", this.state.membership, "json",
(membership)=>{this.handleMembershipChange("type", membership.type);});
};
const alerthandler = useAlertHandler();
const API = useAPI();
let { data: membertypes, loading: loadingMembertypes } = useGet({
path: "/membertypes",
queryParams: {limit: 100, association__slug: association.slug},
resolve: data => data && data.results
});
handleMembershipChange = (field, value) => {
this.setState(prevState => {
let membership = prevState.membership;
membership[field] = value;
return {membership: membership};
const handleSubmit = () => {
API.callv3({
url: membership.url,
method: "PATCH",
object: membership,
on_succes: (data) => {
alerthandler.handleAlertHandler("green", "Saved membership");
},
on_failure: (err) => {
alerthandler.handleAlertHandler("red", "Saving of membership went wrong");
console.error(err);
},
});
};
render() {
return (
<AvForm id={"membership_form"} onValidSubmit={this.handleValidSubmit} ref={c => (this.form = c)}>
<h4>Membership</h4>
{ this.props.wide
?
<x-fragment>
<AvField
type={"date"}
name={"date_joined"}
label={"Date Joined"}
value={this.state.membership.date_joined}
onChange={(event) => this.handleMembershipChange("date_joined", event.target.value)}
disabled={true}
/>
<AvField
type={"select"}
name={"type"}
label={"Type"}
value={this.state.membership.type_url}
onChange={(event) => this.handleMembershipChange("type_url", event.target.value)}
disabled={true}
>
<option key={uuidv4()} value={this.state.membership.type.url}>{ this.state.membership.type.type }</option>
</AvField>
<AvField
type={"select"}
name={"visible_after_date_left"}
label={"My info still visible after I left:"}
value={this.state.membership.visible_after_date_left}
onChange={(event) => this.handleMembershipChange("visible_after_date_left", event.target.value)}
disabled={false}
>
<option value={true}>Yes</option>
<option value={false}>No</option>
</AvField>
</x-fragment>
:
<x-fragment>
<Col>
<Row>
<Col className={"membership_form_col_narrow"} xs={"12"} sm={"3"}>
<Label className={"membership_form_label_narrow"} for={"date_joined"}>Date Joined</Label>
</Col>
<Col xs={"12"} sm={"2"}>
<AvField
type={"date"}
name={"date_joined"}
id={"date_joined"}
value={this.state.membership.date_joined}
onChange={(event) => this.handleMembershipChange("date_joined", event.target.value)}
disabled={true}
/>
</Col>
</Row><Row>
<Col className={"membership_form_col_narrow"} xs={"12"} sm={"3"}>
<Label className={"membership_form_label_narrow"} for={"type"}>Type</Label>
</Col>
<Col xs={"12"} sm={"2"}>
<AvField
type={"select"}
name={"type"}
id={"type"}
value={this.state.membership.type_url}
onChange={(event) => this.handleMembershipChange("type_url", event.target.value)}
disabled={true}
>
{ this.props.membertypes.map(membertype=>
<option key={uuidv4()} value={membertype.url}>{ membertype.type }</option>
) }
</AvField>
</Col>
</Row><Row>
<Col className={"membership_form_col_narrow"} xs={"12"} sm={"3"}>
<Label className={"membership_form_label_narrow"} for={"visible_after_date_left"}>My info still visible after I left:</Label>
</Col>
<Col xs={"12"} sm={"2"}>
<AvField
type={"select"}
name={"visible_after_date_left"}
id={"visible_after_date_left"}
value={this.state.membership.visible_after_date_left}
onChange={(event) => this.handleMembershipChange("visible_after_date_left", event.target.value)}
>
<option value={"true"}>Yes</option>
<option value={"false"}>No</option>
</AvField>
</Col>
<Col xs={"12"} sm={"2"}>
<Button color={"success"} type={"submit"}>Save</Button>
</Col>
</Row>
</Col>
</x-fragment>
}
</AvForm>
);
}
}
const handleMembershipChange = (field, value) => setMembership(prevState => ({...prevState, [field]: value}));
console.log(propMembership);
return (
<ValidatorForm
onSubmit={handleSubmit}
onError={errors => console.log(errors)}
>
<Wrapper>
<IconHolder Icon={CalendarToday}/>
<DateField
name={"Date joined"}
value={membership.date_joined}
onChange={date=>handleMembershipChange("date_joined", date)}
helperText={"Only the board can change this."}
disabled
/>
</Wrapper>
<Wrapper>
<IconHolder Icon={DirectionsWalkIcon}/>
<SelectField
name={"Current Membertype"}
value={membership.type}
onChange={event=>handleMembershipChange("date_joined", event.target.value)}
disabled
>
{ membertypes && membertypes.map((membertype, m)=>(
<MenuItem key={m} value={membertype.url}>{ membertype.type }</MenuItem>
)) }
</SelectField>
</Wrapper>
<Wrapper>
<IconHolder Icon={TransferWithinAStationIcon}/>
<SelectField
name={"New Membertype"}
value={membership.new_type}
onChange={event=>handleMembershipChange("date_joined", event.target.value)}
helperText={membership.date_left === null
? "What membertype do you want to be after ...?"
: "Disabled because you have ended your membership"
}
disabled={membership.date_left !== null}
>
{ membertypes && membertypes.map((membertype, m)=>(
<MenuItem key={m} value={membertype.url}>{ membertype.type }</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/>
<Button variant={"contained"} color={"primary"} type={"submit"}>
Save
</Button>
</Wrapper>
</ValidatorForm>
);
};
MembershipForm.propTypes = {
membership: PropTypes.object.isRequired,
association: PropTypes.object.isRequired
};
import Button from "@material-ui/core/Button";
import Container from "@material-ui/core/Container";