It's difficult for me to figure out why the login functionality is not working in the simple authentication programme
I'm building with react and redux. I used django to create APIs, but I'm just starting out with react and redux. Whenever I try to login from the frontend
I get 404 Page Not Found error.
I have the following as part of the redux action (auth.jsx)
export const login = (email, password) => async dispatch => {
const config = {
headers: {
'Content-Type':'application/json'
}
};
const body = JSON.stringify({email, password});
try{
const res = await axios.post(`${process.env.REACT_APP_API_URL}/user/login`, body, config)
dispatch({
type: LOGIN_SUCCESS,
payload: res.data
})
dispatch(load_user());
} catch (err){
dispatch({
type: LOGIN_FAIL,
})
}
console.log('You hit the wrong url')
}
Redux DevTools displays the catch in the try and catch block``type(pin):"LOGIN_FAIL"`
Login.jsx
const Login = ({ login }) => {
const [formData, setFormData] = useState({
email: '',
password: ''
});
const {email, password} = formData;
const onChange = e => setFormData ({ ...formData, [e.target.name]: e.target.value});
const onSubmit = e => {
e.preventDefault();
login(email, password);
}
return(
<div className='container'>
<Form onSubmit={e => onSubmit(e)}>
<Form.Group className="mb-3" controlId="formBasicEmail">
<Form.Control type="email" placeholder="example#email.com" onChange={e => onChange(e)} required />
</Form.Group>
<Form.Group className="mb-3" controlId="formBasicPassword">
<Form.Control type="password" placeholder="Password" minLength='6' onChange={e => onChange(e)} required />
</Form.Group>
<Button variant="primary" type="submit">
Login
</Button>
<p>Don't have an account? <Link to='/account/register'>Register</Link></p>
<p>Forgotten password? <Link to = '/account/password-reset'>Reset your password</Link></p>
</Form>
</div>
)
// const mapStateToProps = state => ({
// })
}
export default connect(null, {login}) (Login)
When I click on the submit button I get 404 Page Not Found error. And I know that the axios function is not functioning properly
because the url for the login page is http://localhost:3000/user/login and the the API is process.env.REACT_APP_API_URL}/user/login as shown in the code
above. Also, REACT_APP_API_URL = 'http://localhost:8000' It's now obvious that the API I'm sending the post request to is http://localhost:8000/user/login.
If the registered user login details email is example#gmail.com and the password react-redux12345! when I try to login with those details I get the following url
output on the console http://localhost:3000/account/undefined/user/login (1)I dont't know why undefined is appearing in the middle of the
url instead of at the end. (2) I still don't know why undefined is present in the requested url. Please I want a solution to this.
Related
So I'm trying to validate if the user and password inserted are in the API database for now my code only asks for a username and a password and gives it a token given by the API even if the user does not exist.
My problem is how to call the API to validate if the user exists or not.
I'm trying to create an if cycle to communicate with the API but I'm not getting anywhere thoughts?
This is my code:
import React, { useState } from "react";
import { useNavigate } from "react-router-dom";
import"./App.css";
const Login = () => {
const [username, setUsername] = useState("");
const [Password, setPassword] = useState("");
const [error] = useState(null);
const [loading] = useState(false);
const navigate = useNavigate();
const handleLogin = () => {
console.log("name------->", username);
console.log("pass------->", Password);
var axios = require("axios");
var data = JSON.stringify({
"password": Password,
"username": username,
});
var config = {
method: "post",
url: "https://api.secureme.pt/api/v1/auth/login",
headers: {
"Content-Type": "application/json",
},
data: data,
};
axios(config)
.then(function (response) {
console.log("token----->", response.data.token);
sessionStorage.setItem("token", response.data.token);
navigate("/home");
})
.catch(function (error) {
console.log(error);
});
};
return (
<div className="Login">
<div className="title">
Login
</div>
<br />
<br />
<div>
Username: <br />
<input
type="text"
value={username}
onChange={(e) => setUsername(e.target.value)}
/>
</div>
<div>
Password: <br />
<input
type="password"
value={Password}
onChange={(e) => setPassword(e.target.value)}
/>
</div>
<br />
{error && <div className="error">{error}</div>}
<input className="button"
type="button"
value={loading ? "Loading..." : "Login"}
disabled={loading}
onClick={handleLogin}
/>
</div>
);
};
export default Login;
I would 100% add that logic on the server end.
So your login endpoint: https://api.secureme.pt/api/v1/auth/login, would contain logic like;
Get username and password.
Check if username and password exist in database.
If so, return access token.
If not, handle accordingly by returning a failed auth error code.
That being said, if you're persistent to do it on the front end.
Without knowing what database you're using - it's difficult to share any examples.
But in your handleLogin() function, before your call the login endpoint with Axios, just before that - check if the username and password exist in the database.
To do this, obviously depending on the database - you would have to install/import relevant package(s) to make that request.
Another solution would be to have a separate endpoint on the server end that would check if the credentials exist and return a boolean.
I am creating simple form application that will input user data and insert them into MongoDB. I am using Axios for CRUD operations and all operations are working in backend (tested in Postman). When I created frontend part (ReactJS) I managed to display all users and delete them by ID. But POST method for creating new user is not working. I am getting 500 Internal server error.
Also I am using FormData and useState. But when calling handleSubmit() method, FormData is empty.
CreateUser.js
const CreateUser = () => {
const [firstName, setFirstName] = useState("");
const [lastName, setLastName] = useState("");
const [email, setEmail] = useState("");
const submitHandler = (e) => {
e.preventDefault();
const formData = new FormData();
formData.set("firstName", firstName);
formData.set("lastName", lastName);
formData.set("email", email);
dispatch(createNewUser(formData)); //calling POST function from UserActions.js
};
return (
<form onSubmit={submitHandler}>
<input
type="text"
placeholder="Enter your first name"
value={firstName}
onChange={(e) => setFirstName(e.target.value)}
/>
<input
type="text"
placeholder="Enter your last name"
value={lastName}
onChange={(e) => setLastName(e.target.value)}
/>
<input
type="email"
placeholder="Enter your e-mail"
value={email}
onChange={(e) => setEmail(e.target.value)}
/>
<button className="button" type="submit">
Create
</button>
</form>
);
};
export default CreateUser;
Also I am using Redux for state managment so I have my action setup too.
UserActions.js
export const createNewUser = (userData) => async (dispatch) => {
try {
const config = {
headers: {
"Content-Type": "application/json",
},
};
const { data } = await axios.post("/api/v1/user/new", userData, config);
dispatch({
payload: data
});
} catch (error) {
console.log(error.response);
}
};
Console will display message that firstName lastName email are empty because their require value is set to true.
const userSchema = new mongoose.Schema({
firstName: {
type: String,
required: [true, "Please enter your first name"],
}.....
module.exports = mongoose.model("User", userSchema);
But when I am using console.log() to check their values on input, that works fine. Only passing those values to formData is not working. Or am I missing something else ?
Thanks
TLDR: FormData is empty when trying to submit inserted values to MongoDB while using Axios to POST data
I'm developing a web app in React and firebase and I'm having trouble getting it to work.
Here is my code
import React, { useRef, useState } from "react"
import { Form, Button, Card, Alert } from "react-bootstrap"
import { useAuth } from "../contexts/AuthContext"
import { Link, useHistory, Redirect, Route } from "react-router-dom"
import { db } from "../firebase"
import Dashboard from "../components/Dashboard"
export default function UpdateProfile() {
const usernameRef = useRef()
const emailRef = useRef()
const passwordRef = useRef()
const passwordConfirmRef = useRef()
const { updateUser, currentUser, updatePassword } = useAuth()
const [error, setError] = useState("")
const [loading, setLoading] = useState(false)
const history = useHistory()
function handleSubmit(e) {
e.preventDefault()
if (passwordRef.current.value !== passwordConfirmRef.current.value) {
return setError("Passwords do not match")
}
if (passwordRef.current.value) {
updatePassword(passwordRef.current.value)
}
const uid = currentUser.uid
db.collection('users').doc(uid).get()
.then(snapshot => {
const data = snapshot.data()
try {
setLoading(true)
setError("")
updateUser(usernameRef.current.value, emailRef.current.value, data)
history.push('/dashboard')
} catch {
setError("Failed to update account")
}
setLoading(false)
})
}
return (
<>
<Card>
<Card.Body>
<h2 className="text-center mb-4">Update Profile</h2>
{error && <Alert variant="danger">{error}</Alert>}
<Form onSubmit={handleSubmit}>
<Form.Group id="username">
<Form.Label>Name</Form.Label>
<Form.Control
type="text"
ref={usernameRef}
required
defaultValue={currentUser.username}
/>
</Form.Group>
<Form.Group id="email">
<Form.Label>Email</Form.Label>
<Form.Control
type="email"
ref={emailRef}
required
defaultValue={currentUser.email}
/>
</Form.Group>
<Form.Group id="password">
<Form.Label>Password</Form.Label>
<Form.Control
type="password"
ref={passwordRef}
placeholder="Leave blank to keep the same"
/>
</Form.Group>
<Form.Group id="password-confirm">
<Form.Label>Password Confirmation</Form.Label>
<Form.Control
type="password"
ref={passwordConfirmRef}
placeholder="Leave blank to keep the same"
/>
</Form.Group>
<Button disabled={loading} className="w-100" type="submit">
Update
</Button>
</Form>
</Card.Body>
</Card>
<div className="w-100 text-center mt-2">
<Link to="/">Cancel</Link>
</div>
</>
)
}
This is the code for the user's edit function: enter a value in the form and press the button to run handleSubmit.
function updateUser(username, email, data) {
const uid = data.uid
db.collection('users').doc(uid).set({
email: email,
username: username,
}, {merge: true})
}
useEffect(() => {
const unsubscribe = auth.onAuthStateChanged(async(user) => {
if (user) {
const uid = user.uid
console.log(uid)
await db.collection('users').doc(uid).get()
.then(snapshot => {
const data = snapshot.data()
setCurrentUser(data)
setLoading(false)
})
}
})
return unsubscribe
}, [])
And the following code rewrites the firestore data After this updateUser function is executed, we want to do a history.push in then of handleSubmit to redirect to /dashboard, but we want to get the console to say "success! in the console and the "failure! in the console and the message "success!" appears on the app.
When I looked at the firestore data, I found that the values I entered were properly reflected in the firestore.
This tells me that the then part of handleSubmit is not working, but I don't know why it's not working.
If you have a solution, I'd love to hear it.
Thank you.
You need to
Either await or put a .catch onto the updateUser Promise chain (the try/catch around it will only catch async errors if the Promise is awaited)
Return the Promise from updateUser
Pass a function to the .then callback - your .then(console.log("success!!")) invokes console.log immediately and passes undefined to the .then
function handleSubmit(e) {
e.preventDefault()
if (passwordRef.current.value !== passwordConfirmRef.current.value) {
return setError("Passwords do not match")
}
if (passwordRef.current.value) {
updatePassword(passwordRef.current.value)
}
const uid = currentUser.uid
db.collection('users').doc(uid).get()
.then(snapshot => {
const data = snapshot.data()
setLoading(true)
setError("")
return updateUser(usernameRef.current.value, emailRef.current.value, data);
})
.then(() => {
// Success
history.push('/dashboard')
})
.catch((error) => {
setError("failed!!")
})
.finally(() => {
setLoading(false)
});
}
function updateUser(username, email, data) {
const uid = data.uid
return db.collection('users').doc(uid).set({
email: email,
username: username,
}, { merge: true })
.then(() => console.log("success!!"))
}
I'm building an APP with Firebase and react.
In that APP, when a user edits their information and presses the submit button, it redirects them to the user information page by history.push().
Both the user's information and the page redirection work well, but after redirecting the page, the user's information that was edited is not reflected, and the page displays the previous version of the user's information.
Here's my code.
import React, { useRef, useState } from "react"
import { Form, Button, Card, Alert } from "react-bootstrap"
import { useAuth } from "../contexts/AuthContext"
import { Link, useHistory, Redirect, Route } from "react-router-dom"
import { db } from "../firebase"
import Dashboard from "../components/Dashboard"
export default function UpdateProfile() {
const usernameRef = useRef()
const emailRef = useRef()
const passwordRef = useRef()
const passwordConfirmRef = useRef()
const { updateUser, currentUser, updatePassword } = useAuth()
const [error, setError] = useState("")
const [loading, setLoading] = useState(false)
const history = useHistory()
function handleSubmit(e) {
e.preventDefault()
if (passwordRef.current.value !== passwordConfirmRef.current.value) {
return setError("Passwords do not match")
}
if (passwordRef.current.value) {
updatePassword(passwordRef.current.value)
}
const uid = currentUser.uid
db.collection('users').doc(uid).get()
.then(snapshot => {
const data = snapshot.data()
try {
setLoading(true)
setError("")
updateUser(usernameRef.current.value, emailRef.current.value, data)
history.push('/dashboard')
} catch {
setError("Failed to update account")
}
setLoading(false)
})
}
return (
<>
<Card>
<Card.Body>
<h2 className="text-center mb-4">Update Profile</h2>
{error && <Alert variant="danger">{error}</Alert>}
<Form onSubmit={handleSubmit}>
<Form.Group id="username">
<Form.Label>Name</Form.Label>
<Form.Control
type="text"
ref={usernameRef}
required
defaultValue={currentUser.username}
/>
</Form.Group>
<Form.Group id="email">
<Form.Label>Email</Form.Label>
<Form.Control
type="email"
ref={emailRef}
required
defaultValue={currentUser.email}
/>
</Form.Group>
<Form.Group id="password">
<Form.Label>Password</Form.Label>
<Form.Control
type="password"
ref={passwordRef}
placeholder="Leave blank to keep the same"
/>
</Form.Group>
<Form.Group id="password-confirm">
<Form.Label>Password Confirmation</Form.Label>
<Form.Control
type="password"
ref={passwordConfirmRef}
placeholder="Leave blank to keep the same"
/>
</Form.Group>
<Button disabled={loading} className="w-100" type="submit">
Update
</Button>
</Form>
</Card.Body>
</Card>
<div className="w-100 text-center mt-2">
<Link to="/">Cancel</Link>
</div>
</>
)
}
And I use AuthContext to pass Firebase credentials to each component.
This is part of the AuthContext file.
function updateUser(username, email, data) {
const uid = data.uid
db.collection('users').doc(uid).set({
email: email,
username: username,
}, {merge: true})
}
useEffect(() => {
const unsubscribe = auth.onAuthStateChanged(async(user) => {
if (user) {
const uid = user.uid
console.log(uid)
await db.collection('users').doc(uid).get()
.then(snapshot => {
const data = snapshot.data()
setCurrentUser(data)
setLoading(false)
})
}
})
return unsubscribe
}, [])
Do you know how to reflect the values I have entered on the edit screen?
since updateUser is an async function so you should use either async await or .then syntax in your updateUser function so that it calls the history.push after updating the user data
function updateUser(username, email, data) {
const uid = data.uid
return db.collection('users').doc(uid).set({
email: email,
username: username,
}, {merge: true})
}
updateUser(usernameRef.current.value, emailRef.current.value, data)
.then(() => {
history.push('/dashboard');
}
I am new to using React and JSX and was having a problem storing data from my API call into local storage. I call fetch asynchronously and my call returns a JSON of a user object (this is for a user-based web app). When I store that JSON item into local storage (after converting it to a string) and I try to access that item later, localStorage.getItem returns null and I am unable to retrieve the data. Any help or insight as to what I am doing incorrectly will be greatly appreciated.
Login.js
import React, { Component, useState } from "react";
import {Button, Form, FormGroup, Label, Input} from 'reactstrap';
import {useHistory} from 'react-router-dom';
export const Login = () => {
const [email_or_username, setName] = useState('');
const [password, setPassword] = useState('');
const [is_contributor, setContributor] = useState(false);
const history = useHistory();
return (
<div>
<Form className="login-form">
<h1>
<div className="text-right">
<Button
href="/register"
className=" btn-dark text-right">
sign up
</Button>
</div>
<span className="font-weight-bold">Mindify</span>
</h1>
<FormGroup>
<Label>Username or Email</Label>
<h2></h2>
<Input
value={email_or_username}
placeholder = "Username or Email"
onChange={e => setName(e.target.value)}/>
</FormGroup>
<FormGroup>
<label>Password</label>
<h2></h2>
<Input
value={password}
placeholder = "Password"
onChange={e => setPassword(e.target.value)}/>
</FormGroup>
<FormGroup>
<div className="text-center">
<Input
type="checkbox"
value={is_contributor}
onChange={e => setContributor(e.target.checked)}/>
Contributor
</div>
</FormGroup>
<Button onClick={async () =>{
const login = {email_or_username, password, is_contributor};
const response = await fetch('http://127.0.0.1:5000/api/login', {
method: 'POST',
headers:{
'Content-Type': 'application/json'
},
body: JSON.stringify(login)
})
.then(response => {
if (response.status === 201) {
response.json().then(data => { // store user in localStorage as token
window.localStorage.setItem("user", JSON.stringify(data.user));
console.log(JSON.parse(window.localStorage.getItem("user"))); // prints correctly here
})
console.log("Successful Login");
console.log(JSON.parse(window.localStorage.getItem("user"))); // prints null here
const ref="/homepage";
history.push(ref);
//redirect to home page
}
else if (response.status === 204) {
console.log("Invalid Username or Password or Incorrect Permissions");
const ref="/";
history.push(ref);
// reload login page
}
})
.catch(error => console.log(error))
}}
className="btn-lg btn-dark btn-block">
Log in</Button>
</Form>
</div>);
}
That is because response.json() is asynchronous, thus you will need the wait for response.json() to be returned before you can carry out any subsequent logic. If any subsequent logic is dependent on response.json(), you should modify your statement such that the required logic is handed only after it is returned.
response.json().then(data => {
window.localStorage.setItem("user", JSON.stringify(data.user));
console.log(JSON.parse(window.localStorage.getItem("user")));
const ref="/homepage";
history.push(ref);
// carry out other logic below
})