Skip to content
This repository was archived by the owner on Jan 25, 2020. It is now read-only.

Commit

Permalink
Merge pull request #58 from BoilerMake/rsvps
Browse files Browse the repository at this point in the history
Rsvps!
  • Loading branch information
nickysemenza authored Sep 13, 2017
2 parents ddcd600 + d713fbf commit 55b49db
Show file tree
Hide file tree
Showing 14 changed files with 344 additions and 17 deletions.
7 changes: 5 additions & 2 deletions src/actions/application.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ function receiveApplication (json, onlyUpdateNonFormFields = false) {
};
}

export function saveApplication(suppressToast = false) {
export function saveApplication(suppressToast = false, isRSVPAction = false) {
return (dispatch, getState) => {
let data = getState().application.applicationForm;
return apiFetch('users/me/application',
Expand All @@ -43,7 +43,10 @@ export function saveApplication(suppressToast = false) {
.then((json) => {
if(json.success) {
if(!suppressToast) {
toastr.success('Success!', json.data.message);
if(isRSVPAction)
toastr.success('Success!', 'Your RSVP has been saved.');
else
toastr.success('Success!', json.data.message);
}
//this api endpoint returns the updated application
dispatch(receiveApplication(json,true));
Expand Down
16 changes: 15 additions & 1 deletion src/assets/_application.scss
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
padding: 30px 0;
}
.application {
background: $white;
background: none;
.text-input {
width: 100%;
padding: 15px 20px;
Expand Down Expand Up @@ -50,6 +50,13 @@
border: 2px solid $darkBlue;
}
}
.rsvp-button {
@extend .application-button
}
.rsvp-button-selected {
@extend .rsvp-button;
border: 2px solid $green;
}

.submit {
outline: none;
Expand Down Expand Up @@ -324,3 +331,10 @@ input:checked + .slider:before {
}
}
}
.appInfoBanner {
background: $darkBlue-o;
border-radius: 15px;
color: white;
padding: 20px;
margin-bottom: 20px;
}
2 changes: 1 addition & 1 deletion src/assets/_footer.scss
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
flex-shrink: 0;
color: $pink;
text-align: center;
background: $lightGray;
background: $white;
box-shadow: 0px 500px 0px 500px #EFEFEF;

p {
Expand Down
21 changes: 21 additions & 0 deletions src/assets/index.scss
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,27 @@ body {
font-family: $font-body;
color: $darkBlue;
}
.section {
padding-bottom: 20px;
p {
font-size: 16px;
}
}
.fancy {
background: rgba(25,42,80,1);
background: -moz-linear-gradient(-45deg, rgba(25,42,80,1) 0%, rgba(55,40,105,1) 34%, rgba(238,42,124,1) 69%, rgba(246,149,129,1) 100%);
background: -webkit-gradient(left top, right bottom, color-stop(0%, rgba(25,42,80,1)), color-stop(34%, rgba(55,40,105,1)), color-stop(69%, rgba(238,42,124,1)), color-stop(100%, rgba(246,149,129,1)));
background: -webkit-linear-gradient(-45deg, rgba(25,42,80,1) 0%, rgba(55,40,105,1) 34%, rgba(238,42,124,1) 69%, rgba(246,149,129,1) 100%);
background: -o-linear-gradient(-45deg, rgba(25,42,80,1) 0%, rgba(55,40,105,1) 34%, rgba(238,42,124,1) 69%, rgba(246,149,129,1) 100%);
background: -ms-linear-gradient(-45deg, rgba(25,42,80,1) 0%, rgba(55,40,105,1) 34%, rgba(238,42,124,1) 69%, rgba(246,149,129,1) 100%);
background: linear-gradient(135deg, rgba(25,42,80,1) 0%, rgba(55,40,105,1) 34%, rgba(238,42,124,1) 69%, rgba(246,149,129,1) 100%);
filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#192a50', endColorstr='#f69581', GradientType=1 );
padding: 50px 5%;
color: white;
a {
color:$lightBlue;
}
}
.none {
display: none;
}
Expand Down
2 changes: 1 addition & 1 deletion src/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@ export const DEBUG_MODE = process.env.BM_REACT_APP_DEBUG_MODE || false;
export const SENTRY_URL = process.env.BM_REACT_APP_SENTRY_URL || '';
export const API_BASE_URL = process.env.BM_REACT_APP_API_BASE_URL;
export const GITHUB_CLIENT_ID = process.env.BM_REACT_APP_GITHUB_CLIENT_ID || '';
export const ALLOW_SIGNUPS = process.env.BM_REACT_APP_ALLOW_SIGNUPS || false;
export const ALLOW_SIGNUPS = process.env.BM_REACT_APP_ALLOW_SIGNUPS || false;
83 changes: 83 additions & 0 deletions src/pages/Application/ApplicationConsts.js
Original file line number Diff line number Diff line change
Expand Up @@ -69,4 +69,87 @@ export const isFirstHackathonOptions = [{
}, {
label: 'No',
value: false
}];
export const skillOptions = [{
label: 'android',
value: 'android'
},{
label: 'C',
value: 'C'
},{
label: 'css',
value: 'css'
},{
label: 'design',
value: 'design'
},{
label: 'go',
value: 'go'
},{
label: 'hardware',
value: 'hardware'
},{
label: 'html',
value: 'html'
},{
label: 'ios',
value: 'ios'
},{
label: 'java',
value: 'java'
},{
label: 'js',
value: 'js'
},{
label: 'mobile',
value: 'mobile'
},{
label: 'nodejs',
value: 'nodejs'
},{
label: 'obj-c',
value: 'obj-c'
},{
label: 'php',
value: 'php'
},{
label: 'puzzle',
value: 'puzzle'
},{
label: 'python',
value: 'python'
},{
label: 'ruby',
value: 'ruby'
},{
label: 'swift',
value: 'swift'
},{
label: 'webdev',
value: 'webdev'
}];
export const dietOptions = [
{
label: 'Vegan',
value: 'vegan'
}, {
label: 'Vegetarian',
value: 'vegetarian'
}, {
label: 'Gluten Free',
value: 'glutenfree'
}];
export const shirtOptions = [
{
label: 'Extra Large',
value: 'xl'
}, {
label: 'Large',
value: 'l'
}, {
label: 'Medium',
value: 'm'
}, {
label: 'Small',
value: 's'
}];
136 changes: 136 additions & 0 deletions src/pages/Application/ApplicationDecision.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
import React, { Component } from 'react';
import ApplicationTextField from "./ApplicationTextField";
import ApplicationSelectField from "./ApplicationSelectField";
import ApplicationRSVPToggle from "./ApplicationRSVPToggle";
import {dietOptions, shirtOptions, skillOptions} from "./ApplicationConsts";

class ApplicationForm extends Component {
render () {
// let decisionMap = {
// 4: 'EXPIRED',
// 3: 'ACCEPT',
// 2: 'WAITLIST',
// 1: 'REJECT',
// 0: 'UNDECIDED'
// };
const { applicationForm } = this.props.application;
const isLoading = this.props.application.loading;

let transitMessage;
switch(applicationForm.school.transit_method) {
case "bus":
transitMessage = <div className="section">
<p>We'll be sending a bus to {applicationForm.school.name}!</p>
<p>Join the Facebook event <a href={`https://www.facebook.com/events/${applicationForm.school.facebook_event_id}`}>here</a> to stay up to date!</p>
</div>;
break;
case "car":
transitMessage = <div className="section">
<p>Sadly we won't be able to send a bus to <b>{applicationForm.school.name}.</b></p>
<p>However, if you're willing to get here by your own means, we'd love to have you!.</p>
<p><i>Please note that we will not be providing any form of travel reimbursements.</i></p>
</div>;
break;
default:
case "walk":
transitMessage = <p>Well, you have it easy! BoilerMake will be happening in the Black & Gold Gyms of the CoRec on campus.</p>;
break;
}

let rsvpYes =
<div className="section">
<h2>Neat! Just a few more steps.</h2>
<p>Providing us with a phone number (optional) will allow us to send you important event updates!
We will be providing everyone with lanyard nametags, you can pick up to 3 skills to be displayed on them.
Lastly, if you have any special dietary requests, please <a href="mailto:[email protected]">email us!</a></p>
<div className="row">
<div className="col-6">
<label>Phone #</label>
<ApplicationTextField field="phone"/>
</div>
<div className="col-6">
<label>Pick up to 3 Skills</label>
<ApplicationSelectField field="skills" multi searchable options={skillOptions}/>
</div>
</div>
<div className="row">
<div className="col-6">
<label>T-shirt size</label>
<ApplicationSelectField field="tshirt" options={shirtOptions}/>
</div>
<div className="col-6">
<label>Dietary Restrictions</label>
<ApplicationSelectField field="diet" multi searchable options={dietOptions}/>
</div>
</div>
<br/>
<button disabled={isLoading} onClick={()=>{this.props.saveApplication(false, true)}} className="submit">Save RSVP</button>
</div>;

let rsvpNo = <p className="section">Aw <span role="img" aria-label="Sad">😢</span> Please come back and apply next year though! </p>;

let decisionForm;
switch(applicationForm.decision) {
case 3://ACCEPT
decisionForm = (<div className="section">
<h1>You're in!</h1>
<p>Congratulations, we’re excited to invite you to this year’s retro twist on BoilerMake. <span role="img" aria-label="Heart">💜</span>
<br/>
All we need from you now is to RSVP so we know whether to expect you there or not!</p>
<h2>Getting to BoilerMake</h2>
{transitMessage}
<p>Can you come? You must RSVP {applicationForm.rsvp_deadline ? <span>by {applicationForm.rsvp_deadline}</span> : <span>soon</span>} or else we will offer your spot to someone else.</p>
<ApplicationRSVPToggle/>
{
applicationForm.rsvp !== null
? applicationForm.rsvp === 1
? rsvpYes
: rsvpNo
: null//don't show rest of form if they haven't clicked yes or no yet
}
</div>);
break;
case 2://WAITLIST
decisionForm = (<div className="section">
<h1>Thanks for applying.</h1>
<p>Unfortunately, we cannot accept you just yet. But don’t fret! We’ll let you know if space opens up so that you can hopefully attend BoilerMake this year.</p>
</div>);
break;
case 4://EXPIRED
decisionForm = (<div className="section">
<h1>Sorry about that.</h1>
<p>Unfortunately, your acceptance offer has expired. We hope to see you at next year’s BoilerMake!</p>
</div>);
break;
default:
decisionForm = <div className="section"><h1>There was an error!</h1><p>Sorry for the inconvenience. Please email us at <a href="mailto:[email protected]">[email protected]</a></p></div>
}
return (<div>
{decisionForm}
</div>
);
}
}

//now the redux integration layer
import {
saveApplication,
toggleApplicationFieldValue
} from '../../actions/application';
import { bindActionCreators } from 'redux';
import { connect } from 'react-redux'
function mapStateToProps (state) {
return {
user: state.user,
application: state.application,
};
}

const mapDispatchToProps = (dispatch) => {
return bindActionCreators({
saveApplication,
toggleApplicationFieldValue
}, dispatch)
};

export default connect(mapStateToProps, mapDispatchToProps)(ApplicationForm);
5 changes: 4 additions & 1 deletion src/pages/Application/ApplicationForm.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@ class ApplicationForm extends Component {
onDrop={this.props.onResumeDrop.bind(this)}
style={{border: 'none', height: '100%'}}
>
{applicationForm.completed ? <div className="appInfoBanner">
Hey there - just a heads up: Your application is complete and is under review. Expect to hear back by Sept 22 at the latest.
</div> : null}
<div className="row">
<div className="col-6">
<label>First Name</label>
Expand Down Expand Up @@ -95,7 +98,7 @@ class ApplicationForm extends Component {
<label>Upload Resume (PDF only)</label>
<button type="button" onClick={() => { dropzoneRef.open() }} className="application-button">Drop or click to upload</button>
<ResumeUploadProgressIndicator/>
{ applicationForm.resume_uploaded ? <div>You've uploaded <a href={applicationForm.resume_get_url} target="_blank" rel="noopener noreferrer" >{applicationForm.resume_filename}</a></div> : null }
{ applicationForm.resume_uploaded ? <p>You've uploaded <a href={applicationForm.resume_get_url} target="_blank" rel="noopener noreferrer" >{applicationForm.resume_filename}</a></p> : null }
</div>
<div className="col-6">
<label>Is this your first hackathon?</label>
Expand Down
34 changes: 34 additions & 0 deletions src/pages/Application/ApplicationRSVPToggle.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import React from 'react';
import { changeApplicationFieldValue, saveApplication } from '../../actions/application';
import { bindActionCreators } from 'redux';
import { connect } from 'react-redux';

const ApplicationRSVPToggle = ({changeApplicationFieldValue, saveApplication, field, applicationForm, disabled, isLoading, styles}) =>
<div className="section">
<button
disabled={applicationForm.rsvp === 1 || isLoading}
className={applicationForm.rsvp !== null && applicationForm.rsvp === 1 ? 'rsvp-button-selected' : 'rsvp-button'}
onClick={()=>{changeApplicationFieldValue('rsvp', 1); saveApplication(true)}}>
I'll be there!
</button>
<button
disabled={applicationForm.rsvp === 0 || isLoading}
className={applicationForm.rsvp !== null && applicationForm.rsvp === 0 ? 'rsvp-button-selected' : 'rsvp-button'}
onClick={()=>{changeApplicationFieldValue('rsvp', 0); saveApplication(true)}}>
I can't make it
</button>
<br />
</div>;

function mapStateToProps (state) {
return {
applicationForm: state.application.applicationForm,
isLoading: state.application.isLoading
};
}

const mapDispatchToProps = (dispatch) => {
return bindActionCreators({changeApplicationFieldValue, saveApplication}, dispatch)
};

export default connect(mapStateToProps, mapDispatchToProps)(ApplicationRSVPToggle);
Loading

0 comments on commit 55b49db

Please sign in to comment.