️ 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 20041af4 authored by TJHeeringa's avatar TJHeeringa

Updated AssociationInfoForm

parent be1bef14
......@@ -37,35 +37,10 @@ import { ValidatorForm } from "react-material-ui-form-validator";
import FontAwesomeIconHolder from "../Fields/FontAwesomeIconHolder";
export const AssociationForm = (props) => {
const alertHandler = useAlertHandler();
let [association, setAssociation] = useState({...props.association});
const resetAssociation = () => setAssociation({...props.association});
const handleAssociationChange = (field, value) => {console.log(value); setAssociation(prevState=>({...prevState, [field]: value}));};
const handleValidSubmit = (event, values) => {
let to_be_patched_association = {...association};
(props.association.photo === association.photo) && delete to_be_patched_association.photo;
(props.association.logo === association.logo) && delete to_be_patched_association.logo;
(props.association.bylaws === association.bylaws) && delete to_be_patched_association.bylaws;
(props.association.articles_of_association === association.articles_of_association) && delete to_be_patched_association.articles_of_association;
(props.association.privacy_statement === association.privacy_statement) && delete to_be_patched_association.privacy_statement;
(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)=>{
props.handleAssociationChange(patched_association);
alertHandler.handleAlertHandler("green", "Save successful");
},
()=>{alertHandler.handleAlertHandler("red", "Save failed");},
);
};
export const AssociationForm = ({ association, handleChange, onUpdate, onCancel }) => {
return (
<ValidatorForm
onSubmit={handleValidSubmit}
onSubmit={onUpdate}
onError={errors => console.log(errors)}
>
<Typography variant={"h5"}>General</Typography>
......@@ -74,7 +49,7 @@ export const AssociationForm = (props) => {
<TextField
name={"name"}
value={association.name}
onChange={(event)=>handleAssociationChange("name",event.target.value)}
onChange={(event)=>handleChange("name",event.target.value)}
/>
</Wrapper>
<Wrapper>
......@@ -82,7 +57,7 @@ export const AssociationForm = (props) => {
<TextField
name={"short_name"}
value={association.short_name}
onChange={(event)=>handleAssociationChange("short_name",event.target.value)}
onChange={(event)=>handleChange("short_name",event.target.value)}
/>
</Wrapper>
<Wrapper>
......@@ -90,22 +65,24 @@ export const AssociationForm = (props) => {
<TextField
name={"description"}
value={association.description}
onChange={(event)=>handleAssociationChange("description",event.target.value)}
onChange={(event)=>handleChange("description",event.target.value)}
multiline
/>
</Wrapper>
<Wrapper>
<IconHolder Icon={PhotoIcon}/>
<FileField
onChange={(event)=>handleAssociationChange("photo",event.target.files[0])}
onChange={(event)=>handleChange("photo",event.target.files[0])}
name={"photo"}
helperText={"Photo for the home page."}
/>
</Wrapper>
<Wrapper>
<IconHolder Icon={PhotoSizeSelectLargeIcon}/>
<FileField
name={"logo"}
onChange={(event)=>handleAssociationChange("logo",event.target.files[0])}
onChange={(event)=>handleChange("logo",event.target.files[0])}
helperText={"The logo is the icon used in the blue navigation bar on top of your screen. Please, upload a white version."}
/>
</Wrapper>
......@@ -115,7 +92,7 @@ export const AssociationForm = (props) => {
<TextField
name={"email"}
value={association.email}
onChange={(event)=>handleAssociationChange("email",event.target.value)}
onChange={(event)=>handleChange("email",event.target.value)}
/>
</Wrapper>
<Wrapper>
......@@ -123,7 +100,7 @@ export const AssociationForm = (props) => {
<TextField
name={"phone_number"}
value={association.phone_number}
onChange={(event)=>handleAssociationChange("phone_number",event.target.value)}
onChange={(event)=>handleChange("phone_number",event.target.value)}
/>
</Wrapper>
<Wrapper>
......@@ -131,7 +108,7 @@ export const AssociationForm = (props) => {
<TextField
name={"whatsapp"}
value={association.whatsapp}
onChange={(event)=>handleAssociationChange("whatsapp",event.target.value)}
onChange={(event)=>handleChange("whatsapp",event.target.value)}
/>
</Wrapper>
<Wrapper>
......@@ -139,7 +116,7 @@ export const AssociationForm = (props) => {
<TextField
name={"discord"}
value={association.discord}
onChange={(event)=>handleAssociationChange("discord",event.target.value)}
onChange={(event)=>handleChange("discord",event.target.value)}
/>
</Wrapper>
<Wrapper>
......@@ -147,7 +124,7 @@ export const AssociationForm = (props) => {
<TextField
name={"instagram"}
value={association.instagram}
onChange={(event)=>handleAssociationChange("instagram",event.target.value)}
onChange={(event)=>handleChange("instagram",event.target.value)}
/>
</Wrapper>
<Wrapper>
......@@ -155,7 +132,7 @@ export const AssociationForm = (props) => {
<TextField
name={"facebook"}
value={association.facebook}
onChange={(event)=>handleAssociationChange("facebook",event.target.value)}
onChange={(event)=>handleChange("facebook",event.target.value)}
/>
</Wrapper>
<Wrapper>
......@@ -163,7 +140,7 @@ export const AssociationForm = (props) => {
<TextField
name={"snapchat"}
value={association.snapchat}
onChange={(event)=>handleAssociationChange("snapchat",event.target.value)}
onChange={(event)=>handleChange("snapchat",event.target.value)}
/>
</Wrapper>
<Wrapper>
......@@ -171,7 +148,7 @@ export const AssociationForm = (props) => {
<TextField
name={"LinkedIn"}
value={association.linkedin}
onChange={(event)=>handleAssociationChange("linkedin",event.target.value)}
onChange={(event)=>handleChange("linkedin",event.target.value)}
/>
</Wrapper>
......@@ -181,7 +158,7 @@ export const AssociationForm = (props) => {
<TextField
name={"zip_code"}
value={association.zip_code}
onChange={(event)=>handleAssociationChange("zip_code",event.target.value)}
onChange={(event)=>handleChange("zip_code",event.target.value)}
/>
</Wrapper>
<Wrapper>
......@@ -189,7 +166,7 @@ export const AssociationForm = (props) => {
<TextField
name={"city"}
value={association.city}
onChange={(event)=>handleAssociationChange("city",event.target.value)}
onChange={(event)=>handleChange("city",event.target.value)}
/>
</Wrapper>
<Wrapper>
......@@ -197,7 +174,7 @@ export const AssociationForm = (props) => {
<TextField
name={"address"}
value={association.address}
onChange={(event)=>handleAssociationChange("address",event.target.value)}
onChange={(event)=>handleChange("address",event.target.value)}
/>
</Wrapper>
<Wrapper>
......@@ -205,7 +182,7 @@ export const AssociationForm = (props) => {
<TextField
name={"Room"}
value={association.room}
onChange={(event)=>handleAssociationChange("room",event.target.value)}
onChange={(event)=>handleChange("room",event.target.value)}
/>
</Wrapper>
......@@ -215,7 +192,7 @@ export const AssociationForm = (props) => {
<TextField
name={"zip_code"}
value={association.postal_zipcode}
onChange={(event)=>handleAssociationChange("postal_zipcode",event.target.value)}
onChange={(event)=>handleChange("postal_zipcode",event.target.value)}
/>
</Wrapper>
<Wrapper>
......@@ -223,7 +200,7 @@ export const AssociationForm = (props) => {
<TextField
name={"city"}
value={association.postal_city}
onChange={(event)=>handleAssociationChange("postal_city",event.target.value)}
onChange={(event)=>handleChange("postal_city",event.target.value)}
/>
</Wrapper>
<Wrapper>
......@@ -231,7 +208,7 @@ export const AssociationForm = (props) => {
<TextField
name={"address"}
value={association.postal_address}
onChange={(event)=>handleAssociationChange("postal_address",event.target.value)}
onChange={(event)=>handleChange("postal_address",event.target.value)}
/>
</Wrapper>
......@@ -239,17 +216,27 @@ export const AssociationForm = (props) => {
<Wrapper>
<IconHolder Icon={GavelIcon}/>
<FileField
onChange={(event)=>handleAssociationChange("articles_of_association",event.target.files[0])}
name={"Articles of Association"}
helperText={"Dutch: Statuten."}
onChange={(event)=>handleChange("articles_of_association_en",event.target.files[0])}
name={"Articles of Association - EN"}
helperText={"Dutch: Statuten, English version."}
/>
<FileField
onChange={(event)=>handleChange("articles_of_association_nl",event.target.files[0])}
name={"Articles of Association - NL"}
helperText={"Dutch: Statuten, Dutch version."}
/>
</Wrapper>
<Wrapper>
<IconHolder Icon={LineStyleIcon}/>
<FileField
onChange={(event)=>handleAssociationChange("bylaws",event.target.files[0])}
name={"bylaws"}
helperText={"Dutch: Huishoudelijk Regelement."}
onChange={(event)=>handleChange("bylaws_en",event.target.files[0])}
name={"Bylaws - EN"}
helperText={"Dutch: Huishoudelijk Regelement, English version."}
/>
<FileField
onChange={(event)=>handleChange("bylaws_nl",event.target.files[0])}
name={"Bylaws - NL"}
helperText={"Dutch: Huishoudelijk Regelement, Dutch version."}
/>
</Wrapper>
<Wrapper>
......@@ -257,7 +244,7 @@ export const AssociationForm = (props) => {
<DateField
name={"founding_date"}
value={association.founding_date}
onChange={date => handleAssociationChange("founding_date", date)}
onChange={date => handleChange("founding_date", date)}
helperText={""}
disableFuture
/>
......@@ -267,7 +254,7 @@ export const AssociationForm = (props) => {
<DateField
name={"dissolution_date"}
value={association.dissolution_date}
onChange={date => handleAssociationChange("dissolution_date", date)}
onChange={date => handleChange("dissolution_date", date)}
disabled
helperText={"Connect the SU if you want to dissolve your association."}
/>
......@@ -277,7 +264,7 @@ export const AssociationForm = (props) => {
<Wrapper>
<IconHolder Icon={AssignmentLateIcon}/>
<FileField
onChange={(event)=>handleAssociationChange("privacy_statement", event.target.files[0])}
onChange={(event)=>handleChange("privacy_statement", event.target.files[0])}
name={"Privacy Statement"}
/>
</Wrapper>
......@@ -285,7 +272,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)=>handleChange("terms_of_service", event.target.files[0])}
/>
</Wrapper>
......@@ -298,7 +285,7 @@ export const AssociationForm = (props) => {
<div>
<Button type={"submit"} variant={"contained"} color={"primary"}>Save</Button>
&nbsp;
<Button variant={"contained"} onClick={resetAssociation}>Cancel</Button>
<Button variant={"contained"} onClick={onCancel}>Cancel</Button>
</div>
</Wrapper>
</ValidatorForm>
......@@ -307,5 +294,9 @@ export const AssociationForm = (props) => {
AssociationForm.propTypes = {
association: PropTypes.object.isRequired,
handleAssociationChange: PropTypes.func.isRequired
};
\ No newline at end of file
handleChange: PropTypes.func.isRequired,
onCancel: PropTypes.func.isRequired,
onUpdate: PropTypes.func.isRequired
};
export default AssociationForm;
\ No newline at end of file
import Info from "App/Components/Info/Info";
import PropTypes from "prop-types";
import React from "react";
import AssociationType from "../Types/Association";
export const AssociationInfo = ({ association }) => {
const morphAssociationToData = (association) => {
let data = [];
data["General"] = {
"Description": association.description,
};
data["Contact"] = {
"Email": association.email,
"Phone number": association.phone_number,
"Whatsapp": association.whatsapp,
"Discord": association.discord,
"LinkedIn": association.linkedin,
"Facebook": association.facebook,
"Instagram": association.instagram,
"Snapchat": association.snapchat,
};
data["Visiting Location"] = {
"Zip Code": association.zip_code + (" ") + association.city,
"Address": association.address,
"Room": association.room,
};
data["Postal"] = {
"Zip Code": association.postal_zipcode + (" ") + association.postal_city,
"Address": association.postal_address,
};
data["Constitutional"] = {
"Articles of Association": <a href={association.articles_of_association}>Articles of Association</a>,
"Bylaws": <a href={association.bylaws}>Bylaws</a>,
"Founding date": association.founding_date,
};
data["Legal"] = {
"Privacy Statement": <a href={association.privacy_statements}>Privacy Statement</a>,
"Terms of Service": <a href={association.terms_of_service}>Terms of Service</a>
};
return data;
const AssociationInfo = ({ association }) => {
// const data = useMemo(() => {
let data = [];
data["General"] = {
"Name": association.name,
"Short name": association.short_name,
"Description": association.description,
};
data["Contact"] = {
"Email": association.email,
"Phone number": association.phone_number,
"Whatsapp": association.whatsapp,
"Discord": association.discord,
"LinkedIn": association.linkedin,
"Facebook": association.facebook,
"Instagram": association.instagram,
"Snapchat": association.snapchat,
};
data["Visiting Location"] = {
"Zip Code": association.zip_code + (" ") + association.city,
"Address": association.address,
"Room": association.room,
};
data["Postal"] = {
"Zip Code": association.postal_zipcode + (" ") + association.postal_city,
"Address": association.postal_address,
};
data["Constitutional"] = {
"Articles of Association": <><a href={association.articles_of_association_en}>Articles of Association</a> <a href={association.articles_of_association_nl}>Statuten</a></>,
"Bylaws": <><a href={association.bylaws_en}>Bylaws</a> <a href={association.bylaws_nl}>Huishoudelijk Regelement</a></>,
"Founding date": association.founding_date,
};
data["Legal"] = {
"Privacy Statement": <a href={association.privacy_statements}>Privacy Statement</a>,
"Terms of Service": <a href={association.terms_of_service}>Terms of Service</a>
};
// return data;
// },[association]);
return (
<Info
headerless={false}
data={morphAssociationToData(association)}
data={data}
/>
);
};
AssociationInfo.propTypes = {
association: PropTypes.object.isRequired
};
\ No newline at end of file
association: AssociationType
};
export default AssociationInfo;
\ No newline at end of file
import React from "react";
import InfoForm from "./InfoForm";
import AssociationInfo from "../Info/AssociationInfo";
import AssociationForm from "../Forms/AssociationForm";
import {useAPI} from "../../Contexts/API";
import {useAlertHandler} from "../../Contexts/AlertHandler";
import AssociationType from "../Types/Association";
const AssociationInfoWrapper = ({ info }) => <AssociationInfo association={info}/>;
const AssociationFormWrapper = ({ formObject, handleFormObjectChange, ...props }) => <AssociationForm
association={formObject}
handleChange={handleFormObjectChange}
{...props}
/>;
const AssociationInfoForm = ({ association, ...props }) => {
const API = useAPI();
const alertHandler = useAlertHandler();
const onUpdate = (to_be_patched_association) => {
// remove the file fields if no file is provided to prevent validation issues on the backend.
(to_be_patched_association.photo === association.photo) && delete to_be_patched_association.photo;
(to_be_patched_association.logo === association.logo) && delete to_be_patched_association.logo;
(to_be_patched_association.bylaws_en === association.bylaws_en) && delete to_be_patched_association.bylaws_en;
(to_be_patched_association.bylaws_nl === association.bylaws_nl) && delete to_be_patched_association.bylaws_nl;
(to_be_patched_association.articles_of_association_en === association.articles_of_association_en) && delete to_be_patched_association.articles_of_association_en;
(to_be_patched_association.articles_of_association_nl === association.articles_of_association_nl) && delete to_be_patched_association.articles_of_association_nl;
(to_be_patched_association.privacy_statement === association.privacy_statement) && delete to_be_patched_association.privacy_statement;
(to_be_patched_association.terms_of_service === association.terms_of_service) && delete to_be_patched_association.terms_of_service;
API.callv4({
url: to_be_patched_association.url,
method: "PATCH",
object: to_be_patched_association,
json_or_form_data: "form-data",
on_succes: () => {
alertHandler.success("Association succesfully updated.");
},
on_failure: () => {
alertHandler.failure("Update of Association failed.");
},
});
};
return (
<InfoForm
onUpdate={onUpdate}
title={"About the association"}
infoFormObject={association}
infoOrForm={"info"}
InfoComponent={AssociationInfoWrapper}
FormComponent={AssociationFormWrapper}
{...props}
/>
);
};
AssociationInfoForm.propTypes = {
association: AssociationType
};
export default AssociationInfoForm;
......@@ -7,45 +7,47 @@ import Wrapper from "../Fields/Wrapper";
import useInfoFormState from "../Hooks/useInfoFormState";
import Block from "../PageLayout/Content/Block";
const defaultFieldAndValueToStateChanges = (field, value) => ({[field]: value});
const dummyFunction = () => {};
const defaultFieldAndValueToStateChanges = (field, value, prevState) => ({...prevState, [field]: value});
const InfoForm = ({infoFormObject: propInfoFormObject, InfoComponent, FormComponent, fieldAndValueToStateChanges, title, onUpdate: propOnUpdate, onDelete: propOnDelete, onCreate: propOnCreate, onCancel: propOnCancel, ...props}) => {
const InfoForm = ({infoFormObject: propInfoFormObject, InfoComponent, FormComponent, fieldAndValueToStateChanges, title, onUpdate: propOnUpdate, onDelete: propOnDelete, onCreate: propOnCreate, onCancel: propOnCancel, initialInfoOrFormState, showInfoFormStateButton, ...props}) => {
const [infoFormObjectChanges, setInfoFormObjectChanges] = useState({});
const infoFormObject = useMemo(()=>({...propInfoFormObject, infoFormObjectChanges}),[propInfoFormObject, infoFormObjectChanges]);
const infoFormObject = {...propInfoFormObject, ...infoFormObjectChanges};
const [formType, toggleFormType] = useInfoFormState("info");
const [formType, toggleFormType] = useInfoFormState(initialInfoOrFormState);
const handleInfoFormObjectChange = (field, value) => {
setInfoFormObjectChanges(prevState => ({...prevState, ...fieldAndValueToStateChanges(field, value, prevState)}));
};
const onUpdate = useCallback((data)=>{
const baseCallback = useCallback(()=>{
toggleFormType();
setInfoFormObjectChanges({});
return propOnUpdate(data);
}, [toggleFormType, propOnUpdate]);
const onDelete = useCallback((data)=>{
toggleFormType();
setInfoFormObjectChanges({});
return propOnDelete(data);
}, [toggleFormType, propOnDelete]);
const onCreate = useCallback((data)=>{
toggleFormType();
setInfoFormObjectChanges({});
return propOnCreate(data);
}, [toggleFormType, propOnCreate]);
const onCancel = useCallback(()=>{
toggleFormType();
setInfoFormObjectChanges({});
return propOnCancel();
}, [toggleFormType, propOnCancel]);
}, [toggleFormType, setInfoFormObjectChanges]);
const onUpdate = ()=>{
propOnUpdate(infoFormObject);
baseCallback();
};
const onDelete = ()=>{
propOnDelete(infoFormObject);
baseCallback();
};
const onCreate = ()=>{
propOnCreate(infoFormObject);
baseCallback();
};
const onCancel = ()=>{
propOnCancel(infoFormObject);
baseCallback();
};
return (
<Block>
<Wrapper>
<Typography>{ title }</Typography>
<Typography variant={"h4"}>{ title }</Typography>
<div>
<Button variant={"contained"} onClick={toggleFormType}>{ formType === "info" ? "Edit" : "View" }</Button>
{ showInfoFormStateButton && <Button color={"primary"} variant={"contained"} onClick={toggleFormType}>{ formType === "info" ? "Edit" : "View" }</Button> }
</div>
</Wrapper>
<hr className={"box-title-separator"}/>
......@@ -71,20 +73,27 @@ const InfoForm = ({infoFormObject: propInfoFormObject, InfoComponent, FormCompon
};
InfoForm.propTypes = {
infoOrForm: PropTypes.string.isRequired,
initialInfoOrFormState: PropTypes.string,
showInfoFormStateButton: PropTypes.bool,
infoFormObject: PropTypes.object,
InfoComponent: PropTypes.node.isRequired,
FormComponent: PropTypes.node.isRequired,
InfoComponent: PropTypes.elementType.isRequired,
FormComponent: PropTypes.elementType.isRequired,
fieldAndValueToStateChanges: PropTypes.func,
title: PropTypes.string.isRequired,
onCreate: PropTypes.func.isRequired,
onUpdate: PropTypes.func.isRequired,
onDelete: PropTypes.func.isRequired,
onCancel: PropTypes.func.isRequired,
onCreate: PropTypes.func,
onUpdate: PropTypes.func,
onDelete: PropTypes.func,
onCancel: PropTypes.func
};
InfoForm.defaultProps = {
onCreate: dummyFunction,
onUpdate: dummyFunction,
onDelete: dummyFunction,
onCancel: dummyFunction,
infoFormObject: {},
initialInfoOrFormState: "info",
showInfoFormStateButton: true,
fieldAndValueToStateChanges: defaultFieldAndValueToStateChanges
};
......
import PropTypes from "prop-types";
const AssociationType = PropTypes.object.isRequired;
export default AssociationType;
\ No newline at end of file
const InfoOrForm = (props, propName, componentName) => {