Merge branch 'master' into enhancement/database-uri

This commit is contained in:
Jim LAURIE 2018-02-07 17:57:14 +01:00 committed by GitHub
commit e963ee1414
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 331 additions and 481 deletions

View File

@ -15,6 +15,9 @@ import InputDescription from 'components/InputDescription';
import InputErrors from 'components/InputErrors'; import InputErrors from 'components/InputErrors';
import InputAddon from 'components/InputAddon'; import InputAddon from 'components/InputAddon';
// Utils
import validateInput from 'utils/inputsValidations';
import styles from './styles.scss'; import styles from './styles.scss';
class InputAddonWithErrors extends React.Component { // eslint-disable-line react/prefer-stateless-function class InputAddonWithErrors extends React.Component { // eslint-disable-line react/prefer-stateless-function
@ -24,7 +27,7 @@ class InputAddonWithErrors extends React.Component { // eslint-disable-line reac
const { value, errors } = this.props; const { value, errors } = this.props;
// Prevent the input from displaying an error when the user enters and leaves without filling it // Prevent the input from displaying an error when the user enters and leaves without filling it
if (value && !isEmpty(value)) { if (!isEmpty(value)) {
this.setState({ hasInitialValue: true }); this.setState({ hasInitialValue: true });
} }
@ -35,6 +38,11 @@ class InputAddonWithErrors extends React.Component { // eslint-disable-line reac
} }
componentWillReceiveProps(nextProps) { componentWillReceiveProps(nextProps) {
// Show required error if the input's value is received after the compo is mounted
if (!isEmpty(nextProps.value) && !this.state.hasInitialValue) {
this.setState({ hasInitialValue: true });
}
// Check if errors have been updated during validations // Check if errors have been updated during validations
if (nextProps.didCheckErrors !== this.props.didCheckErrors) { if (nextProps.didCheckErrors !== this.props.didCheckErrors) {
// Remove from the state the errors that have already been set // Remove from the state the errors that have already been set
@ -50,7 +58,7 @@ class InputAddonWithErrors extends React.Component { // eslint-disable-line reac
handleBlur = ({ target }) => { handleBlur = ({ target }) => {
// Prevent from displaying error if the input is initially isEmpty // Prevent from displaying error if the input is initially isEmpty
if (!isEmpty(target.value) || this.state.hasInitialValue) { if (!isEmpty(target.value) || this.state.hasInitialValue) {
const errors = this.validate(target.value); const errors = validateInput(target.value, this.props.validations);
this.setState({ errors, hasInitialValue: true }); this.setState({ errors, hasInitialValue: true });
} }
} }
@ -135,48 +143,6 @@ class InputAddonWithErrors extends React.Component { // eslint-disable-line reac
</div> </div>
); );
} }
validate = (value) => {
const requiredError = { id: 'components.Input.error.validation.required' };
let errors = [];
mapKeys(this.props.validations, (validationValue, validationKey) => {
switch (validationKey) {
case 'maxLength': {
if (value.length > validationValue) {
errors.push({ id: 'components.Input.error.validation.maxLength' });
}
break;
}
case 'minLength': {
if (value.length < validationValue) {
errors.push({ id: 'components.Input.error.validation.minLength' });
}
break;
}
case 'required': {
if (value.length === 0) {
errors.push({ id: 'components.Input.error.validation.required' });
}
break;
}
case 'regex': {
if (!new RegExp(validationValue).test(value)) {
errors.push({ id: 'components.Input.error.validation.regex' });
}
break;
}
default:
errors = [];
}
});
if (includes(errors, requiredError)) {
errors = reject(errors, (error) => error !== requiredError);
}
return errors;
}
} }
InputAddonWithErrors.defaultProps = { InputAddonWithErrors.defaultProps = {

View File

@ -15,6 +15,9 @@ import InputDescription from 'components/InputDescription';
import InputErrors from 'components/InputErrors'; import InputErrors from 'components/InputErrors';
import InputDate from 'components/InputDate'; import InputDate from 'components/InputDate';
// Utils
import validateInput from 'utils/inputsValidations';
import styles from './styles.scss'; import styles from './styles.scss';
class InputDateWithErrors extends React.Component { // eslint-disable-line react/prefer-stateless-function class InputDateWithErrors extends React.Component { // eslint-disable-line react/prefer-stateless-function
@ -24,7 +27,7 @@ class InputDateWithErrors extends React.Component { // eslint-disable-line react
const { value, errors } = this.props; const { value, errors } = this.props;
// Prevent the input from displaying an error when the user enters and leaves without filling it // Prevent the input from displaying an error when the user enters and leaves without filling it
if (value && !isEmpty(value)) { if (!isEmpty(value)) {
this.setState({ hasInitialValue: true }); this.setState({ hasInitialValue: true });
} }
@ -35,6 +38,11 @@ class InputDateWithErrors extends React.Component { // eslint-disable-line react
} }
componentWillReceiveProps(nextProps) { componentWillReceiveProps(nextProps) {
// Show required error if the input's value is received after the compo is mounted
if (!isEmpty(nextProps.value) && !this.state.hasInitialValue) {
this.setState({ hasInitialValue: true });
}
// Check if errors have been updated during validations // Check if errors have been updated during validations
if (nextProps.didCheckErrors !== this.props.didCheckErrors) { if (nextProps.didCheckErrors !== this.props.didCheckErrors) {
// Remove from the state the errors that have already been set // Remove from the state the errors that have already been set
@ -50,7 +58,7 @@ class InputDateWithErrors extends React.Component { // eslint-disable-line react
handleBlur = ({ target }) => { handleBlur = ({ target }) => {
// Prevent from displaying error if the input is initially isEmpty // Prevent from displaying error if the input is initially isEmpty
if (!isEmpty(get(target, 'value')) || this.state.hasInitialValue) { if (!isEmpty(get(target, 'value')) || this.state.hasInitialValue) {
const errors = this.validate(target.value); const errors = validateInput(target.value, this.props.validations);
this.setState({ errors, hasInitialValue: true }); this.setState({ errors, hasInitialValue: true });
} }
} }
@ -133,30 +141,6 @@ class InputDateWithErrors extends React.Component { // eslint-disable-line react
</div> </div>
); );
} }
validate = (value) => {
const requiredError = { id: 'components.Input.error.validation.required' };
let errors = [];
mapKeys(this.props.validations, (validationValue, validationKey) => {
switch (validationKey) {
case 'required': {
if (value.length === 0) {
errors.push({ id: 'components.Input.error.validation.required' });
}
break;
}
default:
errors = [];
}
});
if (includes(errors, requiredError)) {
errors = reject(errors, (error) => error !== requiredError);
}
return errors;
}
} }
InputDateWithErrors.defaultProps = { InputDateWithErrors.defaultProps = {

View File

@ -15,6 +15,9 @@ import InputDescription from 'components/InputDescription';
import InputErrors from 'components/InputErrors'; import InputErrors from 'components/InputErrors';
import InputEmail from 'components/InputEmail'; import InputEmail from 'components/InputEmail';
// Utils
import validateInput from 'utils/inputsValidations';
import styles from './styles.scss'; import styles from './styles.scss';
class InputEmailWithErrors extends React.Component { // eslint-disable-line react/prefer-stateless-function class InputEmailWithErrors extends React.Component { // eslint-disable-line react/prefer-stateless-function
@ -24,7 +27,7 @@ class InputEmailWithErrors extends React.Component { // eslint-disable-line reac
const { value, errors } = this.props; const { value, errors } = this.props;
// Prevent the input from displaying an error when the user enters and leaves without filling it // Prevent the input from displaying an error when the user enters and leaves without filling it
if (value && !isEmpty(value)) { if (!isEmpty(value)) {
this.setState({ hasInitialValue: true }); this.setState({ hasInitialValue: true });
} }
@ -35,6 +38,11 @@ class InputEmailWithErrors extends React.Component { // eslint-disable-line reac
} }
componentWillReceiveProps(nextProps) { componentWillReceiveProps(nextProps) {
// Show required error if the input's value is received after the compo is mounted
if (!isEmpty(nextProps.value) && !this.state.hasInitialValue) {
this.setState({ hasInitialValue: true });
}
// Check if errors have been updated during validations // Check if errors have been updated during validations
if (nextProps.didCheckErrors !== this.props.didCheckErrors) { if (nextProps.didCheckErrors !== this.props.didCheckErrors) {
// Remove from the state the errors that have already been set // Remove from the state the errors that have already been set
@ -50,7 +58,7 @@ class InputEmailWithErrors extends React.Component { // eslint-disable-line reac
handleBlur = ({ target }) => { handleBlur = ({ target }) => {
// Prevent from displaying error if the input is initially isEmpty // Prevent from displaying error if the input is initially isEmpty
if (!isEmpty(target.value) || this.state.hasInitialValue) { if (!isEmpty(target.value) || this.state.hasInitialValue) {
const errors = this.validate(target.value); const errors = validateInput(target.value, this.props.validations, 'email');
this.setState({ errors, hasInitialValue: true }); this.setState({ errors, hasInitialValue: true });
} }
} }
@ -131,53 +139,6 @@ class InputEmailWithErrors extends React.Component { // eslint-disable-line reac
</div> </div>
); );
} }
validate = (value) => {
const emailRegex = new RegExp(/^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/);
const requiredError = { id: 'components.Input.error.validation.required' };
let errors = [];
mapKeys(this.props.validations, (validationValue, validationKey) => {
switch (validationKey) {
case 'maxLength': {
if (value.length > validationValue) {
errors.push({ id: 'components.Input.error.validation.maxLength' });
}
break;
}
case 'minLength': {
if (value.length < validationValue) {
errors.push({ id: 'components.Input.error.validation.minLength' });
}
break;
}
case 'required': {
if (value.length === 0) {
errors.push({ id: 'components.Input.error.validation.required' });
}
break;
}
case 'regex': {
if (!new RegExp(validationValue).test(value)) {
errors.push({ id: 'components.Input.error.validation.regex' });
}
break;
}
default:
errors = [];
}
});
if (!emailRegex.test(value)) {
errors.push({ id: 'components.Input.error.validation.email' });
}
if (includes(errors, requiredError)) {
errors = reject(errors, (error) => error !== requiredError);
}
return errors;
}
} }
InputEmailWithErrors.defaultProps = { InputEmailWithErrors.defaultProps = {

View File

@ -9,6 +9,9 @@ import InputDescription from 'components/InputDescription';
import InputErrors from 'components/InputErrors'; import InputErrors from 'components/InputErrors';
import InputNumber from 'components/InputNumber'; import InputNumber from 'components/InputNumber';
// Utils
import validateInput from 'utils/inputsValidations';
import styles from './styles.scss'; import styles from './styles.scss';
class InputNumberWithErrors extends React.Component { // eslint-disable-line react/prefer-stateless-function class InputNumberWithErrors extends React.Component { // eslint-disable-line react/prefer-stateless-function
@ -18,7 +21,7 @@ class InputNumberWithErrors extends React.Component { // eslint-disable-line rea
const { value, errors } = this.props; const { value, errors } = this.props;
// Prevent the input from displaying an error when the user enters and leaves without filling it // Prevent the input from displaying an error when the user enters and leaves without filling it
if (value && !isEmpty(value)) { if (!isEmpty(value)) {
this.setState({ hasInitialValue: true }); this.setState({ hasInitialValue: true });
} }
@ -29,6 +32,11 @@ class InputNumberWithErrors extends React.Component { // eslint-disable-line rea
} }
componentWillReceiveProps(nextProps) { componentWillReceiveProps(nextProps) {
// Show required error if the input's value is received after the compo is mounted
if (!isEmpty(nextProps.value) && !this.state.hasInitialValue) {
this.setState({ hasInitialValue: true });
}
// Check if errors have been updated during validations // Check if errors have been updated during validations
if (nextProps.didCheckErrors !== this.props.didCheckErrors) { if (nextProps.didCheckErrors !== this.props.didCheckErrors) {
// Remove from the state the errors that have already been set // Remove from the state the errors that have already been set
@ -44,7 +52,7 @@ class InputNumberWithErrors extends React.Component { // eslint-disable-line rea
handleBlur = ({ target }) => { handleBlur = ({ target }) => {
// Prevent from displaying error if the input is initially isEmpty // Prevent from displaying error if the input is initially isEmpty
if (!isEmpty(target.value) || this.state.hasInitialValue) { if (!isEmpty(target.value) || this.state.hasInitialValue) {
const errors = this.validate(target.value); const errors = validateInput(target.value, this.props.validations);
this.setState({ errors, hasInitialValue: true }); this.setState({ errors, hasInitialValue: true });
} }
} }
@ -127,48 +135,6 @@ class InputNumberWithErrors extends React.Component { // eslint-disable-line rea
</div> </div>
); );
} }
validate = (value) => {
const requiredError = { id: 'components.Input.error.validation.required' };
let errors = [];
mapKeys(this.props.validations, (validationValue, validationKey) => {
switch (validationKey) {
case 'max': {
if (parseInt(value, 10) > validationValue) {
errors.push({ id: 'components.Input.error.validation.max' });
}
break;
}
case 'min': {
if (parseInt(value, 10) < validationValue) {
errors.push({ id: 'components.Input.error.validation.min' });
}
break;
}
case 'required': {
if (value.length === 0) {
errors.push({ id: 'components.Input.error.validation.required' });
}
break;
}
case 'regex': {
if (!new RegExp(validationValue).test(value)) {
errors.push({ id: 'components.Input.error.validation.regex' });
}
break;
}
default:
errors = [];
}
});
if (includes(errors, requiredError)) {
errors = reject(errors, (error) => error !== requiredError);
}
return errors;
}
} }
InputNumberWithErrors.defaultProps = { InputNumberWithErrors.defaultProps = {

View File

@ -15,6 +15,9 @@ import InputDescription from 'components/InputDescription';
import InputErrors from 'components/InputErrors'; import InputErrors from 'components/InputErrors';
import InputPassword from 'components/InputPassword'; import InputPassword from 'components/InputPassword';
// Utils
import validateInput from 'utils/inputsValidations';
import styles from './styles.scss'; import styles from './styles.scss';
class InputPasswordWithErrors extends React.Component { class InputPasswordWithErrors extends React.Component {
@ -24,7 +27,7 @@ class InputPasswordWithErrors extends React.Component {
const { value, errors } = this.props; const { value, errors } = this.props;
// Prevent the input from displaying an error when the user enters and leaves without filling it // Prevent the input from displaying an error when the user enters and leaves without filling it
if (value && !isEmpty(value)) { if (!isEmpty(value)) {
this.setState({ hasInitialValue: true }); this.setState({ hasInitialValue: true });
} }
@ -35,6 +38,11 @@ class InputPasswordWithErrors extends React.Component {
} }
componentWillReceiveProps(nextProps) { componentWillReceiveProps(nextProps) {
// Show required error if the input's value is received after the compo is mounted
if (!isEmpty(nextProps.value) && !this.state.hasInitialValue) {
this.setState({ hasInitialValue: true });
}
// Check if errors have been updated during validations // Check if errors have been updated during validations
if (nextProps.didCheckErrors !== this.props.didCheckErrors) { if (nextProps.didCheckErrors !== this.props.didCheckErrors) {
// Remove from the state the errors that have already been set // Remove from the state the errors that have already been set
@ -50,7 +58,7 @@ class InputPasswordWithErrors extends React.Component {
handleBlur = ({ target }) => { handleBlur = ({ target }) => {
// Prevent from displaying error if the input is initially isEmpty // Prevent from displaying error if the input is initially isEmpty
if (!isEmpty(target.value) || this.state.hasInitialValue) { if (!isEmpty(target.value) || this.state.hasInitialValue) {
const errors = this.validate(target.value); const errors = validateInput(target.value, this.props.validations);
this.setState({ errors, hasInitialValue: true }); this.setState({ errors, hasInitialValue: true });
} }
} }
@ -120,48 +128,6 @@ class InputPasswordWithErrors extends React.Component {
</div> </div>
); );
} }
validate = (value) => {
const requiredError = { id: 'components.Input.error.validation.required' };
let errors = [];
mapKeys(this.props.validations, (validationValue, validationKey) => {
switch (validationKey) {
case 'maxLength': {
if (value.length > validationValue) {
errors.push({ id: 'components.Input.error.validation.maxLength' });
}
break;
}
case 'minLength': {
if (value.length < validationValue) {
errors.push({ id: 'components.Input.error.validation.minLength' });
}
break;
}
case 'required': {
if (value.length === 0) {
errors.push({ id: 'components.Input.error.validation.required' });
}
break;
}
case 'regex': {
if (!new RegExp(validationValue).test(value)) {
errors.push({ id: 'components.Input.error.validation.regex' });
}
break;
}
default:
errors = [];
}
});
if (includes(errors, requiredError)) {
errors = reject(errors, (error) => error !== requiredError);
}
return errors;
}
} }
InputPasswordWithErrors.defaultProps = { InputPasswordWithErrors.defaultProps = {

View File

@ -15,6 +15,9 @@ import InputDescription from 'components/InputDescription';
import InputErrors from 'components/InputErrors'; import InputErrors from 'components/InputErrors';
import InputSearch from 'components/InputSearch'; import InputSearch from 'components/InputSearch';
// Utils
import validateInput from 'utils/inputsValidations';
import styles from './styles.scss'; import styles from './styles.scss';
class InputSearchWithErrors extends React.Component { // eslint-disable-line react/prefer-stateless-function class InputSearchWithErrors extends React.Component { // eslint-disable-line react/prefer-stateless-function
@ -24,7 +27,7 @@ class InputSearchWithErrors extends React.Component { // eslint-disable-line rea
const { value, errors } = this.props; const { value, errors } = this.props;
// Prevent the input from displaying an error when the user enters and leaves without filling it // Prevent the input from displaying an error when the user enters and leaves without filling it
if (value && !isEmpty(value)) { if (!isEmpty(value)) {
this.setState({ hasInitialValue: true }); this.setState({ hasInitialValue: true });
} }
@ -35,6 +38,11 @@ class InputSearchWithErrors extends React.Component { // eslint-disable-line rea
} }
componentWillReceiveProps(nextProps) { componentWillReceiveProps(nextProps) {
// Show required error if the input's value is received after the compo is mounted
if (!isEmpty(nextProps.value) && !this.state.hasInitialValue) {
this.setState({ hasInitialValue: true });
}
// Check if errors have been updated during validations // Check if errors have been updated during validations
if (nextProps.didCheckErrors !== this.props.didCheckErrors) { if (nextProps.didCheckErrors !== this.props.didCheckErrors) {
// Remove from the state the errors that have already been set // Remove from the state the errors that have already been set
@ -50,7 +58,7 @@ class InputSearchWithErrors extends React.Component { // eslint-disable-line rea
handleBlur = ({ target }) => { handleBlur = ({ target }) => {
// Prevent from displaying error if the input is initially isEmpty // Prevent from displaying error if the input is initially isEmpty
if (!isEmpty(target.value) || this.state.hasInitialValue) { if (!isEmpty(target.value) || this.state.hasInitialValue) {
const errors = this.validate(target.value); const errors = validateInput(target.value, this.props.validations);
this.setState({ errors, hasInitialValue: true }); this.setState({ errors, hasInitialValue: true });
} }
} }
@ -131,48 +139,6 @@ class InputSearchWithErrors extends React.Component { // eslint-disable-line rea
</div> </div>
); );
} }
validate = (value) => {
const requiredError = { id: 'components.Input.error.validation.required' };
let errors = [];
mapKeys(this.props.validations, (validationValue, validationKey) => {
switch (validationKey) {
case 'maxLength': {
if (value.length > validationValue) {
errors.push({ id: 'components.Input.error.validation.maxLength' });
}
break;
}
case 'minLength': {
if (value.length < validationValue) {
errors.push({ id: 'components.Input.error.validation.minLength' });
}
break;
}
case 'required': {
if (value.length === 0) {
errors.push({ id: 'components.Input.error.validation.required' });
}
break;
}
case 'regex': {
if (!new RegExp(validationValue).test(value)) {
errors.push({ id: 'components.Input.error.validation.regex' });
}
break;
}
default:
errors = [];
}
});
if (includes(errors, requiredError)) {
errors = reject(errors, (error) => error !== requiredError);
}
return errors;
}
} }
InputSearchWithErrors.defaultProps = { InputSearchWithErrors.defaultProps = {

View File

@ -9,6 +9,9 @@ import InputDescription from 'components/InputDescription';
import InputErrors from 'components/InputErrors'; import InputErrors from 'components/InputErrors';
import InputTextArea from 'components/InputTextArea'; import InputTextArea from 'components/InputTextArea';
// Utils
import validateInput from 'utils/inputsValidations';
import styles from './styles.scss'; import styles from './styles.scss';
class InputTextAreaWithErrors extends React.Component { // eslint-disable-line react/prefer-stateless-function class InputTextAreaWithErrors extends React.Component { // eslint-disable-line react/prefer-stateless-function
@ -18,7 +21,7 @@ class InputTextAreaWithErrors extends React.Component { // eslint-disable-line r
const { value, errors } = this.props; const { value, errors } = this.props;
// Prevent the input from displaying an error when the user enters and leaves without filling it // Prevent the input from displaying an error when the user enters and leaves without filling it
if (value && !isEmpty(value)) { if (!isEmpty(value)) {
this.setState({ hasInitialValue: true }); this.setState({ hasInitialValue: true });
} }
@ -29,6 +32,11 @@ class InputTextAreaWithErrors extends React.Component { // eslint-disable-line r
} }
componentWillReceiveProps(nextProps) { componentWillReceiveProps(nextProps) {
// Show required error if the input's value is received after the compo is mounted
if (!isEmpty(nextProps.value) && !this.state.hasInitialValue) {
this.setState({ hasInitialValue: true });
}
// Check if errors have been updated during validations // Check if errors have been updated during validations
if (nextProps.didCheckErrors !== this.props.didCheckErrors) { if (nextProps.didCheckErrors !== this.props.didCheckErrors) {
// Remove from the state the errors that have already been set // Remove from the state the errors that have already been set
@ -44,7 +52,7 @@ class InputTextAreaWithErrors extends React.Component { // eslint-disable-line r
handleBlur = ({ target }) => { handleBlur = ({ target }) => {
// Prevent from displaying error if the input is initially isEmpty // Prevent from displaying error if the input is initially isEmpty
if (!isEmpty(target.value) || this.state.hasInitialValue) { if (!isEmpty(target.value) || this.state.hasInitialValue) {
const errors = this.validate(target.value); const errors = validateInput(target.value, this.props.validations);
this.setState({ errors, hasInitialValue: true }); this.setState({ errors, hasInitialValue: true });
} }
} }
@ -127,48 +135,6 @@ class InputTextAreaWithErrors extends React.Component { // eslint-disable-line r
</div> </div>
); );
} }
validate = (value) => {
const requiredError = { id: 'components.Input.error.validation.required' };
let errors = [];
mapKeys(this.props.validations, (validationValue, validationKey) => {
switch (validationKey) {
case 'maxLength': {
if (value.length > validationValue) {
errors.push({ id: 'components.Input.error.validation.maxLength' });
}
break;
}
case 'minLength': {
if (value.length < validationValue) {
errors.push({ id: 'components.Input.error.validation.minLength' });
}
break;
}
case 'required': {
if (value.length === 0) {
errors.push({ id: 'components.Input.error.validation.required' });
}
break;
}
case 'regex': {
if (!new RegExp(validationValue).test(value)) {
errors.push({ id: 'components.Input.error.validation.regex' });
}
break;
}
default:
errors = [];
}
});
if (includes(errors, requiredError)) {
errors = reject(errors, (error) => error !== requiredError);
}
return errors;
}
} }
InputTextAreaWithErrors.defaultProps = { InputTextAreaWithErrors.defaultProps = {

View File

@ -9,6 +9,9 @@ import InputDescription from 'components/InputDescription';
import InputErrors from 'components/InputErrors'; import InputErrors from 'components/InputErrors';
import InputText from 'components/InputText'; import InputText from 'components/InputText';
// Utils
import validateInput from 'utils/inputsValidations';
import styles from './styles.scss'; import styles from './styles.scss';
class InputTextWithErrors extends React.Component { // eslint-disable-line react/prefer-stateless-function class InputTextWithErrors extends React.Component { // eslint-disable-line react/prefer-stateless-function
@ -18,7 +21,7 @@ class InputTextWithErrors extends React.Component { // eslint-disable-line react
const { value, errors } = this.props; const { value, errors } = this.props;
// Prevent the input from displaying an error when the user enters and leaves without filling it // Prevent the input from displaying an error when the user enters and leaves without filling it
if (value && !isEmpty(value)) { if (!isEmpty(value)) {
this.setState({ hasInitialValue: true }); this.setState({ hasInitialValue: true });
} }
@ -29,6 +32,11 @@ class InputTextWithErrors extends React.Component { // eslint-disable-line react
} }
componentWillReceiveProps(nextProps) { componentWillReceiveProps(nextProps) {
// Show required error if the input's value is received after the compo is mounted
if (!isEmpty(nextProps.value) && !this.state.hasInitialValue) {
this.setState({ hasInitialValue: true });
}
// Check if errors have been updated during validations // Check if errors have been updated during validations
if (nextProps.didCheckErrors !== this.props.didCheckErrors) { if (nextProps.didCheckErrors !== this.props.didCheckErrors) {
// Remove from the state the errors that have already been set // Remove from the state the errors that have already been set
@ -44,7 +52,7 @@ class InputTextWithErrors extends React.Component { // eslint-disable-line react
handleBlur = ({ target }) => { handleBlur = ({ target }) => {
// Prevent from displaying error if the input is initially isEmpty // Prevent from displaying error if the input is initially isEmpty
if (!isEmpty(target.value) || this.state.hasInitialValue) { if (!isEmpty(target.value) || this.state.hasInitialValue) {
const errors = this.validate(target.value); const errors = validateInput(target.value, this.props.validations);
this.setState({ errors, hasInitialValue: true }); this.setState({ errors, hasInitialValue: true });
} }
} }
@ -127,48 +135,6 @@ class InputTextWithErrors extends React.Component { // eslint-disable-line react
</div> </div>
); );
} }
validate = (value) => {
const requiredError = { id: 'components.Input.error.validation.required' };
let errors = [];
mapKeys(this.props.validations, (validationValue, validationKey) => {
switch (validationKey) {
case 'maxLength': {
if (value.length > validationValue) {
errors.push({ id: 'components.Input.error.validation.maxLength' });
}
break;
}
case 'minLength': {
if (value.length < validationValue) {
errors.push({ id: 'components.Input.error.validation.minLength' });
}
break;
}
case 'required': {
if (value.length === 0) {
errors.push({ id: 'components.Input.error.validation.required' });
}
break;
}
case 'regex': {
if (!new RegExp(validationValue).test(value)) {
errors.push({ id: 'components.Input.error.validation.regex' });
}
break;
}
default:
errors = [];
}
});
if (includes(errors, requiredError)) {
errors = reject(errors, (error) => error !== requiredError);
}
return errors;
}
} }
InputTextWithErrors.defaultProps = { InputTextWithErrors.defaultProps = {

View File

@ -0,0 +1,64 @@
import { includes, mapKeys, reject } from 'lodash';
/**
* [validateInput description]
* @param {String || Number} value Input's value
* @param {Object} inputValidations
* @param {String} [type='text'] Optionnal: the input's type only for email
* @return {Array} Array of errors to be displayed
*/
const validateInput = (value, inputValidations = {}, type = 'text') => {
let errors = [];
const emailRegex = new RegExp(/^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/);
// handle i18n
const requiredError = { id: 'components.Input.error.validation.required' };
mapKeys(inputValidations, (validationValue, validationKey) => {
switch (validationKey) {
case 'max':
if (parseInt(value, 10) > validationValue) {
errors.push({ id: 'components.Input.error.validation.max' });
}
break;
case 'maxLength':
if (value.length > validationValue) {
errors.push({ id: 'components.Input.error.validation.maxLength' });
}
break;
case 'min':
if (parseInt(value, 10) < validationValue) {
errors.push({ id: 'components.Input.error.validation.min' });
}
break;
case 'minLength':
if (value.length < validationValue) {
errors.push({ id: 'components.Input.error.validation.minLength' });
}
break;
case 'required':
if (value.length === 0) {
errors.push({ id: 'components.Input.error.validation.required' });
}
break;
case 'regex':
if (!new RegExp(validationValue).test(value)) {
errors.push({ id: 'components.Input.error.validation.regex' });
}
break;
default:
errors = [];
}
});
if (type === 'email' && !emailRegex.test(value)) {
errors.push({ id: 'components.Input.error.validation.email' });
}
if (includes(errors, requiredError)) {
errors = reject(errors, (error) => error !== requiredError);
}
return errors;
}
export default validateInput;

View File

@ -10,7 +10,7 @@ import { get, map, some } from 'lodash';
import cn from 'classnames'; import cn from 'classnames';
import { FormattedMessage } from 'react-intl'; import { FormattedMessage } from 'react-intl';
import InputCheckbox from 'components/InputCheckbox'; import InputCheckbox from 'components/InputCheckboxPlugin';
import styles from './styles.scss'; import styles from './styles.scss';
class Controller extends React.Component { class Controller extends React.Component {

View File

@ -1,6 +1,6 @@
/** /**
* *
* InputCheckbox * InputCheckboxPlugin
* *
*/ */
@ -10,7 +10,7 @@ import cn from 'classnames';
import styles from './styles.scss'; import styles from './styles.scss';
class InputCheckbox extends React.Component { // eslint-disable-line react/prefer-stateless-function class InputCheckboxPlugin extends React.Component { // eslint-disable-line react/prefer-stateless-function
state = { showBackground: false, showCog: false }; state = { showBackground: false, showCog: false };
componentWillReceiveProps(nextProps) { componentWillReceiveProps(nextProps) {
@ -91,19 +91,19 @@ class InputCheckbox extends React.Component { // eslint-disable-line react/prefe
} }
} }
InputCheckbox.contextTypes = { InputCheckboxPlugin.contextTypes = {
onChange: PropTypes.func.isRequired, onChange: PropTypes.func.isRequired,
resetShouldDisplayPoliciesHint: PropTypes.func.isRequired, resetShouldDisplayPoliciesHint: PropTypes.func.isRequired,
setInputPoliciesPath: PropTypes.func.isRequired, setInputPoliciesPath: PropTypes.func.isRequired,
setShouldDisplayPolicieshint: PropTypes.func.isRequired, setShouldDisplayPolicieshint: PropTypes.func.isRequired,
}; };
InputCheckbox.defaultProps = { InputCheckboxPlugin.defaultProps = {
label: '', label: '',
value: false, value: false,
}; };
InputCheckbox.propTypes = { InputCheckboxPlugin.propTypes = {
inputSelected: PropTypes.string.isRequired, inputSelected: PropTypes.string.isRequired,
isOpen: PropTypes.bool.isRequired, isOpen: PropTypes.bool.isRequired,
label: PropTypes.string, label: PropTypes.string,
@ -112,4 +112,4 @@ InputCheckbox.propTypes = {
value: PropTypes.bool, value: PropTypes.bool,
}; };
export default InputCheckbox; export default InputCheckboxPlugin;

View File

@ -1,6 +1,6 @@
/** /**
* *
* InputSearch * InputSearchContainer
* *
*/ */
@ -10,15 +10,17 @@ import { findIndex, has, includes, isEmpty, map, toLower } from 'lodash';
import cn from 'classnames'; import cn from 'classnames';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import Label from 'components/Label';
import InputSearchLi from 'components/InputSearchLi'; import InputSearchLi from 'components/InputSearchLi';
import styles from './styles.scss'; import styles from './styles.scss';
class InputSearch extends React.Component { // eslint-disable-line react/prefer-stateless-function class InputSearchContainer extends React.Component { // eslint-disable-line react/prefer-stateless-function
state = { state = {
errors: [], errors: [],
filteredUsers: this.props.values, filteredUsers: this.props.values,
isAdding: false, isAdding: false,
isFocused: false,
users: this.props.values, users: this.props.values,
value: '', value: '',
autoFocus: false, autoFocus: false,
@ -38,6 +40,8 @@ class InputSearch extends React.Component { // eslint-disable-line react/prefer-
} }
} }
handleBlur = () => this.setState({ isFocused: !this.state.isFocused });
handleChange = ({ target }) => { handleChange = ({ target }) => {
const filteredUsers = isEmpty(target.value) ? const filteredUsers = isEmpty(target.value) ?
this.state.users this.state.users
@ -54,6 +58,8 @@ class InputSearch extends React.Component { // eslint-disable-line react/prefer-
this.setState({ value: target.value, filteredUsers }); this.setState({ value: target.value, filteredUsers });
} }
handleFocus = () => this.setState({ isFocused: !this.state.isFocused });
handleClick = (item) => { handleClick = (item) => {
if (this.state.isAdding) { if (this.state.isAdding) {
const id = has(item, '_id') ? '_id' : 'id'; const id = has(item, '_id') ? '_id' : 'id';
@ -76,18 +82,18 @@ class InputSearch extends React.Component { // eslint-disable-line react/prefer-
render() { render() {
return ( return (
<div className={cn(styles.inputSearch, 'col-md-6')}> <div className={cn(styles.inputSearch, 'col-md-6')}>
<label htmlFor={this.props.name}> <Label htmlFor={this.props.name} message={this.props.label} />
<FormattedMessage id={this.props.label} values={this.props.labelValues} />
</label>
<div className={cn('input-group')}> <div className={cn('input-group')}>
<span className={cn('input-group-addon', styles.addon)} /> <span className={cn('input-group-addon', styles.addon, this.state.isFocused && styles.addonFocus,)} />
<FormattedMessage id="users-permissions.InputSearch.placeholder"> <FormattedMessage id="users-permissions.InputSearch.placeholder">
{(message) => ( {(message) => (
<input <input
className={cn('form-control', !isEmpty(this.state.errors) ? 'is-invalid': '')} className={cn('form-control', !isEmpty(this.state.errors) ? 'is-invalid': '')}
id={this.props.name} id={this.props.name}
name={this.props.name} name={this.props.name}
onBlur={this.handleBlur}
onChange={this.handleChange} onChange={this.handleChange}
onFocus={this.handleFocus}
value={this.state.value} value={this.state.value}
placeholder={message} placeholder={message}
type="text" type="text"
@ -96,7 +102,7 @@ class InputSearch extends React.Component { // eslint-disable-line react/prefer-
)} )}
</FormattedMessage> </FormattedMessage>
</div> </div>
<div className={styles.ulContainer}> <div className={cn(styles.ulContainer, this.state.isFocused && styles.ulFocused)}>
<ul> <ul>
{map(this.state.filteredUsers, (user) => ( {map(this.state.filteredUsers, (user) => (
<InputSearchLi <InputSearchLi
@ -113,7 +119,7 @@ class InputSearch extends React.Component { // eslint-disable-line react/prefer-
} }
} }
InputSearch.defaultProps = { InputSearchContainer.defaultProps = {
labelValues: { labelValues: {
number: 0, number: 0,
}, },
@ -121,13 +127,15 @@ InputSearch.defaultProps = {
values: [], values: [],
}; };
InputSearch.propTypes = { InputSearchContainer.propTypes = {
didDeleteUser: PropTypes.bool.isRequired, didDeleteUser: PropTypes.bool.isRequired,
didFetchUsers: PropTypes.bool.isRequired, didFetchUsers: PropTypes.bool.isRequired,
didGetUsers: PropTypes.bool.isRequired, didGetUsers: PropTypes.bool.isRequired,
getUser: PropTypes.func.isRequired, getUser: PropTypes.func.isRequired,
label: PropTypes.string.isRequired, label: PropTypes.shape({
labelValues: PropTypes.object, id: PropTypes.string,
params: PropTypes.object,
}).isRequired,
name: PropTypes.string.isRequired, name: PropTypes.string.isRequired,
onClickAdd: PropTypes.func.isRequired, onClickAdd: PropTypes.func.isRequired,
onClickDelete: PropTypes.func.isRequired, onClickDelete: PropTypes.func.isRequired,
@ -135,4 +143,4 @@ InputSearch.propTypes = {
values: PropTypes.array, values: PropTypes.array,
}; };
export default InputSearch; export default InputSearchContainer;

View File

@ -4,6 +4,7 @@
margin-top: .9rem; margin-top: .9rem;
background-color: rgba(16, 22, 34, 0.02); background-color: rgba(16, 22, 34, 0.02);
border: 1px solid #E3E9F3; border: 1px solid #E3E9F3;
border-right: 0;
border-bottom: 0px; border-bottom: 0px;
border-radius: 0.25rem; border-radius: 0.25rem;
border-bottom-left-radius: 0!important; border-bottom-left-radius: 0!important;
@ -46,6 +47,7 @@
padding-left: 1rem; padding-left: 1rem;
background-size: 0 !important; background-size: 0 !important;
border: 1px solid #E3E9F3; border: 1px solid #E3E9F3;
border-left: 0;
border-bottom: 0px; border-bottom: 0px;
border-radius: 0.25rem; border-radius: 0.25rem;
border-bottom-right-radius: 0; border-bottom-right-radius: 0;
@ -72,3 +74,12 @@
padding: 1px 0; padding: 1px 0;
} }
} }
.addonFocus {
border-color: #78caff;
border-right: 0;
}
.ulFocused {
border-color: #78caff;
}

View File

@ -11,7 +11,7 @@ import { FormattedMessage } from 'react-intl';
import { get, isEmpty, map, takeRight, toLower, without } from 'lodash'; import { get, isEmpty, map, takeRight, toLower, without } from 'lodash';
import BoundRoute from 'components/BoundRoute'; import BoundRoute from 'components/BoundRoute';
import Input from 'components/Input'; import Input from 'components/InputsIndex';
import styles from './styles.scss'; import styles from './styles.scss';
@ -36,7 +36,7 @@ class Policies extends React.Component { // eslint-disable-line react/prefer-sta
{!this.props.shouldDisplayPoliciesHint ? ( {!this.props.shouldDisplayPoliciesHint ? (
<Input <Input
customBootstrapClass="col-md-12" customBootstrapClass="col-md-12"
label="users-permissions.Policies.InputSelect.label" label={{ id: 'users-permissions.Policies.InputSelect.label' }}
name={this.props.inputSelectName} name={this.props.inputSelectName}
onChange={this.handleChange} onChange={this.handleChange}
selectOptions={this.props.selectOptions} selectOptions={this.props.selectOptions}

View File

@ -3,7 +3,9 @@
"forgot-password": [ "forgot-password": [
{ {
"customBootstrapClass": "col-md-12", "customBootstrapClass": "col-md-12",
"label": "users-permissions.Auth.form.forgot-password.email.label", "label": {
"id": "users-permissions.Auth.form.forgot-password.email.label"
},
"name": "email", "name": "email",
"type": "email", "type": "email",
"placeholder": "users-permissions.Auth.form.forgot-password.email.placeholder" "placeholder": "users-permissions.Auth.form.forgot-password.email.placeholder"
@ -12,20 +14,26 @@
"login": [ "login": [
{ {
"customBootstrapClass": "col-md-12", "customBootstrapClass": "col-md-12",
"label": "users-permissions.Auth.form.login.username.label", "label": {
"id": "users-permissions.Auth.form.login.username.label"
},
"name": "identifier", "name": "identifier",
"type": "text", "type": "text",
"placeholder": "users-permissions.Auth.form.login.username.placeholder" "placeholder": "users-permissions.Auth.form.login.username.placeholder"
}, },
{ {
"customBootstrapClass": "col-md-12", "customBootstrapClass": "col-md-12",
"label": "users-permissions.Auth.form.login.password.label", "label": {
"id": "users-permissions.Auth.form.login.password.label"
},
"name": "password", "name": "password",
"type": "password" "type": "password"
}, },
{ {
"customBootstrapClass": "col-md-6", "customBootstrapClass": "col-md-6",
"label": "users-permissions.Auth.form.login.rememberMe.label", "label": {
"id": "users-permissions.Auth.form.login.rememberMe.label"
},
"name": "rememberMe", "name": "rememberMe",
"type": "checkbox" "type": "checkbox"
} }
@ -33,26 +41,34 @@
"register": [ "register": [
{ {
"customBootstrapClass": "col-md-12", "customBootstrapClass": "col-md-12",
"label": "users-permissions.Auth.form.register.username.label", "label": {
"id": "users-permissions.Auth.form.register.username.label"
},
"name": "username", "name": "username",
"type": "text", "type": "text",
"placeholder": "users-permissions.Auth.form.register.username.placeholder" "placeholder": "users-permissions.Auth.form.register.username.placeholder"
}, },
{ {
"customBootstrapClass": "col-md-12", "customBootstrapClass": "col-md-12",
"label": "users-permissions.Auth.form.register.password.label", "label": {
"id": "users-permissions.Auth.form.register.password.label"
},
"name": "password", "name": "password",
"type": "password" "type": "password"
}, },
{ {
"customBootstrapClass": "col-md-12", "customBootstrapClass": "col-md-12",
"label": "users-permissions.Auth.form.register.confirmPassword.label", "label": {
"id": "users-permissions.Auth.form.register.confirmPassword.label"
},
"name": "confirmPassword", "name": "confirmPassword",
"type": "password" "type": "password"
}, },
{ {
"customBootstrapClass": "col-md-12", "customBootstrapClass": "col-md-12",
"label": "users-permissions.Auth.form.register.email.label", "label": {
"id": "users-permissions.Auth.form.register.email.label"
},
"name": "email", "name": "email",
"placeholder": "users-permissions.Auth.form.register.email.placeholder", "placeholder": "users-permissions.Auth.form.register.email.placeholder",
"type": "email" "type": "email"
@ -63,7 +79,9 @@
"customBootstrapClass": "col-md-12", "customBootstrapClass": "col-md-12",
"name": "email", "name": "email",
"type": "email", "type": "email",
"label": "users-permissions.Auth.form.register-success.email.label", "label": {
"id": "users-permissions.Auth.form.register-success.email.label"
},
"placeholder": "users-permissions.Auth.form.register-success.email.placeholder" "placeholder": "users-permissions.Auth.form.register-success.email.placeholder"
} }
], ],
@ -72,13 +90,17 @@
"customBootstrapClass": "col-md-12", "customBootstrapClass": "col-md-12",
"name": "password", "name": "password",
"type": "password", "type": "password",
"label": "users-permissions.Auth.form.register.password.label" "label": {
"id": "users-permissions.Auth.form.register.password.label"
}
}, },
{ {
"customBootstrapClass": "col-md-12", "customBootstrapClass": "col-md-12",
"name": "passwordConfirmation", "name": "passwordConfirmation",
"type": "password", "type": "password",
"label": "users-permissions.Auth.form.register.confirmPassword.label" "label": {
"id": "users-permissions.Auth.form.register.confirmPassword.label"
}
} }
] ]
} }

View File

@ -18,7 +18,7 @@ import LogoStrapi from 'assets/images/logo_strapi.png';
// Design // Design
import Button from 'components/Button'; import Button from 'components/Button';
import Input from 'components/Input'; import Input from 'components/InputsIndex';
// Utils // Utils
import injectSaga from 'utils/injectSaga'; import injectSaga from 'utils/injectSaga';
@ -173,7 +173,7 @@ export class AuthPage extends React.Component { // eslint-disable-line react/pre
didCheckErrors={this.props.didCheckErrors} didCheckErrors={this.props.didCheckErrors}
errors={get(this.props.formErrors, [findIndex(this.props.formErrors, ['name', input.name]), 'errors'])} errors={get(this.props.formErrors, [findIndex(this.props.formErrors, ['name', input.name]), 'errors'])}
key={get(input, 'name')} key={get(input, 'name')}
label={this.props.match.params.authType === 'forgot-password' && this.props.submitSuccess? 'users-permissions.Auth.form.forgot-password.email.label.success' : get(input, 'label')} label={this.props.match.params.authType === 'forgot-password' && this.props.submitSuccess? { id: 'users-permissions.Auth.form.forgot-password.email.label.success' } : get(input, 'label')}
name={get(input, 'name')} name={get(input, 'name')}
onChange={this.props.onChangeInput} onChange={this.props.onChangeInput}
placeholder={get(input, 'placeholder')} placeholder={get(input, 'placeholder')}

View File

@ -15,8 +15,8 @@ import cn from 'classnames';
// Design // Design
import BackHeader from 'components/BackHeader'; import BackHeader from 'components/BackHeader';
import Input from 'components/Input'; import Input from 'components/InputsIndex';
import InputSearch from 'components/InputSearch'; import InputSearch from 'components/InputSearchContainer';
import PluginHeader from 'components/PluginHeader'; import PluginHeader from 'components/PluginHeader';
import Plugins from 'components/Plugins'; import Plugins from 'components/Plugins';
import Policies from 'components/Policies'; import Policies from 'components/Policies';
@ -159,7 +159,7 @@ export class EditPage extends React.Component { // eslint-disable-line react/pre
customBootstrapClass="col-md-12" customBootstrapClass="col-md-12"
errors={get(this.props.editPage, ['formErrors', findIndex(this.props.editPage.formErrors, ['name', 'name']), 'errors'])} errors={get(this.props.editPage, ['formErrors', findIndex(this.props.editPage.formErrors, ['name', 'name']), 'errors'])}
didCheckErrors={this.props.editPage.didCheckErrors} didCheckErrors={this.props.editPage.didCheckErrors}
label="users-permissions.EditPage.form.roles.label.name" label={{ id: 'users-permissions.EditPage.form.roles.label.name' }}
name="name" name="name"
onChange={this.props.onChangeInput} onChange={this.props.onChangeInput}
type="text" type="text"
@ -170,7 +170,7 @@ export class EditPage extends React.Component { // eslint-disable-line react/pre
<div className="row"> <div className="row">
<Input <Input
customBootstrapClass="col-md-12" customBootstrapClass="col-md-12"
label="users-permissions.EditPage.form.roles.label.description" label={{ id: 'users-permissions.EditPage.form.roles.label.description' }}
name="description" name="description"
onChange={this.props.onChangeInput} onChange={this.props.onChangeInput}
type="textarea" type="textarea"
@ -185,8 +185,12 @@ export class EditPage extends React.Component { // eslint-disable-line react/pre
didFetchUsers={this.props.editPage.didFetchUsers} didFetchUsers={this.props.editPage.didFetchUsers}
didGetUsers={this.props.editPage.didGetUsers} didGetUsers={this.props.editPage.didGetUsers}
getUser={this.props.getUser} getUser={this.props.getUser}
label="users-permissions.EditPage.form.roles.label.users" label={{
labelValues={{ number: size(get(this.props.editPage, ['modifiedData', 'users'])) }} id: 'users-permissions.EditPage.form.roles.label.users',
params: {
number: size(get(this.props.editPage, ['modifiedData', 'users'])),
},
}}
onClickAdd={this.props.onClickAdd} onClickAdd={this.props.onClickAdd}
onClickDelete={this.props.onClickDelete} onClickDelete={this.props.onClickDelete}
name="users" name="users"