MetaPhase-Consulting/State-TalentMAP

View on GitHub
src/Components/TextInput/TextInput.jsx

Summary

Maintainability
A
0 mins
Test Coverage
A
100%
import { useEffect, useState } from 'react';
import PropTypes from 'prop-types';
import { get } from 'lodash';
import { usePrevious } from 'hooks';

const TextInput = props => {
  const [input, setInput] = useState(props.value || '');

  const changeText = e => {
    setInput(get(e, 'target.value'));
  };

  const prevInput = usePrevious(input);

  useEffect(() => {
    const shouldUpdate = (input || prevInput) && input !== prevInput;
    if (shouldUpdate) {
      props.changeText(input);
    }
  }, [input]);

  useEffect(() => {
    const shouldUpdate = props.value !== input;
    if (shouldUpdate) {
      changeText({ target: { value: props.value } });
    }
  }, [props.value]);

  const { id, labelSrOnly, type, label, labelMessage, placeholder, inputProps,
    containerProps, customContainerClass, disabled } = props;
  let labelClass;
  // set the input class based on "type" prop
  let inputClass;
  // set the parent div class based on "type" prop
  let parentClass;
  // check the "type" prop
  switch (type) {
    case 'error':
      labelClass = 'usa-input-error-message';
      inputClass = 'input-error';
      parentClass = 'usa-input-error';
      break;
    case 'success':
      inputClass = 'usa-input-success';
      break;
    case 'focus':
      inputClass = 'usa-input-focus';
      break;
    default:
      inputClass = '';
      parentClass = '';
  }
  // set an optional message
  const message = labelMessage.length ?
    (
      <span className={labelClass} id={`${id}-input-error-message`} role="alert">
        {labelMessage}
      </span>
    ) :
    null;

  return (
    <div className={`usa-grid-full ${parentClass} ${customContainerClass}`} {...containerProps}>
      <label htmlFor={id} className={labelSrOnly ? 'usa-sr-only' : ''}>{label}</label>
      <input
        id={id}
        disabled={disabled}
        name="input-type-text"
        type="text"
        value={input}
        onChange={changeText}
        className={inputClass}
        placeholder={placeholder}
        {...inputProps}
      />
      {message}
    </div>
  );
};

TextInput.propTypes = {
  id: PropTypes.string.isRequired,
  labelSrOnly: PropTypes.bool,
  disabled: PropTypes.bool,
  changeText: PropTypes.func,
  type: PropTypes.oneOf(['success', 'error', 'focus']),
  label: PropTypes.string,
  labelMessage: PropTypes.string,
  value: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
  placeholder: PropTypes.string,
  inputProps: PropTypes.shape({}),
  containerProps: PropTypes.shape({}),
  customContainerClass: PropTypes.string,
};

TextInput.defaultProps = {
  labelSrOnly: false,
  disabled: false,
  changeText: () => {},
  type: undefined,
  label: '',
  labelMessage: '',
  value: null,
  placeholder: '',
  inputProps: {},
  containerProps: {},
  customContainerClass: '',
};

export default TextInput;