This webpage is in a perpetual state of loading and I don't know why. It's almost as if it's awaiting the data. I tested the backend and the user exists and should be being sent but it's just waiting. I also tried isolating the the code so that it's just the bare minimum needed and there's still the perpetual loading. The This is what it looks like: Edit user Error Below is the code:
UserEditScreens.js
import axios from "axios";
import React, { useContext, useEffect, useReducer, useState } from "react";
import Container from "react-bootstrap/Container";
import Button from "react-bootstrap/Button";
import Form from "react-bootstrap/Form";
import { Helmet } from "react-helmet-async";
import { useNavigate, useParams } from "react-router-dom";
import { toast } from "react-toastify";
import LoadingBox from "../components/LoadingBox";
import MessageBox from "../components/MessageBox";
import { getError } from "../utils";
import { Store } from "./Store";
const reducer = (state, action) => {
switch (action.value) {
case "FETCH_REQUEST":
return { ...state, loading: true };
case "FETCH_SUCCESS":
return { ...state, loading: false };
case "FETCH_FAIL":
return { ...state, loading: false, error: action.payload };
case "UPDATE_REQUEST":
return { ...state, loadingUpdate: true };
case "UPDATE_SUCCESS":
return { ...state, loadingUpdate: false };
case "UPDATE_FAIL":
return { ...state, loadingUpdate: false };
default:
return state;
}
};
export default function UserEditScreen() {
const [{ loading, error, loadingUpdate }, dispatch] = useReducer(reducer, {
loading: true,
error: "",
});
const { state } = useContext(Store);
const { userInfo } = state;
const params = useParams();
const { id: userId } = params;
const navigate = useNavigate();
const [firstName, setFirstName] = useState("");
const [lastName, setLastName] = useState("");
const [email, setEmail] = useState("");
const [isAdmin, setIsAdmin] = useState(false);
useEffect(() => {
const fetchData = async () => {
try {
dispatch({ type: "FETCH_REQUEST" });
const { data } = await axios.get(`/api/users/${userId}`, {
headers: { authorization: `Bearer ${userInfo.token}` },
});
dispatch({ type: "FETCH_SUCCESS", payload: data });
} catch (err) {
dispatch({ type: "FETCH_FAIL", payload: getError(err) });
}
};
fetchData();
}, [userInfo, userId]);
const submitHandler = async (e) => {
e.preventDefault();
try {
dispatch({ type: "UPDATE_REQUEST" });
await axios.put(
`/api/users/${userId}`,
{ _id: userId, firstName, lastName, email, isAdmin },
{ headers: { Authorization: `Bearer ${userInfo.token}` } }
);
dispatch({ type: "UPDATE_SUCCESS" });
toast.success("User updated successfully");
navigate("/admin/users");
} catch (error) {
toast.error(getError(error));
dispatch({ type: "UPDATE_FAIL" });
}
};
return (
<Container>
<Helmet>Edit User #{userId}</Helmet>
<h1>Edit User #{userId}</h1>
{loading ? (
<LoadingBox></LoadingBox>
) : error ? (
<MessageBox variant="danger">{error}</MessageBox>
) : (
<Form onSubmit={submitHandler}>
<Form.Group className="mb-3" controlId="firstName">
<Form.Label>First Name</Form.Label>
<Form.Control
value={firstName}
type="name"
onChange={(e) => setFirstName(e.target.value)}
required
></Form.Control>
</Form.Group>
<Form.Group>
<Form.Label>Last Name</Form.Label>
<Form.Control
value={lastName}
type="name"
onChange={(e) => setLastName(e.target.value)}
required
></Form.Control>
</Form.Group>
<Form.Group className="mb-3" controlId="lastName">
<Form.Label>Email</Form.Label>
<Form.Control
value={email}
type="email"
onChange={(e) => setEmail(e.target.value)}
required
></Form.Control>
</Form.Group>
<Form.Check
className="mb-3"
type="checkbox"
id="isAdmin"
label="isAdmin"
checked={isAdmin}
onChange={(e) => setIsAdmin(e.target.checked)}
></Form.Check>
<div>
<Button disabled={loadingUpdate} type="submit">
Update
</Button>
{loadingUpdate && <LoadingBox></LoadingBox>}
</div>
</Form>
)}
</Container>
);
}
UserRoutes.js
import express from "express";
import User from "../models/userModel.js";
import bcrypt from "bcryptjs";
import { generateToken, isAuth } from "../utils.js";
import expressAsyncHandler from "express-async-handler";
const userRouter = express.Router();
userRouter.get(
"/",
isAuth,
expressAsyncHandler(async (req, res) => {
const users = await User.find();
res.send(users);
})
);
userRouter.get(
"/:id",
isAuth,
expressAsyncHandler(async (req, res) => {
const user = await User.findById(req.params.id);
if (user) {
console.log(user);
res.send(user);
} else {
res.status(404).send({ message: "User Not Found" });
}
})
);
userRouter.put(
"/:id",
isAuth,
expressAsyncHandler(async (req, res) => {
if (user) {
const user = await User.findById(req.params.id);
user.firstName = req.body.firstName || user.firstName;
user.lastName = req.body.lastName || user.lastName;
user.email = req.body.email || user.email;
user.isAdmin = Boolean(req.body.isAdmin);
const updatedUser = await user.save();
res.send({ message: "User Updated", user: updatedUser });
} else {
res.status(404).send({ message: "User Not Found" });
}
})
);
userRouter.post(
"/signin",
expressAsyncHandler(async (req, res) => {
const user = await User.findOne({ email: req.body.email });
if (user) {
if (bcrypt.compareSync(req.body.password, user.password)) {
res.send({
_id: user._id,
name: user.firstName,
email: user.email,
token: generateToken(user),
});
return;
}
}
res.status(401).send({ message: "Invalid email or password" });
})
);
userRouter.post(
"/signup",
expressAsyncHandler(async (req, res) => {
const newUser = new User({
firstName: req.body.firstName,
lastName: req.body.firstName,
email: req.body.email,
password: bcrypt.hashSync(req.body.password),
});
const user = await newUser.save();
res.send({
_id: user._id,
firstName: user.firstName,
email: user.email,
isAdmin: user.isAdmin,
token: generateToken(user),
});
})
);
userRouter.put(
"/profile",
isAuth,
expressAsyncHandler(async (req, res) => {
const user = await User.findById(req.user._id);
if (user) {
user.name = req.body.name || user.name;
user.email = req.body.email || user.email;
if (req.body.password) {
user.password = bcrypt.hashSync(req.body.password, 8);
}
const updatedUser = await user.save();
res.send({
_id: updatedUser._id,
name: updatedUser.name,
email: updatedUser.email,
isAdmin: updatedUser.isAdmin,
token: generateToken(updatedUser),
});
} else {
res.status(404).send({ message: "User not found" });
}
})
);
export default userRouter;
Related
Scenario : When I create/register user1 ,the verification mail is sent to that email id and he(user1) is being verified successfully and I am able to change password for user1. After creating user1 , I am creating/registering user2 ,where the verification email is sent to the account .After clicking the link , it's becomes INVALID Overall , I am only able to create one user
Languages used : MERN stack
Backend => route.js :
const express = require("express");
const router = express.Router();
const User = require("../models/userModel");
const Doctor = require("../models/doctorModel");
const bcrypt = require("bcryptjs");
const jwt = require("jsonwebtoken");
const authMiddleware = require("../middlewares/authMiddleware");
const sendEmail = require("../utils/sendMail");
const Token = require("../models/tokenModel");
const Appointment = require("../models/appointmentModel");
const moment = require("moment");
router.post("/register", async (req, res) => {
try {
const userExists = await User.findOne({ email: req.body.email });
if (userExists) {
return res
.status(200)
.send({ message: "User already exists", success: false });
}
const password = req.body.password;
const salt = await bcrypt.genSalt(10);
const hashedPassword = await bcrypt.hash(password, salt);
req.body.password = hashedPassword;
const newuser = new User(req.body);
const result = await newuser.save();
await sendEmail(result, "verifyemail");
res
.status(200)
.send({ message: "User created successfully", success: true });
} catch (error) {
console.log(error);
res
.status(500)
.send({ message: "Error creating user", success: false, error });
}
});
router.post("/login", async (req, res) => {
try {
const result = await User.findOne({ data: req.body.userId });
console.log(result);
const user = await User.findOne({ email: req.body.email });
if (!user) {
return res
.status(200)
.send({ message: "User does not exist", success: false });
}
if (user.isVerified === false) {
return res
.status(200)
.send({ message: "User not Verified", success: false });
}
const isMatch = await bcrypt.compare(req.body.password, user.password);
if (!isMatch) {
return res
.status(200)
.send({ message: "Password is incorrect", success: false });
} else {
const dataToBeSentToFrontend = {
id: user._id,
email: user.email,
name: user.name,
};
const token = jwt.sign(dataToBeSentToFrontend, process.env.JWT_SECRET, {
expiresIn: "1d",
});
res
.status(200)
.send({ message: "Login successful", success: true, data: token });
}
} catch (error) {
console.log(error);
res
.status(500)
.send({ message: "Error logging in", success: false, error });
}
});
router.post("/get-user-info-by-id", authMiddleware, async (req, res) => {
try {
const user = await User.findOne({ _id: req.body.userId });
user.password = undefined;
if (!user) {
return res
.status(200)
.send({ message: "User does not exist", success: false });
} else {
res.status(200).send({
success: true,
data: user,
});
}
} catch (error) {
res
.status(500)
.send({ message: "Error getting user info", success: false, error });
}
});
router.post("/send-password-reset-link", async (req, res) => {
try {
const result = await User.findOne({ email: req.body.email });
await sendEmail(result, "resetpassword");
res.send({
success: true,
message: "Password reset link sent to your email successfully",
});
} catch (error) {
res.status(500).send(error);
}
});
router.post("/resetpassword", async (req, res) => {
try {
const tokenData = await Token.findOne({ token: req.body.token });
if (tokenData) {
const password = req.body.password;
const salt = await bcrypt.genSalt(10);
const hashedPassword = await bcrypt.hash(password, salt);
await User.findOneAndUpdate({
_id: tokenData.userid,
password: hashedPassword,
});
await Token.findOneAndDelete({ token: req.body.token });
res.send({ success: true, message: "Password reset successfull" });
} else {
res.send({ success: false, message: "Invalid token" });
}
} catch (error) {
res.status(500).send(error);
}
});
router.post("/verifyemail", async (req, res) => {
try {
const tokenData = await Token.findOne({ token: req.body.token });
if (tokenData) {
await User.findOneAndUpdate({ _id: tokenData.userid, isVerified: true });
await Token.findOneAndDelete({ token: req.body.token });
res.send({ success: true, message: "Email Verified Successlly" });
} else {
res.send({ success: false, message: "Invalid token" });
}
} catch (error) {
res.status(500).send(error);
}
});
Backend => sendEmail.js :
const nodemailer = require("nodemailer");
const bcrypt = require("bcrypt");
const Token = require("../models/tokenModel");
module.exports = async (user, mailType) => {
try {
const transporter = nodemailer.createTransport({
service: "gmail",
host: "smtp.gmail.com",
port: 587,
secure: true,
auth: {
user: "sh***********th#gmail.com",
pass: "e**************l",
},
});
const encryptedToken = bcrypt
.hashSync(user._id.toString(), 10)
.replaceAll("/", "");
const token = new Token({
userid: user._id,
token: encryptedToken,
});
await token.save();
let mailOptions, emailContent;
if (mailType === "verifyemail") {
emailContent = `<div><h1>Please click on the below link to verify your email address</h1> ${encryptedToken} </div>`;
mailOptions = {
from: "sh************th#gmail.com",
to: user.email,
subject: "Verify Email For MERN Auth",
html: emailContent,
};
} else {
emailContent = `<div><h1>Please click on the below link to reset your password</h1> ${encryptedToken} </div>`;
mailOptions = {
from: "shanshangeeth#gmail.com",
to: user.email,
subject: "Reset Password",
html: emailContent,
};
}
await transporter.sendMail(mailOptions);
} catch (error) {
console.log(error);
}
};
Backend => authMiddleware.js :
const jwt = require("jsonwebtoken");
module.exports = async (req, res, next) => {
try {
const token = req.headers["authorization"].split(" ")[1];
jwt.verify(token, process.env.JWT_SECRET, (err, decoded) => {
if (err) {
return res.status(401).send({
message: "Auth failed",
success: false,
});
} else {
req.body.userId = decoded.id;
next();
}
});
} catch (error) {
return res.status(401).send({
message: "Auth failed",
success: false,
});
}
};
Backend => tokenmodel.js :
const mongoose = require("mongoose");
const tokenSchema = new mongoose.Schema(
{
userid: {
type: String,
required: true,
},
token: {
type: String,
required: true,
},
},
{ timestamps: true }
);
const tokenModel = mongoose.model("tokens", tokenSchema);
module.exports = tokenModel;
Backend => userModel.js
const mongoose = require("mongoose");
const userSchema = new mongoose.Schema(
{
name: {
type: String,
required: true,
},
email: {
type: String,
required: true,
},
password: {
type: String,
required: true,
},
isVerified: {
type: Boolean,
default: false,
},
isDoctor: {
type: Boolean,
default: false,
},
isDoctor: {
type: Boolean,
default: false,
},
isAdmin: {
type: Boolean,
default: false,
},
seenNotifications: {
type: Array,
default: [],
},
unseenNotifications: {
type: Array,
default: [],
},
},
{
timestamps: true,
}
);
const userModel = mongoose.model("users", userSchema);
module.exports = userModel;
Frontend => VerifyEmail.js
path="/verifyemail/:token" in app.js inside PublicRoute
import React, { useState, useEffect } from "react";
import { useParams } from "react-router-dom";
import { toast } from "react-hot-toast";
import axios from "axios";
function VerifyEmail() {
const [emailVerified, setEmailVerified] = useState("");
const params = useParams();
const verifyToken = async () => {
try {
toast.loading();
const response = await axios.post("/api/user/verifyemail", {
token: params.token,
});
if (response.data.success) {
setEmailVerified("true");
} else {
setEmailVerified("false");
}
toast.dismiss();
} catch (error) {
toast.dismiss();
setEmailVerified("false");
}
};
useEffect(() => {
verifyToken();
}, []);
console.log(emailVerified);
return (
<div className="flex min-h-screen p-5 justify-center items-center">
{emailVerified == "" && (
<h1 className="text-primary text-4xl">
Please wait we are verifying your email
</h1>
)}
{emailVerified == "true" && (
<h1 className="text-primary text-4xl">
Your email verified successfully
</h1>
)}
{emailVerified == "false" && (
<h1 className="text-primary text-4xl">
Invalid or Expired Token
{console.log(emailVerified)}
</h1>
)}
</div>
);
}
export default VerifyEmail;
Frontend =>ProtectedRoute.js
import React from "react";
import { Navigate, useNavigate } from "react-router-dom";
import { useEffect } from "react";
import { useDispatch, useSelector } from "react-redux";
import axios from "axios";
import { setUser } from "../redux/userSlice";
import { showLoading, hideLoading } from "../redux/alertsSlice";
function ProtectedRoute(props) {
const { user } = useSelector((state) => state.user);
const dispatch = useDispatch();
const navigate = useNavigate();
const getUser = async () => {
try {
dispatch(showLoading());
const response = await axios.post(
"/api/user/get-user-info-by-id",
{ token: localStorage.getItem("token") },
{
headers: {
Authorization: `Bearer ${localStorage.getItem("token")}`,
},
}
);
console.log('TOKEN ("token") : ', localStorage.getItem("token"));
dispatch(hideLoading());
if (response.data.success) {
dispatch(setUser(response.data.data));
console.log(response.data.data);
} else {
localStorage.clear();
navigate("/login");
}
} catch (error) {
dispatch(hideLoading());
localStorage.clear();
navigate("/login");
}
};
useEffect(() => {
if (!user) {
getUser();
}
}, [user]);
if (localStorage.getItem("token")) {
return props.children;
} else {
return <Navigate to="/login" />;
}
}
export default ProtectedRoute;
Frontend=> VerifyEmail.js
import React, { useState, useEffect } from "react";
import { useParams } from "react-router-dom";
import { toast } from "react-hot-toast";
import axios from "axios";
function VerifyEmail() {
const [emailVerified, setEmailVerified] = useState("");
const params = useParams();
const verifyToken = async () => {
try {
toast.loading();
const response = await axios.post("/api/user/verifyemail", {
token: params.token,
});
if (response.data.success) {
setEmailVerified("true");
} else {
setEmailVerified("false");
}
toast.dismiss();
} catch (error) {
toast.dismiss();
setEmailVerified("false");
}
};
useEffect(() => {
verifyToken();
}, []);
console.log(emailVerified);
return (
<div className="flex min-h-screen p-5 justify-center items-center">
{emailVerified == "" && (
<h1 className="text-primary text-4xl">
Please wait we are verifying your email
</h1>
)}
{emailVerified == "true" && (
<h1 className="text-primary text-4xl">
Your email verified successfully
</h1>
)}
{emailVerified == "false" && (
<h1 className="text-primary text-4xl">
Invalid or Expired Token
{console.log(emailVerified)}
</h1>
)}
</div>
);
}
export default VerifyEmail;
Frontend => userSlice.js
import { createSlice } from "#reduxjs/toolkit";
export const userSlice = createSlice({
name: "user",
initialState: {
user: null
},
reducers: {
setUser: (state , action) => {
state.user = action.payload;
}
},
});
export const { setUser , reloadUserData } = userSlice.actions;
When I create/register user1 , the verification mail is sent to that email id and he(user1) is being verified successfully and I am able to change password for user1. After creating user1 , I am creating/registering user2 ,where the verification email is sent to the account .After clicking the link , it's becomes INVALID Overall , I am only able to create one user who's being verified
I am having an issue with my React Redux and Node app. I am trying to Log in an existing user but in my console i am getting the following error:
Uncaught (in promise) TypeError: error.response.data is undefined
The console points to the following block of code:
export const login = (email, password) => async (dispatch) => {
const body = { email, password };
try {
const res = await axios.post('http://localhost:5000/api/auth', body);
dispatch({
type: LOGIN_SUCCESS,
payload: res.data
});
dispatch(loadUSer());
} catch (err) {
const errors = err.response.data.errors;
if (errors) {
errors.forEach((error) => dispatch(setAlert(error.msg, 'danger')));
}
dispatch({
type: LOGIN_FAIL
});
}
};
This is my server side for user auth auth.js:
const express = require('express');
const router = express.Router();
const User = require('../../models/User');
const auth = require('../../middleware/auth');
const config = require('config');
const bcrypt = require('bcryptjs');
const jwt = require('jsonwebtoken');
const { check , validationResult } = require('express-validator/');
//#route GET api/auth
//#desc Test route
//#access public
router.get('/',auth, async(req, res)=> {
try{
const user = await User.findById(req.user.id).select('-password');
res.json(user);
}catch(err){
console.error(err.message);
res.status(500).send('Server Error');
}
});
//#route POST api/auth
//#desc Authenticate user & get token
//#access public
router.post('/', [
check('email', 'Plese include a valid email').isEmail(),
check('password', 'Password is required').exists()
],
async (req, res)=> {
const errors = validationResult(req);
if(!errors.isEmpty()){
return res.status(400).json({ errors:errors.array()}); //400 is for bad requests
}
const { email, password } = req.body;
try{
//See if user exists
let user = await User.findOne({ email });
if(!user){
return res.status(400).json({ errors: [{ msg:'Invalid credentials' }] });
}
//Compare the input password, plane text, to the encrypted password.
const isMatch = await bcrypt.compare(password, user.password);
if(!isMatch){
return res.status(400).json({ errors: [{ msg:'Invalid credentials' }] });
}
//Return jsonwebtoken -> this for users to be logged in right after registration
const payload = {
user:{
id: user.id
}
}
jwt.sign(
payload,
config.get('jwtSecret'),
{expiresIn: 360000}, //change to 3600 for production
(err, token)=>{
if(err) throw err;
res.json({ token });
}
)
}catch(err){
console.error(err.message);
res.status(500).send('Server Error');
}
});
module.exports = router;
And this is my Login component:
import React, { Fragment, useState } from 'react'
/* import axios, { Axios } from 'axios'; */
import { Link, Navigate } from 'react-router-dom'
import { connect } from 'react-redux';
import { PropTypes } from 'prop-types';
import { login } from '../../actions/auth';
const Login = ({ login, isAuthenticated }) => {
const [formData, setFormData] = useState({
email: '',
password: ''
});
const { email, password } = formData;
const onChange = e => setFormData({
...formData, [e.target.name]:e.target.value
});
const onSubmit = async e => {
e.preventDefault();
login(email, password);
}
//Redirect if logged in
if(isAuthenticated){
return <Navigate to="/dashboard"/>;
}
return (
<Fragment>
<section className='container'>
<h1 className="large text-primary">Sign Up</h1>
<p className="lead"><i className="fas fa-user"></i> Sign Into Your Account</p>
<form className="form" action="create-profile.html" onSubmit={e => onSubmit(e)}>
<div className="form-group">
<input type="email"
placeholder="Email Address"
name="email" value={email}
onChange={e => onChange(e)}
required/>
</div>
<div className="form-group">
<input
type="password"
placeholder="Password"
name="password"
minLength="6"
value={password}
onChange={e => onChange(e)}
required
/>
</div>
<input type="submit" className="btn btn-primary" value="Login" />
</form>
<p className="my-1">
Don´t have an account? <Link to="/register">Sign up</Link>
</p>
</section>
</Fragment>
)
}
Login.propTypes = {
login: PropTypes.func.isRequired,
isAuthenticated: PropTypes.bool
}
const mappedStateToProps = state => ({
isAuthenticated: state.auth.isAuthenticated
})
export default connect(mappedStateToProps , { login })(Login)
For some reason there are sometimes i am able to login and sometimes i encounter this issue but i cannot figure out what am i doing wrong.
My redux devtools also show the AUTH_ERROR action type:
This is my auth.js in my actions directory.
export const loadUSer = () => async dispatch => {
if(localStorage.token){
setAuthToken(localStorage.token);
}
try {
const res = await axios.get('http://localhost:5000/api/auth');
dispatch({
type: USER_LOADED,
payload: res.data
})
} catch (error) {
dispatch({
type:AUTH_ERROR
})
}
}
auth.js (reducers directory):
import{
REGISTER_FAIL,
REGISTER_SUCCESS,
USER_LOADED,
AUTH_ERROR,
LOGIN_SUCCESS,
LOGIN_FAIL,
LOGOUT
} from '../actions/types'
const initialState = {
token: localStorage.getItem('token'),
isAuthenticated: null,
loading: true,
user: null
}
function authReducer(state = initialState, action){
const { type, payload } = action
switch (type) {
case USER_LOADED:
return {
...state,
isAuthenticated:true,
loading: false,
user:payload
}
case LOGIN_SUCCESS:
case REGISTER_SUCCESS:
localStorage.setItem('token', payload.token);
return {
...state,
...payload,
isAuthenticated: true,
loading: false
}
case LOGOUT:
case LOGIN_FAIL:
case REGISTER_FAIL:
case AUTH_ERROR:
localStorage.removeItem('token');
return {
...state,
toke: null,
isAuthenticated: false,
loading: false
}
default:
return state;
}
}
export default authReducer
So i first log in with an user everything works fine, i logout and log in with a different user and also works, i now logout and want to login to the first user again and the error shows up. The only difference between both users is that one has a profile and the other one doesn´t.
When i try to log in with the user with no profile my app crashes and my vscode terminal shows a different errors:
Can't set headers after they are sent to the client
I'm creating new app(e-commerce) using react and react-redux with axios. For back-end using Mongo-DB(MERN stack).
There is no problem when saving data to database, but when i get that data from database middleware can not reach token from headers. But postman work fine both get and save data.
I use the same middleware when saving data to database, it work fine. But when i try to fetch data from database i get unauthorized error.
here is my code.
FOR BACK-END;
Server file;
import express from "express";
import connectDB from "./config/db.js";
import dotenv from "dotenv";
import colors from "colors";
import productRoutes from "./routes/productRoutes.js";
import userRouters from "./routes/userRoutes.js";
import shippingAddressRoutes from "./routes/shippingAddressRoutes.js";
import { notFound, errorHandler } from "./middleware/errorMiddleware.js";
dotenv.config();
connectDB();
const app = express();
// body parser
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
// API route
app.get("/", (req, res) => {
res.send("API is running....");
});
// route for products
app.use("/api/products", productRoutes);
// route for users
app.use("/api/users", userRouters);
// route for shipping address
app.use("/api/shippingaddress", shippingAddressRoutes);
app.use(notFound);
app.use(errorHandler);
const PORT = process.env.PORT || 5000;
app.listen(
PORT,
console.log(
`Server running in ${process.env.NODE_ENV} mode on port ${PORT}`.yellow.bold
)
);
shippingAddressRoute file;
import express from "express";
import {
saveAddress,
changeAddress,
getAddress,
} from "../controllers/shippingAddressController.js";
import protect from "../middleware/authMiddleware.js";
const router = express.Router();
router
.route("/")
.get(protect, getAddress)
.post(protect, saveAddress)
.put(protect, changeAddress);
export default router;
shippingAddressController file;
import asyncHandler from "express-async-handler";
import ShippingAddress from "../models/shippingAddressModel.js";
import User from "../models/userModel.js";
// #desc get address
// #route GET /api/shippingaddress
// #access Private
const getAddress = asyncHandler(async (req, res) => {
const user = User.findById(req.user._id);
if (user) {
const { email } = req.body;
const shippingAddress = await ShippingAddress.findOne({
userEmail: email,
});
if (shippingAddress) {
res.status(200);
res.json({
address: shippingAddress.address,
city: shippingAddress.city,
postalCode: shippingAddress.postalCode,
county: shippingAddress.country,
email: shippingAddress.userEmail,
});
} else {
res.status(404);
throw new Error("Address not found");
}
} else {
res.status(404);
throw new Error("User not found");
}
});
// #desc save address
// #route POST /api/shippingaddress
// #access Private
const saveAddress = asyncHandler(async (req, res) => {
const user = User.findById(req.user._id);
if (user) {
const { address, city, postalCode, country, email } = req.body;
const existAddress = await ShippingAddress.findOne({ userEmail: email });
if (existAddress) {
res.status(400);
throw new Error(
"User already has an address. If you want to change address, try CHANGE ADDRESS."
);
} else {
const createdAddress = await ShippingAddress.create({
user: req.user._id,
address,
city,
postalCode,
country,
userEmail: email,
});
if (createdAddress) {
res.status(201);
res.json({
address: createdAddress.address,
city: createdAddress.city,
postalCode: createdAddress.postalCode,
county: createdAddress.country,
email: createdAddress.userEmail,
});
} else {
res.status(400);
throw new Error("Address did not save");
}
}
} else {
res.status(404);
throw new Error("User not found");
}
});
// #desc change address
// #route PUT /api/shippingaddress
// #access Private
const changeAddress = asyncHandler(async (req, res) => {
const user = await User.findById(req.user._id);
if (user) {
const { email } = req.body;
const shippingAddress = await ShippingAddress.findOne({
userEmail: email,
});
if (shippingAddress) {
shippingAddress.address = req.body.address || shippingAddress.address;
shippingAddress.city = req.body.city || shippingAddress.city;
shippingAddress.postalCode =
req.body.postalCode || shippingAddress.postalCode;
shippingAddress.country = req.body.country || shippingAddress.country;
const updatedShippingAddress = await shippingAddress.save();
res.status(200);
res.json({
address: updatedShippingAddress.address,
city: updatedShippingAddress.city,
postalCode: updatedShippingAddress.postalCode,
county: updatedShippingAddress.country,
email: updatedShippingAddress.userEmail,
});
} else {
res.status(404);
throw new Error("Address not found");
}
} else {
res.status(404);
throw new Error("User not found");
}
});
export { getAddress, saveAddress, changeAddress };
authMiddleware file;
import jwt from "jsonwebtoken";
import User from "../models/userModel.js";
import asyncHandler from "express-async-handler";
const protect = asyncHandler(async (req, res, next) => {
let token = req.headers.token;
if (
req.headers.authorization &&
req.headers.authorization.startsWith("Bearer")
) {
try {
// get token from req
token = req.headers.authorization.split(" ")[1];
// verify token
const decode = jwt.verify(token, process.env.JWT_SECRET);
// get user from token
req.user = await User.findById(decode.id).select("-password");
next();
} catch (error) {
res.status(401);
throw new Error("Not1 Authorized");
}
}
if (!token) {
res.status(401);
throw new Error("Not2 Authorized");
}
});
export default protect;
FOR FRONT-END;
shippingAction file;
import { createAsyncThunk } from "#reduxjs/toolkit";
import shippingServices from "./shippingServices";
// get address
export const getAddress = createAsyncThunk(
"shipping/get",
async (userInfo, thunkAPI) => {
try {
return await shippingServices.get(userInfo);
} catch (error) {
const message =
(error.response &&
error.response.data &&
error.response.data.message) ||
error.message ||
error.toString();
return thunkAPI.rejectWithValue(message);
}
}
);
// save address
export const saveAddress = createAsyncThunk(
"shipping/save",
async (addressInfo, thunkAPI) => {
try {
return await shippingServices.save(addressInfo);
} catch (error) {
const message =
(error.response &&
error.response.data &&
error.response.data.message) ||
error.message ||
error.toString();
return thunkAPI.rejectWithValue(message);
}
}
);
// update address
export const updateAddress = createAsyncThunk(
"shipping/update",
async (addressInfo, thunkAPI) => {
try {
return await shippingServices.update(addressInfo);
} catch (error) {
const message =
(error.response &&
error.response.data &&
error.response.data.message) ||
error.message ||
error.toString();
return thunkAPI.rejectWithValue(message);
}
}
);
shippingServices file;
import axios from "axios";
const SHIPPING_ADDRESS_URL = "/api/shippingaddress";
// save address
const save = async (addressInfo) => {
const config = {
headers: {
Authorization: `Bearer ${addressInfo.token}`,
},
};
const { data } = await axios.post(SHIPPING_ADDRESS_URL, addressInfo, config);
return data;
};
// get address
const get = async (userInfo) => {
const config = {
headers: {
Authorization: `Bearer ${userInfo.token}`,
},
};
const { data } = await axios.get(SHIPPING_ADDRESS_URL, userInfo, config);
return data;
};
// update address
const update = async (addressInfo) => {
const config = {
headers: {
Authorization: `Bearer ${addressInfo.token}`,
},
};
const { data } = await axios.put(SHIPPING_ADDRESS_URL, addressInfo, config);
return data;
};
const shippingServices = {
save,
get,
update,
};
export default shippingServices;
shippigPage file;
import React, { useState, useEffect } from "react";
import { Link, useNavigate } from "react-router-dom";
import { Form, Button } from "react-bootstrap";
import { useDispatch, useSelector } from "react-redux";
import FormContainer from "../components/FormContainer";
import Message from "../components/Message";
import Loader from "../components/Loader";
import { shippingSliceAction } from "../features/shipping/shippingSlice";
import { saveAddress, getAddress } from "../features/shipping/shippingAction";
function ShippingPage() {
const { user } = useSelector((state) => state.auth);
const { shippingAddress, isLoading, isSuccess, isError, message } =
useSelector((state) => state.shipping);
const [address, setAddress] = useState("");
const [city, setCity] = useState("");
const [postalCode, setPostalCode] = useState("");
const [country, setCountry] = useState("");
const [comMessage, setComMessage] = useState(null);
const dispatch = useDispatch();
const navigate = useNavigate();
useEffect(() => {
if (shippingAddress) {
setAddress(shippingAddress.address);
setCity(shippingAddress.city);
setPostalCode(shippingAddress.postalCode);
setCountry(shippingAddress.country);
} else {
const userInfo = {
token: user.token,
email: user.email,
};
dispatch(getAddress(userInfo));
}
}, []);
const submitHandler = (e) => {
e.preventDefault();
if (!user) {
navigate("/login");
} else {
if (!address || !city || !postalCode || !country) {
setComMessage("Please fill all fields");
setTimeout(() => setComMessage(null), 3000);
} else {
dispatch(
shippingSliceAction.takeAddress({
email: user.email,
address,
city,
postalCode,
country,
})
);
localStorage.setItem(
"userAddress",
JSON.stringify({
email: user.email,
address,
city,
postalCode,
country,
})
);
}
}
};
const saveContinue = () => {
if (!user) {
navigate("/login");
} else {
dispatch(
saveAddress({
email: user.email,
address,
city,
postalCode,
country,
token: user.token,
})
);
if (isSuccess) {
setComMessage("Your Address Saved");
setTimeout(() => dispatch(shippingSliceAction.reset()), 3000);
setTimeout(() => setComMessage(null), 3000);
setTimeout(() => navigate("/payment"), 4000);
}
}
};
return (
<FormContainer>
<h1>Shipping</h1>
{comMessage && <Message variant="danger">{comMessage}</Message>}
<Form onSubmit={submitHandler}>
<Form.Group controlId="address">
<Form.Label>Address</Form.Label>
<Form.Control
type="text"
placeholder="Enter Address"
value={address}
onChange={(e) => setAddress(e.target.value)}
></Form.Control>
</Form.Group>
<Form.Group controlId="city">
<Form.Label>City</Form.Label>
<Form.Control
type="text"
placeholder="Enter City"
value={city}
onChange={(e) => setCity(e.target.value)}
></Form.Control>
</Form.Group>
<Form.Group controlId="postalCode">
<Form.Label>Postal Code</Form.Label>
<Form.Control
type="number"
placeholder="Enter Postal Code"
value={postalCode}
onChange={(e) => setPostalCode(e.target.value)}
></Form.Control>
</Form.Group>
<Form.Group controlId="country">
<Form.Label>Country</Form.Label>
<Form.Control
type="text"
placeholder="Enter Country"
value={country}
onChange={(e) => setCountry(e.target.value)}
></Form.Control>
</Form.Group>
<Button className="shippingButton" type="submit" variant="primary">
Continue without saving
</Button>
{isLoading && <Loader />}
{isSuccess && <Message variant="success"></Message>}
{isError && <Message variant="danger">{message}</Message>}
<Button
className="shippingButton save"
type="button"
variant="secondary"
onClick={saveContinue}
>
Save my address and continue
</Button>
</Form>
</FormContainer>
);
}
export default ShippingPage;
// shippingServices.js
const { data } = await axios.get(SHIPPING_ADDRESS_URL, userInfo, config);
this should be
const { data } = await axios.get(SHIPPING_ADDRESS_URL, config);
Also stop using unnecessary packages like express-async-handler,
just cover entire middle-ware function body with try/catch block, call next(error) in catch block & it will work just fine.
I'm trying to create login form with react and mongoDB
here is my controller:
authenticate: function (req, res, next) {
Admin.findOne({
username: req.body.username
}, function (err, adminInfo) {
if (err) {
next(err);
} else {
if (bcrypt.compareSync(req.body.password, adminInfo.password)) {
const token = jwt.sign({
id: adminInfo._id
},
req.app.get("secretKey"), {
expiresIn: "1h"
}
);
res.json({
status: "success",
message: "admin found!!!",
data: {
user: adminInfo,
token: token
},
});
} else {
res.json({
status: "error",
message: "Invalid email/password!!!",
data: null,
});
}
}
});
}
and here is my LoginForm.jsx:
const LoginForm = (props) => {
const [username, setUsername] = useState("");
const [password, setPassword] = useState("");
const [routeRedirect, setRouteRedirect] = useState(false);
const [error, setError] = useState(false);
const login = (e) => {
e.preventDefault();
const admin = {
username,
password,
};
axios
.post("/login/authenticate", admin)
.then((res) => {
if (res.data.errors) {
setError(true);
} else {
return null;
}
})
.catch((err) => console.log(err));
setRouteRedirect(true);
};
return (
<ContactWrapper>
<ContactContainer>
{routeRedirect ? (
<Fragment>Hello</Fragment>
) : (
<Fragment>
<Title>LOGIN</Title>
<LoginForm onSubmit={login}>
<FormLabel>Username:</FormLabel>
<FormInput
type="text"
name="username"
onChange={(e) => setUsername(e.target.value)}
/>
<FormLabel>Password:</FormLabel>
<FormInput
type="password"
name="password"
onChange={(e) => setPassword(e.target.value)}
/>
<LoginButton type="submit">Login</LoginButton>
</LoginForm>
</Fragment>
)}
</ContactContainer>
</ContactWrapper>
);
};
export default LoginForm;
How can I authenticate username and password when click on button?
I tried to put in wrong password and wrong username and it still give me the "Hello"
How can I fix this?
Thank you
Here is my github project if you want to look over my code:
https://github.com/nathannewyen/the-beuter
It seems like you call "setRouteRedirect(true)" no matter the result of the api call.
You should probably setRouteRedirect in the then function of your post if the result satisfies you.
This call
axios
.post("/login/authenticate", admin)
.then((res) => {
if (res.data.errors) {
setError(true);
} else {
return null;
}
})
.catch((err) => console.log(err));
Does not block the code, so after sending the request, setRouteRedirect will be called.
I am using react-redux, axios, and JWT to create a registration system to a simple web app I built. No matter what is entered, I get a "Please enter all fields error". I have programmed other errors, and even when all input is valid I get the same one. I do not see any compilation error either in dev tools or in my terminal. This is my first try at authentication/registration.
This is my registerModal:
class RegisterModal extends Component{
state = {
Modal: false,
name: '',
email: '',
password:'',
msg: null
}
static propTypes ={
isAuthenticated: PropTypes.bool,
error: PropTypes.object.isRequired,
register: PropTypes.func.isRequired,
clearErrors: PropTypes.func.isRequired
}
componentDidUpdate(prevProps){
const {error} = this.props;
if(error !== prevProps.error){
//reg error
if(error.id === 'REGISTER_FAIL'){
this.setState({msg: error.msg.msg})
}else{
this.setState({msg: null});
}
}
}
toggle = () =>{
this.props.clearErrors();
this.setState({
Modal: !this.state.Modal
});
}
onChange = (e)=>{
this.setState(
{[e.target.name]: e.target.value}
);
}
onSubmit = e =>{
e.preventDefault();
const{name, email, password} = this.state;
//create user object
const newUser = {
name,
email,
password
};
this.props.register(newUser);
}
render(){
return(
<div>
<NavLink onClick = {this.toggle} href ="#" color = "danger">
Register
</NavLink>
<Modal
isOpen={this.state.Modal}
toggle={this.toggle} >
<ModalHeader toggle={this.toggle}>Register</ModalHeader>
<ModalBody>
{this.state.msg ? <Alert color = "danger">{this.state. msg}</Alert>: null}
<Form onSubmit = {this.onSubmit}>
<FormGroup>
<Label for ="name">Name</Label>
<Input
type = "text"
name= "name"
id = "name"
placeholder="Name"
onChange = {this.onChange}>
</Input>
</FormGroup>
<FormGroup>
<Label for ="Email">Email </Label>
<Input
type = "email"
name= "email"
id = 'email'
placeholder="Enter email"
onChange = {this.onChange}>
</Input>
</FormGroup>
<FormGroup>
<Label for ="Password">Password</Label>
<Input
type = "password"
name= "password"
id = "password"
placeholder="Password"
onChange = {this.onChange}>
</Input>
</FormGroup>
<Button
color="success"
style={{marginTop:'2rem'}}
block>
Register</Button>
</Form>
</ModalBody>
</Modal>
</div>
);
}
}
const mapStateToProps = (state) => ({
isAuthenticated: state.auth.isAuthenticated,
error: state.error
});
export default connect(
mapStateToProps,
{register, clearErrors})(RegisterModal);
This is in my auth.js file in routes folder:
//POST api/auth
//#desc Auth user
router.post('/', (req, res)=> {
const { email, password } = req.body;
//validation
if(!email || !password){
return res.status(400).json({msg: 'Please enter all fields'});
}
//Check for existing user
User.findOne({email})
.then(user =>{
if(!user) return res.status(400).json({msg: 'User does not exists'})
//Validate password
bcrypt.compare(password, user.password)
.then(isMatch =>{
if(!isMatch) return res.status(400).json({ msg: 'Invalid credentials'});
jwt.sign(
{id: user.id},
config.get('jwtSecret'),
{expiresIn: 3600},
(err, token) => {
if(err) throw err;
res.json({
token,
user: {
id: user.id,
name: user.name,
email: user.email
}
});
}
)
})
});
});
authActions.js:
//check tokens and register user
export const loadUser = () => (dispatch, getState) => {
//user loading
dispatch({type: USER_LOADING});
axios.get('/api/auth/user', tokenConfig(getState))
.then(res => dispatch({
type: USER_LOADED,
payload: res.data
}))
.catch(err => {
dispatch(returnErrors(err.response.data, err.response.status));
dispatch({
type: AUTH_ERROR
});
});
}
export const register = ({name, email, password}) => dispatch =>{
//headers
const config = {
header: {
'Content-Type': 'application/json'
}
}
//request body
const body = JSON.stringify({name, email, password});
axios.post('/api/users', body, config)
.then(res => dispatch({
type: REGISTER_SUCCESS,
payload:res.data
}))
.catch(err=>{
dispatch(returnErrors(err.response.data, err.response.status, 'REGISTER_FAIL'));
dispatch({
type: REGISTER_FAIL
})
})
}
//setup config /header and token
export const tokenConfig = getState => {
//get token from local storage
const token = getState().auth.token;
//headers
const config = {
headers: {
"Content-type": "application/json"
}
}
//if token add to headers
if(token){
config.headers['x-auth-token'] = token;}
return config;
}
Please let me know if I should add anything.
Assuming your registration route handles the request correctly, changing "header" to "headers" in the config you are passing into the axios.post() of your register action should solve it.