CustomInput.jsx 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234
  1. import React, { Component } from "react";
  2. import PropTypes from "prop-types";
  3. const i18next = require("i18next");
  4. const t = i18next.t;
  5. const isLength = (string, min, max) => {
  6. return !(typeof string !== "string" || string.length < min || string.length > max);
  7. };
  8. const regex = {
  9. azAZ09_: /^[A-Za-z0-9_]+$/,
  10. azAZ09: /^[A-Za-z0-9]+$/,
  11. az09_: /^[a-z0-9_]+$/,
  12. az09: /^[a-z0-9]+$/,
  13. emailSimple: /^[a-zA-Z0-9.!#$%&’*+/=?^_`{|}~-]+@[a-z0-9]+\.[a-z0-9]+(\.[a-z0-9]+)?$/,
  14. password: /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[$@$!%*?&])[A-Za-z\d$@$!%*?&]/,
  15. ascii: /^[\x00-\x7F]+$/,
  16. };
  17. const dictionary = {
  18. username: {
  19. inputType: "text",
  20. minLength: 2,
  21. maxLength: 32,
  22. regex: regex.azAZ09_,
  23. errors: {
  24. format: t("general:invalidUsernameFormat", { characters: `a-z, A-Z, 0-9${ t("general:and") } _` }),
  25. },
  26. },
  27. email: {
  28. inputType: "email",
  29. minLength: 3,
  30. maxLength: 254,
  31. regex: regex.emailSimple,
  32. errors: {
  33. format: t("general:invalidEmailFormat"),
  34. },
  35. },
  36. password: {
  37. inputType: "password",
  38. minLength: 6,
  39. maxLength: 200,
  40. regex: regex.password,
  41. errors: {
  42. format: t("general:invalidPasswordFormat", { characters: "$@$!%*?&" }),
  43. },
  44. },
  45. uniqueCode: {
  46. inputType: "text",
  47. minLength: 8,
  48. maxLength: 8,
  49. regex: regex.azAZ09,
  50. errors: {
  51. length: t("general:invalidCodeLength", { length: 8 }),
  52. format: t("general:invalidCodeFormat"),
  53. },
  54. },
  55. stationDisplayName: {
  56. inputType: "text",
  57. minLength: 2,
  58. maxLength: 32,
  59. regex: regex.azAZ09_,
  60. errors: {
  61. //format: t("general:invalidUsernameFormat", { characters: `a-z, A-Z, 0-9${ t("general:and") } _` }),
  62. format: "Invalid display name format",
  63. },
  64. },
  65. stationDescription: {
  66. inputType: "text",
  67. minLength: 2,
  68. maxLength: 200,
  69. errors: {
  70. //format: t("general:invalidUsernameFormat", { characters: `a-z, A-Z, 0-9${ t("general:and") } _` }),
  71. format: "Invalid description format",
  72. },
  73. },
  74. };
  75. export default class CustomInput extends Component {
  76. static propTypes = {
  77. type: PropTypes.string,
  78. name: PropTypes.string,
  79. label: PropTypes.string,
  80. placeholder: PropTypes.string,
  81. onRef: PropTypes.func,
  82. };
  83. static defaultProps = {
  84. type: "",
  85. name: "",
  86. label: "",
  87. placeholder: "",
  88. valid: false,
  89. onRef: () => {},
  90. };
  91. static initialize = (context) => {
  92. context.input = {}; // eslint-disable-line no-param-reassign
  93. };
  94. static hasInvalidInput = (input, properties) => {
  95. let invalid = false;
  96. if (properties) {
  97. properties.forEach((property) => {
  98. if (!input[property].isValid()) invalid = true;
  99. });
  100. } else {
  101. Object.keys(input).forEach((key) => {
  102. if (!input[key].isValid()) invalid = true;
  103. });
  104. }
  105. return invalid;
  106. };
  107. static isTheSame = (input, properties) => {
  108. let invalid = false;
  109. const value = input[properties[0]].getValue();
  110. properties.forEach((key) => {
  111. if (input[key].getValue() !== value) invalid = true;
  112. });
  113. return invalid;
  114. };
  115. constructor(props) {
  116. super(props);
  117. this.state = {
  118. inputType: dictionary[props.type].inputType,
  119. value: "",
  120. original: "",
  121. errors: [],
  122. pristine: true,
  123. disabled: false,
  124. valid: false,
  125. };
  126. // More values/functions needs like isEmpty, isRequired
  127. }
  128. componentDidMount() {
  129. this.props.onRef(this);
  130. }
  131. componentWillUnmount() {
  132. this.props.onRef(null);
  133. }
  134. onBlur = () => {
  135. this.validate();
  136. };
  137. onFocus = () => {
  138. this.setState({
  139. pristine: false,
  140. });
  141. };
  142. onChange = (event) => {
  143. this.setState({
  144. value: event.target.value,
  145. });
  146. };
  147. setValue = (value, original = false) => {
  148. const state = {
  149. value,
  150. };
  151. if (original) state.original = value;
  152. this.setState(state);
  153. };
  154. getValue = () => {
  155. return this.state.value;
  156. };
  157. listErrors = () => {
  158. let errors = this.state.errors;
  159. let key = 0;
  160. if (errors.length > 0) {
  161. errors = errors.map((error) => {
  162. key++;
  163. return (<li key={ key }>{ error }</li>);
  164. });
  165. return (
  166. <ul className="validation-errors">
  167. { errors }
  168. </ul>
  169. );
  170. } return "";
  171. };
  172. isValid = () => {
  173. return this.state.valid;
  174. };
  175. isOriginal = () => {
  176. return this.state.original === this.state.value;
  177. };
  178. isPristine = () => {
  179. return this.state.pristine;
  180. };
  181. validate = (cb = () => {}) => {
  182. const errors = [];
  183. const info = dictionary[this.props.type];
  184. const value = this.state.value;
  185. if (!isLength(value, info.minLength, info.maxLength)) errors.push((info.errors.length) ? info.errors.length : t("general:valueMustBeBetween", { min: info.minLength, max: info.maxLength }));
  186. if (info.regex && !info.regex.test(value)) errors.push(info.errors.format);
  187. this.setState({
  188. errors,
  189. valid: errors.length === 0,
  190. }, cb);
  191. };
  192. render() {
  193. return (
  194. <label htmlFor={ this.props.name }>
  195. <span>{ this.props.label }</span>
  196. <input
  197. placeholder={ this.props.placeholder }
  198. type={ this.state.inputType }
  199. name={ this.props.name }
  200. value={ this.state.value }
  201. className={ (this.state.errors.length > 0) ? "has-validation-errors" : "" }
  202. onBlur={ this.onBlur }
  203. onFocus={ this.onFocus }
  204. onChange={ this.onChange }
  205. ref={ (input) => this.inputElement = input }
  206. />
  207. { this.listErrors() }
  208. </label>
  209. );
  210. }
  211. }