Skip to content

Instantly share code, notes, and snippets.

@sheminusminus
Last active September 10, 2017 23:53
Show Gist options
  • Save sheminusminus/ec9cd1461f611a26ee8b09b9dac72997 to your computer and use it in GitHub Desktop.
Save sheminusminus/ec9cd1461f611a26ee8b09b9dac72997 to your computer and use it in GitHub Desktop.
Events: 1. Create an event 2. Make a form that allows others to update that event
/**
* eventRouter.js
* @file Handles any requests to route /api/events. Server file.
*/
const axios = require('axios');
const router = require('express').Router();
// events the user can alter, seeded with event 2
// of course this would normally come from a database
const allowedEvents = [2];
// api key
const apiKey = 'MY_API_KEY';
// nb url parts
const eventBase = 'https://emilykolarsandbox.nationbuilder.com/api/v1/sites/emilykolarsandbox/pages/events';
const tokenQuery = `access_token=${apiKey}`;
// content-type and accept headers for requests to nb
const headers = {
'Content-Type': 'application/json',
Accept: 'application/json',
};
// parse the nb response for info relevant to the front-end
function parseEvent(data) {
const name = data.name || '';
const start = data.start_time || new Date();
const end = data.end_time || new Date();
const status = data.status || '';
const venue = data.venue ? data.venue.name : '';
const capacity = data.capacity || 0;
const id = data.id || '';
return {
id,
name,
start,
end,
status,
venue,
capacity,
};
}
// get a specific event's data
router.get('/:id', (req, res) => {
const id = parseInt(req.params.id, 10);
if (allowedEvents.includes(id)) {
const url = `${eventBase}/${req.params.id}?${tokenQuery}`;
axios.get(url, {
headers,
}).then((resp) => {
const event = parseEvent(resp.data.event);
res.json(event);
}).catch(() => {
res.json({ message: 'An error occurred' });
});
}
});
// get all event data
router.get('/', (req, res) => {
const url = `${eventBase}?limit=20&${tokenQuery}`;
axios.get(url, { headers }).then((resp) => {
const events = [];
const results = resp.data.results;
for (let i = 0; i < results.length; i++) {
const event = parseEvent(results[i]);
const eventId = parseInt(event.id, 10);
// if the user can access this event, add it to the response data
if (allowedEvents.includes(eventId)) {
events.push(event);
}
}
res.json(events);
}).catch(() => {
res.json({ message: 'An error occurred' });
});
});
// create new event {
router.post('/', (req, res) => {
const url = `${eventBase}?${tokenQuery}`;
axios.post(url, {
event: {
venue: {
name: req.body.venue,
},
name: req.body.event,
capacity: req.body.capacity,
start_time: req.body.start,
end_time: req.body.end,
status: req.body.status,
},
}, { headers }).then((resp) => {
const event = parseEvent(resp.data.event);
const eventId = parseInt(event.id, 10);
// allow editor-access to the new event
allowedEvents.push(eventId);
res.json(event);
}).catch(() => {
res.json({ message: 'An error occurred' });
});
});
// update event data
router.put('/:id', (req, res) => {
const id = parseInt(req.params.id, 10);
if (allowedEvents.includes(id)) {
const url = `${eventBase}/${id}?${tokenQuery}`;
axios.put(url, {
event: {
venue: {
name: req.body.venue,
},
name: req.body.event,
capacity: req.body.capacity,
start_time: req.body.start,
end_time: req.body.end,
status: req.body.status,
},
}, { headers }).then((resp) => {
const event = parseEvent(resp.data.event);
res.json(event);
}).catch((error) => {
res.json({ message: error.response.data.message });
});
}
});
module.exports = router;
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Events NB Exercise</title>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.18.1/moment.min.js"></script>
</head>
<body>
<h3>Super-Event-Admin 9000</h3>
New Event <input type="radio" name="eventType" value="CREATE" checked /><br />
Edit Existing <input type="radio" name="eventType" value="UPDATE" /><br />
<select id="selection" disabled>
<option disabled selected>Select an event</option>
</select>
<hr/>
<form id="edit">
<label>Venue Name</label><br />
<input type="text" id="venue" placeholder="where is it?" /><br />
<label>Event Name</label><br />
<input type="text" id="event" placeholder="name your event" /><br />
<label>Happening On</label><br />
<input type="date" id="start" /><br />
<label>Capacity</label><br />
<input type="number" id="capacity" /><br />
<input type="submit" id="submitEdits" value="Save Changes" />
</form>
<script src="./script.js"></script>
</body>
</html>
/**
* index.js
* @file Launches a basic express server and sends the index.html over all unmatched routes. Server main.
*/
const path = require('path');
const express = require('express');
const bodyParser = require('body-parser');
const app = express();
const eventRouter = require('./server/eventRouter');
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());
app.use(express.static('./pub'));
app.use('/api/events', eventRouter);
app.get('*', (req, res) => {
res.sendFile(path.resolve(__dirname, 'pub/index.html'));
});
app.listen(3000, () => {
console.log('the magic happens on port 3000');
});
/**
* script.js
* @file Client script for creating new events and editing existing events. Loaded by index.html.
*/
window.addEventListener('load', function() {
// global values
const baseUrl = '/api/events';
const axios = window.axios;
const moment = window.moment;
let mode = 'CREATE';
// ui
let edit = document.querySelector('#edit');
let venueEL = document.querySelector('#venue');
let nameEl = document.querySelector('#event');
let capacityEl = document.querySelector('#capacity');
let startEl = document.querySelector('#start');
let selectEl = document.getElementById('selection');
let modeEls = document.getElementsByName('eventType');
// data references
let start = moment();
let end = moment();
let status = 'unlisted';
// clear the form
function clearFields() {
edit.reset();
}
// inject event info into the form
// save start, end, and status data
function fillEventFields(data) {
start = moment(data.start) || moment();
end = moment(data.end) || moment().add(3, 'hours');
status = data.status || 'unlisted';
venueEL.value = data.venue || '';
nameEl.value = data.name || '';
capacityEl.value = data.capacity || 0;
startEl.value = start.format('YYYY-MM-DD');;
}
// request the event data from our api
function getEventsData(callback) {
axios.get(baseUrl).then((resp) => {
callback(resp.data);
}).catch((error) => {
console.error(error);
});
}
// fetch selected event's info and fill fields
function setEvent(id) {
const url = baseUrl + '/' + id;
axios.get(url).then((resp) => {
fillEventFields(resp.data);
}).catch((err) => {
console.log(err);
});
}
// create option for each event
function makeOption(data) {
let opt = document.createElement('option');
opt.value = data.id;
opt.textContent = data.name;
return opt;
}
// rebuild event select element
function listEvents(events) {
while (selectEl.firstChild) {
selectEl.removeChild(selectEl.firstChild);
}
const firstOpt = document.createElement('option');
firstOpt.setAttribute('disabled', 'disabled');
firstOpt.textContent = 'Select an event';
firstOpt.setAttribute('selected', 'selected');
selectEl.appendChild(firstOpt);
for (let i = 0; i < events.length; i++) {
const opt = makeOption(events[i]);
selectEl.appendChild(opt);
}
}
// set whether we're in edit mode or create mode
function updateMode() {
if (mode === 'CREATE') {
clearFields();
selectEl.selectedIndex = 0;
selectEl.setAttribute('disabled', 'disabled');
} else {
selectEl.removeAttribute('disabled');
}
}
// send the new or updated event data to our api
function saveEventData(method, url, callback) {
const venue = venueEL.value;
const event = nameEl.value;
const cap = capacityEl.value;
const newStart = moment(startEl.value).hours(start.hours());
const newEnd = moment(startEl.value).hours(end.hours());
axios({
method: method,
url: url,
data: {
venue: venue,
event: event,
start: newStart.format('YYYY-MM-DDTHH:mmZZ'),
end: newEnd.format('YYYY-MM-DDTHH:mmZZ'),
capacity: cap,
status: status,
}
}).then(() => {
clearFields();
getEventsData(callback);
}).catch((error) => {
console.error(error);
});
}
function init() {
// listen for create/edit toggle
modeEls.forEach((el) => {
el.addEventListener('change', (evt) => {
mode = evt.target.value;
updateMode();
});
});
// listen for form submission
edit.addEventListener('submit', (evt) => {
evt.preventDefault();
if (mode === 'UPDATE') {
const url = baseUrl + '/' + selectEl.value;
saveEventData('PUT', url, listEvents);
} else {
saveEventData('POST', baseUrl, listEvents);
}
});
// listen for event selection
selectEl.addEventListener('change', (evt) => {
setEvent(evt.target.value);
});
// query for our initial data
getEventsData(listEvents);
}
// start the thing moving
init();
});
@sheminusminus
Copy link
Author

events-ui

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment