206 lines
5.3 KiB
TypeScript
206 lines
5.3 KiB
TypeScript
import React, { useEffect, useState } from "react";
|
|
import { Text, View, StyleSheet, TouchableOpacity } from "react-native";
|
|
import { useSelector, useDispatch } from "react-redux";
|
|
import { AppDispatch, RootState } from "../../store";
|
|
import { clearVerifyOTPError, sendOTP, verifyOTP } from "../../store/authSlice";
|
|
import { OtpInput } from "react-native-otp-entry";
|
|
import { useRouter } from "expo-router";
|
|
import { useTranslation } from "react-i18next";
|
|
import { AUTH_STATUSES } from "@/constants/types";
|
|
|
|
export default function VerifyOTP() {
|
|
const { phone, otpId, verifyOTPError, sendOTPError, status } = useSelector(
|
|
(state: RootState) => state.auth
|
|
);
|
|
const router = useRouter();
|
|
const dispatch = useDispatch<AppDispatch>();
|
|
const { isLoggedIn } = useSelector((state: RootState) => state.auth);
|
|
const [seconds, setSeconds] = useState(30);
|
|
const [isTimerActive, setIsTimerActive] = useState(true);
|
|
const [resendAttempts, setResendAttempts] = useState(0);
|
|
const maxResendAttempts = 5;
|
|
|
|
const { t } = useTranslation();
|
|
|
|
useEffect(() => {
|
|
dispatch(clearVerifyOTPError());
|
|
}, []);
|
|
|
|
useEffect(() => {
|
|
if (isTimerActive && seconds > 0) {
|
|
const timer = setInterval(() => {
|
|
setSeconds((prev) => prev - 1);
|
|
}, 1000);
|
|
|
|
return () => clearInterval(timer);
|
|
} else if (seconds === 0) {
|
|
setIsTimerActive(false);
|
|
}
|
|
}, [seconds, isTimerActive]);
|
|
|
|
const resendOTP = async () => {
|
|
if (resendAttempts < maxResendAttempts) {
|
|
const newAttempts = resendAttempts + 1;
|
|
setResendAttempts(newAttempts);
|
|
setSeconds(30);
|
|
setIsTimerActive(true);
|
|
dispatch(sendOTP({ phone }));
|
|
dispatch(clearVerifyOTPError());
|
|
}
|
|
};
|
|
|
|
const formattedSeconds = seconds.toString().padStart(2, "0");
|
|
|
|
useEffect(() => {
|
|
if (status === AUTH_STATUSES.SUCCESS && isLoggedIn) {
|
|
router.replace("/"); // This assumes "/" leads to your `TabLayout`
|
|
}
|
|
}, [status, isLoggedIn]);
|
|
|
|
return (
|
|
<View style={styles.container}>
|
|
<Text style={styles.heading}>{t("onboarding.verify-otp")}</Text>
|
|
<View style={styles.body}>
|
|
<Text>
|
|
<Text style={styles.order}>{t("onboarding.enter-otp")}</Text>
|
|
<Text style={styles.phone}> +91 ********{phone?.slice(-2)}.</Text>
|
|
</Text>
|
|
|
|
<View style={styles.otpContainer}>
|
|
<OtpInput
|
|
numberOfDigits={4}
|
|
focusColor="#006C4D"
|
|
onTextChange={() => {
|
|
dispatch(clearVerifyOTPError());
|
|
}}
|
|
onFilled={(code) => {
|
|
dispatch(verifyOTP({ phone, otpId, otp: code }));
|
|
}}
|
|
autoFocus={true}
|
|
type="numeric"
|
|
focusStickBlinkingDuration={500}
|
|
textInputProps={{
|
|
accessibilityLabel: "One-Time Password",
|
|
}}
|
|
textProps={{
|
|
accessibilityRole: "text",
|
|
accessibilityLabel: "OTP digit",
|
|
allowFontScaling: false,
|
|
}}
|
|
/>
|
|
|
|
{(verifyOTPError || sendOTPError) && (
|
|
<Text style={styles.error}>{verifyOTPError || sendOTPError}</Text>
|
|
)}
|
|
|
|
<View style={styles.otpResend}>
|
|
{isTimerActive ? (
|
|
<Text>
|
|
<Text style={styles.otpText}>{t("onboarding.resend-otp")}</Text>{" "}
|
|
<Text style={styles.timer}>00:{formattedSeconds}</Text>
|
|
</Text>
|
|
) : (
|
|
<TouchableOpacity
|
|
onPress={resendOTP}
|
|
disabled={resendAttempts >= maxResendAttempts}
|
|
>
|
|
<Text
|
|
style={{
|
|
...styles.resendOTP,
|
|
color:
|
|
resendAttempts < maxResendAttempts
|
|
? "#006C4D"
|
|
: "#B0B7C5",
|
|
}}
|
|
>
|
|
{t("onboarding.resend-otp")}
|
|
</Text>
|
|
</TouchableOpacity>
|
|
)}
|
|
</View>
|
|
</View>
|
|
</View>
|
|
</View>
|
|
);
|
|
}
|
|
|
|
const styles = StyleSheet.create({
|
|
container: {
|
|
padding: 16,
|
|
paddingTop: 0,
|
|
},
|
|
heading: {
|
|
fontSize: 28,
|
|
fontStyle: "normal",
|
|
fontWeight: "bold",
|
|
lineHeight: 36.4,
|
|
letterSpacing: -0.56,
|
|
},
|
|
body: {
|
|
marginTop: 24,
|
|
},
|
|
phone: {
|
|
color: "#252A34",
|
|
fontSize: 14,
|
|
fontWeight: "bold",
|
|
lineHeight: 20,
|
|
},
|
|
order: {
|
|
color: "#949CAC",
|
|
fontSize: 14,
|
|
fontWeight: "bold",
|
|
lineHeight: 20,
|
|
},
|
|
otpContainer: {
|
|
padding: 0,
|
|
marginTop: 32,
|
|
alignItems: "center",
|
|
justifyContent: "center",
|
|
},
|
|
otpInput: {
|
|
width: "80%",
|
|
justifyContent: "space-between",
|
|
},
|
|
inputField: {
|
|
borderColor: "#D8DDE7",
|
|
borderRadius: 4,
|
|
backgroundColor: "#ffffff",
|
|
color: "#252A34",
|
|
textAlign: "center",
|
|
fontFamily: "Inter",
|
|
fontSize: 20,
|
|
fontWeight: "bold",
|
|
height: 56,
|
|
width: 56,
|
|
},
|
|
error: {
|
|
color: "#D51D10",
|
|
fontFamily: "Inter",
|
|
fontSize: 12,
|
|
fontWeight: "bold",
|
|
lineHeight: 20,
|
|
marginTop: 8,
|
|
},
|
|
otpResend: {
|
|
marginTop: 28,
|
|
},
|
|
otpText: {
|
|
color: "#949CAC",
|
|
fontFamily: "Inter",
|
|
fontSize: 14,
|
|
fontWeight: "bold",
|
|
},
|
|
timer: {
|
|
color: "#252A34",
|
|
fontSize: 14,
|
|
fontWeight: "bold",
|
|
},
|
|
resendOTP: {
|
|
fontFamily: "Inter",
|
|
fontSize: 14,
|
|
fontWeight: "bold",
|
|
paddingTop: 8,
|
|
paddingBottom: 8,
|
|
},
|
|
});
|