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.
Contact Form ideas
// 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) {
// 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} />
</Route>
);
}
import actionTypes from './actionTypes';
const {
SUBMIT_CONTACT_ATTEMPT,
SUBMIT_CONTACT_FAILED,
SUBMIT_CONTACT_SUCCEEDED,
} = actionTypes;
function submitContactAttempt(values) {
return {
type: SUBMIT_CONTACT_ATTEMPT,
values,
};
}
function submitContactFailed(error) {
return {
type: SUBMIT_CONTACT_FAILED,
error,
};
}
function submitContactSucceeded() {
return {
type: SUBMIT_CONTACT_SUCCEEDED,
}
}
export default {
submitContactAttempt,
submitContactFailed,
submitContactSucceeded,
};
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,
};
// 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,
};
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 {
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>
<h1>Contact Us!</h1>
<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 = {
statusMessage: React.PropTypes.string,
submitContactAttempt: React.PropTypes.func.isRequired,
}
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);
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);
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;
}
}
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,
];
// 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.';
}
return errors;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment