2022-02-02 21:57:47 +00:00
|
|
|
import React, { useRef, useEffect } from "react";
|
|
|
|
import PropTypes from "prop-types";
|
|
|
|
import InputWrapper from "./styled-code-input";
|
|
|
|
|
|
|
|
const CodeInput = (props) => {
|
2022-02-03 13:06:36 +00:00
|
|
|
const { onSubmit, handleChange, isDisabled } = props;
|
2022-02-02 21:57:47 +00:00
|
|
|
|
|
|
|
const inputsRef = useRef([]);
|
|
|
|
const characters = 6;
|
2022-02-03 11:57:42 +00:00
|
|
|
const allowed = "^[A-Za-z0-9]*$";
|
2022-02-02 21:57:47 +00:00
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
inputsRef.current[0].focus();
|
|
|
|
}, []);
|
|
|
|
|
|
|
|
const onEnter = () => {
|
|
|
|
const code = inputsRef.current.map((input) => input.value).join("");
|
|
|
|
if (code.length === characters) {
|
|
|
|
onSubmit && onSubmit(code);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
const handleOnChange = (e) => {
|
|
|
|
if (e.target.value.match(allowed)) {
|
2022-02-03 13:06:36 +00:00
|
|
|
handleChange();
|
2022-02-02 21:57:47 +00:00
|
|
|
if (e.target.nextElementSibling !== null) {
|
2022-02-03 11:23:20 +00:00
|
|
|
if (e.target.nextElementSibling.nodeName === "HR") {
|
|
|
|
e.target.nextElementSibling.nextElementSibling.focus();
|
|
|
|
}
|
2022-02-02 21:57:47 +00:00
|
|
|
e.target.nextElementSibling.focus();
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
e.target.value = "";
|
|
|
|
}
|
2022-02-03 11:57:42 +00:00
|
|
|
onEnter();
|
2022-02-02 21:57:47 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
const handleOnKeyDown = (e) => {
|
|
|
|
const { key } = e;
|
|
|
|
const target = e.target;
|
|
|
|
|
|
|
|
if (key === "Backspace") {
|
2022-02-03 13:10:03 +00:00
|
|
|
handleChange();
|
2022-02-02 21:57:47 +00:00
|
|
|
if (target.value === "" && target.previousElementSibling !== null) {
|
|
|
|
if (target.previousElementSibling !== null) {
|
2022-02-03 11:23:20 +00:00
|
|
|
if (e.target.previousElementSibling.nodeName === "HR") {
|
|
|
|
e.target.previousElementSibling.previousElementSibling.focus();
|
|
|
|
}
|
2022-02-02 21:57:47 +00:00
|
|
|
target.previousElementSibling.focus();
|
|
|
|
e.preventDefault();
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
target.value = "";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
const handleOnFocus = (e) => {
|
|
|
|
e.target.select();
|
|
|
|
};
|
|
|
|
|
|
|
|
const handleOnPaste = (e) => {
|
|
|
|
const value = e.clipboardData.getData("Text");
|
|
|
|
if (value.match(allowed)) {
|
|
|
|
for (let i = 0; i < characters && i < value.length; i++) {
|
|
|
|
inputsRef.current[i].value = value.charAt(i);
|
|
|
|
if (inputsRef.current[i].nextElementSibling !== null) {
|
|
|
|
inputsRef.current[i].nextElementSibling.focus();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2022-02-03 09:49:27 +00:00
|
|
|
onEnter();
|
2022-02-02 21:57:47 +00:00
|
|
|
e.preventDefault();
|
|
|
|
};
|
|
|
|
|
|
|
|
const elements = [];
|
|
|
|
for (let i = 0; i < characters; i++) {
|
2022-02-07 04:57:49 +00:00
|
|
|
if (i === 3) elements.push(<hr key="InputCode-line" />);
|
|
|
|
|
2022-02-02 21:57:47 +00:00
|
|
|
elements.push(
|
2022-02-07 04:57:49 +00:00
|
|
|
<input
|
|
|
|
key={`InputCode-${i}`}
|
|
|
|
onChange={handleOnChange}
|
|
|
|
onKeyDown={handleOnKeyDown}
|
|
|
|
onFocus={handleOnFocus}
|
|
|
|
onPaste={handleOnPaste}
|
|
|
|
ref={(el) => (inputsRef.current[i] = el)}
|
|
|
|
maxLength={1}
|
|
|
|
disabled={isDisabled}
|
|
|
|
/>
|
2022-02-02 21:57:47 +00:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
return <InputWrapper {...props}>{elements}</InputWrapper>;
|
|
|
|
};
|
|
|
|
|
|
|
|
CodeInput.propTypes = {
|
|
|
|
onSubmit: PropTypes.func.isRequired,
|
2022-02-03 13:06:36 +00:00
|
|
|
handleChange: PropTypes.func,
|
2022-02-03 11:08:45 +00:00
|
|
|
isDisabled: PropTypes.bool,
|
2022-02-02 21:57:47 +00:00
|
|
|
className: PropTypes.string,
|
|
|
|
id: PropTypes.string,
|
|
|
|
style: PropTypes.oneOfType([PropTypes.object, PropTypes.array]),
|
|
|
|
};
|
|
|
|
|
2022-02-03 11:08:45 +00:00
|
|
|
CodeInput.defaultProps = {
|
|
|
|
isDisabled: false,
|
|
|
|
};
|
|
|
|
|
2022-02-02 21:57:47 +00:00
|
|
|
export default CodeInput;
|