Plumbing events
Signed-off-by: James Ketrenos <james_eikona@ketrenos.com>
This commit is contained in:
parent
7aaa2cd1bf
commit
3ba43bc8b8
@ -117,7 +117,7 @@ const App = () => {
|
||||
<Route path="/password" element={
|
||||
<Paper>Not implemented... yet.</Paper>
|
||||
}/>
|
||||
<Route path="/:group" element={<Group />}/>
|
||||
<Route path="/:group/*" element={<Group />}/>
|
||||
{ user && user.mailVerified &&
|
||||
<Route path="/" element={<Dashboard />}/>
|
||||
}
|
||||
|
@ -48,7 +48,7 @@ function Dashboard() {
|
||||
}, [user, setGroups, csrfToken ]);
|
||||
|
||||
const upcomingEvents = groups
|
||||
.filter(group => group.nextEvent > Date.now());
|
||||
.filter(group => group.nextEvent.date > Date.now());
|
||||
|
||||
return (
|
||||
<div className="Dashboard"
|
||||
@ -72,7 +72,7 @@ function Dashboard() {
|
||||
{ upcomingEvents
|
||||
.map((group) => {
|
||||
return <Button key={group.id}
|
||||
onClick={() => navigate(`/${group.group}/${group.nextEventId}`)}
|
||||
onClick={() => navigate(`/${group.group}/${group.nextEvent.event}`)}
|
||||
style={{
|
||||
flexDirection: 'column',
|
||||
display: 'flex',
|
||||
@ -83,8 +83,8 @@ function Dashboard() {
|
||||
<div key={group.id} style={{
|
||||
fontWeight: 'bold'
|
||||
}}>{group.name}</div>
|
||||
{ group.nextEvent &&
|
||||
<div>Next event <Moment fromNow date={group.nextEvent} /> on <Moment format={'MMMM Do YYYY, h: mm: ss a'} date={group.nextEvent}/>.</div>
|
||||
{ group.nextEvent.date &&
|
||||
<div>Next event <Moment fromNow date={group.nextEvent.date} /> on <Moment format={'MMMM Do YYYY, h: mm: ss a'} date={group.nextEvent.date}/>.</div>
|
||||
}
|
||||
</Button>;
|
||||
})
|
||||
|
4
client/src/Event.css
Normal file
4
client/src/Event.css
Normal file
@ -0,0 +1,4 @@
|
||||
.Event {
|
||||
text-align: left;
|
||||
}
|
||||
|
109
client/src/Event.js
Normal file
109
client/src/Event.js
Normal file
@ -0,0 +1,109 @@
|
||||
import React, { useState, useEffect, useContext } from "react";
|
||||
import Paper from '@mui/material/Paper';
|
||||
import {
|
||||
useParams,
|
||||
useNavigate
|
||||
} from "react-router-dom";
|
||||
|
||||
import './Event.css';
|
||||
import { GlobalContext } from "./GlobalContext.js";
|
||||
import { base } from "./Common.js";
|
||||
|
||||
function Event({ groupId }) {
|
||||
const eventId = useParams().event;
|
||||
const { csrfToken, setError } = useContext(GlobalContext);
|
||||
const [ event, setEvent ] = useState(undefined);
|
||||
|
||||
useEffect(() => {
|
||||
if (!csrfToken || event || !eventId || !groupId) {
|
||||
return;
|
||||
}
|
||||
|
||||
const effect = async () => {
|
||||
const res = await window.fetch(
|
||||
`${base}/api/v1/events/${eventId}?groupId=${groupId}`, {
|
||||
method: 'GET',
|
||||
cache: 'no-cache',
|
||||
credentials: 'same-origin',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'CSRF-Token': csrfToken
|
||||
}
|
||||
});
|
||||
const data = await res.json();
|
||||
if (res.status >= 400) {
|
||||
setError(data.message ? data.message : res.statusText);
|
||||
return;
|
||||
}
|
||||
if (!data) {
|
||||
return;
|
||||
}
|
||||
setEvent(data[0]);
|
||||
}
|
||||
effect();
|
||||
}, [eventId, csrfToken, event, setError]);
|
||||
|
||||
const showEvent = (event) => {
|
||||
const fields = Object.getOwnPropertyNames(event)
|
||||
.filter(field => event[field])
|
||||
.map(field => {
|
||||
return <div key={field}
|
||||
style={{
|
||||
display: 'flex',
|
||||
flexDirection: 'row',
|
||||
alignItems: 'flex-start',
|
||||
width: '100%'
|
||||
}}>
|
||||
<div style={{
|
||||
display: 'flex',
|
||||
alignSelf: 'flex-start',
|
||||
fontWeight: 'bold',
|
||||
minWidth: '8rem'
|
||||
}}>{field}</div>
|
||||
<div style={{
|
||||
display: 'flex',
|
||||
alignSelf: 'flex-start',
|
||||
textAlign: 'left'
|
||||
}}>
|
||||
{ typeof event[field] === 'string'
|
||||
&& event[field].match(/^http.*/)
|
||||
&& <a href={event[field]}>{field.toUpperCase()}</a> }
|
||||
{ typeof event[field] === 'string'
|
||||
&& !event[field].match(/^http.*/)
|
||||
&& event[field] }
|
||||
{ typeof event[field] === 'number' && event[field]}
|
||||
</div>
|
||||
</div>
|
||||
} );
|
||||
return <div key={event.id} style={{
|
||||
display: 'flex',
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'space-between',
|
||||
}}>
|
||||
<div style={{
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
alignItems: 'center'
|
||||
}}>{fields}</div>
|
||||
</div>;
|
||||
};
|
||||
|
||||
if (!event) {
|
||||
return <>No event</>;
|
||||
}
|
||||
|
||||
return (
|
||||
<Paper className="Event" style={{
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
padding: '0.5rem',
|
||||
marginTop: '0.25rem',
|
||||
marginBottom: '0.25rem'
|
||||
}}>
|
||||
{ showEvent(event) }
|
||||
</Paper>
|
||||
);
|
||||
}
|
||||
|
||||
export { Event };
|
@ -2,13 +2,15 @@ import React, { useState, useEffect, useContext } from "react";
|
||||
import Paper from '@mui/material/Paper';
|
||||
import {
|
||||
useParams,
|
||||
useNavigate
|
||||
Routes,
|
||||
Route
|
||||
} from "react-router-dom";
|
||||
|
||||
import './Group.css';
|
||||
import { GlobalContext } from "./GlobalContext.js";
|
||||
import { base } from "./Common.js";
|
||||
import { Location } from "./Location.js";
|
||||
import { Event } from "./Event.js";
|
||||
|
||||
function Group() {
|
||||
const { csrfToken, user, setError } = useContext(GlobalContext);
|
||||
@ -110,12 +112,15 @@ function Group() {
|
||||
flexDirection: 'column',
|
||||
textAlign: 'left',
|
||||
}}>
|
||||
{ group && <>
|
||||
<div style={{fontWeight: 'bold'}}>{group.name}</div>
|
||||
<div>Locations</div>
|
||||
{ locations.map(location =>
|
||||
<Location location={location} key={location.id}/>) }
|
||||
</> }
|
||||
<Routes>
|
||||
<Route path="/:event" element={<Event groupId={groupId}/>} />
|
||||
<Route path="/" element={ group && <>
|
||||
<div style={{fontWeight: 'bold'}}>{group.name}</div>
|
||||
<div>Locations</div>
|
||||
{ locations.map(location =>
|
||||
<Location location={location} key={location.id}/>) }
|
||||
</> }/>
|
||||
</Routes>
|
||||
</Paper>
|
||||
);
|
||||
}
|
||||
|
@ -44,9 +44,9 @@ function Location(props) {
|
||||
setLocation(data);
|
||||
}
|
||||
effect();
|
||||
}, [locationId, csrfToken, location]);
|
||||
}, [locationId, csrfToken, location, setError]);
|
||||
|
||||
const createLocation = (location) => {
|
||||
const showLocation = (location) => {
|
||||
const fields = Object.getOwnPropertyNames(location)
|
||||
.filter(field => location[field])
|
||||
.map(field => {
|
||||
@ -109,7 +109,7 @@ function Location(props) {
|
||||
marginTop: '0.25rem',
|
||||
marginBottom: '0.25rem'
|
||||
}}>
|
||||
{ createLocation(location) }
|
||||
{ showLocation(location) }
|
||||
</Paper>
|
||||
);
|
||||
}
|
||||
|
@ -1,8 +1,8 @@
|
||||
const originalEvents = [ {
|
||||
id: 1,
|
||||
name: 'Tuesday',
|
||||
event: 'tuesday',
|
||||
date: Date.now() + 86400 * 14 * 1000 /* 2 weeks from now */
|
||||
groupId: 1,
|
||||
name: 'Tuesday',
|
||||
event: 'tuesday',
|
||||
date: Date.now() + 86400 * 14 * 1000 /* 2 weeks from now */
|
||||
} ];
|
||||
originalEvents.forEach((item, index) => item.id = index + 1);
|
||||
module.exports = originalEvents;
|
@ -1,10 +1,12 @@
|
||||
const originalEvents = require('./event-data.js');
|
||||
const originalGroups = [ {
|
||||
ownerId: 1,
|
||||
name: 'Beer Tuesday',
|
||||
group: 'beer-tuesday',
|
||||
nextEvent: Date.now() + 86400 * 14 * 1000, /* 2 weeks from now */
|
||||
nextEventId: 1
|
||||
ownerId: 1,
|
||||
name: 'Beer Tuesday',
|
||||
group: 'beer-tuesday',
|
||||
} ];
|
||||
|
||||
originalGroups[0].nextEvent = originalEvents[0];
|
||||
originalEvents.forEach(item => item.groupId = 1);
|
||||
originalGroups.forEach((item, index) => item.id = index + 1);
|
||||
|
||||
module.exports = originalGroups;
|
@ -1,10 +1,9 @@
|
||||
'use strict';
|
||||
|
||||
const config = require('config');
|
||||
const express = require('express');
|
||||
const router = express.Router();
|
||||
|
||||
const originalEvents = require('../event-data.js');
|
||||
const originalGroups = require('../group-data.js');
|
||||
|
||||
router.put('/', (req, res) => {
|
||||
const event = req.body;
|
||||
@ -17,19 +16,40 @@ router.get('/google-api-key', (req, res) => {
|
||||
return res.status(200).send({ key: config.get('googleApi') });
|
||||
});
|
||||
|
||||
router.get('/:eventId?', (req, res) => {
|
||||
const { eventId } = req.params;
|
||||
if (eventId) {
|
||||
const event = originalEvents.find(
|
||||
item => item.id === eventId
|
||||
);
|
||||
if (!event) {
|
||||
return res.status(404).send({ message: `Event ${eventId} not found.` });
|
||||
}
|
||||
return res.status(200).send([event]);
|
||||
router.get('/:event?', (req, res) => {
|
||||
const { event } = req.params;
|
||||
const { groupId } = req.query;
|
||||
|
||||
if (!event) {
|
||||
return res.status(200).send(originalEvents);
|
||||
}
|
||||
|
||||
return res.status(200).send(originalEvents);
|
||||
const group = originalGroups.find(item => {
|
||||
return (item.groupId === groupId || item.group === groupId);
|
||||
});
|
||||
|
||||
if (!group) {
|
||||
return res.status(500).send({ message: `Invalid group-event link.` });
|
||||
}
|
||||
|
||||
const found = originalEvents.find((item) => {
|
||||
if (item.groupId !== group.id) {
|
||||
return false;
|
||||
}
|
||||
if (typeof event === 'number') {
|
||||
return item.id === event;
|
||||
}
|
||||
if (typeof event === 'string') {
|
||||
return item.event === event;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
if (!found) {
|
||||
return res.status(404).send({
|
||||
message: `Unable to find ${groupId}:${event}.`
|
||||
});
|
||||
}
|
||||
return res.status(200).send([found]);
|
||||
});
|
||||
|
||||
router.post('/:eventId', (req, res) => {
|
||||
|
@ -1,5 +1,3 @@
|
||||
'use strict';
|
||||
|
||||
const config = require('config');
|
||||
const express = require('express');
|
||||
const router = express.Router();
|
||||
|
Loading…
x
Reference in New Issue
Block a user