BaaS_Driver_Android_App/app/auth/verifyOtp.tsx

260 lines
6.6 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}> {phone}.</Text>
</Text>
<View style={styles.otpContainer}>
<OtpInput
numberOfDigits={4}
focusColor="green"
autoFocus={true}
hideStick={true}
blurOnFilled={true}
disabled={false}
type="numeric"
secureTextEntry={false}
focusStickBlinkingDuration={500}
onTextChange={(text) => console.log(text)}
onFilled={(text) => {
dispatch(verifyOTP({ otpId: `${otpId}`, otp: text, phone }));
}}
textInputProps={{
accessibilityLabel: "One-Time Password",
}}
textProps={{
accessibilityRole: "text",
accessibilityLabel: "OTP digit",
allowFontScaling: false,
}}
theme={{
containerStyle: styles.digitContainer,
pinCodeContainerStyle: styles.pinCodeContainer,
pinCodeTextStyle: styles.pinCodeText,
focusStickStyle: styles.focusStick,
placeholderTextStyle: styles.placeholderText,
disabledPinCodeContainerStyle: styles.disabledPinCodeContainer,
}}
/>
{(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,
},
digitContainer: {
width: "100%",
flexDirection: "row",
justifyContent: "center",
gap: 16,
alignItems: "center",
},
pinCodeContainer: {
width: 56,
height: 56,
borderWidth: 1,
borderColor: "#D8DDE7",
borderRadius: 4,
backgroundColor: "#FFFFFF",
justifyContent: "center",
alignItems: "center",
},
disabledPinCodeContainer: {
backgroundColor: "#F2F4F7",
borderColor: "#E0E4EA",
},
pinCodeText: {
fontSize: 20,
fontWeight: "bold",
color: "#252A34",
textAlign: "center",
fontFamily: "Inter",
},
placeholderText: {
fontSize: 20,
color: "#B0B7C5",
textAlign: "center",
fontWeight: "bold",
},
focusStick: {
width: 2,
height: 24,
backgroundColor: "#252A34",
},
});