CustomInput.jsx 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152
  1. import React, { Component } from "react";
  2. import PropTypes from "prop-types";
  3. const regex = {
  4. azAZ09_: /^[A-Za-z0-9_]+$/,
  5. az09_: /^[a-z0-9_]+$/,
  6. emailSimple: /^[\x00-\x7F]+@[a-z0-9]+\.[a-z0-9]+(\.[a-z0-9]+)?$/,
  7. password: /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[$@$!%*?&])[A-Za-z\d$@$!%*?&]/,
  8. ascii: /^[\x00-\x7F]+$/,
  9. };
  10. const isLength = (string, min, max) => {
  11. return !(typeof string !== "string" || string.length < min || string.length > max);
  12. };
  13. const validation = {
  14. username: (value) => {
  15. const errors = [];
  16. if (!isLength(value, 2, 32)) errors.push("Username must be between 2 and 32 characters long.");
  17. if (!regex.azAZ09_.test(value)) errors.push("Invalid username format. Allowed characters: a-z, A-Z, 0-9 and _.");
  18. return errors;
  19. },
  20. email: (value) => {
  21. const errors = [];
  22. if (!isLength(value, 3, 254)) errors.push("Email must be between 3 and 254 characters long.");
  23. if (value.indexOf("@") !== value.lastIndexOf("@") || !regex.emailSimple.test(value)) errors.push("Invalid email format.");
  24. return errors;
  25. },
  26. password: (value) => {
  27. const errors = [];
  28. if (!isLength(value, 6, 200)) errors.push("Password must be between 6 and 200 characters long.");
  29. if (!regex.password.test(value)) errors.push("Invalid password format.");
  30. return errors;
  31. },
  32. };
  33. export default class CustomInput extends Component {
  34. static propTypes = {
  35. type: PropTypes.string,
  36. inputType: PropTypes.string,
  37. name: PropTypes.string,
  38. value: PropTypes.string,
  39. label: PropTypes.string,
  40. placeholder: PropTypes.string,
  41. customInputEvents: PropTypes.object,
  42. validationCallback: PropTypes.func,
  43. };
  44. static defaultProps = {
  45. type: "text",
  46. inputType: "text",
  47. name: "",
  48. value: "",
  49. label: "",
  50. placeholder: "",
  51. customInputEvents: {},
  52. validationCallback: () => {},
  53. };
  54. static validationCallback = (ctx) => {
  55. return (name, invalid) => {
  56. const inputInvalid = ctx.state.inputInvalid;
  57. inputInvalid[name] = invalid;
  58. ctx.setState({ inputInvalid });
  59. };
  60. };
  61. static hasInvalidInput = (inputInvalid) => {
  62. let invalid = false;
  63. Object.values(inputInvalid).forEach((value) => {
  64. if (value) invalid = true;
  65. });
  66. return invalid;
  67. };
  68. constructor(props) {
  69. super(props);
  70. this.state = {
  71. customInputEvents: props.customInputEvents,
  72. errors: "",
  73. value: props.value,
  74. };
  75. if (this.state.customInputEvents.onBlur) {
  76. const oldOnBlur = this.state.customInputEvents.onBlur;
  77. this.state.customInputEvents.onBlur = () => {
  78. this.onBlurHandler();
  79. oldOnBlur();
  80. };
  81. } else this.state.customInputEvents.onBlur = this.onBlurHandler;
  82. if (this.state.customInputEvents.onChange) {
  83. const oldOnChange = this.state.customInputEvents.onChange;
  84. this.state.customInputEvents.onChange = (event) => {
  85. this.onChangeHandler(event);
  86. oldOnChange(event);
  87. };
  88. } else this.state.customInputEvents.onChange = this.onChangeHandler;
  89. }
  90. onBlurHandler = () => {
  91. this.validateInput();
  92. };
  93. onChangeHandler = (event) => {
  94. this.setState({
  95. value: event.target.value,
  96. });
  97. };
  98. listErrors = () => {
  99. let errors = this.state.errors;
  100. let key = 0;
  101. if (errors.length > 0) {
  102. errors = errors.map((error) => {
  103. key++;
  104. return (<li key={ key }>{ error }</li>);
  105. });
  106. return (
  107. <ul className="validation-errors">
  108. { errors }
  109. </ul>
  110. );
  111. } return "";
  112. };
  113. validateInput = () => {
  114. const value = this.state.value;
  115. const type = this.props.type;
  116. const errors = (validation[type]) ? validation[type](value) : [];
  117. this.setState({ errors });
  118. this.props.validationCallback(this.props.name, errors.length > 0);
  119. };
  120. render() {
  121. return (
  122. <label htmlFor={ this.props.name }>
  123. <span>{ this.props.label }</span>
  124. <input
  125. placeholder={ this.props.placeholder }
  126. type={ this.props.inputType }
  127. name={ this.props.name }
  128. value={ this.state.value }
  129. className={ (this.state.errors.length > 0) ? "has-validation-errors" : "" }
  130. { ...this.state.customInputEvents }
  131. />
  132. { this.listErrors() }
  133. </label>
  134. );
  135. }
  136. }