save form to localStorage

This commit is contained in:
Berkeley Martinez
2015-09-24 20:28:04 -07:00
parent d8a6373b1e
commit 8148c1a19c
6 changed files with 169 additions and 37 deletions

View File

@ -1,5 +1,13 @@
import React, { PropTypes } from 'react'; import React, { PropTypes } from 'react';
import { contain } from 'thundercats-react'; import { contain } from 'thundercats-react';
import debugFactory from 'debug';
import { getDefaults } from '../utils';
import {
inHTMLData,
uriInSingleQuotedAttr
} from 'xss-filters';
import { import {
Button, Button,
Col, Col,
@ -7,6 +15,7 @@ import {
Row, Row,
Well Well
} from 'react-bootstrap'; } from 'react-bootstrap';
import { import {
isAscii, isAscii,
isEmail, isEmail,
@ -14,31 +23,34 @@ import {
isURL isURL
} from 'validator'; } from 'validator';
const defaults = { const debug = debugFactory('freecc:jobs:newForm');
'string': {
value: '', const checkValidity = [
valid: false, 'position',
pristine: true 'locale',
}, 'description',
bool: { 'email',
value: false 'phone',
} 'url',
}; 'logo',
'name',
'highlight'
];
export default contain({ export default contain({
actions: 'jobActions', actions: 'jobActions',
store: 'jobsStore', store: 'jobsStore',
map({ form = {} }) { map({ form = {} }) {
const { const {
position = defaults['string'], position = getDefaults('string'),
locale = defaults['string'], locale = getDefaults('string'),
description = defaults['string'], description = getDefaults('string'),
email = defaults['string'], email = getDefaults('string'),
phone = defaults['string'], phone = getDefaults('string'),
url = defaults['string'], url = getDefaults('string'),
logo = defaults['string'], logo = getDefaults('string'),
name = defaults['string'], name = getDefaults('string'),
highlight = defaults['bool'] highlight = getDefaults('bool')
} = form; } = form;
return { return {
position, position,
@ -51,6 +63,9 @@ export default contain({
name, name,
highlight highlight
}; };
},
subscribeOnWillMount() {
return typeof window !== 'undefined';
} }
}, },
React.createClass({ React.createClass({
@ -69,6 +84,63 @@ export default contain({
highlight: PropTypes.object highlight: PropTypes.object
}, },
handleSubmit(e) {
e.preventDefault();
let valid = true;
checkValidity.forEach((prop) => {
// if value exist, check if it is valid
if (this.props[prop].value) {
valid = valid && !!this.props[prop].valid;
}
});
if (!valid) {
debug('form not valid');
return;
}
const {
position,
locale,
description,
email,
phone,
url,
logo,
name,
highlight,
jobActions
} = this.props;
// sanitize user output
const jobValues = {
position: inHTMLData(position.value),
location: inHTMLData(locale.value),
description: inHTMLData(description.value),
email: inHTMLData(email.value),
phone: inHTMLData(phone.value),
url: uriInSingleQuotedAttr(url.value),
logo: uriInSingleQuotedAttr(logo.value),
name: inHTMLData(name.value),
highlight: !!highlight.value
};
const job = Object.keys(jobValues).reduce((accu, prop) => {
if (jobValues[prop]) {
accu[prop] = jobValues[prop];
}
return accu;
}, {});
debug('job sanitized', job);
jobActions.saveForm(job);
},
componentDidMount() {
const { jobActions } = this.props;
jobActions.getSavedForm();
},
handleChange(name, validator, { target: { value } }) { handleChange(name, validator, { target: { value } }) {
const { jobActions: { handleForm } } = this.props; const { jobActions: { handleForm } } = this.props;
handleForm({ name, value, validator }); handleForm({ name, value, validator });
@ -95,7 +167,9 @@ export default contain({
<Col> <Col>
<Well className='text-center'> <Well className='text-center'>
<h1>Create Your Job Post</h1> <h1>Create Your Job Post</h1>
<form className='form-horizontal'> <form
className='form-horizontal'
onSubmit={ this.handleSubmit }>
<div className='spacer'> <div className='spacer'>
<h2>Job Information</h2> <h2>Job Information</h2>
@ -151,7 +225,7 @@ export default contain({
<h2>Company Information</h2> <h2>Company Information</h2>
</div> </div>
<Input <Input
bsStyle={ locale.bsStyle } bsStyle={ name.bsStyle }
label='Company Name' label='Company Name'
labelClassName={ labelClass } labelClassName={ labelClass }
onChange={ (e) => { onChange={ (e) => {
@ -248,8 +322,9 @@ export default contain({
lgOffset={ 3 }> lgOffset={ 3 }>
<Button <Button
block={ true } block={ true }
bsSize='lg' bsSize='large'
bsStyle='primary'> bsStyle='primary'
type='submit'>
Preview My Ad Preview My Ad
</Button> </Button>
</Col> </Col>

View File

@ -1,4 +1,6 @@
import { Actions } from 'thundercats'; import { Actions } from 'thundercats';
import store from 'store';
import { getDefaults } from '../utils';
import debugFactory from 'debug'; import debugFactory from 'debug';
const debug = debugFactory('freecc:jobs:actions'); const debug = debugFactory('freecc:jobs:actions');
@ -52,12 +54,14 @@ export default Actions({
newState.form = assign( newState.form = assign(
{}, {},
form, form,
{ [name]: { {
value, [name]: {
valid: false, value,
pristine: false, valid: false,
bsStyle: value ? 'error' : null pristine: false,
}} bsStyle: value ? 'error' : null
}
}
); );
return newState; return newState;
} }
@ -70,16 +74,31 @@ export default Actions({
newState.form = assign( newState.form = assign(
{}, {},
form, form,
{ [name]: { {
value, [name]: {
valid: true, value,
pristine: false, valid: true,
bsStyle: value ? 'success' : null pristine: false,
}} bsStyle: value ? 'success' : null
}
}
); );
return newState; return newState;
} }
}; };
},
saveForm: null,
getSavedForm: null,
setForm(job) {
const form = Object.keys(job).reduce((accu, prop) => {
console.log('form', accu);
return Object.assign(
accu,
{ [prop]: getDefaults(typeof prop, job[prop]) }
);
}, {});
return { form };
} }
}) })
.refs({ displayName: 'JobActions' }) .refs({ displayName: 'JobActions' })
@ -111,5 +130,14 @@ export default Actions({
jobActions.setJobs({}); jobActions.setJobs({});
}); });
}); });
jobActions.saveForm.subscribe((form) => {
store.set('newJob', form);
});
jobActions.getSavedForm.subscribe(() => {
const job = store.get('newJob');
jobActions.setForm(job);
});
return jobActions; return jobActions;
}); });

View File

@ -15,13 +15,15 @@ export default Store({ showModal: false })
setError, setError,
openModal, openModal,
closeModal, closeModal,
handleForm handleForm,
setForm
} = cat.getActions('JobActions'); } = cat.getActions('JobActions');
const register = createRegistrar(jobsStore); const register = createRegistrar(jobsStore);
register(setter(setJobs)); register(setter(setJobs));
register(setter(setError)); register(setter(setError));
register(setter(openModal)); register(setter(openModal));
register(setter(closeModal)); register(setter(closeModal));
register(setter(setForm));
register(transformer(findJob)); register(transformer(findJob));
register(handleForm); register(handleForm);

View File

@ -0,0 +1,22 @@
const defaults = {
'string': {
value: '',
valid: false,
pristine: true,
type: 'string'
},
bool: {
value: false,
type: 'boolean'
}
};
export function getDefaults(type, value) {
if (!type) {
return defaults['string'];
}
if (value) {
return Object.assign({}, defaults[type], { value });
}
return defaults[type];
}

View File

@ -30,6 +30,9 @@
"state": { "state": {
"type": "string" "type": "string"
}, },
"url": {
"type": "string"
},
"country": { "country": {
"type": "string" "type": "string"
}, },
@ -39,7 +42,7 @@
"description": { "description": {
"type": "string" "type": "string"
}, },
"isApproverd": { "isApproved": {
"type": "boolean" "type": "boolean"
}, },
"isHighlighted": { "isHighlighted": {

View File

@ -97,12 +97,14 @@
"sanitize-html": "~1.6.1", "sanitize-html": "~1.6.1",
"sort-keys": "^1.1.1", "sort-keys": "^1.1.1",
"source-map-support": "^0.3.2", "source-map-support": "^0.3.2",
"store": "https://github.com/berkeleytrue/store.js.git#feature/noop-server",
"thundercats": "^2.1.0", "thundercats": "^2.1.0",
"thundercats-react": "^0.1.0", "thundercats-react": "^0.1.0",
"twit": "~1.1.20", "twit": "~1.1.20",
"uglify-js": "~2.4.15", "uglify-js": "~2.4.15",
"validator": "^3.22.1", "validator": "^3.22.1",
"webpack": "^1.9.12", "webpack": "^1.9.12",
"xss-filters": "^1.2.6",
"yui": "~3.18.1" "yui": "~3.18.1"
}, },
"devDependencies": { "devDependencies": {