Learn-to-send-email-via-google-script-html-no-server: React component

Created on 29 Jul 2019  路  7Comments  路  Source: dwyl/learn-to-send-email-via-google-script-html-no-server

I'm kinda new to github so I don't know if this is the correct way to suggest this.

I've written a working React Component (without any styles, as the dev chose pure css and I'll style with styled components).

It works as intended, with controlled forms, conditional Thanks component and all that React can offer.

import React, { Component } from 'react'

const config = {
  script:
    'https://script.google.com/macros/s/AKfycbwMxYDrufp73bKdU8gMvxFDdHRuzcR4IKQUB33B7GqwyfyZS04/exec',
  sheet: 'responses',
  // email: '',
}

const Thanks = () => (
  <div className="thankyou_message">
    <h2>Thanks for contacting us! We will get back to you soon!</h2>
  </div>
)

class Form extends Component {
  constructor(props) {
    super(props)
    this.state = {
      form: {
        name: '',
        message: '',
        email: '',
        honeypot: '',
      },
      sent: false,
      clicked: false,
    }

    this.handleChange = this.handleChange.bind(this)
    this.handleClick = this.handleClick.bind(this)
  }

  handleClick = () => {
    const { form } = this.state

    // loading
    this.setState({ clicked: true })

    // sent
    const setSent = () => {
      this.setState({ sent: true })
    }

    // checking if bot
    const { honeypot } = form
    if (honeypot) {
      return false
    }

    // sending through xhr as axios won't work (CORS)
    const xhr = new XMLHttpRequest()
    xhr.open('POST', config.script)
    // xhr.withCredentials = true
    xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded')
    xhr.onreadystatechange = function xhrGo() {
      setSent()
    }
    const encoded = Object.keys(form)
      .map(k => {
        return `${encodeURIComponent(k)}=${encodeURIComponent(form[k])}`
      })
      .join('&')

    // finally sending
    xhr.send(encoded)
    return true
  }

  handleChange = ({ target }) => {
    const { id, value } = target
    const { state } = this
    state.form[id] = value
    this.setState(state)
  }

  render() {
    const {
      form: { name, message, email, honeypot },
      sent,
      clicked,
    } = this.state

    return (
      <>
        {sent ? (
          <Thanks />
        ) : (
          <>
            <form
            // method="POST"
            // action={config.script} // change this url
            >
              <div>
                <fieldset>
                  <label htmlFor="name">
                    Name:
                    <input
                      onChange={this.handleChange}
                      id="name"
                      key="name"
                      name="name"
                      placeholder="What your Mom calls you"
                      value={name}
                    />
                  </label>
                </fieldset>
                <fieldset>
                  <label htmlFor="message">
                    Message:
                    <textarea
                      onChange={this.handleChange}
                      id="message"
                      key="message"
                      name="message"
                      rows={10}
                      placeholder="Tell us what's on your mind..."
                      value={message}
                    />
                  </label>
                </fieldset>
                <fieldset>
                  <label htmlFor="email">
                    Your Email Address:
                    <input
                      onChange={this.handleChange}
                      id="email"
                      key="email"
                      name="email"
                      type="email"
                      required
                      placeholder="[email protected]"
                      value={email}
                    />
                  </label>
                </fieldset>
                <fieldset className="honeypot-field" style={{ display: 'none' }}>
                  <label htmlFor="honeypot">
                    {/* To help avoid spam, utilize a Honeypot technique with a hidden text field; must
                    be empty to submit the form! Otherwise, we assume the user is a spam bot. */}
                    <input
                      onChange={this.handleChange}
                      id="honeypot"
                      key="honeypot"
                      type="text"
                      name="honeypot"
                      value={honeypot}
                    />
                  </label>
                </fieldset>
                {clicked ? (
                  <button type="button" disabled>
                    Loading
                  </button>
                ) : (
                  <button type="button" onClick={() => this.handleClick()}>
                    Send
                  </button>
                )}
              </div>
            </form>
          </>
        )}
      </>
    )
  }
}

export default Form

Most helpful comment

Oh, nice. Feel free to share it, it's kinda a way of 'giving back to the community'

All 7 comments

Thanks for sharing this!

Was there a question or suggestion with this particular issue? Or did it work for you?

This is actually a suggestion. I didn't know where exactly I could put this code and maybe make it available for everyone so I opened this issue. Sorry, kinda new to this "contributing" stuff.

Awesome, this is a great place to share that actually - thanks again for doing that! Just wanted to make sure I didn't miss anything :)

Oh, nice. Feel free to share it, it's kinda a way of 'giving back to the community'

Thanks @angelod1as ! This is a great way to share it, if anyone wants to see this in the main readme, we could add links or references to the FAQ section perhaps. I've seen similar requests before, so definitely something we'll consider if people keep asking for it, too. Thanks again for sharing!

I just updated this form using hooks and React Hook Form. It's below, for comparison and later usage,

import { useCallback, useState } from 'react'
import { useForm } from 'react-hook-form'

const config = {
  script:
    'https://script.google.com/macros/s/AKfycbwMxYDrufp73bKdU8gMvxFDdHRuzcR4IKQUB33B7GqwyfyZS04/exec',
  sheet: 'responses',
  // email: '',
}

export default function Contact() {
  const { register, handleSubmit } = useForm()

  const [sent, setSent] = useState(false)

  const onSubmit = useCallback((data) => {
    const { honeypot } = data

    // checking if bot
    if (honeypot) {
      return false
    }

    // use xhr as axios won't work (CORS)
    const xhr = new XMLHttpRequest()
    xhr.open('POST', config.script)
    // xhr.withCredentials = true
    xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded')
    xhr.onreadystatechange = function xhrGo() {
      setSent(true)
    }

    // preparing data
    const encoded = Object.keys(data)
      .map(k => {
        return `${encodeURIComponent(k)}=${encodeURIComponent(data[k])}`
      })
      .join('&')

    // finally sending
    xhr.send(encoded)
    return true
  }, [])

  return (
    <>
      {sent ? (
        <div className="thankyou_message">
          <h2>Thanks for contacting us! We will get back to you soon!</h2>
        </div>
      ) : (
        <form onSubmit={handleSubmit(onSubmit)}>
          <div>
            <label htmlFor="name">
              Name:
              <input
                ref={register}
                id="name"
                key="name"
                name="name"
                placeholder="What your Mom calls you"
              />
            </label>

            <label htmlFor="message">
              Message:
              <textarea
                ref={register}
                id="message"
                key="message"
                name="message"
                rows={10}
                placeholder="Tell us what's on your mind..."
              />
            </label>

            <label htmlFor="email">
              Your Email Address:
              <input
                ref={register}
                id="email"
                key="email"
                name="email"
                type="email"
                required
                placeholder="[email protected]"
              />
            </label>

            <label htmlFor="honeypot" style={{ display: 'none' }}>
              {/* To help avoid spam, utilize a Honeypot technique with a hidden text field; must
                    be empty to submit the form! Otherwise, we assume the user is a spam bot. */}
              <input
                ref={register}
                id="honeypot"
                key="honeypot"
                type="text"
                name="honeypot"
              />
            </label>

            <input type="submit" />
          </div>
        </form>
      )}
    </>
  )
}
Was this page helpful?
0 / 5 - 0 ratings

Related issues

eleosa picture eleosa  路  4Comments

shaily99 picture shaily99  路  4Comments

joseroma picture joseroma  路  3Comments

Brothman picture Brothman  路  3Comments

sidbatra picture sidbatra  路  4Comments