Search code examples
react-nativetypeerror

TypeError: Cannot read property 'OtpInput' of undefined


I don't even know what the problem is, I can't seem to figure out. Before adding the resend function everything was working perfectly. I can't figure out why is it breaking.

I have tried everything re-installing the dependency, changing the babel.config

import React, {useCallback, useEffect, useState} from 'react';
import {Text, TouchableOpacity, View, Alert} from 'react-native';
import {OtpInput} from 'react-native-otp-entry';
import Icon from 'react-native-vector-icons/AntDesign';
import styles from './OTPScreenStyles';
import {validateOTP} from '../../../api/validateOTP';
import {resendOTP} from 'api/resendOTP';
import {RouteProp} from '@react-navigation/native';
import {RootStackParamList} from '../../../../App';

type OTPScreenRouteProp = RouteProp<RootStackParamList, 'OTPScreen'>;

type OTPScreenProps = {
  navigation: any;
  route: OTPScreenRouteProp;
};

const OTPScreen: React.FC<OTPScreenProps> = ({navigation, route}) => {
  const {email, mobile, requestId} = route.params;
  const [timer, setTimer] = useState(30);
  const [otp, setOtp] = useState('');

  const timeOutCallBack = useCallback(() => {
    setTimer(currTimer => {
      if (currTimer <= 0) return 0;
      return currTimer - 1;
    });
  }, []);

  useEffect(() => {
    if (timer > 0) {
      const timeoutId = setTimeout(timeOutCallBack, 1000);
      return () => clearTimeout(timeoutId);
    }
  }, [timer, timeOutCallBack]);

  const resetTimer = () => {
    if (timer === 0) {
      setTimer(30);
    }
  };

  const handleResendOTP = async () => {
    try {
      const response = await resendOTP(email, mobile, requestId);
      resetTimer();
    } catch (error: any) {
      Alert.alert(
        'Error',
        error.message || 'Failed to resend OTP. Please try again.',
      );
    }
  };

  const handleOtpFilled = async () => {
    try {
      Alert.alert('Success', 'OTP Verified Successfully!', [
        {text: 'OK', onPress: () => navigation.push('SelectCompany')},
      ]);
    } catch (error: any) {
      Alert.alert('Error', error.message || 'Invalid OTP. Please try again.');
    }
  };

  return (
    <View style={styles.ScreenContainer}>
      <TouchableOpacity style={styles.ArrowContainer}>
        <Icon
          name="arrowleft"
          color="#000000"
          size={35}
          onPress={() => {
            navigation.push('PhoneNumber');
          }}
        />
      </TouchableOpacity>
      <View style={styles.DescriptionContainer}>
        <Text style={styles.DescriptionText}>OTP Verification</Text>
        <Text style={styles.DescriptionSubText}>
          Please enter the code sent to your mobile
        </Text>
        <Text style={styles.DescriptionPhoneText}>{mobile}</Text>
      </View>
      <OtpInput
        numberOfDigits={4}
        autoFocus={true}
        onFilled={setOtp}
        theme={{
          containerStyle: styles.OtpInputContainer,
          pinCodeContainerStyle: styles.PinCodeContainer,
          pinCodeTextStyle: styles.PinCodeText,
          focusStickStyle: styles.FocusStick,
          focusedPinCodeContainerStyle: styles.FocusedPinCodeContainer,
        }}
      />
      <View style={styles.FooterContainer}>
        <Text style={styles.FooterText}>
          Didn't get the code?{' '}
          <Text
            style={styles.FooterSubText}
            onPressIn={() => {
              if (timer === 0) {
                handleResendOTP();
              }
            }}>
            Resend
          </Text>{' '}
          in {timer} seconds
        </Text>
      </View>
      <TouchableOpacity
        style={styles.VerifyContainer}
        onPress={handleOtpFilled}>
        <Text style={styles.VerifyText}>Verify</Text>
      </TouchableOpacity>
    </View>
  );
};

export default OTPScreen;

I just want the fucntionality to be implemented. Can someone help?


Solution

  • import React, { useCallback, useEffect, useState } from 'react';
    
    import { Text, TouchableOpacity, View, Alert } from 'react-native';
    
    import { OtpInput } from 'react-native-otp-entry';
    
    import Icon from 'react-native-vector-icons/AntDesign';
    
    import styles from './OTPScreenStyles';
    
    import { validateOTP } from '../../../api/validateOTP';
    
    import { resendOTP } from '../../../api/resendOTP'; // Ensure correct import path
    
    import { RouteProp } from '@react-navigation/native';
    
    import { RootStackParamList } from '../../../../App';
    
    type OTPScreenRouteProp = RouteProp<RootStackParamList, 'OTPScreen'>;
    
    type OTPScreenProps = {
      navigation: any;
      route: OTPScreenRouteProp;
    };
    
    const OTPScreen: React.FC<OTPScreenProps> = ({ navigation, route }) => {
      const { email, mobile, requestId } = route.params;
    
      const [timer, setTimer] = useState(30);
      const [otp, setOtp] = useState('');
    
      const timeOutCallBack = useCallback(() => {
        setTimer(currTimer => {
          if (currTimer <= 0) return 0;
          return currTimer - 1;
        });
      }, []);
    
      useEffect(() => {
        if (timer > 0) {
          const timeoutId = setTimeout(timeOutCallBack, 1000);
          return () => clearTimeout(timeoutId);
        }
      }, [timer, timeOutCallBack]);
    
      const resetTimer = () => {
        if (timer === 0) {
          setTimer(30);
        }
      };
    
      const handleResendOTP = async () => {
        try {
          const response = await resendOTP(email, mobile, requestId);
          console.log(response); // Debug output
          resetTimer();
        } catch (error: any) {
          Alert.alert(
            'Error',
            error.message || 'Failed to resend OTP. Please try again.',
          );
        }
      };
    
      const handleOtpFilled = async () => {
        try {
          // Add validation logic here
          Alert.alert('Success', 'OTP Verified Successfully!', [
            { text: 'OK', onPress: () => navigation.push('SelectCompany') },
          ]);
        } catch (error: any) {
          Alert.alert('Error', error.message || 'Invalid OTP. Please try again.');
        }
      }
    
      return (
    
        <View style={styles.ScreenContainer}>
          <TouchableOpacity style={styles.ArrowContainer}>
            <Icon
              name="arrowleft"
              color="#000000"
              size={35}
              onPress={() => {
                navigation.push('PhoneNumber');
              }}
            />
          </TouchableOpacity>
          <View style={styles.DescriptionContainer}>
            <Text style={styles.DescriptionText}>OTP Verification</Text>
            <Text style={styles.DescriptionSubText}>
              Please enter the code sent to your mobile
            </Text>
            <Text style={styles.DescriptionPhoneText}>{mobile}</Text>
          </View>
          <OtpInput
            numberOfDigits={4}
            autoFocus={true}
            onFilled={setOtp}
            theme={{
              containerStyle: styles.OtpInputContainer,
              pinCodeContainerStyle: styles.PinCodeContainer,
              pinCodeTextStyle: styles.PinCodeText,
              focusStickStyle: styles.FocusStick,
              focusedPinCodeContainerStyle: styles.FocusedPinCodeContainer,
            }}
          />
          <View style={styles.FooterContainer}>
            <Text style={styles.FooterText}>
              Didn't get the code?{' '}
              <Text
                style={styles.FooterSubText}
                onPressIn={() => {
                  if (timer === 0) {
                    handleResendOTP();
                  }
                }}>
                Resend
              </Text>{' '}
              in {timer} seconds
            </Text>
          </View>
          <TouchableOpacity
            style={styles.VerifyContainer}
            onPress={handleOtpFilled}>
            <Text style={styles.VerifyText}>Verify</Text>
          </TouchableOpacity>
        </View>
      );
    };
    
    export default OTPScreen;