import { useEffect, useRef, useState } from 'react'; import { useTranslation } from 'react-i18next'; import { ActivityIndicator, Animated, Keyboard, StyleSheet, Text, TextInput, TouchableOpacity, View, } from 'react-native'; interface OtpFormProps { phone?: string; initialCode?: string; onSubmit?: (otp: string) => void; isLoading?: boolean; error?: string; onResendPress?: () => void; resendTimer: number; } const RegisterConfirmForm = ({ initialCode, onSubmit, isLoading = false, error, onResendPress, resendTimer, }: OtpFormProps) => { const [otp, setOtp] = useState(Array(4).fill('')); const [focusedIndex, setFocusedIndex] = useState(0); const inputRefs = useRef([]); const shakeAnimation = useRef(new Animated.Value(0)).current; const { t } = useTranslation(); useEffect(() => { if (error) { Animated.sequence([ Animated.timing(shakeAnimation, { toValue: 10, duration: 50, useNativeDriver: true }), Animated.timing(shakeAnimation, { toValue: -10, duration: 50, useNativeDriver: true }), Animated.timing(shakeAnimation, { toValue: 10, duration: 50, useNativeDriver: true }), Animated.timing(shakeAnimation, { toValue: 0, duration: 50, useNativeDriver: true }), ]).start(); } }, [error]); useEffect(() => { if (initialCode && initialCode.length === 4 && /^\d{4}$/.test(initialCode)) { setOtp(initialCode.split('')); } }, [initialCode]); // Raqam kiritilganda yoki o'chirilganda const handleChange = (value: string, index: number) => { const cleanValue = value.replace(/[^0-9]/g, ''); const newOtp = [...otp]; // Agar qiymat bo'sh bo'lsa (o'chirilgan bo'lsa) if (value === '') { newOtp[index] = ''; setOtp(newOtp); return; } // Faqat oxirgi kiritilgan raqamni olish newOtp[index] = cleanValue.slice(-1); setOtp(newOtp); // Keyingi katakka o'tish if (newOtp[index] !== '' && index < 3) { inputRefs.current[index + 1]?.focus(); } // Hamma raqam kiritilgan bo'lsa avtomat yuborish const fullCode = newOtp.join(''); if (fullCode.length === 4) { Keyboard.dismiss(); onSubmit?.(fullCode); } }; // Maxsus tugmalar (Backspace) uchun const handleKeyPress = ({ nativeEvent }: any, index: number) => { if (nativeEvent.key === 'Backspace') { // Agar katakda raqam bo'lsa, uni o'chiradi if (otp[index] !== '') { const newOtp = [...otp]; newOtp[index] = ''; setOtp(newOtp); } // Agar katak bo'sh bo'lsa, oldingisiga o'tib uni ham o'chiradi else if (index > 0) { const newOtp = [...otp]; newOtp[index - 1] = ''; setOtp(newOtp); inputRefs.current[index - 1]?.focus(); } } }; return ( {otp.map((digit, index) => ( inputRefs.current[index]?.focus()} style={[ styles.inputBox, focusedIndex === index && styles.inputBoxFocused, digit !== '' && styles.inputBoxFilled, error ? styles.inputBoxError : null, ]} > {digit || '•'} { if (ref) inputRefs.current[index] = ref; }} value={digit} onChangeText={(v) => handleChange(v, index)} onKeyPress={(e) => handleKeyPress(e, index)} onFocus={() => setFocusedIndex(index)} onBlur={() => setFocusedIndex(-1)} keyboardType="number-pad" maxLength={1} style={styles.hiddenInput} caretHidden selectTextOnFocus // Bu 2 marta bosish muammosini oldini olishga yordam beradi /> ))} {error && {error}} onSubmit?.(otp.join(''))} disabled={isLoading || otp.join('').length !== 4} activeOpacity={0.8} style={[ styles.submitButton, (isLoading || otp.join('').length !== 4) && styles.submitButtonDisabled, ]} > {isLoading ? ( ) : ( {t('Kodni tasdiqlash')} )} {resendTimer > 0 ? ( {t('Qayta yuborish vaqti')}:{resendTimer}s ) : ( {t('Kodni qayta yuborish')} )} ); }; const styles = StyleSheet.create({ container: { width: '100%', paddingVertical: 10 }, otpContainer: { flexDirection: 'row', justifyContent: 'space-between', marginBottom: 20, paddingHorizontal: 5, }, inputBox: { width: 60, height: 65, borderRadius: 16, borderWidth: 1.5, borderColor: '#E2E8F0', backgroundColor: '#F8FAFC', alignItems: 'center', justifyContent: 'center', elevation: 1, }, inputBoxFocused: { borderColor: '#3B82F6', backgroundColor: '#FFFFFF', borderWidth: 2, elevation: 4, }, inputBoxFilled: { borderColor: '#3B82F6', backgroundColor: '#FFFFFF', }, inputBoxError: { borderColor: '#EF4444', backgroundColor: '#FFF1F2', }, inputText: { fontSize: 26, fontWeight: '700', color: '#1E293B' }, placeholderText: { color: '#CBD5E1', fontSize: 18 }, hiddenInput: { position: 'absolute', width: '100%', height: '100%', opacity: 0 }, errorText: { color: '#EF4444', fontSize: 14, textAlign: 'center', marginBottom: 20, fontWeight: '500', }, submitButton: { height: 56, backgroundColor: '#3B82F6', borderRadius: 16, alignItems: 'center', justifyContent: 'center', elevation: 3, }, submitButtonDisabled: { backgroundColor: '#94A3B8', elevation: 0 }, submitText: { color: '#FFFFFF', fontSize: 16, fontWeight: '600' }, resendContainer: { alignItems: 'center', marginTop: 25 }, timerText: { color: '#64748B', fontSize: 14 }, timerCount: { color: '#1E293B', fontWeight: '700' }, resendButton: { paddingVertical: 5 }, resendText: { color: '#3B82F6', fontSize: 15, fontWeight: '600', textDecorationLine: 'underline', }, }); export default RegisterConfirmForm;