Commit 126703fc authored by TJHeeringa's avatar TJHeeringa

Laid foundations for Calendar App

parent bfff5087
......@@ -6,7 +6,7 @@ import {
faAt,
faBars,
faCheck,
faChevronLeft, faCookieBite, faExchangeAlt,
faChevronLeft, faCookieBite, faExchangeAlt, faHashtag,
faHome,
faIgloo, faImage, faNewspaper,
faPlus, faShoppingCart,
......@@ -30,7 +30,7 @@ require("bootstrap");
library.add(faSignOutAlt, faUser, faIgloo, faBars, faCheck, faTimes, faHome,
faPlus, faChevronLeft, faWarehouse, faShoppingCart, faSocks, faExchangeAlt,
faNewspaper, faImage, faCookieBite, faAt, faSnapchat, faDiscord);
faNewspaper, faImage, faCookieBite, faAt, faSnapchat, faDiscord, faHashtag);
const App = (props) => {
......
......@@ -23,6 +23,7 @@ import Drawer from "App/Components/Lists/Drawer/Drawer";
import React from "react";
import {useLocation} from "react-router-dom";
import {FontAwesomeIcon} from "@fortawesome/react-fontawesome";
import DateRangeIcon from "@material-ui/icons/DateRange";
const AssociationBoardSideBar = (props) => {
......@@ -145,10 +146,15 @@ const AssociationBoardDrawer = (props) => {
icon: <EventIcon />,
primary: "Events",
items: [
{
icon: <DateRangeIcon />,
primary: "Scheduler",
to: url + "/events/scheduler"
},
{
icon: <AlternateEmailIcon />,
primary: "Calendar",
to: url + "/events/calendar"
to: url + "/events"
},
{
icon: <SubjectIcon />,
......
......@@ -15,9 +15,11 @@ import PropTypes from "prop-types";
import React, {useEffect, useState} from "react";
import {useHistory, useParams} from "react-router-dom";
import {BackButton} from "../../Components/BackButton";
import IconHolder from "../../Components/Fields/IconHolder";
import SelectField from "../../Components/Fields/SelectField";
import EnrollmentOptionForm from "../../Components/Forms/EnrollmentOptionForm";
import EventInfo from "../../Components/Info/EventInfo";
import Event from "../../Components/InfoForms/Event";
import CollapsableList from "../../Components/Lists/CollapsableList";
import FormModal from "../../Components/Modals/FormModal";
......@@ -28,14 +30,15 @@ import { useAlertHandler } from "../../Contexts/AlertHandler";
import { useAPI } from "../../Contexts/API";
const EventDetail = ({ association }) => {
const EventDetail = ({ association, eventsAPI }) => {
const API = useAPI();
const alerthandler = useAlertHandler();
const history = useHistory();
const { slug } = useParams();
const [event, setEvent] = useState(null);
const events = eventsAPI.list() || [];
const event2 = events.filter(event=>event.slug === slug);
const [event, setEvent] = useState({});
const [enrollments, setEnrollments] = useState([]);
const [enrollmentOptions, setEnrollmentOptions] = useState([]);
......@@ -58,7 +61,6 @@ const EventDetail = ({ association }) => {
useEffect(getEvent, [slug]); // eslint-disable-line react-hooks/exhaustive-deps
const [formTypeEvent, setFormTypeEvent] = useState("info");
const [formTypeEnrollment, setFormTypeEnrollment] = useState("info");
const [formTypeOption, setFormTypeOption] = useState("info");
const [open, setOpen] = useState();
......@@ -115,71 +117,66 @@ const EventDetail = ({ association }) => {
return (
<PageContent title={event ? event.name : ""}>
<Grid container spacing={2} justify={"center"}>
<Grid item xs={6}>
<BackButton/>
<Container>
<Block>
<Wrapper>
<Typography variant={"h6"}>Event</Typography>
&nbsp;
<Button color={"primary"} variant={"contained"} onClick={changeFormTypeEvent}>
{ formTypeEvent === "form" ? "View" : "Edit" }
</Button>
</Wrapper>
<hr className={"box-title-separator"}/>
<Event
event={event}
association={association}
infoOrForm={formTypeEvent}
update={true}
/>
</Block>
{ event && event.enrollable &&
<Block>
<Wrapper>
<Typography>Event</Typography>
<Typography variant={"h6"}>Enrollment Options</Typography>
&nbsp;
<Button color={"primary"} variant={"contained"} onClick={changeFormTypeEvent}>
{ formTypeEvent === "form" ? "View" : "Edit" }
<Button color={"primary"} variant={"contained"} onClick={changeFormTypeOption}>
{ formTypeOption === "form" ? "View" : "Edit" }
</Button>
</Wrapper>
<hr className={"box-title-separator"}/>
{ event === null ||
<Event
event={event}
association={association}
infoOrForm={formTypeEvent}
update={true}
{ formTypeOption === "info"
? <SimpleTable
headers={["Price", "Name", "Description"]}
rows={enrollmentOptions.map(option=>enrollmentOptionToTable(option))}
/>
}
</Block>
</Grid>
{ event && event.enrollable &&
<Grid item xs={6}>
<Block>
<Wrapper>
<Typography>Enrollment Options</Typography>
&nbsp;
<Button color={"primary"} variant={"contained"} onClick={changeFormTypeOption}>
{ formTypeOption === "form" ? "View" : "Edit" }
</Button>
</Wrapper>
<hr className={"box-title-separator"}/>
{ formTypeOption === "info"
? <SimpleTable
headers={["Price", "Name", "Description"]}
rows={enrollmentOptions.map(option=>enrollmentOptionToTable(option))}
/>
: <div>
{ enrollmentOptions.map((enrollmentOption, index) => (
<CollapsableList
key={index}
component={EnrollmentOptionForm}
listItemText={enrollmentOption.name}
update={true}
association={association}
calendarEvent={event}
enrollment_option={enrollmentOption}
onSucces={updateEnrollmentOption}
/>
)) }
<Divider/>
: <div>
{ enrollmentOptions.map((enrollmentOption, index) => (
<CollapsableList
key={index}
component={EnrollmentOptionForm}
listItemText={"New"}
update={false}
listItemText={enrollmentOption.name}
update={true}
association={association}
calendarEvent={event}
onSucces={addEnrollmentOption}
enrollment_option={enrollmentOption}
onSucces={updateEnrollmentOption}
/>
</div>
}
</Block>
</Grid>
)) }
<Divider/>
<CollapsableList
component={EnrollmentOptionForm}
listItemText={"New"}
update={false}
association={association}
calendarEvent={event}
onSucces={addEnrollmentOption}
/>
</div>
}
</Block>
}
</Grid>
</Container>
{ event && event.enrollable &&
<Container>
<FormModal
......@@ -208,7 +205,7 @@ const EventDetail = ({ association }) => {
</FormModal>
<Block>
<Wrapper>
<Typography>Enrollments</Typography>
<Typography variant={"h6"}>Enrollments</Typography>
<div>
<Button variant={"contained"} onClick={toggleOpen}>
<Typography>Enroll</Typography>
......
import React from "react";
import {useParams} from "react-router-dom";
import useCollectionAPI from "../../Components/Hooks/useCollectionAPI";
import Members from "../../Contexts/Members";
import EventEnrollmentsManagementAssociationMemberList from "./EventEnrollmentsManagementAssociationMemberList";
import EventEnrollmentsManagementEnrollmentOptions from "./EventEnrollmentsManagementEnrollmentOptions";
import EventEnrollmentsManagementEnrollments from "./EventEnrollmentsManagementEnrollments";
import {BackButton} from "../../Components/BackButton";
const EventEnrollmentsManagement = () => {
const EventEnrollmentsManagement = ({ association }) => {
const { slug } = useParams();
const enrollmentsAPI = useCollectionAPI("/enrollments",
{ event__slug: slug, limit: 1000 }
);
const enrollmentOptionsAPI = useCollectionAPI("/enrollment_options",
{ event__slug: slug, limit: 100 }
);
return (
<>
<EventEnrollmentsManagementAssociationMemberList/>
<EventEnrollmentsManagementEnrollments/>
</>
<Members
association={association}
queryParam={{current: true, limit: 10000}}
>
<BackButton/>
{/*<EventEnrollmentsManagementEnrollmentOptions*/}
{/* enrollmentsAPI={enrollmentsAPI}*/}
{/* enrollmentOptionsAPI={enrollmentOptionsAPI}*/}
{/* event_slug={slug}*/}
{/* association={association}*/}
{/*/>*/}
<EventEnrollmentsManagementEnrollments
enrollmentsAPI={enrollmentsAPI}
/>
<EventEnrollmentsManagementAssociationMemberList
enrollmentsAPI={enrollmentsAPI}
/>
</Members>
);
};
......
const EventEnrollmentsManagementAssociationMemberList = () => null;
import Button from "@material-ui/core/Button";
import Container from "@material-ui/core/Container";
import Typography from "@material-ui/core/Typography";
import PropTypes from "prop-types";
import React, {useState} from "react";
import Wrapper from "../../Components/Fields/Wrapper";
import Block from "../../Components/PageLayout/Content/Block";
import {MemberTable2} from "../../Components/Tables/MemberTable";
const EventEnrollmentsManagementAssociationMemberList = ({ enrollmentsAPI }) => {
const [selection, setSelection] = useState([]);
return (
<Container>
<Block>
<Typography variant={"h5"}>Association Members</Typography>
<hr className={"box-title-separator"}/>
<MemberTable2
initial_headers={["given_name", "surname"]}
selection={{selection: selection, setSelection: setSelection}}
showEditing={false}
showGrouping={false}
showExporter={false}
/>
<Wrapper>
<div/>
<Button variant={"contained"} color={"primary"}>Enroll</Button>
</Wrapper>
</Block>
</Container>
);
};
export default EventEnrollmentsManagementAssociationMemberList;
\ No newline at end of file
import Container from "@material-ui/core/Container";
import Divider from "@material-ui/core/Divider";
import List from "@material-ui/core/List";
import Typography from "@material-ui/core/Typography";
import PropTypes from "prop-types";
import React from "react";
import EnrollmentOptionForm from "../../Components/Forms/EnrollmentOptionForm";
import CollapsableListItem from "../../Components/Lists/CollapsableListItem";
import Block from "../../Components/PageLayout/Content/Block";
const EventEnrollmentsManagementEnrollmentOptions = ({ association, event_slug, enrollmentsAPI, enrollmentOptionsAPI }) => {
const enrollmentOptions = enrollmentOptionsAPI.list() || [];
const calendarEvent = {url: "/events/" + event_slug};
const addEnrollmentOption = (added) => {
enrollmentOptionsAPI.add(added);
};
const updateEnrollmentOption = (edited) => {
enrollmentOptionsAPI.edit(edited, "slug");
};
const removeEnrollmentOption = () => {
};
return (
<Container>
<Block>
<Typography variant={"h5"}>Enrollment Options</Typography>
<hr className={"box-title-separator"}/>
<List>
{ enrollmentOptions.map((enrollmentOption, index) => (
<CollapsableListItem
key={index}
component={EnrollmentOptionForm}
listItemText={enrollmentOption.name}
update={true}
association={association}
calendarEvent={calendarEvent}
enrollment_option={enrollmentOption}
onSucces={updateEnrollmentOption}
/>
)) }
&nbsp;
<Divider/>
&nbsp;
<CollapsableListItem
component={EnrollmentOptionForm}
listItemText={"New"}
update={false}
association={association}
calendarEvent={calendarEvent}
onSucces={addEnrollmentOption}
/>
</List>
</Block>
</Container>
);
};
export default EventEnrollmentsManagementEnrollmentOptions;
\ No newline at end of file
const EventEnrollmentsManagementEnrollments = () => null;
import Container from "@material-ui/core/Container";
import Typography from "@material-ui/core/Typography";
import PropTypes from "prop-types";
import React, {useState} from "react";
import Block from "../../Components/PageLayout/Content/Block";
import ExtremeTable from "../../Components/Tables/ExtremeTable";
import Wrapper from "../../Components/Fields/Wrapper";
import Button from "@material-ui/core/Button";
const EventEnrollmentsManagementEnrollments = ({ enrollmentsAPI }) => {
const enrollments = enrollmentsAPI.list() || [];
const [selection, setSelection] = useState([]);
return (
<Container>
<Block>
<Wrapper>
<Typography variant={"h5"}>Enrolled members</Typography>
<Button color={"secondary"} variant={"outlined"} >Import</Button>
</Wrapper>
<hr className={"box-title-separator"}/>
<ExtremeTable
rows={enrollments}
headers={[
{name: "given_name", title: "Given Name"},
{name: "enrollment_option", title: "Enrollment Option"},
]}
showGrouping={false}
selection={{selection: selection, setSelection: setSelection}}
/>
</Block>
</Container>
);
};
export default EventEnrollmentsManagementEnrollments;
\ No newline at end of file
import PropTypes from "prop-types";
import React, { useEffect, useState } from "react";
import React from "react";
import { Route, Switch } from "react-router-dom";
import {useAlertHandler} from "../../Contexts/AlertHandler";
import {useAPI} from "../../Contexts/API";
import useCollectionAPI from "../../Components/Hooks/useCollectionAPI";
import EventAdd from "./EventAdd";
import EventDetail from "./EventDetail";
import EventEnrollmentsManagement from "./EventEnrollmentsManagement";
import EventList from "./EventList";
import EventTypes from "./EventTypes";
import Scheduler from "./Scheduler";
export const EventsRouter = ({ path, association, board }) => {
const alerthandler = useAlertHandler();
const API = useAPI();
const [events, setEvents] = useState([]);
// Get all the events on mount and put them into the state
useEffect(()=>{
API.callv4({
url: "/events",
queryParams: {association__slug: association.slug, limit:1000},
method: "GET",
on_succes: (response) => setEvents(response.results),
on_failure: () => {
alerthandler.handleAlertHandler("red", "Loading committees failed");
},
});
}, [association]); // eslint-disable-line react-hooks/exhaustive-deps
const addEvent = (event) => setEvents(prevState => prevState.concat(event));
const updateEvent = (edited_event) => setEvents(prevState =>
prevState.map(event=>event.slug === event.slug ? edited_event : event)
const eventsAPI = useCollectionAPI("/events",
{limit: 10000, association__slug: association.slug}
);
const eventTypesAPI = useCollectionAPI("/event_types",
{limit: 10000, association__slug: association.slug}
);
const addEvent = eventsAPI.add;
const updateEvent = (edited_event) => eventsAPI.edit(edited_event, "slug");
const events = eventsAPI.list() || [];
const event_types = eventTypesAPI.list() || [];
return (
<Switch>
<Route exact path={path+"/types"}>
<EventTypes
association={association}
api={eventTypesAPI}
/>
</Route>
<Route exact path={path+"/add"}>
<EventAdd
association={association}
onAdd={addEvent}
/>
</Route>
<Route path={path + "/scheduler"}>
<Scheduler
association={association}
event_types={event_types}
eventsAPI={eventsAPI}
/>
</Route>
<Route path={path+"/:slug/enrollments"}>
<EventEnrollmentsManagement
association={association}
......@@ -50,6 +53,7 @@ export const EventsRouter = ({ path, association, board }) => {
</Route>
<Route path={path+"/:slug"}>
<EventDetail
eventsAPI={eventsAPI}
association={association}
onUpdate={updateEvent}
url={path}
......
......@@ -3,7 +3,7 @@ import Button from "@material-ui/core/Button";
import Divider from "@material-ui/core/Divider";
import makeStyles from "@material-ui/core/styles/makeStyles";
import ContactsIcon from "@material-ui/icons/Contacts";
import CollapsableList from "App/Components/Lists/CollapsableList";
import CollapsableListItem from "App/Components/Lists/CollapsableListItem";
import ConfirmationModal from "App/Components/Modals/ConfirmationModal";
import { useAlertHandler } from "App/Contexts/AlertHandler";
import { Helper } from "App/Helper";
......@@ -13,19 +13,22 @@ import { TextValidator, ValidatorForm } from "react-material-ui-form-validator";
import {Container} from "reactstrap";
import {useGet} from "restful-react";
import IconHolder from "../../Components/Fields/IconHolder";
import TextField from "../../Components/Fields/TextField";
import Wrapper from "../../Components/Fields/Wrapper";
import Block from "../../Components/PageLayout/Content/Block";
import {useAPI} from "../../Contexts/API";
import Wrapper from "../../Components/Fields/Wrapper";
import TextField from "../../Components/Fields/TextField";
import IconHolder from "../../Components/Fields/IconHolder";
import List from "@material-ui/core/List";
const EventTypes = ({ association, api }) => {
const types = api.list() || [];
const postEdit = (edited_type) => api.edit(edited_type, "slug");
const postAdd = (added_type) => api.add(added_type, "slug");
console.log(types);
const EventTypes = ({ association }) => {
let { data: types, loading: loadingMembers, refetch } = useGet({
path: "/event_types",
queryParams: {limit: 10000, association__slug: association.slug},
resolve: data => data && data.results
});
return (
<Container>
<Block>
......@@ -35,24 +38,28 @@ const EventTypes = ({ association }) => {
associated with the type `education` and a poker tournament with `gezelligheid`.
</Typography>
<hr className={"box-title-separator"}/>
{ types && types.map((type, index) => (
<CollapsableList
<List>
{ types && types.map((type, index) => (
<CollapsableListItem
component={EventType}
listItemText={type.type}
key={index}
association={association}
type={type}
postSave={postEdit}
/>
)) }
&nbsp;
<Divider/>
&nbsp;
<CollapsableListItem
component={EventType}
listItemText={type.type}
key={index}
listItemText={"New"}
association={association}
type={type}
postSave={(created_type)=>{refetch();}}
postSave={postAdd}
add={true}
/>
)) }
<Divider/>
<CollapsableList
component={EventType}
listItemText={"New"}
association={association}
postSave={(created_type)=>{refetch();}}
add={true}
/>
</List>
</Block>
</Container>
);
......
This diff is collapsed.
......@@ -27,6 +27,7 @@ import Products from "../../../Pages/Inventory/Products/Products";
import Purchases from "../../../Pages/Inventory/Purchases/Purchases";
import Members from "../../../Contexts/Members";
const BoardMemberRoutes = (props) => {
const {path, association_membership, association} = props;
......@@ -143,20 +144,11 @@ const BoardMemberRoutes = (props) => {
{ /*calendar*/ }
<Route path={path + "/events"}>
<Switch>
<Route exact path={path + "/events/types"}>
<EventTypes
association={association}
/>
</Route>
<Route path={path + "/events/calendar"}>
<EventsRouter
association={association}
path={path + "/events/calendar"}
board={true}
/>
</Route>
</Switch>
<EventsRouter
association={association}
path={path + "/events"}
board={true}
/>
</Route>
{ /*members*/ }
......
export const fromAPItoSchedulerFormat = (calendarEvent) => {