diff --git a/packages/strapi-helper-plugin/lib/src/components/InputNumber/index.js b/packages/strapi-helper-plugin/lib/src/components/InputNumber/index.js
index 8a457abaa4..e1c93ae06e 100644
--- a/packages/strapi-helper-plugin/lib/src/components/InputNumber/index.js
+++ b/packages/strapi-helper-plugin/lib/src/components/InputNumber/index.js
@@ -61,7 +61,10 @@ InputNumber.propTypes = {
placeholder: PropTypes.string,
style: PropTypes.object,
tabIndex: PropTypes.string,
- value: PropTypes.string.isRequired,
+ value: PropTypes.oneOfType([
+ PropTypes.number,
+ PropTypes.string,
+ ]).isRequired,
};
export default InputNumber;
diff --git a/packages/strapi-helper-plugin/lib/src/components/InputNumberWithErrors/index.js b/packages/strapi-helper-plugin/lib/src/components/InputNumberWithErrors/index.js
new file mode 100644
index 0000000000..a677f0d74c
--- /dev/null
+++ b/packages/strapi-helper-plugin/lib/src/components/InputNumberWithErrors/index.js
@@ -0,0 +1,164 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+import { includes, isEmpty, isFunction, mapKeys, reject } from 'lodash';
+import cn from 'classnames';
+
+// Design
+import Label from 'components/Label';
+import InputDescription from 'components/InputDescription';
+import InputErrors from 'components/InputErrors';
+import InputNumber from 'components/InputNumber';
+
+import styles from './styles.scss';
+
+class InputNumberWithErrors extends React.Component { // eslint-disable-line react/prefer-stateless-function
+ state = { errors: [], hasInitialValue: false };
+
+ componentDidMount() {
+ const { value, errors } = this.props;
+
+ // Prevent the input from displaying an error when the user enters and leaves without filling it
+ if (value && !isEmpty(value)) {
+ this.setState({ hasInitialValue: true });
+ }
+
+ // Display input error if it already has some
+ if (!isEmpty(errors)) {
+ this.setState({ errors });
+ }
+ }
+
+ componentWillReceiveProps(nextProps) {
+ // Check if errors have been updated during validations
+ if (nextProps.didCheckErrors !== this.props.didCheckErrors) {
+ // Remove from the state the errors that have already been set
+ const errors = isEmpty(nextProps.errors) ? [] : nextProps.errors;
+ this.setState({ errors });
+ }
+ }
+
+ /**
+ * Set the errors depending on the validations given to the input
+ * @param {Object} target
+ */
+ handleBlur = ({ target }) => {
+ // Prevent from displaying error if the input is initially isEmpty
+ if (!isEmpty(target.value) || this.state.hasInitialValue) {
+ const errors = this.validate(target.value);
+ this.setState({ errors, hasInitialValue: true });
+ }
+ }
+
+ render() {
+ const { autoFocus, errorsClassName, errorsStyle, inputClassName, inputStyle, name, onChange, onFocus, placeholder, value } = this.props;
+ const handleBlur = isFunction(this.props.onBlur) ? this.props.onBlur : this.handleBlur;
+
+ return (
+
+
+
+
+
+
+ );
+ }
+
+ 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) {
+ console.log('ok');
+ 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 = {
+ customBootstrapClass: false,
+ didCheckErrors: false,
+ onBlur: false,
+ onFocus: () => {},
+ errors: [],
+ errorsClassName: '',
+ errorsStyle: {},
+ inputClassName: '',
+ inputStyle: {},
+ placeholder: 'app.utils.placeholder.defaultMessage',
+ validations: {},
+};
+
+InputNumberWithErrors.propTypes = {
+ customBootstrapClass: PropTypes.oneOfType([
+ PropTypes.bool,
+ PropTypes.string,
+ ]),
+ didCheckErrors: PropTypes.bool,
+ errors: PropTypes.array,
+ errorsClassName: PropTypes.string,
+ errorsStyle: PropTypes.object,
+ inputClassName: PropTypes.string,
+ inputStyle: PropTypes.object,
+ onBlur: PropTypes.oneOfType([
+ PropTypes.bool,
+ PropTypes.func,
+ ]),
+ onChange: PropTypes.func.isRequired,
+ onFocus: PropTypes.func,
+ validations: PropTypes.object,
+ value: PropTypes.oneOfType([
+ PropTypes.number,
+ PropTypes.string,
+ ]),
+};
+
+export default InputNumberWithErrors;
diff --git a/packages/strapi-helper-plugin/lib/src/components/InputNumberWithErrors/styles.scss b/packages/strapi-helper-plugin/lib/src/components/InputNumberWithErrors/styles.scss
new file mode 100644
index 0000000000..5d8578e7d5
--- /dev/null
+++ b/packages/strapi-helper-plugin/lib/src/components/InputNumberWithErrors/styles.scss
@@ -0,0 +1,5 @@
+.container {
+ min-width: 200px;
+ margin-bottom: 1.5rem;
+ font-size: 1.3rem;
+}
diff --git a/packages/strapi-helper-plugin/lib/src/components/InputTextWithErrors/index.js b/packages/strapi-helper-plugin/lib/src/components/InputTextWithErrors/index.js
index ccdb9cc6da..035488f249 100644
--- a/packages/strapi-helper-plugin/lib/src/components/InputTextWithErrors/index.js
+++ b/packages/strapi-helper-plugin/lib/src/components/InputTextWithErrors/index.js
@@ -103,6 +103,12 @@ class InputTextWithErrors extends React.Component { // eslint-disable-line react
}
break;
}
+ case 'regex': {
+ if (!new RegExp(validationValue).test(value)) {
+ errors.push({ id: 'components.Input.error.validation.regex' });
+ }
+ break;
+ }
default:
errors = [];
}