Skip to content

Instantly share code, notes, and snippets.

@mc-funk
Last active September 27, 2017 14:27
Show Gist options
  • Save mc-funk/45d796a72e9066a39c7b72619a685ccb to your computer and use it in GitHub Desktop.
Save mc-funk/45d796a72e9066a39c7b72619a685ccb to your computer and use it in GitHub Desktop.

Revisions

  1. mc-funk revised this gist Sep 27, 2017. 1 changed file with 1 addition and 0 deletions.
    1 change: 1 addition & 0 deletions configure.js
    Original file line number Diff line number Diff line change
    @@ -12,6 +12,7 @@ import MenuTabs from './MenuTabs';
    import contact from './contact';

    export default function configureRoutes(store) {
    // We're petending that MenuTabs, which whould really be called App or something, contains the nav elements and will render its children.
    return (
    <Route path="" component={MenuTabs} >
    <Route path="contact" component={contact.ContactContainer} />
  2. mc-funk revised this gist Sep 27, 2017. No changes.
  3. mc-funk revised this gist Sep 27, 2017. 1 changed file with 2 additions and 0 deletions.
    2 changes: 2 additions & 0 deletions contactValidate.js
    Original file line number Diff line number Diff line change
    @@ -34,4 +34,6 @@ export default function contactFormValidator(values) {
    } else if (isInvalidPhoneNumber(phone)) {
    errors.phone = 'Must be a valid phone number.';
    }

    return errors;
    }
  4. mc-funk revised this gist Sep 27, 2017. 1 changed file with 36 additions and 5 deletions.
    41 changes: 36 additions & 5 deletions contactValidate.js
    Original file line number Diff line number Diff line change
    @@ -1,6 +1,37 @@
    /* This should be a function that takes in the values
    * object provided by Redux form and returns an error object
    * where any error text provided would be a property on the object
    * with a key of the form field name.
    */

    // pretend validators use regex.test(string)
    import isInvalidEmail from '../pretendRegexValidators/isInvalidEmail';
    import isInvalidName from '../pretendRegexValidators/isInvalidName';
    import isInvalidPhoneNumber from '../pretendRegexValidators/isInvalidPhoneNumber';

    export default function contactFormValidator(values) {
    const errors = {};
    const {
    firstName,
    lastName,
    email,
    phone,
    } = values;

    // Really I'd prefer to pull all the undefined checks into a function. Or use validate-this :)
    if (firstName === undefined) {
    errors.firstName = `First Name is Required.`;
    } else if (isInvalidName(firstName)) {
    errors.firstName = `First Name cannot contain the characters we said it can't`;
    }
    if (lastName === undefined) {
    errors.lastName = `Last Name is Required.`;
    } else if (isInvalidName(lastName)) {
    errors.lastName = `Last Name cannot contain the characters we said it can't`;
    }
    if (email === undefined) {
    errors.email = `Email is Required.`;
    } else if (isInvalidEmail(email)) {
    errors.email = 'Must be a valid email.';
    }
    if (phone === undefined) {
    errors.phone = `Phone is Required.`;
    } else if (isInvalidPhoneNumber(phone)) {
    errors.phone = 'Must be a valid phone number.';
    }
    }
  5. mc-funk revised this gist Sep 27, 2017. 1 changed file with 68 additions and 1 deletion.
    69 changes: 68 additions & 1 deletion ContactForm.jsx
    Original file line number Diff line number Diff line change
    @@ -1,2 +1,69 @@
    /* I would use redux-form for this */
    import React from 'react';
    import { reduxForm } from 'redux-form';

    import validate from './validate';

    // Caution: Really Old Redux-Form
    function ContactForm({
    handleSubmit,
    disableSubmit,
    fields: {
    firstName,
    lastName,
    email,
    phone,
    comments,
    }
    }) {
    return (
    <form id="contactForm" onSubmit={handleSubmit} >
    <p><strong>First Name</strong><span className="red">*</span></p>
    <input
    {...firstName}
    type="text"
    />
    <p className="red">{firstName.touched && firstName.error}</p>
    <p><strong>Last Name</strong><span className="red">*</span></p>
    <input
    {...lastName}
    type="text"
    />
    <p className="red">{lastName.touched && lastName.error}</p>
    <p><strong>Email Address</strong><span className="red">*</span></p>
    <input
    {...email}
    type="text"
    />
    <p className="red">{email.touched && email.error}</p>
    <p><strong>Phone Number</strong><span className="red">*</span></p>
    <input
    {...phone}
    type="text"
    />
    <p className="red">{phone.touched && phone.error}</p>
    <p><strong>Comments</strong></p>
    <input
    {...comments}
    type="text"
    />
    <button
    disabled={!!disableSubmit}
    onClick={handleSubmit}
    >Submit</button>
    </form>
    )
    }

    /* propTypes */

    export default reduxForm({
    form: 'CONTACT_FORM',
    fields: [
    'firstName',
    'lastName',
    'email',
    'phone',
    'comments',
    ],
    validate,
    })(ContactForm);
  6. mc-funk revised this gist Sep 27, 2017. 6 changed files with 113 additions and 5 deletions.
    22 changes: 19 additions & 3 deletions ContactContainer.jsx
    Original file line number Diff line number Diff line change
    @@ -1,9 +1,11 @@
    import React from 'react';
    import connect from 'react-redux';
    import bindActionCreators from 'redux';

    import Paper from 'material-ui/Paper';

    import ContactForm from './ContactForm';
    import actions from './actions';
    import validateForm from './validate';

    export class ContactContainer extends React.Component {
    @@ -25,10 +27,11 @@ export class ContactContainer extends React.Component {
    // I am so ready to return arrays in React 16
    return (
    <div>
    <h1>Contact Us!</h1>
    <ContactForm />
    {statusMessage &&
    <Paper style={{ backgroundColor: '#f00abc'}}>
    {statusMessage}
    {statusMessage}
    </Paper>
    }
    </div>
    @@ -39,8 +42,21 @@ export class ContactContainer extends React.Component {
    /* declaring PropTypes this way is actualy deprecated, but I still
    need to learn the new ways :)*/
    ContactContainer.propTypes = {
    submitStatus: React.PropTypes.string,
    statusMessage: React.PropTypes.string,
    submitContactAttempt: React.PropTypes.func.isRequired,
    }

    export default connect()(ContactContainer);
    export function mapStateToProps(state) {
    return {
    postingData: state.contact.postingData,
    statusMessage: state.contact.statusMessage,
    }
    }

    export function mapDispatchToProps(dispatch) {
    return bindActionCreators({
    submitContactAttempt: actions.submitContactAttempt,
    })
    }

    export default connect(mapStateToProps, mapDispatchToProps)(ContactContainer);
    3 changes: 2 additions & 1 deletion ContactForm.jsx
    Original file line number Diff line number Diff line change
    @@ -1 +1,2 @@
    /* I would use redux-form for this */
    /* I would use redux-form for this */

    20 changes: 20 additions & 0 deletions configure.js
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,20 @@
    // routes/configure.js

    /* I've been working so long in a react-router app that I'll have to spend more timein the docs
    * to actually set it up. But here's what I'm used to doing. Please note that we have been using a really
    * old version of react-router and I'm fully intending to get up to date on the new one.
    */

    import React from 'react';
    import { Route } from 'react-router';

    import MenuTabs from './MenuTabs';
    import contact from './contact';

    export default function configureRoutes(store) {
    return (
    <Route path="" component={MenuTabs} >
    <Route path="contact" component={contact.ContactContainer} />
    </Route>
    );
    }
    1 change: 1 addition & 0 deletions contactActions.js
    Original file line number Diff line number Diff line change
    @@ -9,6 +9,7 @@ const {
    function submitContactAttempt(values) {
    return {
    type: SUBMIT_CONTACT_ATTEMPT,
    values,
    };
    }

    43 changes: 43 additions & 0 deletions contactApi.js
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,43 @@
    // api/contact.js

    const ourHeaders = {
    // just throwing some things in here, assume there's no auth
    Accept: 'application/json',
    'Content-Type': 'application/json',
    }

    function handleResponse(response) {
    if (response.status === 200) {
    // I'm more used to seeing a 201 in this case
    // I'm going to assume in this case there is no response object
    Promise.resolve();
    }

    if (response.status === 422) {
    /* I'm going to assume that in this case, if there is a 422 there isn't anything that the user can
    * do about it. I hadn't seen 422s before, so I looked it up and it sounds like this would be a case
    * where somehow what we sent to the server was correct but had some sort of syntax error.
    * We're not sending code, so if there's a 422 it seems like the user just needs to try again later,
    * maybe after we have fixed our bug. :)
    */

    const error = new Error(response.statusText);
    Promise.reject(error);
    }
    }

    function postContact(body) {
    const path='https://ourApi.io/contact';
    const jsonBody = JSON.stringify(body);
    const fetchData = {
    method: 'POST',
    body: jsonBody,
    headers: ourHeaders,
    }

    return fetch(path, fetchData).then(handleResponse);
    }

    export default {
    postContact,
    };
    29 changes: 28 additions & 1 deletion contactSagas.js
    Original file line number Diff line number Diff line change
    @@ -1 +1,28 @@
    /* placeholder */
    import { takeLatest } from 'redux-saga';
    import { call, put }from 'redux-saga/effects';

    import { postContact } from '../api/contact';
    import {
    submitContactFailed,
    submitContactSucceeded
    } from './actions';
    import {
    SUBMIT_CONTACT_ATTEMPT,
    } from './actionTypes';

    export function* submitContactSaga({ values }) {
    try {
    yield call(postContact, values);
    yield put(submitContactSucceeded);
    } catch (e) {
    yield submitContactFailed(e);
    }
    }

    export function* watchSubmitContactSaga() {
    yield call(takeLatest, SUBMIT_CONTACT_ATTEMPT, submitContactSaga);
    }

    export default [
    watchSubmitContactSaga,
    ];
  7. mc-funk created this gist Sep 27, 2017.
    46 changes: 46 additions & 0 deletions ContactContainer.jsx
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,46 @@
    import React from 'react';
    import connect from 'react-redux';

    import Paper from 'material-ui/Paper';

    import ContactForm from './ContactForm';
    import validateForm from './validate';

    export class ContactContainer extends React.Component {
    componentWillMount() {
    console.log('hey friends!');
    }

    handleSubmit(values) {
    const { submitContactAttempt } = this.props;

    const errors = validateForm(values);
    if (Object.keys(errors).length) return;

    submitContactAttempt(values);
    }

    render() {
    const { statusMessage } = this.props;
    // I am so ready to return arrays in React 16
    return (
    <div>
    <ContactForm />
    {statusMessage &&
    <Paper style={{ backgroundColor: '#f00abc'}}>
    {statusMessage}
    </Paper>
    }
    </div>
    );
    }
    }

    /* declaring PropTypes this way is actualy deprecated, but I still
    need to learn the new ways :)*/
    ContactContainer.propTypes = {
    submitStatus: React.PropTypes.string,
    submitContactAttempt: React.PropTypes.func.isRequired,
    }

    export default connect()(ContactContainer);
    1 change: 1 addition & 0 deletions ContactForm.jsx
    Original file line number Diff line number Diff line change
    @@ -0,0 +1 @@
    /* I would use redux-form for this */
    9 changes: 9 additions & 0 deletions contactActionTypes.js
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,9 @@
    const SUBMIT_CONTACT_ATTEMPT = 'SUBMIT_CONTACT_ATTEMPT';
    const SUBMIT_CONTACT_FAILED = 'SUBMIT_CONTACT_FAILED';
    const SUBMIT_CONTACT_SUCCEEDED = 'SUBMIT_CONTACT_SUCCEEDED';

    export default {
    SUBMIT_CONTACT_ATTEMPT,
    SUBMIT_CONTACT_FAILED,
    SUBMIT_CONTACT_SUCCEEDED,
    };
    32 changes: 32 additions & 0 deletions contactActions.js
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,32 @@
    import actionTypes from './actionTypes';

    const {
    SUBMIT_CONTACT_ATTEMPT,
    SUBMIT_CONTACT_FAILED,
    SUBMIT_CONTACT_SUCCEEDED,
    } = actionTypes;

    function submitContactAttempt(values) {
    return {
    type: SUBMIT_CONTACT_ATTEMPT,
    };
    }

    function submitContactFailed(error) {
    return {
    type: SUBMIT_CONTACT_FAILED,
    error,
    };
    }

    function submitContactSucceeded() {
    return {
    type: SUBMIT_CONTACT_SUCCEEDED,
    }
    }

    export default {
    submitContactAttempt,
    submitContactFailed,
    submitContactSucceeded,
    };
    36 changes: 36 additions & 0 deletions contactReducer.js
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,36 @@
    import actionTypes from './actionTypes';

    const {
    SUBMIT_CONTACT_ATTEMPT,
    SUBMIT_CONTACT_FAILED,
    SUBMIT_CONTACT_SUCCEEDED,
    } = actionTypes;

    const initialState = {
    postingData: false,
    statusMessage: null,
    }

    export default function contact(state = initialState, action) {
    switch(action.type) {
    case SUBMIT_CONTACT_ATTEMPT: {
    return Object.assign({}, state, {
    postingData: true,
    });
    }
    case SUBMIT_CONTACT_FAILED: {
    return Object.assign({}, state, {
    postingData: false,
    statusMessage: `Sorry, we couldn't process your information at this time. Please try again later.`,
    });
    }
    case SUBMIT_CONTACT_SUCCEEDED: {
    return Object.assign({}, state, {
    postingData: false,
    statusMessage: 'Thank you for your message! We will get back to you in the next 48 hours.',
    });
    }
    default:
    return state;
    }
    }
    1 change: 1 addition & 0 deletions contactSagas.js
    Original file line number Diff line number Diff line change
    @@ -0,0 +1 @@
    /* placeholder */
    6 changes: 6 additions & 0 deletions contactValidate.js
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,6 @@
    /* This should be a function that takes in the values
    * object provided by Redux form and returns an error object
    * where any error text provided would be a property on the object
    * with a key of the form field name.
    */