209 lines
7.2 KiB
JavaScript
Raw Normal View History

2017-07-10 16:34:12 +02:00
/**
*
* InputText
2017-07-11 12:29:43 +02:00
* Customization
* - deactivateErrorHighlight: bool
* allow the user to remove bootstrap class 'has-danger' on the inputText
* - customBootstrapClass : string
* overrides the default 'col-md-6' on the inputText
* - handleBlur: function
* overrides the default input validations
* - errors : array
2017-07-13 16:13:31 +02:00
* - noErrorsDescription : bool
2017-07-19 09:51:23 +02:00
* prevent from displaying errors messages
2017-07-10 16:34:12 +02:00
*
2017-07-11 12:29:43 +02:00
* Required
* - name : string
* - handleChange : function
* - value : string
2017-07-18 17:52:39 +02:00
* - target : string
2017-07-19 09:51:23 +02:00
* - validations : object
2017-07-11 12:29:43 +02:00
*
* Optionnal
* - description : input description
* - handleFocus : function
* - placeholder : string if set to "" nothing will display
2017-08-01 16:47:05 +02:00
*
* - styles are retrieved from the HOC
2017-07-10 16:34:12 +02:00
*/
import PropTypes from 'prop-types';
import { isEmpty, includes, mapKeys, reject, map, isObject, union, findIndex, uniqBy, remove } from 'lodash';
2017-07-13 16:55:59 +02:00
import { FormattedMessage } from 'react-intl';
import WithInput from 'components/WithInput';
2017-07-10 16:34:12 +02:00
class InputText extends React.Component { // eslint-disable-line react/prefer-stateless-function
constructor(props) {
super(props);
this.state = {
2017-07-13 16:13:31 +02:00
errors: [],
2017-07-11 12:29:43 +02:00
hasInitialValue: false,
2017-07-10 16:34:12 +02:00
};
}
2017-07-11 12:29:43 +02:00
componentDidMount() {
2017-07-13 15:24:21 +02:00
if (this.props.value && !isEmpty(this.props.value)) {
2017-07-11 12:29:43 +02:00
this.setState({ hasInitialValue: true });
}
}
2017-07-10 16:34:12 +02:00
componentWillReceiveProps(nextProps) {
if (this.props.errors !== nextProps.errors) {
2017-08-21 15:05:02 +02:00
const errors = uniqBy(union(this.state.errors, nextProps.errors), 'id');
if (isEmpty(nextProps.errors)) remove(errors, (error) => error.id === 'settings-manager.request.error.database.exist');
2017-08-21 15:05:02 +02:00
this.setState({ errors });
2017-07-10 16:34:12 +02:00
}
}
handleBlur = ({ target }) => {
2017-07-11 12:29:43 +02:00
// prevent error display if input is initially empty
2017-07-13 17:18:06 +02:00
if (!isEmpty(target.value) || this.state.hasInitialValue) {
2017-07-11 12:29:43 +02:00
// validates basic string validations
// add custom logic here such as alerts...
2017-08-21 15:05:02 +02:00
// specific check for db
const indexErrorDbExist = findIndex(this.props.errors, ['id', 'settings-manager.request.error.database.exist']);
const errors = indexErrorDbExist !== -1 ?
uniqBy(union(this.props.errors, this.validate(target.value)), 'id') : this.validate(target.value);
this.setState({ errors, hasInitialValue: true });
2017-07-11 12:29:43 +02:00
}
2017-07-10 16:34:12 +02:00
}
// Basic string validations
validate = (value) => {
let errors = [];
2017-07-13 16:55:59 +02:00
// handle i18n
2017-08-17 11:26:01 +02:00
const requiredError = { id: 'settings-manager.request.error.validation.required' };
2017-07-12 18:12:07 +02:00
mapKeys(this.props.validations, (validationValue, validationKey) => {
switch (validationKey) {
case 'maxLength':
if (value.length > validationValue) {
2017-08-17 11:26:01 +02:00
errors.push({ id: 'settings-manager.request.error.validation.maxLength' });
}
break;
case 'minLength':
if (value.length < validationValue) {
2017-08-17 11:26:01 +02:00
errors.push({ id: 'settings-manager.request.error.validation.minLength' });
}
break;
case 'required':
if (value.length === 0) {
2017-08-17 11:26:01 +02:00
errors.push({ id: 'settings-manager.request.error.validation.required' });
}
break;
case 'regex':
if (!new RegExp(validationValue).test(value)) {
2017-08-17 11:26:01 +02:00
errors.push({ id: 'settings-manager.request.error.validation.regex' });
}
break;
default:
2017-07-13 16:13:31 +02:00
errors = [];
}
2017-07-10 16:34:12 +02:00
});
2017-07-13 16:13:31 +02:00
if (includes(errors, requiredError)) {
2017-07-12 18:12:07 +02:00
errors = reject(errors, (error) => error !== requiredError);
2017-07-10 16:34:12 +02:00
}
return errors;
}
2017-07-13 16:55:59 +02:00
renderErrors = () => { // eslint-disable-line consistent-return
2017-07-13 16:13:31 +02:00
if (!this.props.noErrorsDescription) {
return (
2017-07-13 16:55:59 +02:00
map(this.state.errors, (error, key) => {
2017-08-17 11:26:01 +02:00
const displayError = isObject(error) && error.id
? <FormattedMessage {...error} />
: error;
2017-07-13 16:55:59 +02:00
return (
2017-08-22 18:11:06 +02:00
<div key={key} className="form-control-feedback" style={{marginBottom: '1.8rem'}}>{displayError}</div>
2017-07-13 16:55:59 +02:00
);
})
2017-07-13 16:13:31 +02:00
);
}
}
2017-08-22 18:11:06 +02:00
renderFormattedInput = (handleBlur, inputValue, placeholder, marginBottom) => (
<FormattedMessage id={`settings-manager.${placeholder}`}>
2017-08-07 15:23:25 +02:00
{(message) => (
<input
name={this.props.target}
id={this.props.name}
onBlur={handleBlur}
onFocus={this.props.handleFocus}
onChange={this.props.handleChange}
value={inputValue}
type="text"
className={`form-control ${this.state.errors? 'form-control-danger' : ''}`}
placeholder={message}
2017-08-11 10:48:50 +02:00
autoComplete="off"
2017-08-22 18:11:06 +02:00
style={{marginBottom}}
2017-08-07 15:23:25 +02:00
/>
)}
</FormattedMessage>
)
2017-07-10 16:34:12 +02:00
render() {
const inputValue = this.props.value || '';
// override default onBlur
const handleBlur = this.props.handleBlur || this.handleBlur;
// override bootStrapClass
2017-07-11 12:29:43 +02:00
const bootStrapClass = this.props.customBootstrapClass ? this.props.customBootstrapClass : 'col-md-6';
2017-07-10 16:34:12 +02:00
// set error class with override possibility
2017-07-13 16:13:31 +02:00
const bootStrapClassDanger = !this.props.deactivateErrorHighlight && !isEmpty(this.state.errors) ? 'has-danger' : '';
const placeholder = this.props.placeholder || this.props.name;
const label = this.props.name ? <label htmlFor={this.props.name}><FormattedMessage id={`settings-manager.${this.props.name}`} /></label> : '';
2017-08-10 20:41:40 +02:00
const spacer = !this.props.name ? {marginTop: '2.4rem'} : {marginTop: ''};
const marginBottomInput = isEmpty(this.state.errors) ? '4.3rem' : '2.4rem';
2017-08-18 17:02:33 +02:00
const input = placeholder
2017-09-08 14:48:06 +02:00
? this.renderFormattedInput(handleBlur, inputValue, placeholder, marginBottomInput)
2017-08-18 17:02:33 +02:00
: (
<input
name={this.props.target}
id={this.props.name}
onBlur={handleBlur}
onFocus={this.props.handleFocus}
onChange={this.props.handleChange}
value={inputValue}
type="text"
className={`form-control ${this.state.errors? 'form-control-danger' : ''}`}
placeholder={placeholder}
2017-09-08 14:48:06 +02:00
style={{marginBottom: marginBottomInput }}
2017-08-18 17:02:33 +02:00
/>
);
2017-08-07 15:23:25 +02:00
2017-08-09 09:52:00 +02:00
const requiredClass = this.props.validations.required && this.props.addRequiredInputDesign ? this.props.styles.requiredClass : '';
2017-08-22 18:11:06 +02:00
let marginTopSmall = this.props.inputDescription ? '-3rem' : '-1.5rem';
if (!isEmpty(this.state.errors) && this.props.inputDescription) marginTopSmall = '-1.2rem';
2017-07-10 16:34:12 +02:00
return (
2017-08-09 19:47:39 +02:00
<div className={`${this.props.styles.inputText} ${bootStrapClass} ${requiredClass} ${bootStrapClassDanger}`} style={spacer}>
2017-08-07 14:03:22 +02:00
{label}
2017-08-07 15:23:25 +02:00
{input}
2017-08-22 18:11:06 +02:00
<small style={{ marginTop: marginTopSmall }}>{this.props.inputDescription}</small>
2017-07-13 16:13:31 +02:00
{this.renderErrors()}
2017-07-10 16:34:12 +02:00
</div>
);
}
}
InputText.propTypes = {
addRequiredInputDesign: PropTypes.bool,
customBootstrapClass: PropTypes.string,
deactivateErrorHighlight: PropTypes.bool,
errors: PropTypes.array,
handleBlur: PropTypes.func,
handleChange: PropTypes.func.isRequired,
handleFocus: PropTypes.func,
inputDescription: PropTypes.string,
name: PropTypes.string.isRequired,
noErrorsDescription: PropTypes.bool,
placeholder: PropTypes.string,
styles: PropTypes.object,
target: PropTypes.string.isRequired,
validations: PropTypes.object.isRequired,
2017-09-26 11:29:16 +02:00
value: PropTypes.string,
2017-07-10 16:34:12 +02:00
}
export default WithInput(InputText); // eslint-disable-line new-cap