save form to localStorage
This commit is contained in:
@ -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>
|
||||||
|
@ -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;
|
||||||
});
|
});
|
||||||
|
@ -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);
|
||||||
|
22
common/app/routes/Jobs/utils.js
Normal file
22
common/app/routes/Jobs/utils.js
Normal 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];
|
||||||
|
}
|
@ -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": {
|
||||||
|
@ -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": {
|
||||||
|
Reference in New Issue
Block a user