streetmix/streetmix

View on GitHub
assets/scripts/dialogs/SignInDialog.jsx

Summary

Maintainability
B
5 hrs
Test Coverage
import React from 'react'
import { FormattedMessage } from 'react-intl'
import {
  goEmailSignIn,
  goTwitterSignIn,
  goFacebookSignIn,
  goGoogleSignIn
} from '../app/routing'
import Button from '../ui/Button'
import Icon from '../ui/Icon'
import LoadingSpinner from '../ui/LoadingSpinner'
import Dialog from './Dialog'
import './SignInDialog.scss'

export default class SignInDialog extends React.Component {
  constructor (props) {
    super(props)

    this.state = {
      email: '',
      emailSent: false,
      sendingEmail: false,
      error: false,
      signingIn: false
    }

    this.emailInputEl = React.createRef()
  }

  componentDidMount = () => {
    this.emailInputEl.current.focus()
  }

  handleChange = (event) => {
    const target = event.target
    const name = target.name
    const value = target.value

    this.setState({
      [name]: value
    })
  }

  handleFacebookSignIn = (event) => {
    event.preventDefault()

    this.setState({
      signingIn: true
    })

    goFacebookSignIn()
  }

  handleGoogleSignIn = (event) => {
    event.preventDefault()

    this.setState({
      signingIn: true
    })

    goGoogleSignIn()
  }

  handleTwitterSignIn = (event) => {
    event.preventDefault()

    this.setState({
      signingIn: true
    })

    goTwitterSignIn()
  }

  handleGoEmailSignIn = (error, res) => {
    if (error) {
      console.error(error)
      return
    }

    this.setState({
      sendingEmail: false,
      emailSent: true,
      // Reset error state
      error: false
    })
  }

  handleEmailResend = (event) => {
    event.preventDefault()

    this.setState({
      emailSent: false
    })
  }

  handleSubmit = (event) => {
    event.preventDefault()

    // Note: we don't validate the input here;
    // we let HTML5 <input type="email" required /> do validation

    goEmailSignIn(this.state.email, this.handleGoEmailSignIn)

    this.setState({
      sendingEmail: true
    })
  }

  renderErrorMessage = () => {
    return (
      <p className="sign-in-error-message">
        <FormattedMessage
          id="dialogs.sign-in.email-invalid"
          defaultMessage="Oops! That didn’t look like a valid email address. Please try again."
        />
      </p>
    )
  }

  renderSignInWaiting = () => {
    return (
      <Dialog>
        {() => (
          <div className="sign-in-dialog">
            <header>
              <h1 className="sign-in-loading-message">
                <FormattedMessage
                  id="dialogs.sign-in.loading-message"
                  defaultMessage="Signing you in…"
                />
              </h1>
            </header>
            <div
              className="dialog-content sign-in-loading"
              aria-live="polite"
              aria-busy="true"
            >
              <LoadingSpinner />
            </div>
          </div>
        )}
      </Dialog>
    )
  }

  renderEmailSent = () => {
    return (
      <Dialog>
        {() => (
          <div className="sign-in-dialog">
            <header>
              <h1 className="sign-in-loading-message">
                <FormattedMessage
                  id="dialogs.sign-in.loading-message"
                  defaultMessage="Signing you in…"
                />
              </h1>
            </header>
            <div className="dialog-content sign-in-email-sent">
              <p>
                <FormattedMessage
                  id="dialogs.sign-in.sent-message-with-email"
                  defaultMessage="We’ve sent an email to {email}. Please follow the instructions there to continue signing in!"
                  values={{
                    email: (
                      <span className="sign-in-email">{this.state.email}</span>
                    )
                  }}
                />
              </p>
              <p className="sign-in-resend">
                <FormattedMessage
                  id="dialogs.sign-in.email-unreceived"
                  defaultMessage="Didn’t receive it?"
                />
                <br />
                <a onClick={this.handleEmailResend}>
                  <FormattedMessage
                    id="dialogs.sign-in.resend-email"
                    defaultMessage="Resend email"
                  />
                </a>
              </p>
            </div>
          </div>
        )}
      </Dialog>
    )
  }

  render () {
    const { sendingEmail, emailSent, signingIn } = this.state

    if (sendingEmail || signingIn) {
      return this.renderSignInWaiting()
    } else if (emailSent) {
      return this.renderEmailSent()
    }

    return (
      <Dialog>
        {(closeDialog) => (
          <div className="sign-in-dialog">
            <header>
              <h1>
                <FormattedMessage
                  id="dialogs.sign-in.heading"
                  defaultMessage="Sign in / Sign up"
                />
              </h1>
            </header>
            <div className="dialog-content">
              <p>
                <FormattedMessage
                  id="dialogs.sign-in.description"
                  defaultMessage="Save your first design or sign in to access your past designs."
                />
              </p>

              <form onSubmit={this.handleSubmit}>
                <label
                  htmlFor="sign-in-email-input"
                  className="sign-in-email-label"
                >
                  <FormattedMessage
                    id="dialogs.sign-in.email-label"
                    defaultMessage="Email"
                  />
                </label>

                <input
                  type="email"
                  id="sign-in-email-input"
                  ref={this.emailInputEl}
                  value={this.state.email}
                  className={
                    'sign-in-input ' +
                    (this.state.error ? 'sign-in-input-error' : '')
                  }
                  name="email"
                  onChange={this.handleChange}
                  placeholder="test@test.com"
                  required={true}
                />

                {this.state.error && this.renderErrorMessage()}

                <p className="sign-in-email-password-note">
                  <small>
                    <FormattedMessage
                      id="dialogs.sign-in.email-description"
                      defaultMessage="We’ll send you a link to sign in. No password is required."
                    />
                  </small>
                </p>

                <Button
                  type="submit"
                  primary={true}
                  className="sign-in-button sign-in-email-button"
                >
                  <FormattedMessage
                    id="dialogs.sign-in.button.email"
                    defaultMessage="Continue with email"
                  />
                </Button>
              </form>

              <div className="sign-in-social-heading">
                <hr />
                <span>
                  <FormattedMessage
                    id="dialogs.sign-in.social-heading"
                    defaultMessage="or"
                  />
                </span>
              </div>

              <Button
                tertiary={true}
                className="sign-in-button sign-in-social-button sign-in-twitter-button"
                onClick={this.handleTwitterSignIn}
              >
                <Icon icon="twitter" />
                <FormattedMessage
                  id="dialogs.sign-in.button.twitter"
                  defaultMessage="Continue with Twitter"
                />
              </Button>

              <Button
                tertiary={true}
                className="sign-in-button sign-in-social-button sign-in-google-button"
                onClick={this.handleGoogleSignIn}
              >
                <Icon icon="google" />
                <FormattedMessage
                  id="dialogs.sign-in.button.google"
                  defaultMessage="Continue with Google"
                />
              </Button>

              <Button
                tertiary={true}
                className="sign-in-button sign-in-social-button sign-in-facebook-button"
                onClick={this.handleFacebookSignIn}
              >
                <Icon icon="facebook" />
                <FormattedMessage
                  id="dialogs.sign-in.button.facebook"
                  defaultMessage="Continue with Facebook"
                />
              </Button>
            </div>

            <footer>
              <p className="sign-in-disclaimer">
                <FormattedMessage
                  id="dialogs.sign-in.tos"
                  defaultMessage="By clicking one of these buttons, I agree to the {tosLink} and {privacyLink}."
                  values={{
                    tosLink: (
                      <a href="/terms-of-service" target="_blank">
                        <FormattedMessage
                          id="dialogs.sign-in.tos-link-label"
                          defaultMessage="terms of service"
                        />
                      </a>
                    ),
                    privacyLink: (
                      <a href="/privacy-policy" target="_blank">
                        <FormattedMessage
                          id="dialogs.sign-in.privacy-link-label"
                          defaultMessage="privacy policy"
                        />
                      </a>
                    )
                  }}
                />
              </p>
            </footer>
          </div>
        )}
      </Dialog>
    )
  }
}