Ajout HOC WithForm
This commit is contained in:
parent
85acbcbdb5
commit
07f0960c8c
@ -1,26 +1,70 @@
|
||||
import { useState, useEffect } from 'react';
|
||||
import { useEffect } from 'react';
|
||||
import { WithForm } from './WithForm';
|
||||
|
||||
const defaultData = {
|
||||
username: '',
|
||||
password: '',
|
||||
passwordVerification: ''
|
||||
export function UserForm({ form, onSubmit }) {
|
||||
|
||||
useEffect(() => {
|
||||
console.log(form.valid, form.submitted);
|
||||
if (form.valid && form.submitted) onSubmit(form.data);
|
||||
}, [form.valid, form.submitted]);
|
||||
|
||||
return (
|
||||
<form className="form" onSubmit={form.onSubmit}>
|
||||
<div className="field">
|
||||
<label className="label" htmlFor="username">Nom d'utilisateur</label>
|
||||
<div className="control">
|
||||
<input className={`input ${form.hasError('username') ? 'is-danger' : ''}`} type="text"
|
||||
name="username" value={form.field('username', '')}
|
||||
onChange={form.onChange('username')} />
|
||||
</div>
|
||||
{
|
||||
form.hasError('username') ?
|
||||
<p className="help is-danger">{form.error('username')}</p>
|
||||
: null
|
||||
}
|
||||
</div>
|
||||
<div className="field">
|
||||
<label className="label" htmlFor="password">Mot de passe</label>
|
||||
<div className="control">
|
||||
<input className={`input ${form.hasError('password') ? 'is-danger' : ''}`}
|
||||
type="password" name="password"
|
||||
autoComplete='new-password'
|
||||
value={form.field('password', '')}
|
||||
onChange={form.onChange('password')} />
|
||||
</div>
|
||||
{
|
||||
form.hasError('password') ?
|
||||
<p className="help is-danger">{form.error('password')}</p>
|
||||
: null
|
||||
}
|
||||
</div>
|
||||
<div className="field">
|
||||
<label className="label" htmlFor="passwordVerification">Mot de passe (vérification)</label>
|
||||
<div className="control">
|
||||
<input className={`input ${form.hasError('passwordVerification') ? 'is-danger' : ''}`}
|
||||
type="password" name="passwordVerification"
|
||||
autoComplete='new-password'
|
||||
value={form.field('passwordVerification', '')}
|
||||
onChange={form.onChange('passwordVerification')} />
|
||||
</div>
|
||||
{
|
||||
form.hasError('passwordVerification') ?
|
||||
<p className="help is-danger">{form.error('passwordVerification')}</p>
|
||||
: null
|
||||
}
|
||||
</div>
|
||||
<button type="submit" disabled={!form.valid} className="button">Envoyer</button>
|
||||
</form>
|
||||
);
|
||||
};
|
||||
|
||||
const defaultErrors = {
|
||||
username: { hasError: false, message: '' },
|
||||
password: { hasError: false, message: '' },
|
||||
passwordVerification: { hasError: false, message: '' },
|
||||
};
|
||||
|
||||
export function UserForm({ data = defaultData, errors = defaultErrors, onSubmit }) {
|
||||
|
||||
const validators = {
|
||||
username: (value, formData) => {
|
||||
if (value === "") return { hasError: true, message: 'Le nom d\'utilisateur ne peut pas être vide !' }
|
||||
if (!value) return { hasError: true, message: 'Le nom d\'utilisateur ne peut pas être vide !' }
|
||||
return { hasError: false, message: '' };
|
||||
},
|
||||
password: (value, formData) => {
|
||||
if (value === "") return { hasError: true, message: 'Le mot de passe ne peut pas être vide !' }
|
||||
if (!value) return { hasError: true, message: 'Le mot de passe ne peut pas être vide !' }
|
||||
if (value !== formData.passwordVerification) return { hasError: true, message: 'Vos deux mots de passe sont différents !' }
|
||||
return { hasError: false, message: '' };
|
||||
},
|
||||
@ -30,89 +74,4 @@ export function UserForm({ data = defaultData, errors = defaultErrors, onSubmit
|
||||
}
|
||||
};
|
||||
|
||||
const [ formErrors, setFormErrors ] = useState({ ...defaultErrors, ...errors });
|
||||
const [ formData, setFormData ] = useState({ ...defaultData, ...data });
|
||||
|
||||
useEffect(() => {
|
||||
setFormErrors(formErrors => {
|
||||
return { ...formErrors, ...errors };
|
||||
});
|
||||
}, [errors]);
|
||||
|
||||
useEffect(() => {
|
||||
setFormData(formData => {
|
||||
return { ...formData, ...data };
|
||||
});
|
||||
}, [data]);
|
||||
|
||||
|
||||
const hasFormErrors = Object.values(formErrors).reduce((hasFormErrors, fieldError) => {
|
||||
return hasFormErrors || fieldError.hasError;
|
||||
}, false);
|
||||
const { username, password, passwordVerification } = formData;
|
||||
|
||||
const onInputChange = evt => {
|
||||
const name = evt.target.name;
|
||||
const value = evt.target.value;
|
||||
setFormData(formData => {
|
||||
return { ...formData, [name]: value };
|
||||
});
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
Object.keys(formData).forEach(name => {
|
||||
if (typeof validators[name] !== 'function') return;
|
||||
const value = formData[name];
|
||||
const result = validators[name](value, formData);
|
||||
setFormErrors(formErrors => {
|
||||
return { ...formErrors, [name]: result };
|
||||
});
|
||||
});
|
||||
}, [formData]);
|
||||
|
||||
const dispatchSubmit = evt => {
|
||||
evt.preventDefault();
|
||||
if (hasFormErrors) return;
|
||||
if (typeof onSubmit === 'function') onSubmit(formData);
|
||||
};
|
||||
|
||||
return (
|
||||
<form className="form" onSubmit={dispatchSubmit}>
|
||||
<div className="field">
|
||||
<label className="label" htmlFor="username">Nom d'utilisateur</label>
|
||||
<div className="control">
|
||||
<input className={`input ${formErrors.username.hasError ? 'is-danger' : ''}`} type="text" name="username" value={username} onChange={onInputChange} />
|
||||
</div>
|
||||
{
|
||||
formErrors.username.hasError ?
|
||||
<p className="help is-danger">{formErrors.username.message}</p>
|
||||
: null
|
||||
}
|
||||
</div>
|
||||
<div className="field">
|
||||
<label className="label" htmlFor="password">Mot de passe</label>
|
||||
<div className="control">
|
||||
<input className={`input ${formErrors.password.hasError ? 'is-danger' : ''}`} type="password" name="password" autoComplete='new-password' value={password} onChange={onInputChange} />
|
||||
</div>
|
||||
{
|
||||
formErrors.password.hasError ?
|
||||
<p className="help is-danger">{formErrors.password.message}</p>
|
||||
: null
|
||||
}
|
||||
</div>
|
||||
<div className="field">
|
||||
<label className="label" htmlFor="passwordVerification">Mot de passe (vérification)</label>
|
||||
<div className="control">
|
||||
<input className={`input ${formErrors.passwordVerification.hasError ? 'is-danger' : ''}`} type="password" name="passwordVerification" autoComplete='new-password' value={passwordVerification}
|
||||
onChange={onInputChange} />
|
||||
</div>
|
||||
{
|
||||
formErrors.passwordVerification.hasError ?
|
||||
<p className="help is-danger">{formErrors.passwordVerification.message}</p>
|
||||
: null
|
||||
}
|
||||
</div>
|
||||
<button type="submit" disabled={hasFormErrors} className="button">Envoyer</button>
|
||||
</form>
|
||||
);
|
||||
};
|
||||
export const ExtendedUserForm = WithForm(validators)(UserForm);
|
||||
|
73
frontend/src/components/WithForm.js
Normal file
73
frontend/src/components/WithForm.js
Normal file
@ -0,0 +1,73 @@
|
||||
import { useState, useEffect } from 'react';
|
||||
|
||||
export function WithForm(validators) {
|
||||
|
||||
return function(Component) {
|
||||
|
||||
return function WithFormWrapper(props) {
|
||||
|
||||
const [ formData, setFormData ] = useState({});
|
||||
const [ formErrors, setFormErrors ] = useState({});
|
||||
const [ submitted, setSubmitted ] = useState(false);
|
||||
|
||||
const validateField = (name) => {
|
||||
if (typeof validators[name] !== 'function') return;
|
||||
const value = formData[name];
|
||||
const result = validators[name](value, formData);
|
||||
setFormErrors(formErrors => {
|
||||
return { ...formErrors, [name]: result };
|
||||
});
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
Object.keys(formData).forEach(validateField);
|
||||
}, [formData]);
|
||||
|
||||
useEffect(() => {
|
||||
setSubmitted(false);
|
||||
}, [submitted]);
|
||||
|
||||
const form = {
|
||||
field: (name, defaultValue) => {
|
||||
return name in formData ? formData[name] : defaultValue;
|
||||
},
|
||||
|
||||
onChange: (name) => {
|
||||
return (evt) => {
|
||||
const value = evt.target.value;
|
||||
setFormData(formData => {
|
||||
return { ...formData, [name]: value };
|
||||
});
|
||||
};
|
||||
},
|
||||
|
||||
hasError: (name) => {
|
||||
return name in formErrors ? formErrors[name].hasError : false;
|
||||
},
|
||||
|
||||
error: (name) => {
|
||||
return name in formErrors ? formErrors[name].message : '';
|
||||
},
|
||||
|
||||
onSubmit: (evt) => {
|
||||
evt.preventDefault();
|
||||
Object.keys(validators).forEach(validateField);
|
||||
setSubmitted(true);
|
||||
},
|
||||
|
||||
valid: !Object.values(formErrors).reduce((hasErrors, fieldError) => {
|
||||
return hasErrors || fieldError.hasError;
|
||||
}, false),
|
||||
|
||||
data: { ...formData },
|
||||
errors: { ...formErrors },
|
||||
submitted,
|
||||
|
||||
};
|
||||
|
||||
return <Component form={form} {...props} />;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// connect(mapStateToProps)(MyComponent)
|
@ -1,6 +1,6 @@
|
||||
import React from 'react'
|
||||
import Page from './page';
|
||||
import { UserForm } from '../components/UserForm';
|
||||
import { ExtendedUserForm as UserForm } from '../components/UserForm';
|
||||
|
||||
export default class HomePage extends React.PureComponent {
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user