feat: add digits input, complete signin form

This commit is contained in:
Sajad Mirjalili
2025-07-22 18:42:54 +03:30
parent 83c3f05e68
commit d2efafa5a9
12 changed files with 652 additions and 142 deletions

View File

@@ -0,0 +1,106 @@
import React, {
useRef,
useEffect,
type SetStateAction,
type Dispatch,
useState,
type KeyboardEvent,
} from 'react';
import { TextField, Stack } from '@mui/material';
interface DigitInputProps {
onChange: Dispatch<SetStateAction<string[]>>;
}
const DigitInput: React.FC<DigitInputProps> = ({ onChange }) => {
const [code, setCode] = useState<string[]>(['', '', '', '']);
const inputRefs = useRef<Array<HTMLInputElement | null>>([]);
useEffect(() => {
inputRefs.current[0]?.focus();
}, []);
const handleChange = (value: string, index: number) => {
if (!/^\d$/.test(value) && value !== '') return;
const newCode = [...code];
newCode[index] = value;
setCode(newCode);
onChange(newCode);
if (value && index < 4 - 1) {
inputRefs.current[index + 1]?.focus();
}
};
const handleBackspace = (
event: KeyboardEvent<HTMLDivElement>,
index: number,
) => {
event.preventDefault();
if (index >= 0) {
handleChange('', index);
inputRefs.current[index - 1]?.focus();
}
};
const handlePaste = (event: React.ClipboardEvent) => {
event.preventDefault();
const pastedData = event.clipboardData.getData('text').replace(/\D/g, ''); // Remove non-digit characters
const newCode = [...code];
pastedData.split('').forEach((digit, i) => {
if (i < code.length) {
newCode[i] = digit;
}
});
setCode(newCode);
onChange(newCode);
// Focus the next empty input after the last pasted character
const lastIndex = Math.min(pastedData.length, code.length) - 1;
if (lastIndex >= 0 && inputRefs.current[lastIndex]) {
inputRefs.current[lastIndex]?.focus();
}
};
return (
<Stack
direction="row-reverse"
alignItems="center"
sx={{ gap: 2, width: '100%', my: 4 }}
justifyContent="center"
>
{code.map((digit, index) => (
<TextField
key={index}
inputRef={(el) => (inputRefs.current[index] = el)}
value={digit}
onChange={(e) => handleChange(e.target.value, index)}
onKeyDown={(e) => e.key === 'Backspace' && handleBackspace(e, index)}
onPaste={(e) => handlePaste(e)}
slotProps={{
htmlInput: {
maxLength: 1,
sx: {
height: '72px',
},
style: {
textAlign: 'center',
fontSize: '48px',
},
},
}}
variant="standard"
size="medium"
sx={{
width: '83px',
}}
/>
))}
</Stack>
);
};
export default DigitInput;