109 lines
3.1 KiB
TypeScript

import { useState, useEffect, useCallback } from 'react';
import { Alert } from 'react-native';
import { useNavigation, useRoute, RouteProp } from '@react-navigation/native';
import { StackNavigationProp } from '@react-navigation/stack';
import { RootState, useAppDispatch, useAppSelector, verifyOtp } from '@store';
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 useOtpScreen = () => {
const navigation = useNavigation<OtpNavProp>();
const route = useRoute<OtpRouteProp>();
const dispatch = useAppDispatch();
const { mobileNumber } = route.params;
const { loginData, user } = useAppSelector((state: RootState) => state.auth);
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 resetOtp = useCallback(() => {
setOtp(Array(OTP_LENGTH).fill(''));
setActiveIndex(0);
}, []);
const handleKeyPress = useCallback(
(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);
}
}
},
[otp, activeIndex],
);
const handleResend = useCallback(() => {
setTimer(RESEND_TIMER);
resetOtp();
// TODO: dispatch resend/loginWithPhone thunk here if needed
}, [resetOtp]);
const handleVerify = useCallback(async () => {
const otpString = otp.join('');
if (otpString.length !== OTP_LENGTH) return;
setIsLoading(true);
try {
await dispatch(
verifyOtp({ phone: mobileNumber, code: otpString, role: 'CUSTOMER' }),
).unwrap();
navigation.navigate('SetLocationScreen');
} catch (error) {
const message =
typeof error === 'string' ? error : 'Invalid OTP. Please try again.';
Alert.alert('Verification Failed', message);
resetOtp();
} finally {
setIsLoading(false);
}
}, [dispatch, mobileNumber, navigation, otp, resetOtp]);
return {
// data
mobileNumber,
loginData,
user,
otp,
activeIndex,
timer,
isLoading,
otpLength: OTP_LENGTH,
isOtpComplete: otp.join('').length === OTP_LENGTH,
// actions
handleKeyPress,
handleVerify,
handleResend,
};
};