155 lines
4.7 KiB
TypeScript

import React, { useState, useEffect } from 'react';
import {
View,
Text,
TouchableOpacity,
KeyboardAvoidingView,
Platform,
} from 'react-native';
import { useNavigation, useRoute, RouteProp } from '@react-navigation/native';
import { StackNavigationProp } from '@react-navigation/stack';
import { getStyles } from './otpScreen.styles';
import { PrimaryButton } from '@components';
import { useAppTheme } from '@theme';
import { useAppDispatch } from '../../../hooks/useAppDispatch';
import { verifyOtp } from '../../../store/commonreducers/auth';
import { AuthStackParamList } from '../../../navigation/authStack';
type OtpNavProp = StackNavigationProp<AuthStackParamList, 'OtpScreen'>;
type OtpRouteProp = RouteProp<AuthStackParamList, 'OtpScreen'>;
const OTP_LENGTH = 6;
const RESEND_TIMER = 30;
export const OtpScreen: React.FC = () => {
const { colors } = useAppTheme();
const styles = getStyles(colors);
const navigation = useNavigation<OtpNavProp>();
const route = useRoute<OtpRouteProp>();
const dispatch = useAppDispatch();
const { mobileNumber } = route.params;
const [otp, setOtp] = useState<string[]>(Array(OTP_LENGTH).fill(''));
const [activeIndex, setActiveIndex] = useState(0);
const [timer, setTimer] = useState(RESEND_TIMER);
const [isLoading, setIsLoading] = useState(false);
useEffect(() => {
if (timer > 0) {
const interval = setInterval(() => setTimer((t) => t - 1), 1000);
return () => clearInterval(interval);
}
}, [timer]);
const handleKeyPress = (key: string) => {
if (key === 'backspace') {
if (otp[activeIndex] || activeIndex > 0) {
const newOtp = [...otp];
if (otp[activeIndex]) {
newOtp[activeIndex] = '';
} else if (activeIndex > 0) {
newOtp[activeIndex - 1] = '';
setActiveIndex(activeIndex - 1);
}
setOtp(newOtp);
}
} else if (key >= '0' && key <= '9' && activeIndex < OTP_LENGTH) {
const newOtp = [...otp];
newOtp[activeIndex] = key;
setOtp(newOtp);
if (activeIndex < OTP_LENGTH - 1) {
setActiveIndex(activeIndex + 1);
}
}
};
const handleVerify = async () => {
const otpString = otp.join('');
if (otpString.length !== OTP_LENGTH) return;
setIsLoading(true);
await dispatch(verifyOtp({ mobileNumber, otp: otpString }));
setIsLoading(false);
navigation.navigate('SetLocationScreen');
};
return (
<KeyboardAvoidingView
style={styles.container}
behavior={Platform.OS === 'ios' ? 'padding' : 'height'}
>
<View style={styles.content}>
<Text style={styles.title}>Verify OTP</Text>
<Text style={styles.subtitle}>
Code sent to {mobileNumber}
</Text>
<View style={styles.otpContainer}>
{otp.map((digit, index) => (
<View
key={index}
style={[
styles.otpCell,
index === activeIndex && styles.otpCellActive,
digit ? styles.otpCellFilled : null,
]}
>
<Text style={styles.otpCellText}>{digit}</Text>
</View>
))}
</View>
<View style={styles.keypad}>
{[1, 2, 3, 4, 5, 6, 7, 8, 9].map((num) => (
<TouchableOpacity
key={num}
style={styles.key}
onPress={() => handleKeyPress(String(num))}
activeOpacity={0.6}
>
<Text style={styles.keyText}>{num}</Text>
</TouchableOpacity>
))}
<TouchableOpacity
style={styles.key}
onPress={() => handleKeyPress('backspace')}
activeOpacity={0.6}
>
<Text style={styles.keyText}></Text>
</TouchableOpacity>
<TouchableOpacity
style={styles.key}
onPress={() => handleKeyPress('0')}
activeOpacity={0.6}
>
<Text style={styles.keyText}>0</Text>
</TouchableOpacity>
<View style={styles.key} />
</View>
{timer > 0 ? (
<Text style={styles.timerText}>Resend code in {timer}s</Text>
) : (
<TouchableOpacity
onPress={() => {
setTimer(RESEND_TIMER);
setOtp(Array(OTP_LENGTH).fill(''));
setActiveIndex(0);
}}
activeOpacity={0.7}
>
<Text style={styles.resendText}>Resend OTP</Text>
</TouchableOpacity>
)}
<PrimaryButton
title="Verify"
onPress={handleVerify}
isLoading={isLoading}
disabled={otp.join('').length !== OTP_LENGTH}
style={{ marginTop: 24 }}
/>
</View>
</KeyboardAvoidingView>
);
};