Redirects to wrong page when logging in - node.js

it redirects to an empty js file when logging in, not to the js file I wrote. Should I redirect in my database code?
////////////////
const client = require('../../db')
const express = require('express');
const app = express();
const cors = require("cors");
app.use(cors());
app.use(express.json()); //req.body
app.listen(2136, ()=>{
console.log("Sever is now listening at port 5000");
})
client.connect();
app.post("/login", async (req, res) => {
try {
const { email, password } = req.body;
const user = await client.query(
`SELECT * FROM users WHERE email=$1 AND password=$2`,
[email, password]
);
if (user.rows.length === 0) {
res.status(404).send("Kullanıcı adı veya şifre yanlış");
} else {
res.send("Kullanıcı adı veya şifre doğru");
}
}catch (err) {
response
.status(500)
.json({ message: "Error in invocation of API: /login" })
}
});
this is my database code.
///////////////////////
import {
BrowserRouter as Router,
Route
} from "react-router-dom";
import React, { useState } from 'react'
import Navbar from '../../common/Navbar/Navbar';
import AdminPage from './AdminPage';
const User = () => {
const [email, setEmail] = useState("");
const [password, setPassword] = useState("");
const [user, setUser] = useState([]);
const [error, setError] = useState('');
const onSubmitForm = async e => {
e.preventDefault();
try {
const response = await fetch(`http://localhost:2136/login`,{
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ email, password }),
});
console.log(email,password)
console.log(response);
if ((response.status)===404) {
setError('Invalid email or password');
} else
{
window.location.replace(`/AdminPage`);
}
} catch (err) {
console.error(error);
setError('An error occurred. Please try again later.');
}
};
return (
<>
<Navbar/>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap#4.4.1/dist/css/bootstrap.min.css" integrity="sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh" crossorigin="anonymous"></link>
<div className="container text-center">
<h1 className="my-5">Search for the Dormitory You Want</h1>
<form className="d-flex" onSubmit={onSubmitForm}>
<input
type="text"
name="name"
placeholder="Enter email ..."
className="form-control"
value={email}
onChange={e => setEmail(e.target.value)}
/>
<input
type="text"
name="name"
placeholder="Enter password ..."
className="form-control"
value={password}
onChange={e => setPassword(e.target.value)}
/>
<button className="btn btn-success">Submit
</button>
</form>
</div>
</>
)
}
export default User
this is my login page. the page it redirects to is a blank page. i don't understand why.
///////////////
import React, { useState } from 'react'
import AdminNavbar from '../../common/Navbar/AdminNavbar';
const AdminPage = () => {
return (
<>
<AdminNavbar/>
</>
);
}
export default AdminPage
and this the page I want to redirect AdminPage.So what can i do?
///////////////////

The difference between assign() and replace():
replace() removes the current URL from the document history.
With replace() it is not possible to use "back" to navigate back to the original document.
You can use assign method instead of location method

Related

I want to tell reactjs login component whether login was successful or not

I am confused as to how to communicate from the nodejs server to the reactjs login component on whether login was successful or not.
I have a reactjs component that handles login as follows:
Login.js
import React, {useState} from 'react';
import axios from "axios";
const Login = () => {
const [user,setUser] = useState({email:"",password:""});
const handleSubmit = (e) => {
e.preventDefault();
console.log(user);
axios.post('http://localhost:5000/login',user)
.then(function (response) {
console.log(response);
console.log("Successfully done");
})
.catch(function (error) {
console.log("error here")
console.log(error.message);
});
}
return (
<div>
<h1>Login</h1>
<form onSubmit={handleSubmit}>
<div>Email:</div>
<div><input type="text" name="email" placeholder='Enter your email'
onChange={(e)=>setUser({...user,email:e.target.value})}
/></div>
<div>Password:</div>
<div><input type="password" name="password" placeholder='Enter your password'
onChange={(e)=>setUser({...user,password:e.target.value})}
/></div>
<div><input type="submit" value="Add" /></div>
</form>
</div>
)
}
export default Login;
and an expressjs backed that processes the login
server.js
const express = require("express");
const mongoose = require("mongoose");
const User = require("./Models/Conn.js");
const bcrypt = require("bcryptjs");
//const Route1 = require("./Routes/Route.js");
const cors = require('cors');
const app = express();
//app.use("/api",Route1);
app.use(express.json({extended:true}));
app.use(express.urlencoded({extended:true}));
app.use(cors());
const url = "mongodb+srv://pekele:pekele#cluster0.yqaef.mongodb.net/myDatabase?retryWrites=true&w=majority";
mongoose.connect(url)
.then(()=>console.log("connected to database successfully"))
.catch(err=>console.log(err));
app.get("/",(req,res)=> {
res.send("<h1>Welcome Guest</h1>");
});
app.get("/signup",(req,res)=> {
res.json({"id":"1"});
})
app.post("/signup",(req,res)=> {
const {email,password} = req.body;
bcrypt.genSalt(10)
.then(salt=> {
bcrypt.hash(password,salt)
.then(hash => {
const user = new User({email,password:hash});
user.save()
.then(()=>console.log("Successfully saved"))
.catch(error=>console.log(error));
})
}).catch(err=>console.log(err));
})
app.post("/login",(req,res)=> {
const {email,password} = req.body;
console.log(`My email is ${email}`)
User.findOne({email:email}, function (err, doc) {
console.log(doc);
if(doc == null) {
//How do i let react login page know that there is no user with such email
}
if(doc != null) {
const emailDB = doc.email;
const passwordDB = doc.password;
bcrypt.compare(password,passwordDB)
.then(res => {
//How do I tell the react login page that the login was successful
}).catch(err=>console.log(err));
}
});
})
app.listen(5000,()=> console.log("Server listening on port 5000"));
The problem is how do I communicate to the react login page whether the login was successful or not in the app.post("/login",(req,res) ... Thanks
You can send data via -
res.json(data)
res.send("Submitted Successfully!")
res.status(200).send(message)

Page is rendering the users after second submit

currently learning React and want to POST-Data to my Database and after the Post the table with all users should update automatically.
Do you have any suggestion why it is not working?
I try to use the useEffect and add also the allData array, but it is then in an infinite loop.
So currently it is just loading the page if I again press the submit button.
import React from "react";
import { useState, useEffect } from "react";
import axios from "axios";
const Form = () => {
const [Username, setUsername] = useState("");
const [Password, setPassword] = useState("");
const [userList, setUserList] = useState([]);
const allData = () => {
axios.get("http://localhost:3001/api/alluser").then((response) => {
console.log(response.data);
setUserList(response.data);
});
};
useEffect(() => {
allData();
}, []);
const postdata = () => {
axios.post("http://localhost:3001/api", {
Username: Username,
Password: Password,
});
allData();
};
const deletedata = (e) => {
const users_id = e.target.id;
axios.post("http://localhost:3001/api", {
users_id: users_id,
});
};
const clickHandler = (e) => {
deletedata(e);
};
return (
<>
<label name="Username">
<input
onChange={(e) => setUsername(e.target.value)}
type="text"
name="Username"
placeholder="Username"
/>
</label>
<label name="password">
<input
onChange={(e) => setPassword(e.target.value)}
type="text"
name="Password"
placeholder="Password"
/>
</label>
<button onClick={postdata}>Submit</button>
{userList.map((val) => {
return (
<>
<li key={val.users_id}>
{val.users_id}
<button onClick={clickHandler}>
Löschen
</button>
</li>
</>
);
})}
</>
);
};
export default Form;
allData() should wait until axios.post returns the response. You could use callbacks or async/await to achieve it.
const postdata = async () => {
await axios.post("http://localhost:3001/api", {
Username: Username,
Password: Password,
});
allData();
};
or
const postdata = () => {
axios.post("http://localhost:3001/api", {
Username: Username,
Password: Password,
}).then(() => { allData(); });
};

How to display error message on the mern app

I'm trying to display an error message when a user tries to sign in with an unregistered user but I'm not able to get that error message on the frontend(reactjs) that I am sending from my backend(nodejs, express, MongoDB).
I am using redux to handle the state of the react app.
user login form onSubmit code:
const onSubmit = (data) => {
if (isLogin) {
dispatch(signin(data, history));
} else {
dispatch(signup(data, history));
}
};
actions creators for auth
import * as api from "../api";
export const signin = (formData, history) => async (dispatch) => {
try {
// login the user
const { data } = await api.signIn(formData);
dispatch({ type: "AUTH", data });
history.push("/");
} catch (error) {
console.log(error);
dispatch({ type: "ERROR", data: error.response.data.message });
}
};
export const signup = (formData, history) => async (dispatch) => {
try {
// sign up the user
const { data } = await api.signUp(formData);
dispatch({ type: "AUTH", data });
history.push("/");
} catch (error) {
console.log(error);
}
};
reducers for auth:
const authReducer = (state = { authData: null }, action) => {
switch (action.type) {
case "AUTH":
localStorage.setItem("profile", JSON.stringify({ ...action?.data }));
return { state, authData: action?.data };
case "LOGOUT":
localStorage.clear();
return { state, authData: null };
case "ERROR":
return { state, authData: action?.data };
default:
return state;
}
};
export default authReducer;
Backend sign in code
const signin = async (req, res) => {
const { email, password } = req.body;
try {
const existingUser = await User.findOne({ email });
if (!existingUser)
return res.status(404).json({ message: "User doesn't exist." });
const isPasswordCorrect = await bcrypt.compare(
password,
existingUser.password
);
if (!isPasswordCorrect)
res.status(404).json({ message: "Invalid Credentials" });
const token = jwt.sign(
{ email: existingUser.email, id: existingUser._id },
"test",
{ expiresIn: "1h" }
);
res.status(200).json({ result: existingUser, token });
} catch (error) {
res.status(500).json({ message: "Something went wrong" });
}
};
sign API
import axios from "axios";
const API = axios.create({
baseURL: process.env.REACT_APP_BASE_URL,
});
export const signIn = (formData) => API.post("/user/signin", formData);
export const signUp = (formData) => API.post("/user/signup", formData);
Anyone, please help me with this.
Screenshots of the error response in Postman:
I just debugged the issue. First install redux-devtools-extension by npm install --save redux-devtools-extension
Then apply this in store(index.js file in your case) as follows
import React from "react";
import ReactDOM from "react-dom";
import { Provider } from "react-redux";
import { createStore, applyMiddleware } from "redux";
import thunk from "redux-thunk";
import App from "./App";
import { reducers } from "./reducers";
import { composeWithDevTools } from "redux-devtools-extension";
const middleware = [thunk];
const store = createStore(
reducers,
composeWithDevTools(applyMiddleware(...middleware))
);
ReactDOM.render(
<React.StrictMode>
<Provider store={store}>
<App />
</Provider>
</React.StrictMode>,
document.getElementById("root")
);
And now you can use the error message anywhere as follows (your Auth.js file)
import React, { useState } from "react";
import { useSelector } from "react-redux";
import Input from "../utils/Input";
import Label from "../utils/Label";
import { useForm, FormProvider } from "react-hook-form";
import { GoogleLogin } from "react-google-login";
import { useDispatch } from "react-redux";
import { useHistory } from "react-router";
import { signin, signup } from "../../actions/auth";
const Auth = () => {
const [isLogin, setIsLogin] = useState(true);
const formMethods = useForm();
const auth = useSelector((state) => state.auth);
const { authData } = auth;
const { handleSubmit } = formMethods;
console.log(authData);
const dispatch = useDispatch();
const history = useHistory();
const changeScreen = () => {
setIsLogin(false);
dispatch({ type: "LOGOUT" });
};
const onSubmit = (data) => {
if (isLogin) {
dispatch(signin(data, history));
} else {
dispatch(signup(data, history));
}
};
const googleSuccess = async (res) => {
const result = res?.profileObj;
const token = res?.tokenId;
try {
dispatch({ type: "AUTH", data: { result, token } });
history.push("/");
} catch (error) {
console.log(error);
}
};
const googleFailure = (error) => {
console.log(error);
console.log("Google sign in was unsuccessful");
};
return (
<section className="col-start-1 col-end-2 md:col-start-2 md:col-end-3 row-start-2 row-end-3 md:row-start-1 md:row-end-2 mx-3 sm:mx-0 md:my-auto">
<div className=" w-full max-w-md bg-primaryOne px-6 py-8 rounded-md shadow-md mx-auto">
<FormProvider {...formMethods}>
<form className="" onSubmit={handleSubmit(onSubmit)}>
<div className="w-full flex justify-around mb-2">
<button
className={`${
isLogin
? "bg-secondaryTwo"
: "transition bg-transparent hover:bg-secondaryTwo"
} text-white text-xs font-bold px-6 py-4 rounded-full`}
type="button"
onClick={() => setIsLogin(true)}
>
LOG IN
</button>
<button
className={`${
!isLogin
? "bg-secondaryTwo"
: "transition bg-transparent hover:bg-secondaryTwo"
} text-white text-xs font-bold px-6 py-4 rounded-full`}
type="button"
onClick={() => changeScreen()}
>
SIGN UP
</button>
</div>
<div>
{!isLogin && (
<div>
<Label labelName="Name" />
<Input inputName="name" type="text" bgColor="primaryTwo" />
</div>
)}
<div>
<Label labelName="Email" />
<Input inputName="email" type="email" bgColor="primaryTwo" />
</div>
<div>
<Label labelName="Password" />
<Input
inputName="password"
type="password"
bgColor="primaryTwo"
/>
</div>
</div>
<div className="text-center">
<button
type="button"
onClick={() => setIsLogin(!isLogin)}
className="text-neutral font-extralight text-xs pt-6"
>
{authData && <h1 style={{ color: "red" }}>{authData}</h1>}
{!isLogin
? "Already have an account? Log In"
: "Don't have an account? Sign Up"}
</button>
</div>
<button className="bg-secondaryTwo hover:bg-secondaryOne transition px-4 py-3 w-full rounded-md text-white font-bold mt-4 shadow-md">
{isLogin ? "Log In" : "Sign Up"}
</button>
<div className="flex items-center py-6">
<div className="w-1/2 h-px bg-white bg-opacity-40"></div>
<p className="text-white px-1 text-xs">OR</p>
<div className="w-1/2 h-px bg-white bg-opacity-40"></div>
</div>
<div>
<GoogleLogin
clientId={process.env.REACT_APP_GOOGLE_CLIENT_ID}
onSuccess={googleSuccess}
onFailure={googleFailure}
cookiePolicy="single_host_origin"
render={(renderProps) => (
<button
className="bg-blue-600 hover:bg-blue-500 transition px-4 py-3 w-full rounded-md text-white font-bold mb-4 shadow-md"
type="button"
onClick={renderProps.onClick}
disabled={renderProps.disabled}
>
<i className="fab fa-google mr-2"></i>Continue with Google
</button>
)}
/>
</div>
</form>
</FormProvider>
</div>
</section>
);
};
export default Auth;
And one last thing. Check nested object before using its properties like error.response.data.message (your auth.js actions file)
import * as api from "../api";
export const signin = (formData, history) => async (dispatch) => {
try {
// login the user
const { data } = await api.signIn(formData);
dispatch({ type: "AUTH", data });
history.push("/");
} catch (error) {
console.log("An error occured while ");
const errMsg =
error.response && error.response.data.message
? error.response.data.message
: error.message;
dispatch({ type: "ERROR", data: errMsg });
console.log(errMsg);
}
};
export const signup = (formData, history) => async (dispatch) => {
try {
// sign up the user
const { data } = await api.signUp(formData);
dispatch({ type: "AUTH", data });
history.push("/");
} catch (error) {
console.log(error);
}
};
Hope it helps!
As far as I understood, everything is working fine, and actually, there is no error happening on the frontend side. You have to check the status code of "await api.signIn(formData);" response. If it is 200, it means that everything is ok otherwise you have to check the message in the response to get the message error. As on the frontend there is thrown error to be catched.
you can aslo use react-toastify . you can get status code and response message from error and store it in state object in reducers/auth.js and access it using useSelector() then create if else conditions according to status code and pass message to toast(#error_message#).
just see react-toastify and know how to use it.

How do I implement login functionality in a MERN app?

I am developing a (simple-to-use) note-taking web application on my localhost (port 3000 for frontend, port 5000 for the backend). I'm having trouble implementing the user login functionality. I'll try to distill the problem here.
My main App.jsx component has a LoginScreen.jsx component as a child, which is here:
import { useState, useEffect } from 'react';
import { Link } from 'react-router-dom';
import AuthService from '../services/auth.js';
import './LoginScreen.css';
const LoginScreen = ({ history }) => {
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
const [error, setError] = useState('');
useEffect(() => {
if (localStorage.getItem('authToken')) history.push('/');
}, [history]);
const loginHandler = async e => {
e.preventDefault();
try {
const data = { email, password };
AuthService.loginUser(data).then(response => {
localStorage.setItem('authToken', response.data.token);
});
history.push('/');
} catch (error) {
setError(error.response.data.error);
setTimeout(() => {
setError('');
}, 5000);
}
};
return (
<div className="login-screen">
<form
className="login-screen__form"
onSubmit={loginHandler}
autoComplete="off"
>
<h3 className="login-screen__title">Login</h3>
{error && <span className="error-message">{error}</span>}
<div className="form-group">
<label htmlFor="email">Email:</label>
<input
type="email"
required
id="email"
placeholder="enter email"
value={email}
onChange={e => setEmail(e.target.value)}
tabIndex={1}
/>
</div>
<div className="form-group">
<label htmlFor="password">
Password:{' '}
<Link
to="/forgotpassword"
className="login-screen__forgotpassword"
tabIndex={4}
>
Forgot Password?
</Link>
</label>
<input
type="password"
required
id="password"
placeholder="enter password"
value={password}
onChange={e => setPassword(e.target.value)}
tabIndex={2}
/>
</div>
<button type="submit" className="btn btn-primary" tabIndex={3}>
Login
</button>
<span className="login-screen__subtext">
Don't have an account? <Link to="/register">Register</Link>
</span>
</form>
</div>
);
};
export default LoginScreen;
When the user clicks "Login," that should trigger the AuthService, shown here:
import http from '../routing/http-auth.js';
class AuthService {
loginUser = data => http.post('/login', data);
registerUser = data => http.post('/register', data);
userForgotPassword = data => http.post('/forgotpassword', data);
userPasswordReset = data => http.put('/passwordreset/:resetToken', data);
}
export default new AuthService();
The http in the above file is an axios instance, shown below.
import axios from 'axios';
export default axios.create({
baseURL: 'http://localhost:5000/api/v1/auth',
headers: {
'Content-type': 'application/json'
}
});
So, the request is routed to the backend, where it goes here:
import express from 'express';
import AuthController from './auth.controller.js';
const router = express.Router();
router.route('/register').post(AuthController.register);
router.route('/login').post(AuthController.login);
router.route('/forgotpassword').post(AuthController.forgotPassword);
router.route('/passwordreset/:resetToken').put(AuthController.passwordReset);
export default router;
And then here:
static login = async (req, res, next) => {
const email = req.body.email;
const password = req.body.password;
if (!email || !password) {
return next(
new ErrorResponse('please provide an email and password', 400)
);
}
try {
const user = await User.findOne({ email }).select('+password');
if (!user) return next(new ErrorResponse('invalid credentials', 401));
const isMatch = await user.matchPasswords(password);
if (!isMatch) return next(new ErrorResponse('invalid credentials', 401));
sendToken(user, 200, res);
} catch (error) {
next(error);
}
};
This all worked on a dummy application, but now, it's not working in my note-taking app. I get the error:
Uncaught (in promise) TypeError: Cannot read property 'data' of undefined
at loginHandler (LoginScreen.jsx:27)
How can I make this work?
Your TypeError: Cannot read property 'data' of undefined means that your code tried to read the .data property from a undefined (null, missing) object.
At line 27 your code does setError(error.response.data.error); Therefore your error message means error exists but error.response does not.
Put console.log(error) right before that line 27 (or set a breakpoint) so you can make sure you understand the error object you catch.
It would be nice if the error message said TypeError: Cannot read property 'data' of an undefined object named error.response. But it doesn't so you must make that inference yourself.

post route is not working for user registeration

This is the code for my post route. I am using registerPost to post a new user to mongoDB data base. Have a User schema made. The code for my registerPost function doesn't seem to be running.
export const registerPost = async (req, res) => {
const {username, password} = req.body;
const newUser = new User({username, password});
try {
await newUser.save();
console.log(newUser);
res.status(201).json(newUser);
} catch (error) {
res.status(409).json({ message: error.message });
}
}
These are the routes. Am not able to get a the /auth to go through on form submit. No console log no anything. I am missing something but am not sure.
import express from 'express';
import { getPosts } from '../controllers/posts.js'
import { createPost, updatePost, deletePost, registerPost } from '../controllers/posts.js'
const router = express.Router();
router.get('/', getPosts);
router.post('/', createPost);
router.patch('/:id', updatePost);
router.delete('/:id', deletePost);
router.post('/auth', registerPost);
export default router;
This is the react form code for the register part.
import React, { useEffect, useState } from 'react';
import { TextField, Button, Typography, Paper } from '#material-ui/core';
import useStyles from './styles.css';
const Auth = () => {
const [username, setUsername] = useState('')
const [password, setPassword] = useState('')
const divStyle = {
backgroundColor: 'white',
};
return (
<div style = {divStyle}>
<form>
<h1>Registration</h1>
<TextField
name='username'
variant='outlined'
label='username'
fullWidth
onChange={(e) => {
setUsername( e.target.value)
}}
/>
<TextField
name='password'
variant='outlined'
label='password'
fullWidth
onChange={(e) => {
setPassword( e.target.value)
}}
/>
<Button variant="container" color="primary" size="large" type="submit" fullwidth>Register</Button>
</form>
</div>
);
}
export default Auth;
Api doc
import axios from 'axios';
const url = 'http://localhost:5000/posts';
export const fetchPosts = () => axios.get(url);
export const createPost = (newPost) => axios.post(url, newPost);
export const updatePost = (id, updatedPost) => axios.patch(`${url}/${id}`, updatedPost);
export const deletePost = (id) => axios.delete(`${url}/${id}`);
export const likePost = (id) => axios.patch(`${url}/${id}/likePost`);

Resources