diff --git a/src/components/Html.js b/src/components/Html.js index 7612569..f0f9c3d 100644 --- a/src/components/Html.js +++ b/src/components/Html.js @@ -21,7 +21,7 @@ class Html extends React.Component { - + {style && }
diff --git a/src/components/RsvpButton/RsvpButton.css b/src/components/RsvpButton/RsvpButton.css index 16d55de..646f3a7 100644 --- a/src/components/RsvpButton/RsvpButton.css +++ b/src/components/RsvpButton/RsvpButton.css @@ -27,7 +27,7 @@ } .rsvpGroup { - width: 60%; + width: 65%; } .rsvpButtonGroup { @@ -64,6 +64,27 @@ box-shadow: 0 0 4px #fff; } +.inputInvalid { + animation: shake 0.5s linear; +} + +.invalidMsg { + display: none; + padding: 10px 16px; + border: 4px solid var(--colour-red); + border-radius: 14px; + background: transparent; + color: #fff; + text-decoration: none; + font-size: 18px; + line-height: 1.3333333; + transition: opacity ease-in-out 0.25s, box-shadow ease-in-out 0.25s; +} + +.invalidMsgVisible { + display: inline-block; +} + .button { display: block; box-sizing: border-box; @@ -89,3 +110,28 @@ opacity: 1; box-shadow: 0 0 4px #fff; } + +@keyframes shake { + 8%, + 41% { + transform: translateX(-10px); + } + + 25%, + 58% { + transform: translateX(10px); + } + + 75% { + transform: translateX(-5px); + } + + 92% { + transform: translateX(5px); + } + + 0%, + 100% { + transform: translateX(0); + } +} diff --git a/src/components/RsvpButton/RsvpButton.js b/src/components/RsvpButton/RsvpButton.js index 9679714..ecb47c7 100644 --- a/src/components/RsvpButton/RsvpButton.js +++ b/src/components/RsvpButton/RsvpButton.js @@ -1,8 +1,12 @@ -import React from 'react'; +import React, { PropTypes } from 'react'; import withStyles from 'isomorphic-style-loader/lib/withStyles'; import s from './RsvpButton.css'; +import fetch from '../../core/fetch'; class RsvpButton extends React.Component { + static propTypes = { + focusCallback: PropTypes.func, + }; constructor(props) { super(props); @@ -13,7 +17,45 @@ class RsvpButton extends React.Component { this.setState({ showRsvpForm: true }); setTimeout(() => { this.rsvpInput.focus(); - }, 250); + }, 500); + } + + handleRsvpFocus = () => { + if (this.props.focusCallback) { + this.props.focusCallback(true); + } + this.setState({ inputError: false }); + } + + handleRsvpBlur = () => { + if (this.props.focusCallback) { + this.props.focusCallback(false); + } + } + + handleFormSubmit = (event) => { + event.preventDefault(); + fetch(`rsvp/${this.rsvpInput.value}`) + .then(data => { + if (data.status === 200) { + location.href = data.url; + } else { + this.setState({ + inputInvalid: true, + inputInvalidMsg: 'Sorry, that RSVP code is invalid.', + }); + setTimeout(() => { + this.setState({ + inputInvalid: false, + }); + }, 500); + } + }).catch(() => { + this.setState({ + inputInvalid: true, + inputInvalidMsg: 'Sorry, there was a problem validating your RSVP code, please try again later.', + }); + }); } render() { @@ -35,14 +77,19 @@ class RsvpButton extends React.Component { this.state.showRsvpForm ? s.rsvpFormVisible : null, ].join(' ')} > - +