diff --git a/src/components/RsvpCard/RsvpCard.css b/src/components/RsvpCard/RsvpCard.css
index bb542d8..4487307 100644
--- a/src/components/RsvpCard/RsvpCard.css
+++ b/src/components/RsvpCard/RsvpCard.css
@@ -44,10 +44,11 @@
color: #616161;
font-size: 18px;
line-height: 1.3333333;
- transition:
- border-color ease-in-out 0.3s,
- box-shadow ease-in-out 0.3s,
- background-color ease-in-out 0.3s;
+ transition: border-color ease-in-out 0.3s, box-shadow ease-in-out 0.3s, background-color ease-in-out 0.3s;
+}
+
+.input:disabled {
+ opacity: 0.5;
}
.input:focus {
@@ -87,3 +88,7 @@
.rsvpSummarySuccess {
opacity: 1;
}
+
+.rsvpSummaryReadOnly {
+ opacity: 1;
+}
diff --git a/src/components/RsvpCard/RsvpCard.js b/src/components/RsvpCard/RsvpCard.js
index f43ba91..309f329 100644
--- a/src/components/RsvpCard/RsvpCard.js
+++ b/src/components/RsvpCard/RsvpCard.js
@@ -21,6 +21,7 @@ class RsvpCard extends React.Component {
starter: PropTypes.string,
main: PropTypes.string,
}).isRequired,
+ isEditable: PropTypes.bool.isRequired,
};
constructor(props) {
@@ -32,6 +33,11 @@ class RsvpCard extends React.Component {
saveMain: this.props.person.main !== '-1' ? 'saved' : null,
saveDietary: this.props.person.dietary ? 'saved' : null,
};
+
+ if (!this.props.isEditable) {
+ this.state.summaryState = 'readonly';
+ this.state.summary = 'Sorry, you can no longer change your RSVP.';
+ }
}
isRSVPComplete(prop, value) {
@@ -143,6 +149,7 @@ class RsvpCard extends React.Component {
defaultValue="-1"
onChange={this.handleAttendingChange}
onFocus={this.props.focusCallback}
+ disabled={!this.props.isEditable}
>
: null}
{starters.map((starter, index) => (
@@ -220,6 +229,7 @@ class RsvpCard extends React.Component {
defaultValue={this.props.person.main}
onChange={this.handleMainChange}
onFocus={this.props.focusCallback}
+ disabled={!this.props.isEditable}
>
{this.props.person.main === '-1' ? : null}
{mains.map((main, index) => (
@@ -249,6 +259,7 @@ class RsvpCard extends React.Component {
onChange={this.handleDietaryChange}
onBlur={this.handleDietaryBlur}
onFocus={this.props.focusCallback}
+ disabled={!this.props.isEditable}
placeholder="None"
/>
@@ -262,6 +273,7 @@ class RsvpCard extends React.Component {
className={[
s.rsvpSummary,
this.state.summaryState === 'success' ? s.rsvpSummarySuccess : null,
+ this.state.summaryState === 'readonly' ? s.rsvpSummaryReadOnly : null,
].join(' ')}
>
{this.state.summary}
diff --git a/src/routes/rsvp/Rsvp.js b/src/routes/rsvp/Rsvp.js
index e3f1474..cb983a4 100644
--- a/src/routes/rsvp/Rsvp.js
+++ b/src/routes/rsvp/Rsvp.js
@@ -14,6 +14,8 @@ class Rsvp extends React.Component {
starter: PropTypes.string,
main: PropTypes.string,
})).isRequired,
+ rsvpEnd: PropTypes.string.isRequired,
+ isEditable: PropTypes.bool.isRequired,
};
constructor(props) {
@@ -38,11 +40,16 @@ class Rsvp extends React.Component {
Odpovezte prosÃm
{this.props.people.map(person => (
-
+
))}
-
You can modify the above details up until XX/XX/XXXX
+
You can modify the above details up until {this.props.rsvpEnd}
diff --git a/src/routes/rsvp/index.js b/src/routes/rsvp/index.js
index 4b9d3ca..b7decf9 100644
--- a/src/routes/rsvp/index.js
+++ b/src/routes/rsvp/index.js
@@ -3,13 +3,44 @@ import Layout from '../../components/Layout';
import fetchQL from '../../core/fetchQL';
import Rsvp from './Rsvp';
import NotFound from '../notFound/NotFound';
+import { rsvpEndDate } from '../../config';
let title = 'RSVP';
+const months = [
+ 'January',
+ 'February',
+ 'March',
+ 'April',
+ 'May',
+ 'June',
+ 'July',
+ 'August',
+ 'September',
+ 'October',
+ 'November',
+ 'December',
+];
+
export default {
path: '/rsvp/:password',
+ getRsvpEnd() {
+ const date = rsvpEndDate.getDate();
+ let dateSuffix = 'th';
+ if (date === 1 || date === 21 || date === 31) { dateSuffix = 'st'; }
+ if (date === 2 || date === 22) { dateSuffix = 'nd'; }
+ if (date === 3 || date === 23) { dateSuffix = 'rd'; }
+ const month = months[rsvpEndDate.getMonth()];
+ const year = rsvpEndDate.getFullYear();
+ return `${date}${dateSuffix} ${month} ${year}`;
+ },
+
+ isEditable() {
+ return new Date() < rsvpEndDate;
+ },
+
async action({ params }) {
if (!params.password) {
return { redirect: '/' };
@@ -32,7 +63,16 @@ export default {
return {
title,
- component: ,
+ component: (
+
+
+
+ ),
};
},
diff --git a/src/server.js b/src/server.js
index 609cc08..f333440 100644
--- a/src/server.js
+++ b/src/server.js
@@ -21,7 +21,7 @@ import models from './data/models';
import schema from './data/schema';
import routes from './routes';
import assets from './assets'; // eslint-disable-line import/no-unresolved
-import { port, auth, starters, mains } from './config';
+import { port, auth, starters, mains, rsvpEndDate } from './config';
import Person from './data/models/Person';
import Rollbar from './core/rollbar';
import { sendSlackMsgWithDebounce } from './core/slack';
@@ -143,27 +143,40 @@ app.get('/rsvp/:code', bouncer.block, (req, res, next) => {
app.post('/rsvp/save', (req, res) => {
try {
- const update = {};
- update[req.body.prop] = req.body.value;
- Person.update(update, {
- where: {
- key: req.body.key,
- },
- }).then(() => {
- Person.findOne({
- where: { key: req.body.key },
- }).then(data => {
- if (data.completed) {
- const attending = `\nAttending: ${data.attending ? 'Yes' : 'No'}`;
- const starter = (data.attending && data.starter !== -1) ? `\nStarter: ${starters[data.starter]}` : '';
- const main = (data.attending && data.main !== -1) ? `\nMain: ${mains[data.main]}` : '';
- const dietary = (data.attending && data.dietary) ? `\nDietary requirements: ${data.dietary}` : '';
+ if (new Date() > rsvpEndDate) {
+ res.json({
+ success: false,
+ err: 'RSVP end date has elapsed',
+ });
+ } else {
+ const update = {};
+ update[req.body.prop] = req.body.value;
+ Person.update(update, {
+ where: {
+ key: req.body.key,
+ },
+ }).then(() => {
+ Person.findOne({
+ where: { key: req.body.key },
+ }).then(data => {
+ if (data.completed) {
+ const attending = `\nAttending: ${data.attending ? 'Yes' : 'No'}`;
+ const starter = (data.attending && data.starter !== -1) ? `\nStarter: ${starters[data.starter]}` : '';
+ const main = (data.attending && data.main !== -1) ? `\nMain: ${mains[data.main]}` : '';
+ const dietary = (data.attending && data.dietary) ? `\nDietary requirements: ${data.dietary}` : '';
- sendSlackMsgWithDebounce(`${data.firstname} ${data.lastname} has saved their RSVP:${attending}${starter}${main}${dietary}`, req.body.key);
- }
- res.json({
- success: true,
- prop: req.body.prop,
+ sendSlackMsgWithDebounce(`${data.firstname} ${data.lastname} has saved their RSVP:${attending}${starter}${main}${dietary}`, req.body.key);
+ }
+ res.json({
+ success: true,
+ prop: req.body.prop,
+ });
+ }).catch(err => {
+ Rollbar.handleError(err);
+ res.json({
+ success: false,
+ err,
+ });
});
}).catch(err => {
Rollbar.handleError(err);
@@ -172,13 +185,7 @@ app.post('/rsvp/save', (req, res) => {
err,
});
});
- }).catch(err => {
- Rollbar.handleError(err);
- res.json({
- success: false,
- err,
- });
- });
+ }
} catch (err) {
Rollbar.handleError(err);
res.json({