diff --git a/client/components/Mission.js b/client/components/Mission.js index 10b36c8..4aa5036 100644 --- a/client/components/Mission.js +++ b/client/components/Mission.js @@ -1,9 +1,10 @@ import React from 'react'; import moment from 'moment'; import _ from 'lodash'; -import { Card, Table, Button, Pill } from 'elemental'; +import { Alert, Card, Table, ButtonGroup, Button, Pill } from 'elemental'; import { Map, TileLayer } from 'react-leaflet'; import MissionForm from './MissionForm'; +import * as http from '../lib/http'; const formatDate = date => moment(date).format(moment.localeData().longDateFormat('L')); @@ -24,6 +25,7 @@ export default React.createClass({ contextTypes: { volunteers: React.PropTypes.object, + volunteer: React.PropTypes.object, }, getDefaultProps() { @@ -66,6 +68,21 @@ export default React.createClass({ this.props.onChange(mission); }, + setMessage(text, type) { + this.setState({ message: { text, type } }); + _.delay(() => this.setState({ message: null }), 5000); + }, + + setMissionState(status) { + const mission = this.props.mission; + http.put(`/api/volunteer/missions/${mission.id}?status=${status}`) + .then(() => { + mission.crew.find(a => a.volunteer.id === this.context.volunteer.id).status = status; + this.props.onChange(mission); + }) + .catch(({ error }) => this.setMessage(error, 'danger')); + }, + toggleEdit() { const isEditing = !this.state.isEditing; this.setState({ isEditing }); @@ -104,8 +121,13 @@ export default React.createClass({ const position = this.state.position; const right = { float: 'right' }; + const isMyMission = this.context.volunteer && !!mission.crew.find(a => a.volunteer.id === this.context.volunteer.id); + return ( + {this.state.message && + {this.state.message.text} + } {this.props.isEditable ? : @@ -114,6 +136,17 @@ export default React.createClass({ {this.renderCrew(mission.crew)} + {isMyMission && +

+ Change your participation state: + + + + + +

+ } + {position && diff --git a/client/components/Volunteer.js b/client/components/Volunteer.js index 14b5f26..7c41b5c 100644 --- a/client/components/Volunteer.js +++ b/client/components/Volunteer.js @@ -8,6 +8,10 @@ import * as http from '../lib/http'; export default React.createClass({ + childContextTypes: { + volunteer: React.PropTypes.object, + }, + getInitialState() { return { volunteer: null, @@ -19,6 +23,12 @@ export default React.createClass({ }; }, + getChildContext() { + return { + volunteer: this.state.volunteer, + }; + }, + componentDidMount() { if (!this.state.hasVisitedBefore) { window.localStorage.setItem('hasVisitedBefore', true); @@ -42,6 +52,13 @@ export default React.createClass({ this.setState({ isEditing: !this.state.isEditing }); }, + updateMission(newMission) { + const missions = this.state.missions; + const index = _.findIndex(missions, mission => mission.id === newMission.id); + missions[index] = newMission; + this.setState({ missions }); + }, + renderMissions() { if (!this.state.missions) return null; @@ -51,7 +68,7 @@ export default React.createClass({ return (
- {this.state.missions.map(mission => )} + {this.state.missions.map(mission => )}
); }, diff --git a/routes/api/volunteers.js b/routes/api/volunteers.js index 6dd2c84..23ee38f 100644 --- a/routes/api/volunteers.js +++ b/routes/api/volunteers.js @@ -135,6 +135,39 @@ exports.changeToken = (req, res) => { }); }; +/** + * Change the Status of a Volunteer + */ +exports.changeMissionStatus = (req, res) => { + const token = req.token; + const missionID = req.params.id; + const newStatus = req.query.status; + const allowedStatus = ['pending', 'yes', 'no']; + + if (!allowedStatus.includes(newStatus)) { + return res.apiError('not allowed'); + } + + Mission.model + .findById(missionID) + .populate('crew.volunteer', 'token') + .exec((err2, mission) => { + if (err2) return res.apiError(err2.detail.errmsg); + if (!mission) return res.apiError('not found'); + + const match = mission.crew.find(a => a.volunteer.token === token); + + if (match) { + match.status = newStatus; + mission.save((err3) => { + if (err3) return res.apiError(err3.detail.errmsg); + res.apiResponse({ success: true }); + }); + } + else res.apiError('not found'); + }); +}; + /** * Delete Volunteer by ID */ diff --git a/routes/index.js b/routes/index.js index 7506676..a9b8a13 100644 --- a/routes/index.js +++ b/routes/index.js @@ -32,6 +32,7 @@ exports = module.exports = (app) => { app.put('/api/volunteer', keystone.middleware.api, hasToken, api.volunteers.update); app.post('/api/volunteer', keystone.middleware.api, api.volunteers.create); app.post('/api/volunteer/token', keystone.middleware.api, api.volunteers.changeToken); + app.put('/api/volunteer/missions/:id', keystone.middleware.api, hasToken, api.volunteers.changeMissionStatus); // Uploaded images should not be publicly accessible app.use('/uploads', isAdminOrOwner, express.static('uploads', { redirect: false }));