how to call function after async task react - reactjs

i want to navigate to dashboard after login and dashboard is protected route
const handleLogin = (e) => {
e.preventDefault();
if (email || password) {
dispatch(loginUser({ email, password }));
navigate("/dashboard");
} else {
toast.error("Please Enter Email and Password");
}
};
i am using redux toolkit createAsyncThunk for api request
export const loginUser = createAsyncThunk("auth/login", async (userDetails) => {
try {
const { email, password } = userDetails;
const res = await fetch("http://localhost:5000/api/users/login", {
method: "post",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
email,
password,
}),
});
const result = await res.json();
if (result.error) {
toast.error(result.error);
} else {
toast.success("Login successfull");
localStorage.setItem("user", JSON.stringify(result));
return result;
}
} catch (error) {
console.log(error);
}
});
when i click on login it try to navigate the page before the state update what i want the navigate function wait untill the api respone recieve then navigate to dashboard

dispatch(loginUser({ email, password })); returns a promise, you can wait for the promise to resolve before doing additional work:
const handleLogin = () => {
dispatch(loginUser({ email, password })).then(() => {
navigate("/dashboard");
})
}
see Unwrapping Result Actions

Related

NextJs creating user document in mongodb after google sign in

i want to create a user document after i sign in with google in my nextjs application. I can sign in but it's not creating the document after it. This is my function
const handleSignIn = async () => {
try {
await signIn("google");
await addUser();
} catch (error) {
console.log("Erro");
}
};
The addUser function is
const addUser = async () => {
if (status === "authenticated") {
const user = {
name: session.user.name,
email: session.user.email,
avatar: session.user.image,
};
try {
await fetch("/api/new_user", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(user),
});
} catch (error) {
console.log(error);
}
} else {
console.log("Not logged in");
}
};
This is how i'm creating the new document in my new_user.ts file in the api folder
export default async function handleNewUser(req:NextApiRequest, res:NextApiResponse){
const client = await clientPromise;
const db = client.db("bookdb");
const coll: Collection = db.collection("users");
const user = req.body
console.log(user)
try {
await coll.insertOne(user)
res.status(200).json({response:'Success'})
} catch (error) {
res.status(500).json({error:'Erro'})
To make sure it was working, i triggered manually the addUser function after signing in and it worked.
What am i doing wrong here?
this is my snippet for google auth sign in with mongodb and nextjs using typescript and prisma.
signIn: async ({user, account}) => {
if (account?.provider === 'google') {
const googleAuthData = {
name: user.name,
email: user.email,
image: user.image,
authProvider: 'google',
password: ''
}
const exist = await prisma.user.findFirst({
where: {email: user.email},
});
if (exist) {
const result = await prisma.user.update({
where: {email: user.email},
data: {image: user.image},
});
} else {
const result = await prisma.user.create({
data: googleAuthData,
});
}
}
return true;
},

Get user info with JWT in React

I´m storing the user token in the localstorage after a user logs in, and i would like to know how i can use this token that is in the localstorage to fetch the user info.
backend login.js
module.exports.login = async (req, res) => {
const { email, password } = req.body;
try {
const user = await User.findOne({ email: email });
if (!user) return res.status(404).json({ message: "Usuário não cadastrado!" });
const isMatch = bcrypt.compare(password, user.password);
if (!isMatch) return res.status(400).json({ message: "Email e/ou senha incorretos." });
const token = tokenGenereator(user._id);
return res.status(200).json({ result: user, token });
} catch (error) {
console.log(error)
}
};
frontend login.js
export const login = (data, history) => {
return async (dispatch) => {
try {
const userData = await api.login(data);
localStorage.setItem("userToken", JSON.stringify(userData.data.token));
dispatch(
setUser({
fullname: userData.data.fullname,
email: userData.data.email,
isAuth: true,
})
);
history.push("/home");
} catch (error) {
if (error.response && error.response.data.message) {
dispatch(
setNotification({
variant: "danger",
message: error.response.data.message,
})
);
}
}
};
};
I pass the token to the backend
// i would pass the jwt to the function as a parameter
export const fetchUser = (data) => {
return async (dispatch) => {
const user = await api.getUserData(data);
console.log(user);
};
};
And i recieve
module.exports.getCurrentUser = async (req, res) => {
const { token } = req.body;
// i dont know what to do from here...
};

Axios PUT Data with Params

My backend API route is /api/updateUser/:id
How am I supposed to POST data into this API? I'm familiar with POST request for non params APIs but this one has an /:id in the route.
Can someone show me an example with this demo code
state = {
username: "random123",
password: "random123",
userid: "qwertyuiop",
};
saveDetails = async () => {
const { username, password, userid } = this.state;
let data = new FormData();
data.append('username',username);
data.append('password',password);
axios
.put(apiEndPoint+'?id='+this.state.userid, data) //this is where I need help
.then(async (response) => {
if (response.data) {
console.log("success");
} else {
console.log("issue");
}
})
.catch((err) => {
console.log("error",err);
});
};
This is the working example for Path Parameter Axios PUT request -
saveDetails = async () => {
const { username, password, userid } = this.state;
axios
.put(apiEndPoint+"updateUser/"+userid, {
username:username,
password:password,
})
.then(async (response) => {
if (response.data) {
console.log("done");
} else {
console.log("error");
}
})
.catch((err) => {
console.log("error",err);
});
};

Gets 401 error while user tries to do Fetch Get request after authentication

I'm trying to get user details after user looged in but user is getting 401 error even user is looged in with 200 ok.
Explanation of process:
i have logged in user using fetch post request.
stored username,role,staffid to async storage
now i want to list all user (with /api/staff endpoint response throws user firstname and last name )with fetch get request but whenever i make GET request it
throws 401 error.
It will be lifesaver to crack this step for me,thank you!
here is my code
import AsyncStorage from "#react-native-community/async-storage";
import React, { useState, useEffect } from "react";
import { SafeAreaView, Text, StyleSheet, Alert } from "react-native";
import AuthService from "../api/auth-service";
import BASE_URL from "../api/baseUrl";
export default function HomeScreen(props) {
const [firstName, setFirstName] = useState({});
const [lastName, setLastName] = useState({});
const [userValue, setUserValue] = useState({});
useEffect(() => {
let mounted = true;
if (mounted) {
getDataFromStorage();
getUserInfo();
}
return () => {
mounted = false;
};
}, []);
const getDataFromStorage = async () => {
let user = await AsyncStorage.getItem("LoggedInUser");
setUserValue(JSON.parse(user));
};
const getUserInfo=async()=>{
return fetch(BASE_URL+"/api/staff")
.then((response) => {
if(response.ok){
console.log(response);
}else{
console.log(response.status);
}
})
.catch((error) => {
console.log(error);
this.setState({ errorMsg: "Error retreiving data" });
});
}
return (
<SafeAreaView>
<Text>
{"Good morning " + userValue.username + " "}
{"you role is " + userValue.role +"your staff id is " + userValue.staffId+" " + "your first name is "+ firstName +"this is your last name"+lastName}
</Text>
</SafeAreaView>
);
}
authservice.js
import AsyncStorage from "#react-native-community/async-storage";
import BASE_URL from "./baseUrl";
class AuthService {
login(Username, Password, role) {
console.log(Username, role);
return fetch(BASE_URL + "/api/authentication/login", {
method: "POST",
headers: {
Accept: "application/json",
"Content-Type": "application/json",
},
body: JSON.stringify({
Username,
Password,
}),
}).then((res) => {
if (res.ok) {
console.log("the login response", res);
return res.json();
} else {
alert("Invalid Username or Password");
window.stop();
}
});
}
logout() {
AsyncStorage.getAllKeys().then((keys) => AsyncStorage.multiRemove(keys));
}
}
export default new AuthService();
login.js
const submitData = async () => {
AuthService.login(Username, Password).then(
(data) => {
console.log(JSON.stringify(data));
AsyncStorage.setItem("LoggedInUser", JSON.stringify(data));
if (data.role == "Admin") {
console.log(data.username);
navigation.navigate("adminPage");
} else {
navigation.navigate("staffpage");
}
},
(error) => {
Alert.alert(error);
}
);
};
According to developer.mozilla.org
The HTTP 401 Unauthorized client error status response code indicates that the request has not been applied because it lacks valid authentication credentials for the target resource.
It's seems the user doesn't have right to access the API. Make sure that the getUserInfo() API, /api/staff, don't need any authentication token in header of your HTTP request.
I have a feeling that you may need to resolve one more promise in AuthService.login.
res.json() is actually a promise which needs to be resolved as well, so you may need one more then block like so:
return fetch(BASE_URL + "/api/authentication/login", {
method: "POST",
headers: {
Accept: "application/json",
"Content-Type": "application/json",
},
body: JSON.stringify({
Username,
Password,
}),
}).then((res) => {
if (res.ok) {
console.log("the login response", res);
return res.json();
} else {
alert("Invalid Username or Password");
window.stop();
}
}).then(finalData=>finalData )// <---------- add this
.catch(err=> err)
It happens because getDataFromStorage is an async function so you have to resolve it first. Also in login.js we have to await before navigate to make sure that the data is saved in AsyncStorage. Please update the following part of your code:
login.js
const submitData = async () => {
AuthService.login(Username, Password).then(
async (data) => {
console.log(JSON.stringify(data));
await AsyncStorage.setItem("LoggedInUser", JSON.stringify(data));
if (data.role == "Admin") {
console.log(data.username);
navigation.navigate("adminPage");
} else {
navigation.navigate("staffpage");
}
},
(error) => {
Alert.alert(error);
}
);
};
next, initialize userValue with null
const [userValue, setUserValue] = useState(null);
Now have 2 useEffect,
useEffect(() => {
let mounted = true; //Why this required as it doesn't mean anything
if (!userValue) {
getDataFromStorage();
}
return () => {
mounted = false;
};
}, []);
useEffect(()=>{
if(userValue){
getUserInfo()
}
},[userValue])

Fetch Post Request not returning payload but return status code (200)

So I am trying to create a user using redux-form. I have an express post route on the backend. NOTE: using redux-thunk for middleware, whatwg-fetch with webpack and babel-polyfill.
routes.post('/signup', async (req, res) => {
try {
const createdUser = await userController.createUser(req.body);
const JSONCreatedUser = JSON.stringify(createdUser);
res.json({
confirmation: 'success',
result: createdUser,
});
return JSONCreatedUser;
} catch (error) {
res.statusMessage = error.toString();
res.status(409).json({
confirmation: 'failure',
error: error.toString(),
});
}
});
So the problem I am having is that when I use postman. I will get the entire user object back.
But when I submit it using form I only get
Apimanager.js
export const signUserUpApi = async (url, params) => {
try {
const response = await fetch(url, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(params),
});
const { status, statusText } = response;
if (status === 409) {
throw new Error(statusText);
}
return response;
} catch (error) {
throw new Error(error.toString());
}
};
action.js
import constants from '../constants';
import { signUserUpApi } from '../utils/APIManager';
const signUserUpUrl = process.env.SIGN_USER_UP_URL || 'http://localhost:3000/user/signup';
export const signUserUp = (user) => {
return async (dispatch) => {
try {
const createdUser = await signUserUpApi(signUserUpUrl, user);
dispatch({
type: constants.SIGN_USER_UP,
user: createdUser,
});
return createdUser;
} catch (error) {
throw new Error(error);
}
};
};
export const signUserIn = (user) => {
return {
type: constants.SIGN_USER_UP,
user,
};
};
What I am trying to do is to get the User Object I created when I submit the form and redirect back to the page.
This is what I get back and it did create the user.
First thing, I need is why am I getting the https status code back and not the user object?
Second thing, what are the ways to redirect to the home page when a user successfully signed up logged in.

Resources