Next.js template
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

BaseInputField.js 4.7KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187
  1. import { ErrorMessage } from 'formik';
  2. import PropTypes from 'prop-types';
  3. import React, { useEffect, useRef, useState } from 'react';
  4. import { ReactComponent as CapsLock } from '../../../assets/images/svg/caps-lock.svg';
  5. import { ReactComponent as EyeOff } from '../../../assets/images/svg/eye-off.svg';
  6. import { ReactComponent as EyeOn } from '../../../assets/images/svg/eye-on.svg';
  7. import { ReactComponent as Search } from '../../../assets/images/svg/search.svg';
  8. import IconButton from '../IconButton/IconButton';
  9. const BaseInputField = ({
  10. type,
  11. label,
  12. field,
  13. form,
  14. placeholder,
  15. clearPlaceholderOnFocus = true,
  16. isSearch,
  17. className,
  18. disabled,
  19. centerText,
  20. link,
  21. errorMessage,
  22. autoFocus,
  23. isCapsLockOn,
  24. ...props
  25. }) => {
  26. const [inputPlaceholder, setPlaceholder] = useState(placeholder);
  27. const inputField = useRef(null);
  28. useEffect(() => {
  29. if (autoFocus) {
  30. inputField.current.focus();
  31. }
  32. }, [autoFocus, inputField]);
  33. useEffect(() => {
  34. if (errorMessage) {
  35. form.setFieldError(field.name, errorMessage);
  36. }
  37. }, [errorMessage]); // eslint-disable-line
  38. useEffect(() => {
  39. setPlaceholder(placeholder);
  40. }, [placeholder]);
  41. const [inputType, setInputType] = useState('password');
  42. const passwordInput = type === 'password' ? ' c-input--password' : '';
  43. const showPassword = () => {
  44. if (inputType === 'password') {
  45. setInputType('text');
  46. } else {
  47. setInputType('password');
  48. }
  49. };
  50. // Nester Formik Field Names get bugged because of Undefined values, so i had to fix it like this
  51. // If you ask why 0 and 1? I dont see a need for forms to be nested more then 2 levels?
  52. const fieldName = field.name.split('.');
  53. const formError =
  54. fieldName[0] && fieldName[1]
  55. ? form.errors[fieldName[0]] && form.errors[fieldName[0]][fieldName[1]]
  56. : form.errors[fieldName[0]];
  57. const formTouched =
  58. fieldName[0] && fieldName[1]
  59. ? form.touched[fieldName[0]] && form.touched[fieldName[0]][fieldName[1]]
  60. : form.touched[fieldName[0]];
  61. function styles() {
  62. let style = 'c-input';
  63. if (formError && formTouched) {
  64. style += ` c-input--error`;
  65. }
  66. if (type === 'password') {
  67. style += ` c-input--password`;
  68. }
  69. if (isSearch) {
  70. style += ` c-input--search`;
  71. }
  72. if (centerText) {
  73. style += ` c-input--center-text`;
  74. }
  75. if (type === 'number') {
  76. style += ` c-input--demi-bold`;
  77. }
  78. if (className) {
  79. style += ` ${className}`;
  80. }
  81. return style;
  82. }
  83. const additionalActions = () => {
  84. if (!clearPlaceholderOnFocus) {
  85. return null;
  86. }
  87. return {
  88. onFocus: () => {
  89. setPlaceholder('');
  90. },
  91. onBlur: (e) => {
  92. setPlaceholder(placeholder);
  93. field.onBlur(e);
  94. },
  95. };
  96. };
  97. return (
  98. <div className={styles()}>
  99. {!!label && (
  100. <label className="c-input__label" htmlFor={field.name}>
  101. {label}
  102. </label>
  103. )}
  104. {link && <div className="c-input__link">{link}</div>}
  105. <div className="c-input__field-wrap">
  106. <input
  107. ref={inputField}
  108. type={type === 'password' ? inputType : type}
  109. placeholder={inputPlaceholder}
  110. disabled={disabled}
  111. {...field}
  112. {...props}
  113. {...additionalActions()}
  114. className="c-input__field"
  115. />
  116. {!!isSearch && <Search className="c-input__icon" />}
  117. {!!passwordInput && (
  118. <>
  119. {isCapsLockOn && <CapsLock className="c-input__caps-lock" />}
  120. <IconButton
  121. onClick={() => {
  122. showPassword();
  123. }}
  124. className="c-input__icon"
  125. >
  126. {inputType === 'password' ? <EyeOff /> : <EyeOn />}
  127. </IconButton>
  128. </>
  129. )}
  130. </div>
  131. <ErrorMessage name={field.name}>
  132. {(errorMessage) => (
  133. <span className="c-input__error">{errorMessage}</span>
  134. )}
  135. </ErrorMessage>
  136. </div>
  137. );
  138. };
  139. BaseInputField.propTypes = {
  140. type: PropTypes.string,
  141. field: PropTypes.shape({
  142. name: PropTypes.string,
  143. onFocus: PropTypes.func,
  144. onBlur: PropTypes.func,
  145. }),
  146. form: PropTypes.shape({
  147. errors: PropTypes.shape({}),
  148. setFieldError: PropTypes.func,
  149. touched: PropTypes.shape({}),
  150. }),
  151. label: PropTypes.oneOfType([PropTypes.string, PropTypes.shape({})]),
  152. placeholder: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
  153. disabled: PropTypes.bool,
  154. isSearch: PropTypes.bool,
  155. className: PropTypes.string,
  156. link: PropTypes.node,
  157. errorMessage: PropTypes.string,
  158. centerText: PropTypes.bool,
  159. clearPlaceholderOnFocus: PropTypes.bool,
  160. demiBold: PropTypes.bool,
  161. touched: PropTypes.bool,
  162. autoFocus: PropTypes.bool,
  163. isCapsLockOn: PropTypes.bool,
  164. };
  165. export default BaseInputField;