Search code examples
reactjsmongodbredux

MERN stack Forget Password doesn't work on frontend (Postman works perfectly fine)


MERN stack Forget Password doesn't work on frontend (Postman works perfectly fine). when put the email and click the send button then showing this error - user not found I'm trying but I can't solve the problem. Please give me some advice.

userController.js

const ErrorHandler = require("../utils/errorHandler");
const catchAsyncErrors = require("../middleware/catchAsyncError");
const User = require('../models/userModel');
const sendEmail = require("../utils/sendMail")

exports.forgotPassword = catchAsyncErrors(async (req, res, next) => {
  const user = await User.findOne({email: req.body.email});

  if (!user) {
    return next(new ErrorHandler("User not found", 404));
  }

  const resetToken = user.getResetPasswordToken();

  await user.save({ validateBeforeSave: false });

  const resetPasswordUrl =`${req.protocol}://${req.get("host")}/api/v1/password/reset/${resetToken}`;

  const message = `Your password reset token is :- \n\n ${resetPasswordUrl} \n\nIf you have not requested this email then, please ignore it.`;

  try {
    await sendEmail({
      email: user.email,
      subject: `Ecommerce Password Recovery`,
      message,
    });

    res.status(200).json({
      success: true,
      message: `Email sent to ${user.email} successfully`,
    });
  } catch (error) {
    user.resetPasswordToken = undefined;
    user.resetPasswordExpire = undefined;

    await user.save({ validateBeforeSave: false });

    return next(new ErrorHandler(error.message, 500));
  }
});

userRoute.js

const express = require("express");
const router = express.Router();
const {forgotPassword} = require("../controllers/userController");
router.route("/password/forgot").post(forgotPassword);

app.js

const user = require('./routes/userRoute');
app.use('/api/v1',user);

userConstant.js

export const FORGOT_PASSWORD_REQUEST = "FORGOT_PASSWORD_REQUEST";
export const FORGOT_PASSWORD_SUCCESS = "FORGOT_PASSWORD_SUCCESS";
export const FORGOT_PASSWORD_FAIL = "FORGOT_PASSWORD_FAIL";
export const CLEAR_ERRORS ="CLEAR_ERRORS";

userReducer.js

import {
    FORGOT_PASSWORD_REQUEST,
    FORGOT_PASSWORD_SUCCESS,
    FORGOT_PASSWORD_FAIL,
    CLEAR_ERRORS
  } from "../constants/userConstant";
 export const forgotPasswordReducer = (state = {}, action) => {
    switch (action.type) {
      case FORGOT_PASSWORD_REQUEST:
        return {
          ...state,
          loading: true,
          error: null,
        };
      case FORGOT_PASSWORD_SUCCESS:
        return {
          ...state,
          loading: false,
          message: action.payload,
        };
      case FORGOT_PASSWORD_FAIL:
        return {
          ...state,
          loading: false,
          error: action.payload,
        };
  
      case CLEAR_ERRORS:
        return {
          ...state,
          error: null,
        };
  
      default:
        return state;
    }
  };

userAction.js

import {
    FORGOT_PASSWORD_REQUEST,
    FORGOT_PASSWORD_SUCCESS,
    FORGOT_PASSWORD_FAIL,
    CLEAR_ERRORS
  } from "../constants/userConstant";
export const forgotPassword = (email) => async (dispatch) => {
  try {
    dispatch({ type: FORGOT_PASSWORD_REQUEST });

    const { data } = await axios.post(`/api/v1/password/forgot`, email);

    dispatch({ type: FORGOT_PASSWORD_SUCCESS, payload: data.message });
  } catch (error) {
    dispatch({
      type: FORGOT_PASSWORD_FAIL,
      payload: error.response.data.message,
    });
  }
};

ForgotPassword.js

import React, { Fragment, useState, useEffect } from "react";
import "./ForgetPassword.css";
import Loader from "../Loader/Loader";
import { useDispatch, useSelector } from "react-redux";
import { clearErrors, forgotPassword } from "../../actions/userAction";

const ForgetPassword = () => {
  const dispatch = useDispatch();

  const { error, message, loading } = useSelector(
    (state) => state.forgotPassword
  );

  const [email, setEmail] = useState("");

  const forgotPasswordSubmit = (e) => {
    e.preventDefault();

    const myForm = new FormData();

    myForm.set("email", email);
    dispatch(forgotPassword(myForm));
  };

  useEffect(() => {
    if (error) {
      alert(error);
      dispatch(clearErrors());
    }
    if (message) {
      alert(message);
    }
  }, [dispatch, error, message]);

  return (
    <Fragment>
      {loading ? (
        <Loader />
      ) : (
        <Fragment>
          <div className="forgotPasswordContainer">

              <form className="forgotPasswordForm" onSubmit={forgotPasswordSubmit}>
              <h2 className="forgotPasswordHeading">Forgot Password</h2>
                <input className="inputsignforgot" type="email" placeholder="Email" required name="email"
                  value={email} onChange={(e) => setEmail(e.target.value)} />
                <input type="submit" value="Send" className="forgotPasswordBtn" />
              </form>

        
          </div>
        </Fragment>
      )}
    </Fragment>
  );
};

export default ForgetPassword;

App.js

import ForgotPassword from './components/Users/ForgotPassword';
<Route path='/password/forgot' exact element={<ForgotPassword/>} />

Solution

  • Try to change the dispatch call to accept the email as a parameter in ForgotPassword (as @AndrewAllison suggested):

    const forgotPasswordSubmit = (e) => {
      e.preventDefault();
      dispatch(forgotPassword(email));
    };
    

    Also, change your axios call to send the body parameter as an object:

    export const forgotPassword = (email) => async (dispatch) => {
      try {
        dispatch({ type: FORGOT_PASSWORD_REQUEST });
    
        // Send body param as object
        const { data } = await axios.post(`/api/v1/password/forgot`, { email });
    
        dispatch({ type: FORGOT_PASSWORD_SUCCESS, payload: data.message });
      } catch (error) {
        dispatch({
          type: FORGOT_PASSWORD_FAIL,
          payload: error.response.data.message,
        });
      }
    };