155 lines
4.7 KiB
TypeScript
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>
|
|
);
|
|
};
|