/**
*
* Input
*
*/
import React from 'react';
import moment from 'moment';
import PropTypes from 'prop-types';
import { get, isEmpty, map, mapKeys, isObject, reject, includes } from 'lodash';
import { FormattedMessage } from 'react-intl';
import DateTime from 'react-datetime';
import DateTimeStyle from 'react-datetime/css/react-datetime.css';
import styles from './styles.scss';
class Input extends React.Component { // eslint-disable-line react/prefer-stateless-function
constructor(props) {
super(props);
this.state = {
errors: [],
hasInitialValue: false,
showPassword: false,
isFocus: false,
};
}
componentDidMount() {
if (this.props.value && !isEmpty(this.props.value)) {
this.setState({ hasInitialValue: true });
}
if (!isEmpty(this.props.errors)) {
this.setState({ errors: this.props.errors });
}
}
componentWillReceiveProps(nextProps) {
// Check if errors have been updated during validations
if (this.props.didCheckErrors !== nextProps.didCheckErrors) {
// Remove from the state errors that are already set
const errors = isEmpty(nextProps.errors) ? [] : nextProps.errors;
this.setState({ errors });
}
}
handleBlur = ({ target }) => {
// prevent error display if input is initially empty
if (!isEmpty(target.value) || this.state.hasInitialValue) {
// validates basic string validations
// add custom logic here such as alerts...
const errors = this.validate(target.value);
this.setState({ errors, hasInitialValue: true });
}
}
handleChangeCheckbox = (e) => {
const target = {
type: 'checkbox',
value: !this.props.value,
name: this.props.name,
};
this.props.onChange({ target });
}
handleBlurEmail = (e) => {
this.setState({ isFocus: !this.state.isFocus });
if (this.props.handleBlur) {
this.props.handleBlur(e);
} else {
this.handleBlur(e);
}
}
handleFocusEmail = (e) => {
this.setState({ isFocus: !this.state.isFocus });
if (this.props.onFocus) {
this.props.onFocus(e);
}
}
handleToggle = (e) => {
const target = {
type: 'toggle',
name: this.props.name,
value: e.target.id === 'on',
}
this.props.onChange({ target });
}
handleShowPassword = () => this.setState({ showPassword: !this.state.showPassword });
renderErrors = (errorStyles) => { // eslint-disable-line consistent-return
if (!this.props.noErrorsDescription) {
const divStyle = errorStyles || styles.errorContainer;
return (
map(this.state.errors, (error, key) => {
const displayError = isObject(error) && error.id
?
: error;
return (
{displayError}
);
})
);
}
}
renderInputCheckbox = (requiredClass, inputDescription) => {
const title = !isEmpty(this.props.title) ?
: '';
const spacer = !inputDescription ? : ;
return (
)
}
renderInputDate = (requiredClass, inputDescription) => {
let spacer = !isEmpty(this.props.inputDescription) ? : ;
if (!this.props.noErrorsDescription && !isEmpty(this.state.errors)) {
spacer = ;
}
const value = isObject(this.props.value) && this.props.value._isAMomentObject === true ?
this.props.value :
moment(this.props.value);
return (
this.props.onChange({ target: {
name: this.props.name,
value: moment
}})}
/>
{inputDescription}
{this.renderErrors(styles.errorContainerTextArea)}
{spacer}
)
}
renderInputEmail = (requiredClass, inputDescription, handleBlur) => {
let spacer = !isEmpty(this.props.inputDescription) ? : ;
if (!this.props.noErrorsDescription && !isEmpty(this.state.errors)) {
spacer = ;
}
return (
{(placeholder) => (
)}
{inputDescription}
{this.renderErrors()}
{spacer}
)
}
renderFormattedInput = (handleBlur, inputValue, placeholder) => (
{(message) => (
)}
)
renderInputPassword = (requiredClass, inputDescription, handleBlur) => {
let spacer = !isEmpty(this.props.inputDescription) ? : ;
if (!this.props.noErrorsDescription && !isEmpty(this.state.errors)) {
spacer = ;
}
const color = this.state.showPassword ? { color: 'black' } : { color: '#9EA7B8' };
const type = this.state.showPassword ? 'text' : 'password';
return (
{(placeholder) => (
)}
{inputDescription}
{this.renderErrors()}
{spacer}
);
}
renderInputSelect = (requiredClass, inputDescription, handleBlur) => {
let spacer = !isEmpty(this.props.inputDescription) ? : ;
if (!this.props.noErrorsDescription && !isEmpty(this.state.errors)) {
spacer = ;
}
return (
{inputDescription}
{this.renderErrors()}
{spacer}
);
}
renderInputSearch = (requiredClass, inputDescription, handleBlur) => {
let spacer = !isEmpty(this.props.inputDescription) ? : ;
if (!this.props.noErrorsDescription && !isEmpty(this.state.errors)) {
spacer = ;
}
return (
{(placeholder) => (
)}
{inputDescription}
{this.renderErrors()}
{spacer}
);
}
renderInputTextArea = (requiredClass, inputDescription, handleBlur) => {
let spacer = !isEmpty(this.props.inputDescription) ? : ;
if (!this.props.noErrorsDescription && !isEmpty(this.state.errors)) {
spacer = ;
}
return (
{(placeholder) => (
)}
{inputDescription}
{this.renderErrors(styles.errorContainerTextArea)}
{spacer}
)
}
renderInputToggle = () => {
const btnClassOff = this.props.value ? 'btn' : `btn ${styles.gradientOff}`;
const btnClassOn = this.props.value ? `btn ${styles.gradientOn}` : 'btn';
const spacer = this.props.inputDescription ? : ;
const inputDescription = this.props.inputDescription ?
: '';
return (
{inputDescription}
{spacer}
);
}
render() {
const inputValue = this.props.value || '';
// override default onBlur
const handleBlur = this.props.onBlur || this.handleBlur;
const placeholder = this.props.placeholder || this.props.label;
const label = this.props.label ?
: ;
const requiredClass = get(this.props.validations, 'required') && this.props.addRequiredInputDesign ?
styles.requiredClass : '';
const input = placeholder ? this.renderFormattedInput(handleBlur, inputValue, placeholder)
: ;
const link = !isEmpty(this.props.linkContent) ? : '';
let inputDescription = !isEmpty(this.props.inputDescription) ? : '';
if (!isEmpty(this.props.linkContent) && !isEmpty(this.props.inputDescription)) {
inputDescription = }} />;
}
let spacer = !isEmpty(this.props.inputDescription) ? : ;
if (!this.props.noErrorsDescription && !isEmpty(this.state.errors)) {
spacer = ;
}
if (this.props.search) {
return this.renderInputSearch(requiredClass, inputDescription, handleBlur);
}
switch (this.props.type) {
case 'select':
return this.renderInputSelect(requiredClass, inputDescription, handleBlur);
case 'textarea':
return this.renderInputTextArea(requiredClass, inputDescription, handleBlur);
case 'checkbox':
return this.renderInputCheckbox(requiredClass, inputDescription);
case 'date':
return this.renderInputDate(requiredClass, inputDescription);
case 'password':
return this.renderInputPassword(requiredClass, inputDescription, handleBlur);
case 'toggle':
return this.renderInputToggle();
case 'email':
return this.renderInputEmail(requiredClass, inputDescription, handleBlur);
case 'search':
return this.renderInputSearch(requiredClass, inputDescription, handleBlur)
default:
}
const addonInput = this.props.addon ?
{input}
: input;
return (
{label}
{addonInput}
{inputDescription}
{this.renderErrors()}
{spacer}
);
}
validate = (value) => {
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(this.props.validations, (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 (this.props.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;
}
}
Input.propTypes = {
addon: PropTypes.oneOfType([
PropTypes.bool,
PropTypes.string,
]),
addRequiredInputDesign: PropTypes.bool,
autoFocus: PropTypes.bool,
customBootstrapClass: PropTypes.string,
deactivateErrorHighlight: PropTypes.bool,
didCheckErrors: PropTypes.bool,
disabled: PropTypes.bool,
errors: PropTypes.array,
inputDescription: PropTypes.string,
label: PropTypes.string.isRequired,
labelValues: PropTypes.object,
linkContent: PropTypes.shape({
link: PropTypes.string,
description: PropTypes.string,
}),
name: PropTypes.string.isRequired,
noErrorsDescription: PropTypes.bool,
onBlur: PropTypes.oneOfType([
PropTypes.bool,
PropTypes.func,
]),
onChange: PropTypes.func.isRequired,
onFocus: PropTypes.oneOfType([
PropTypes.bool,
PropTypes.func,
]),
placeholder: PropTypes.string,
search: PropTypes.bool,
selectOptions: PropTypes.array,
selectOptionsFetchSucceeded: PropTypes.bool,
title: PropTypes.string,
type: PropTypes.string.isRequired,
validations: PropTypes.object.isRequired,
value: PropTypes.oneOfType([
PropTypes.string,
PropTypes.bool,
PropTypes.number,
]),
};
Input.defaultProps = {
addon: false,
addRequiredInputDesign: false,
autoFocus: false,
deactivateErrorHighlight: false,
didCheckErrors: false,
disabled: false,
errors: [],
inputDescription: '',
labelValues: {},
linkContent: {},
noErrorsDescription: false,
onBlur: false,
onFocus: () => {},
placeholder: '',
search: false,
selectOptions: [],
selectOptionsFetchSucceeded: false,
value: ''
};
export default Input;