While building a MERN project from EdRoh on youtube, i got this problem where on the register page when i submit the form data it should redirect to login page and the data should get stored on mongodb database. When i checked it with Postman it is working fine i am able to post the data to database. But when i try to register through front end on register page, my page is not redirecting and my server is also not responding with any error or success message. I have installed morgan which logs the http status code with the CRUD method. But it is not logging anything.I have also installed cors. I am using multer to store the data and JWT for token verification on backend and using formik for forms and yup to send the data to my server through the api i built.
I am linking the screenshot and the code which i think might be useful for anyone to helpme. enter image description here
This is form.jsx file which has two forms component which are rendered conditionally.
import { useState } from 'react';
import {
Box,
Button,
TextField,
useMediaQuery,
Typography,
useTheme,
} from '@mui/material';
import EditOutlinedIcon from '@mui/icons-material/EditOutlined';
import { Formik } from 'formik';
import * as yup from 'yup';
import { useNavigate } from 'react-router-dom';
import { useDispatch } from 'react-redux';
import { setLogin } from 'state';
import Dropzone from 'react-dropzone';
import FlexBetween from 'components/FlexBetween';
const registerSchema = yup.object().shape({
firstName: yup.string().required('required'),
lastName: yup.string().required('required'),
email: yup.string().email('invalid email').required('required'),
password: yup.string().required('required'),
location: yup.string().required('required'),
occupation: yup.string().required('required'),
picture: yup.string().required('required'),
});
const loginSchema = yup.object().shape({
email: yup.string().email('invalid email').required('required'),
password: yup.string().required('required'),
});
const initialValuesRegister = {
firstName: '',
lastName: '',
email: '',
password: '',
location: '',
occupation: '',
picture: '',
};
const initialValuesLogin = {
email: '',
password: '',
};
const Form = () => {
const [pageType, setPageType] = useState('login');
const { palette } = useTheme();
const dispatch = useDispatch();
const navigate = useNavigate();
const isNonMobile = useMediaQuery('(min-width:600px)');
const isLogin = pageType === 'login';
const isRegister = pageType === 'register';
const register = async (values, onSubmitProps) => {
// this allows us to send form info with image
const formData = new FormData();
for (let value in values) {
formData.append(value, values[value]);
}
formData.append('picturePath', values.picture.name);
const savedUserResponse = await fetch(
'http://localhost:3001/auth/register',
{
method: 'POST',
body: formData,
}
);
const savedUser = await savedUserResponse.json();
onSubmitProps.resetForm();
if (savedUser) {
setPageType('login');
}
};
const login = async (values, onSubmitProps) => {
const loggedInResponse = await fetch('http://localhost:3001/auth/login', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(values),
});
const loggedIn = await loggedInResponse.json();
onSubmitProps.resetForm();
if (loggedIn) {
dispatch(
setLogin({
user: loggedIn.user,
token: loggedIn.token,
})
);
navigate('/home');
}
};
const handleFormSubmit = async (values, onSubmitProps) => {
if (isLogin) await login(values, onSubmitProps);
if (isRegister) await register(values, onSubmitProps);
};
return (
<Formik
onSubmit={handleFormSubmit}
initialValues={isLogin ? initialValuesLogin : initialValuesRegister}
validationSchema={isLogin ? loginSchema : registerSchema}
>
{({
values,
errors,
touched,
handleBlur,
handleChange,
handleSubmit,
setFieldValue,
resetForm,
}) => (
<form onSubmit={handleSubmit}>
<Box
display='grid'
gap='30px'
gridTemplateColumns='repeat(4, minmax(0, 1fr))'
sx={{
'& > div': { gridColumn: isNonMobile ? undefined : 'span 4' },
}}
>
{isRegister && (
<>
<TextField
label='First Name'
onBlur={handleBlur}
onChange={handleChange}
value={values.firstName}
name='firstName'
error={
Boolean(touched.firstName) && Boolean(errors.firstName)
}
helperText={touched.firstName && errors.firstName}
sx={{ gridColumn: 'span 2' }}
/>
<TextField
label='Last Name'
onBlur={handleBlur}
onChange={handleChange}
value={values.lastName}
name='lastName'
error={Boolean(touched.lastName) && Boolean(errors.lastName)}
helperText={touched.lastName && errors.lastName}
sx={{ gridColumn: 'span 2' }}
/>
<TextField
label='Location'
onBlur={handleBlur}
onChange={handleChange}
value={values.location}
name='location'
error={Boolean(touched.location) && Boolean(errors.location)}
helperText={touched.location && errors.location}
sx={{ gridColumn: 'span 4' }}
/>
<TextField
label='Occupation'
onBlur={handleBlur}
onChange={handleChange}
value={values.occupation}
name='occupation'
error={
Boolean(touched.occupation) && Boolean(errors.occupation)
}
helperText={touched.occupation && errors.occupation}
sx={{ gridColumn: 'span 4' }}
/>
<Box
gridColumn='span 4'
border={`1px solid ${palette.neutral.medium}`}
borderRadius='5px'
p='1rem'
>
<Dropzone
acceptedFiles='.jpg,.jpeg,.png'
multiple={false}
onDrop={(acceptedFiles) =>
setFieldValue('picture', acceptedFiles[0])
}
>
{({ getRootProps, getInputProps }) => (
<Box
{...getRootProps()}
border={`2px dashed ${palette.primary.main}`}
p='1rem'
sx={{ '&:hover': { cursor: 'pointer' } }}
>
<input {...getInputProps()} />
{!values.picture ? (
<p>Add Picture Here</p>
) : (
<FlexBetween>
<Typography>{values.picture.name}</Typography>
<EditOutlinedIcon />
</FlexBetween>
)}
</Box>
)}
</Dropzone>
</Box>
</>
)}
<TextField
label='Email'
onBlur={handleBlur}
onChange={handleChange}
value={values.email}
name='email'
error={Boolean(touched.email) && Boolean(errors.email)}
helperText={touched.email && errors.email}
sx={{ gridColumn: 'span 4' }}
/>
<TextField
label='Password'
type='password'
onBlur={handleBlur}
onChange={handleChange}
value={values.password}
name='password'
error={Boolean(touched.password) && Boolean(errors.password)}
helperText={touched.password && errors.password}
sx={{ gridColumn: 'span 4' }}
/>
</Box>
{/* BUTTONS */}
<Box>
<Button
fullWidth
type='submit'
sx={{
m: '2rem 0',
p: '1rem',
backgroundColor: palette.primary.main,
color: palette.background.alt,
'&:hover': { color: palette.primary.main },
}}
>
{isLogin ? 'LOGIN' : 'REGISTER'}
</Button>
<Typography
onClick={() => {
setPageType(isLogin ? 'register' : 'login');
resetForm();
}}
sx={{
textDecoration: 'underline',
color: palette.primary.main,
'&:hover': {
cursor: 'pointer',
color: palette.primary.light,
},
}}
>
{isLogin
? "Don't have an account? Sign Up here."
: 'Already have an account? Login here.'}
</Typography>
</Box>
</form>
)}
</Formik>
);
};
export default Form;
this is app.js file
import { BrowserRouter, Navigate, Routes, Route } from 'react-router-dom';
import Homepage from 'scenes/homePage';
import LoginPage from 'scenes/loginPage';
import ProfilePage from 'scenes/profilePage';
import { useMemo } from 'react';
import { useSelector } from 'react-redux';
import { CssBaseline, ThemeProvider } from '@mui/material';
import { createTheme } from '@mui/material/styles';
import { themeSettings } from './theme';
function App() {
const mode = useSelector((state) => state.mode);
const theme = useMemo(() => createTheme(themeSettings(mode)), [mode]);
const isAuth = Boolean(useSelector((state) => state.token));
return (
<div className='app'>
<BrowserRouter>
<ThemeProvider theme={theme}>
<CssBaseline />
<Routes>
<Route
path='/'
element={<LoginPage />}
/>
<Route
path='/home'
element={isAuth ? <Homepage /> : <Navigate to='/' />}
/>
<Route
path='/profile/:userId'
element={isAuth ? <ProfilePage /> : <Navigate to='/' />}
/>
</Routes>
</ThemeProvider>
</BrowserRouter>
</div>
);
}
export default App;
this is the auth controller logic for backend.
import bcrypt from 'bcrypt';
import jwt from 'jsonwebtoken';
import User from '../models/User.js';
/* REGISTER USER */
export const register = async (req, res) => {
try {
const {
firstName,
lastName,
email,
password,
picturePath,
friends,
location,
occupation,
} = req.body;
const salt = await bcrypt.genSalt();
const passwordHash = await bcrypt.hash(password, salt);
const newUser = new User({
firstName,
lastName,
email,
password: passwordHash,
picturePath,
friends,
location,
occupation,
viewedProfile: Math.floor(Math.random() * 10000),
impressions: Math.floor(Math.random() * 10000),
});
const savedUser = await newUser.save();
res.status(201).json(savedUser);
} catch (err) {
res.status(500).json({ error: err.message });
}
};
/* LOGGING IN */
export const login = async (req, res) => {
try {
const { email, password } = req.body;
const user = await User.findOne({ email: email });
if (!user) return res.status(400).json({ msg: 'User does not exist. ' });
const isMatch = await bcrypt.compare(password, user.password);
if (!isMatch) return res.status(400).json({ msg: 'Invalid credentials. ' });
const token = jwt.sign({ id: user._id }, process.env.JWT_SECRET);
delete user.password;
res.status(200).json({ token, user });
} catch (err) {
res.status(500).json({ error: err.message });
}
};
this is index.js file from backend
import express from 'express';
import bodyParser from 'body-parser';
import mongoose from 'mongoose';
import cors from 'cors';
import dotenv from 'dotenv';
import multer from 'multer';
import helmet from 'helmet';
import morgan from 'morgan';
import path from 'path';
import { fileURLToPath } from 'url';
import authRoutes from './routes/auth.js';
import userRoutes from './routes/users.js';
import postRoutes from './routes/posts.js';
import { register } from './controllers/auth.js';
import { createPost } from './controllers/posts.js';
import { verifyToken } from './middleware/auth.js';
import User from './models/User.js';
import Post from './models/Post.js';
import { users, posts } from './data/index.js';
/* CONFIGURATIONS */
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
dotenv.config();
const app = express();
app.use(express.json());
app.use(helmet());
app.use(helmet.crossOriginResourcePolicy({ policy: 'cross-origin' }));
app.use(morgan('common'));
app.use(bodyParser.json({ limit: '30mb', extended: true }));
app.use(bodyParser.urlencoded({ limit: '30mb', extended: true }));
app.use(cors());
app.use('/assets', express.static(path.join(__dirname, 'public/assets')));
/* FILE STORAGE */
const storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, 'public/assets');
},
filename: function (req, file, cb) {
cb(null, file.originalname);
},
});
const upload = multer({ storage });
/* ROUTES WITH FILES */
app.post('/auth/register', upload.single('picture'), register);
app.post('/posts', verifyToken, upload.single('picture'), createPost);
/* ROUTES */
app.use('/auth', authRoutes);
app.use('/users', userRoutes);
app.use('/posts', postRoutes);
/* MONGOOSE SETUP */
const PORT = process.env.PORT || 6001;
mongoose
.connect(process.env.MONGO_URL, {
useNewUrlParser: true,
useUnifiedTopology: true,
})
.then(() => {
app.listen(PORT, () => console.log(`Server Port: ${PORT}`));
/* ADD DATA ONE TIME */
// User.insertMany(users);
// Post.insertMany(posts);
})
.catch((error) => console.log(`${error} did not connect`));
I tried to send data to my server using frontend and the server should have responsed with 201 status code and my data should have been inserted in my database.
I was expecting that when my user register then they will be redirected to login page and after logging in they should see the homepage.