refactor form to do validation right in component
parent
c63a983fb9
commit
891341532b
|
@ -37,22 +37,31 @@ const checkValidity = [
|
|||
'highlight'
|
||||
];
|
||||
|
||||
function formatValue(value, validator, type = 'string') {
|
||||
const formated = getDefaults(type);
|
||||
if (validator && type === 'string') {
|
||||
formated.valid = validator(value);
|
||||
}
|
||||
if (value) {
|
||||
formated.value = value;
|
||||
formated.bsStyle = formated.valid ? 'success' : 'error';
|
||||
}
|
||||
return formated;
|
||||
}
|
||||
|
||||
function isValidURL(data) {
|
||||
return isURL(data, { 'require_protocol': true });
|
||||
}
|
||||
|
||||
function isValidPhone(data) {
|
||||
return isMobilePhone(data, 'en-US');
|
||||
}
|
||||
|
||||
export default contain({
|
||||
actions: 'jobActions',
|
||||
store: 'jobsStore',
|
||||
map({ form = {} }) {
|
||||
const {
|
||||
position = getDefaults('string'),
|
||||
locale = getDefaults('string'),
|
||||
description = getDefaults('string'),
|
||||
email = getDefaults('string'),
|
||||
phone = getDefaults('string'),
|
||||
url = getDefaults('string'),
|
||||
logo = getDefaults('string'),
|
||||
name = getDefaults('string'),
|
||||
highlight = getDefaults('bool')
|
||||
} = form;
|
||||
return {
|
||||
position,
|
||||
locale,
|
||||
description,
|
||||
|
@ -62,6 +71,17 @@ export default contain({
|
|||
logo,
|
||||
name,
|
||||
highlight
|
||||
} = form;
|
||||
return {
|
||||
position: formatValue(position, isAscii),
|
||||
locale: formatValue(locale, isAscii),
|
||||
description: formatValue(description, isAscii),
|
||||
email: formatValue(email, isEmail),
|
||||
phone: formatValue(phone, isValidPhone),
|
||||
url: formatValue(url, isValidURL),
|
||||
logo: formatValue(logo, isValidURL),
|
||||
name: formatValue(name, isAscii),
|
||||
highlight: formatValue(highlight, null, 'bool')
|
||||
};
|
||||
},
|
||||
subscribeOnWillMount() {
|
||||
|
@ -86,11 +106,12 @@ export default contain({
|
|||
|
||||
handleSubmit(e) {
|
||||
e.preventDefault();
|
||||
const props = this.props;
|
||||
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 (props[prop].value && props[prop].type !== 'boolean') {
|
||||
valid = valid && !!props[prop].valid;
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -141,9 +162,9 @@ export default contain({
|
|||
jobActions.getSavedForm();
|
||||
},
|
||||
|
||||
handleChange(name, validator, { target: { value } }) {
|
||||
handleChange(name, { target: { value } }) {
|
||||
const { jobActions: { handleForm } } = this.props;
|
||||
handleForm({ name, value, validator });
|
||||
handleForm({ [name]: value });
|
||||
},
|
||||
|
||||
render() {
|
||||
|
@ -156,8 +177,10 @@ export default contain({
|
|||
url,
|
||||
logo,
|
||||
name,
|
||||
highlight
|
||||
highlight,
|
||||
jobActions: { handleForm }
|
||||
} = this.props;
|
||||
const { handleChange } = this;
|
||||
const labelClass = 'col-sm-offset-1 col-sm-2';
|
||||
const inputClass = 'col-sm-6';
|
||||
|
||||
|
@ -178,13 +201,7 @@ export default contain({
|
|||
bsStyle={ position.bsStyle }
|
||||
label='Position'
|
||||
labelClassName={ labelClass }
|
||||
onChange={ (e) => {
|
||||
this.handleChange(
|
||||
'position',
|
||||
isAscii,
|
||||
e
|
||||
);
|
||||
}}
|
||||
onChange={ (e) => handleChange('position', e) }
|
||||
placeholder='Position'
|
||||
type='text'
|
||||
value={ position.value }
|
||||
|
@ -193,13 +210,7 @@ export default contain({
|
|||
bsStyle={ locale.bsStyle }
|
||||
label='Location'
|
||||
labelClassName={ labelClass }
|
||||
onChange={ (e) => {
|
||||
this.handleChange(
|
||||
'locale',
|
||||
isAscii,
|
||||
e,
|
||||
);
|
||||
}}
|
||||
onChange={ (e) => handleChange('locale', e) }
|
||||
placeholder='Location'
|
||||
type='text'
|
||||
value={ locale.value }
|
||||
|
@ -208,13 +219,7 @@ export default contain({
|
|||
bsStyle={ description.bsStyle }
|
||||
label='Description'
|
||||
labelClassName={ labelClass }
|
||||
onChange={ (e) => {
|
||||
this.handleChange(
|
||||
'description',
|
||||
isAscii,
|
||||
e
|
||||
);
|
||||
}}
|
||||
onChange={ (e) => handleChange('description', e) }
|
||||
placeholder='Description'
|
||||
rows='10'
|
||||
type='textarea'
|
||||
|
@ -228,13 +233,7 @@ export default contain({
|
|||
bsStyle={ name.bsStyle }
|
||||
label='Company Name'
|
||||
labelClassName={ labelClass }
|
||||
onChange={ (e) => {
|
||||
this.handleChange(
|
||||
'name',
|
||||
isAscii,
|
||||
e,
|
||||
);
|
||||
}}
|
||||
onChange={ (e) => handleChange('name', e) }
|
||||
placeholder='Foo, INC'
|
||||
type='text'
|
||||
value={ name.value }
|
||||
|
@ -243,13 +242,7 @@ export default contain({
|
|||
bsStyle={ email.bsStyle }
|
||||
label='Email'
|
||||
labelClassName={ labelClass }
|
||||
onChange={ (e) => {
|
||||
this.handleChange(
|
||||
'email',
|
||||
isEmail,
|
||||
e
|
||||
);
|
||||
}}
|
||||
onChange={ (e) => handleChange('email', e) }
|
||||
placeholder='Email'
|
||||
type='email'
|
||||
value={ email.value }
|
||||
|
@ -258,13 +251,7 @@ export default contain({
|
|||
bsStyle={ phone.bsStyle }
|
||||
label='Phone'
|
||||
labelClassName={ labelClass }
|
||||
onChange={ (e) => {
|
||||
this.handleChange(
|
||||
'phone',
|
||||
(data) => isMobilePhone(data, 'en-US'),
|
||||
e
|
||||
);
|
||||
}}
|
||||
onChange={ (e) => handleChange('phone', e) }
|
||||
placeholder='555-123-1234'
|
||||
type='tel'
|
||||
value={ phone.value }
|
||||
|
@ -273,13 +260,7 @@ export default contain({
|
|||
bsStyle={ url.bsStyle }
|
||||
label='URL'
|
||||
labelClassName={ labelClass }
|
||||
onChange={ (e) => {
|
||||
this.handleChange(
|
||||
'url',
|
||||
(data) => isURL(data, { 'require_protocol': true }),
|
||||
e
|
||||
);
|
||||
}}
|
||||
onChange={ (e) => handleChange('url', e) }
|
||||
placeholder='http://freecatphotoapp.com'
|
||||
type='url'
|
||||
value={ url.value }
|
||||
|
@ -288,13 +269,7 @@ export default contain({
|
|||
bsStyle={ logo.bsStyle }
|
||||
label='Logo'
|
||||
labelClassName={ labelClass }
|
||||
onChange={ (e) => {
|
||||
this.handleChange(
|
||||
'logo',
|
||||
(data) => isURL(data, { 'require_protocol': true }),
|
||||
e
|
||||
);
|
||||
}}
|
||||
onChange={ (e) => handleChange('logo', e) }
|
||||
placeholder='http://freecatphotoapp.com/logo.png'
|
||||
type='url'
|
||||
value={ logo.value }
|
||||
|
@ -304,17 +279,15 @@ export default contain({
|
|||
<h2>Make it stand out</h2>
|
||||
</div>
|
||||
<Input
|
||||
checked={ highlight.value }
|
||||
label='Highlight your ad'
|
||||
labelClassName={ 'col-sm-offset-1 col-sm-6'}
|
||||
onChange={ (e) => {
|
||||
this.handleChange(
|
||||
'highlight',
|
||||
() => { return true; },
|
||||
e
|
||||
);
|
||||
}}
|
||||
type='checkbox'
|
||||
value={ highlight.value } />
|
||||
onChange={
|
||||
({ target: { checked } }) => handleForm({
|
||||
highlight: !!checked
|
||||
})
|
||||
}
|
||||
type='checkbox' />
|
||||
<div className='spacer' />
|
||||
<Row>
|
||||
<Col
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
import { Actions } from 'thundercats';
|
||||
import store from 'store';
|
||||
import { getDefaults } from '../utils';
|
||||
import debugFactory from 'debug';
|
||||
|
||||
const debug = debugFactory('freecc:jobs:actions');
|
||||
|
@ -41,32 +40,7 @@ export default Actions({
|
|||
closeModal() {
|
||||
return { showModal: false };
|
||||
},
|
||||
handleForm({ name, value, validator = () => {} }) {
|
||||
if (!name) {
|
||||
// operation noop
|
||||
return { replace: null };
|
||||
}
|
||||
if (!validator(value)) {
|
||||
return {
|
||||
transform(oldState) {
|
||||
const { form } = oldState;
|
||||
const newState = assign({}, oldState);
|
||||
newState.form = assign(
|
||||
{},
|
||||
form,
|
||||
{
|
||||
[name]: {
|
||||
value,
|
||||
valid: false,
|
||||
pristine: false,
|
||||
bsStyle: value ? 'error' : null
|
||||
}
|
||||
}
|
||||
);
|
||||
return newState;
|
||||
}
|
||||
};
|
||||
}
|
||||
handleForm(value) {
|
||||
return {
|
||||
transform(oldState) {
|
||||
const { form } = oldState;
|
||||
|
@ -74,14 +48,7 @@ export default Actions({
|
|||
newState.form = assign(
|
||||
{},
|
||||
form,
|
||||
{
|
||||
[name]: {
|
||||
value,
|
||||
valid: true,
|
||||
pristine: false,
|
||||
bsStyle: value ? 'success' : null
|
||||
}
|
||||
}
|
||||
value
|
||||
);
|
||||
return newState;
|
||||
}
|
||||
|
@ -89,15 +56,7 @@ export default Actions({
|
|||
},
|
||||
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]) }
|
||||
);
|
||||
}, {});
|
||||
|
||||
setForm(form) {
|
||||
return { form };
|
||||
}
|
||||
})
|
||||
|
|
|
@ -18,5 +18,5 @@ export function getDefaults(type, value) {
|
|||
if (value) {
|
||||
return Object.assign({}, defaults[type], { value });
|
||||
}
|
||||
return defaults[type];
|
||||
return Object.assign({}, defaults[type]);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue