javascriptreactjsmongodbcreatecontext

console error :Uncaught (in promise) TypeError: Cannot read properties of undefined (reading 'data') at handleClick


In this page the user can login, but if the untilDate is bigger than the current date it should log out the user. The code runs fine 1/2 times, the other giving me the error on the title. I am working with createContext for user login. This is the AuthContext file

import React from "react";
import { createContext, useEffect, useReducer } from "react";

const INITIAL_STATE = {
  user: JSON.parse(localStorage.getItem("user")) || null,
  loading: false,
  error: null,
};

export const AuthContext = createContext(INITIAL_STATE);

const AuthReducer = (state, action) => {
  switch (action.type) {
    case "LOGIN_START":
      return {
        user: null,
        loading: true,
        error: null,
      };
    case "LOGIN_SUCCESS":
      return {
        user: action.payload,
        loading: false,
        error: null,
      };

    case "LOGOUT":
      return {
        user: null,
        loading: false,
        error: null,
      };
    case "LOGIN_FAILURE":
      return {
        user: null,
        loading: false,
        error: action.payload,
      };
    case "UPDATE_USER_DATE":
      const updatedUser = { ...state.user };
      updatedUser.activeUntil = action.payload;
      return {
        ...state,
        user: updatedUser,
      };

    default:
      return state;
  }
};

export const AuthContextProvider = ({ children }) => {
  const [state, dispatch] = useReducer(AuthReducer, INITIAL_STATE);

  useEffect(() => {
    localStorage.setItem("user", JSON.stringify(state.user));
  }, [state.user]);

  return (
    <AuthContext.Provider
      value={{
        user: state.user,
        loading: state.loading,
        error: state.error,
        dispatch,
      }}
    >
      {children}
    </AuthContext.Provider>
  );
};

When the user clicks the login button, it runs the handleClick function:

  const handleClick = async (e) => {
    e.preventDefault();
    dispatch({ type: "LOGIN_START" });
    let date = new Date().toJSON();
    let userdate = date;
    try {
      const res = await axios.post("/auth/signin", credentials);
      dispatch({ type: "LOGIN_SUCCESS", payload: res.data.details });
      userdate = user.activeUntil;
      //do if date is <=current datem dispatch logout
    } catch (err) {
      if (userdate > date) {
        console.log("undefined data");
      } else {
        dispatch({ type: "LOGIN_FAILURE", payload: err.response.data });
      }
    }

    if (userdate > date) {
      dispatch({ type: "LOGOUT" });
      console.log("If you are seeing this your contract has expired");
    } else {
      // navigate("/myinfo");
    }
  };


The console error happens from this line dispatch({ type: "LOGIN_FAILURE", payload: err.response.data });

Is there a way I can bypass this error or a different way I can write my code to make it work? This is the full code of login page

import React from "react";
import axios from "axios";
import { useContext, useState } from "react";
import { useNavigate } from "react-router-dom";
import { AuthContext } from "../../context/AuthContext";
import {
  Container,
  FormWrap,
  FormContent,
  Form,
  FormInput,
  FormButton,
  Icon,
  FormH1,
  SpanText,
  IconWrapper,
  IconL,
} from "./signinElements";
import Image from "../../images/Cover.png";

const Login = () => {
  const [credentials, setCredentials] = useState({
    namekey: undefined,
    password: undefined,
  });
  /* */
  // to view current user in console
  const { user, loading, error, dispatch } = useContext(AuthContext);
  let msg;
  const navigate = useNavigate();

  const handleChange = (e) => {
    setCredentials((prev) => ({ ...prev, [e.target.id]: e.target.value }));
  };

  const handleClick = async (e) => {
    e.preventDefault();
    dispatch({ type: "LOGIN_START" });
    let date = new Date().toJSON();
    let userdate = date;
    try {
      const res = await axios.post("/auth/signin", credentials);
      dispatch({ type: "LOGIN_SUCCESS", payload: res.data.details });
      userdate = user.activeUntil;
      //do if date is <=current datem dispatch logout
    } catch (err) {
      if (userdate > date) {
        console.log("undefined data");
      } else {
        dispatch({ type: "LOGIN_FAILURE", payload: err.response.data });
      }
    }

    if (userdate > date) {
      dispatch({ type: "LOGOUT" });
      console.log("If you are seeing this your contract has expired");
    } else {
      // navigate("/myinfo");
    }
  };
  // console.log(user.activeUntil); //type to view current user in console

  return (
    <>
      <Container>
        <IconWrapper>
          <IconL to="/">
            <Icon src={Image}></Icon>
          </IconL>
        </IconWrapper>
        <FormWrap>
          <FormContent>
            <Form action="#">
              <FormH1>
                Sign in with the namekey and password written to you on your
                contract.
              </FormH1>
              <FormInput
                type="namekey"
                placeholder="Namekey"
                id="namekey"
                onChange={handleChange}
                required
              />
              <FormInput
                type="password"
                placeholder="Password"
                id="password"
                onChange={handleChange}
              />

              <FormButton disabled={loading} onClick={handleClick}>
                Login
              </FormButton>
              <SpanText>{msg}</SpanText>
              {error && <SpanText>{error.message}</SpanText>}
              {error && (
                <SpanText>
                  Forgot namekey or password? Contact our support team +355 69
                  321 5237
                </SpanText>
              )}
            </Form>
          </FormContent>
        </FormWrap>
      </Container>
    </>
  );
};

export default Login;


Solution

  • The problem was i was trying to call a localy stored user and 1 time it wasnt loaded and the other it was. Simply fixed it by changing the if statement to check directly in result details without having to look in local storage.

    const [expired, setExpired] = useState(false);
    
      const handleClick = async (e) => {
        e.preventDefault();
        dispatch({ type: "LOGIN_START" });
    
        try {
          const res = await axios.post("/auth/signin", credentials);
          dispatch({ type: "LOGIN_SUCCESS", payload: res.data.details });
          let date = new Date().toJSON();
          if (res.data.details.activeUntil < date) {
            dispatch({ type: "LOGOUT" });
            console.log("Users contract has expired");
            setExpired(!expired);
          } else {
            navigate("/myinfo");
          }
        } catch (err) {
          dispatch({ type: "LOGIN_FAILURE", payload: err.response.data });
        }
      };