import React, { useCallback, useEffect, useRef, useState } from 'react'; import { NativeSyntheticEvent, StyleSheet, TextInput, TextInputKeyPressEventData, View, } from 'react-native'; import { BoxDigit } from '../box-digit'; import { IOTPInput } from './types'; import { EMPTY_VALUE, initCode, isAutoFillSupported, keysValid, } from '../../common/constants'; export const OTPInput = ({ onSubmit, autoSubmit, pinCount = 6, boxSelectedStyle, boxStyle, digitStyle, boxContainerStyle, variant = 'default', }: IOTPInput) => { const [code, setCode] = useState(initCode(pinCount)); const [idxFocusing, setIdxFocusing] = useState(0); const inputRef = useRef(); const handleOnPress = (idx: number) => { return () => { inputRef?.current?.focus?.(); setIdxFocusing(idx); }; }; // Handle box digit here const handleOnKeyPress = ({ nativeEvent: { key }, }: NativeSyntheticEvent) => { if (key === 'Backspace') { if (idxFocusing >= 0) { if (idxFocusing > 0 && !code[idxFocusing]) { setIdxFocusing((preValue: number) => preValue - 1); } const newCode = code.map((item, idx) => idx === idxFocusing ? '' : item ); if (!autoSubmit) { const otp = newCode.join(''); onSubmit?.(otp); } setCode(newCode); } return; } const keyPressed = key.trim(); if (idxFocusing <= pinCount - 1 && keysValid(keyPressed)) { const keyPressedLength = keyPressed.length; if (keyPressedLength === 1) { const newCode = [...code]; newCode[idxFocusing] = keyPressed; if (!autoSubmit) { const otp = newCode.join(''); onSubmit?.(otp); } setCode(newCode); if (idxFocusing < pinCount - 1) { setIdxFocusing((preValue: number) => preValue + 1); } } else { const newCode = []; for (let i = 0; i < keyPressedLength; i++) { newCode[i] = keyPressed[i]; } if (!autoSubmit) { const otp = newCode.join(''); onSubmit?.(otp); } setCode(newCode); const idxDigitFocusing = keyPressedLength < 1 ? 0 : keyPressedLength >= pinCount ? pinCount - 1 : keyPressedLength; setIdxFocusing(() => idxDigitFocusing); } } }; // Handle submit otp here const handleSubmit = useCallback(() => { try { const otp = code.join(''); if (otp.length === pinCount) { inputRef.current?.clear?.(); setCode(initCode(pinCount)); setIdxFocusing(0); onSubmit?.(otp); } } catch (error) {} }, [code, onSubmit, pinCount]); // effect useEffect(() => { if (autoSubmit) { handleSubmit(); } }, [autoSubmit, handleSubmit]); useEffect(() => { setTimeout(() => { inputRef?.current?.focus?.(); }, 600); }, []); return ( {initCode(pinCount).map((_: string, idx: number) => { const digit = code[idx] || EMPTY_VALUE; const isValueFocused = idxFocusing === idx; return ( ); })} | undefined} textContentType={isAutoFillSupported ? 'oneTimeCode' : 'none'} keyboardType="numeric" /> ); }; const styles = StyleSheet.create({ container: { width: '100%', height: 72, }, inputContainer: { width: 0, height: '100%', zIndex: -1, opacity: 1, ...StyleSheet.absoluteFillObject, }, boxContainer: { flexDirection: 'row', justifyContent: 'space-between', paddingHorizontal: 20, }, });