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;