adding data in firebase firestore React - reactjs

I have singUp function. I successfuly create a new user in Authentication section. After that I can even get his uid. But I have no idea why setting a new document in collection user function doesn't work. Like it would be never start.. Even .then() or .catch() methods doesn't show their console.log(). I am using almost the same code in another project and everything is fine there.
export const signUp = (newUser) => {
return (dispatch, getState) => {
firebase.firestore().collection('users').where('nick', '==', newUser.nick).get()
.then(snapshot => {
if (snapshot.empty) {
firebase.auth().createUserWithEmailAndPassword(
newUser.email,
newUser.password
).then((resp) => {
console.log(resp)
console.log(resp.user.uid)
firebase.firestore().collection("users").doc(resp.user.uid).set({
name: newUser.name,
age: newUser.age
}).then(function () {
console.log("Document successfully written!");
}).catch(function (error) {
console.error("Error writing document: ", error);
});
}).then(() => {
dispatch({ type: "SIGNUP_SUCCESS" });
}).catch((err) => {
console.log(err)
let error;
if (err.code === 'auth/email-already-in-use')
error = 'Adres e-mail jest już w użyciu!'
dispatch({ type: "SIGNUP_ERROR", error })
})
} else {
let error = 'Ten nick jest już zajęty!'
dispatch({ type: "SIGNUP_ERROR", error })
}
})
}
}
And my console :

You need to return the promise from setting the user's collection as follows:
export const signUp = (newUser) => {
return (dispatch, getState) => {
firebase.firestore().collection('users').where('nick', '==', newUser.nick).get()
.then(snapshot => {
if (snapshot.empty) {
firebase.auth().createUserWithEmailAndPassword(
newUser.email,
newUser.password
).then((resp) => {
console.log(resp)
console.log(resp.user.uid)
// ******* add the return statement here *******
return firebase.firestore().collection("users").doc(resp.user.uid).set({
name: newUser.name,
age: newUser.age
}).then(function () {
console.log("Document successfully written!");
}).catch(function (error) {
console.error("Error writing document: ", error);
});
}).then(() => {
dispatch({ type: "SIGNUP_SUCCESS" });
}).catch((err) => {
console.log(err)
let error;
if (err.code === 'auth/email-already-in-use')
error = 'Adres e-mail jest już w użyciu!'
dispatch({ type: "SIGNUP_ERROR", error })
})
} else {
let error = 'Ten nick jest już zajęty!'
dispatch({ type: "SIGNUP_ERROR", error })
}
})
}
}

Related

About firebase token service

i am following Ryan Dunghel Ecommerce course, i am using firebase admin to verify the token client sent, but some magic happened, the token ok for the first time i log, but after i refresh the page, everything gone, also happened with Google login,enter image description here i find out the similar question too, someone please give me advise, i dont want to stop thing course. thank.
App.js
const App = () => {
const dispatch = useDispatch();
// to check firebase auth state
useEffect(() => {
const unsubscribe = auth.onAuthStateChanged(async (user) => {
if (user) {
const idTokenResult = await user.getIdTokenResult();
console.log("user", user);
currentUser(idTokenResult.token)
.then((res) => {
dispatch({`enter code here`
type: "LOGGED_IN_USER",
payload: {
name: res.data.name,
email: res.data.email,
token: idTokenResult.token,
role: res.data.role,
_id: res.data._id,
},
});
})
.catch((err) => console.log(err));
}
});
// cleanup
return () => unsubscribe();
}, [dispatch]);
login.js
const handleSubmit = async (e) => {
e.preventDefault();
// setLoading(true);
try {
let result = await signInWithEmailAndPassword(auth,email, password);
const { user } = result;
const TokenResult = await user.getIdTokenResult();
createOrUpdateUser(TokenResult.token)
.then((res) => {
dispatch({
type: userActionType.USER_LOGGED_IN,
payload: {
name: res.data.name,
email: res.data.email,
token: TokenResult.token,
role: res.data.role,
_id: res.data._id,
},
});
console.log(res);
roleRedirect(res);
})
.catch((err) => console.log(err));
} catch (error) {
console.log(error);
toast.error(error.message);
}
};
middleware, where verify token
exports.authCheck = async (req, res, next) => {
// console.log(req.headers); // token
try {
const firebaseUser = await admin
.auth()
.verifyIdToken(req.headers.authtoken);
// console.log("FIREBASE USER IN AUTHCHECK", firebaseUser);
req.user = firebaseUser;
next();
} catch (err) {
res.status(401).json({
err: "Invalid or expired token",
});
}
};

how to wait for returned response from redux actions using UseDispatch Hook

I am new to redux and
I am now trying to write a login component.
my redux actions is something like this.
export const fetchToken = (params) => {
return (dispatch) => {
const config = {
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
};
return axios
.post(`${baseUri}/api/token`, params, config)
.then((res) => {
dispatch({
type: LOGGED_IN,
payload: res.data,
});
})
.catch((err) => {
console.log(err);
alert('Provided username and password is incorrect');
});
};
};
as you can see I am returning a promise. I try to use it in the component but it's not working.
I am using useDispatch hooks from react-redux
my code look like this
const checkValidate = () => {
if (email.length < 1 || password.length < 1) {
alert('Please fill all the details');
return;
} else {
const params = new URLSearchParams();
params.append('username', email);
params.append('password', password);
params.append('grant_type', 'password');
dispatch(fetchToken(params)).then((res) => {
alert('success')
}).catch((err) => alert('not success'));
}
// navigation.navigate('Home');
};
As you can see I am alerting the success. The problem is that if I write the wrong username and password. The response always goes into success response. It will alert success then It will alert the response from the fetchToken action which is alert('Provided username and password is incorrect'); Is there anything wrong with my code.
And also whenever I try to console.log the then response it will always return undefined
When you do
.then((res) => {
dispatch({
type: LOGGED_IN,
payload: res.data,
});
})
.catch((err) => {
console.log(err);
alert('Provided username and password is incorrect');
});
you remove the error and the result from the chain. If you want them to be passed to the next .then or .catch, you have to return/rethrow it:
.then((res) => {
dispatch({
type: LOGGED_IN,
payload: res.data,
});
+ return res
})
.catch((err) => {
console.log(err);
alert('Provided username and password is incorrect');
+ throw err
});

Internal server error 500 react post to firebase

I'm getting a 500 error when posting to my firebase database. However, when I post via postman, it works fine, thus I'm having a lot of trouble debugging this. For the moment, I've hardcoded the categoryId and also the newRow, to make sure there wasn't a problem with my state somehow.
I think the handleSubmit is the only relevant function
handleSubmit = (event) => {
event.preventDefault();
const categoryId = "1RegisterInfo";
const newRow = {
index: "3",
body: "this.state.body",
dataType: "this.state.dataType",
visit: "test",
};
this.props.postRow(categoryId, { newRow });
};
action
export const postRow = (categoryId, rowData) => (dispatch) => {
dispatch({ type: "LOADING_UI" });
axios
.post(`/category/${categoryId}`, rowData)
.then((res) => {
dispatch({
type: "POST_ROW",
payload: res.data,
});
dispatch(clearErrors());
})
.catch((err) => {
dispatch({
type: "SET_ERRORS",
payload: err.response.data,
});
});
};
cloud function
exports.postRow = (req, res) => {
if (req.body.body.trim() === "") {
return res.status(400).json({ comment: "Must not be empty" });
}
if (req.body.index.trim() === "") {
return res.status(400).json({ comment: "Must not be empty" });
}
if (req.body.dataType.trim() === "") {
return res.status(400).json({ comment: "Must not be empty" });
}
if (req.body.visit.trim() === "") {
return res.status(400).json({ comment: "Must not be empty" });
}
const newRow = {
index: req.body.index,
dataType: req.body.dataType,
visit: req.body.visit,
body: req.body.body,
createdAt: new Date().toISOString(),
categoryId: req.params.categoryId,
disapproveCount: 0,
approveCount: 0,
};
db.doc(`/categories/${req.params.categoryId}`)
.get()
.then((doc) => {
if (!doc.exists) {
return res.status(404).json({ error: "Category not found" });
}
})
.then(() => {
return db.collection("rows").add(newRow);
})
.then(() => {
res.json(newRow);
})
.catch((err) => {
console.log(err);
res.status(500).json({ error: "Something went wrong" });
});
};
Any help appreciated!
You're not sending the right payload.
{ newRow }
is the same as
{
newRow: {
index: '3',
body: this.state.body,
dataType: this.state.dataType,
visit: 'test',
},
}
You're passing the above data in the request body and so req.body.body is undefined causing req.body.body.trim() to fail.
this.props.postRow(categoryId, { newRow })
should be
this.props.postRow(categoryId, newRow)
I would recommend using Joi or something similar to validate the request payload before trying to do any other operation.

Sending response of multiple api calls from action to view file in react js with redux

I am beginner to React JS and Redux and have got stuck in a problem. I have to call a login api and if that return success I need to call another api using axios to get user details. Following is my function in action doing it:
export const login = (username, password) => (dispatch) => {
return AuthServicee.login(username, password).then(
(data) => {
if(data.success) {
userService.getUserDetails(username).then((data) => {
localStorage.setItem("user", JSON.stringify(data.data));
dispatch({
type: LOGIN_SUCCESS,
payload: { user: data },
});
return Promise.resolve();
},(error) => {
const message =
(error.response &&
error.response.data &&
error.response.data.message) ||
error.message ||
error.toString();
dispatch({
type: LOGIN_FAIL,
});
dispatch({
type: SET_MESSAGE,
payload: message,
});
return Promise.reject();
}).catch(err => {
dispatch({
type: LOGIN_FAIL,
});
});;
} else {
dispatch({
type: LOGIN_FAIL,
});
dispatch({
type: SET_MESSAGE,
payload: data.error,
});
}
},
(error) => {
const message =
(error.response &&
error.response.data &&
error.response.data.message) ||
error.message ||
error.toString();
dispatch({
type: LOGIN_FAIL,
});
dispatch({
type: SET_MESSAGE,
payload: message,
});
return Promise.reject();
}
);
};
I am calling the above function from my login page as following:
const handleLogin = (e) => {
e.preventDefault();
setLoading(true);
form.current.validateAll();
if (checkBtn.current.context._errors.length === 0) {
dispatch(login(username, password))
.then(() => {
setLoading(false);
if (props !=null && props.isAuthenticated) {
props.history.push("/home");
}
})
.catch(() => {
setLoading(false);
});
} else {
setLoading(false);
}
};
Now since I have return with the first API call, it returns data as soon as the first API provides a response and does not wait for the second call to finish. It should wait till both API calls are finished and then return the result to Login.js.
Can someone please help me here?
Working Solution as per cb dev answer
const login = async (username, password) => {
try {
const loginRes = await loginUser(username, password);
if (loginRes.data != null && loginRes.data.success) {
localStorage.setItem("access_token", loginRes.data.data);
const getUserRes = await getUserDetail(loginRes.data.data, username);
localStorage.setItem("user", JSON.stringify(getUserRes.data));
return getUserRes.data;
} else {
return loginRes.data;
}
}catch (err) {
console.log("Something went wrong with the login process...");
console.log(`I can log the error here: ${err}`);
}
}
function loginUser(username, password) {
return new Promise((resolve, reject) => {
const response = axios
.post(API_URL + "users/authenticate", {
username,
password,
});
resolve(response);
});
}
function getUserDetail(access_token, username) {
return new Promise((resolve, reject) => {
console.log(`Login_step2: I've got ${access_token}...`);
var url = apiConfig.API_BASE_URL + "users?username="+username;
resolve (axios.get(url, { headers: authHeader() }));
});
}
You should be using async-await syntax. It will make your code much nicer to read and will be a lot easier to control the behavior you're intending.
https://javascript.info/async-await
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/await
Something like this:
CodeSandbox Link
import React from "react";
import "./styles.css";
function mockLogin_step1() {
return new Promise((resolve, reject) => {
setTimeout(() => resolve("Login_step1 success"), 1000);
});
}
function mockLogin_step2(something) {
return new Promise((resolve, reject) => {
console.log(`Login_step2: I've got ${something}...`);
setTimeout(() => resolve("Login_step2 success"), 1000);
});
}
function App() {
async function doLogin() {
try {
console.log("Calling async API login STEP 1");
const step1Result = await mockLogin_step1();
console.log(step1Result);
console.log("Calling async API login STEP 2");
const step2Result = await mockLogin_step2("something from step1");
console.log(step2Result);
console.log("I can dispatch something here...");
} catch (err) {
console.log("Something went wrong with the login process...");
console.log("An error probably happened on step1 or step2...");
console.log(`I can log the error here: ${err}`);
console.log("I can dispatch something here...");
}
}
return <button onClick={doLogin}>Login</button>;
}
export default App;
The resulting log:

Returning response from Dispatch

I'm implementing login functionality to my application and am trying to return the response from a dispatched thunk action. I'm purposely entering the incorrect password because i'd like for the errors that are set in my backend to display within an antd notification on the frontend. My expected response should be:
return res.status(400).json({
success: false,
message: 'Invalid email address or password.',
});
but instead i'm getting the following in the console:
Error: Request failed with status code 400
Route:
const loginUser = async (req, res) => {
// Validate Login Input
const { error } = validateLoginInput(req.body);
if (error)
return res
.status(400)
.json({ success: false, message: error.details[0].message });
req.body.email = req.body.email.toLowerCase();
req.body = sanitize(req.body);
const { email, password } = req.body;
try {
// See if user exists
let user = await User.findOne({ email });
if (!user) {
return res.status(400).json({
success: false,
message: 'Invalid email address or password.',
});
}
// Compare passwords
const isMatch = await bcrypt.compare(password, user.password);
if (!isMatch) {
return res.status(400).json({
success: false,
message: 'Invalid email address or password.',
});
}
// Return jsonwebtoken
const payload = {
user: {
id: user.id,
},
};
jwt.sign(
payload,
process.env.JWT_SECRET,
{ expiresIn: 3600 },
(error, token) => {
if (error) throw error;
res.json({ token });
}
);
} catch (error) {
res.status(500).json({ success: false, messsage: 'Server error' });
}
};
Actions:
export const loginBegin = () => ({
type: LOGIN_BEGIN,
});
export const loginSuccess = (user) => ({
type: LOGIN_SUCCESS,
payload: user,
});
export const loginFail = (error) => ({
type: LOGIN_FAIL,
payload: error,
});
Thunk:
export const attemptLogin = (formData) => async (dispatch) => {
dispatch(loginBegin());
return await postLogin(formData)
.then((res) => {
dispatch(loginSuccess(res.data));
console.log(res.data); <-- This doesn't even show in console
})
// .then(() => {
// setTimeout(() => {
// dispatch(push('/app'));
// }, 2000);
// })
.catch((error) => {
dispatch(loginFail(error));
});
};
onSubmit:
const onSubmit = async (values) => {
const { email, password } = values;
setLoading(true);
try {
const response = await dispatch(attemptLogin({ email, password }));
console.log(response); <-- returns undefined
if (response.data.success) {
setLoading(false);
notification['success']({
message: 'Congrats!',
description: response.message,
});
} else {
notification['error']({
message: 'Uh-oh!',
description: response.message,
});
}
} catch (error) {
console.log(error);
}
};
The problem is that you are not returning the response in the promise. Also, if you are getting a 400 response, it probably rejects the promise or throws an error.
export const attemptLogin = (formData) => async (dispatch) => {
dispatch(loginBegin());
return await postLogin(formData)
.then((res) => {
dispatch(loginSuccess(res.data));
return res;
})
.catch((error) => {
dispatch(loginFail(error));
return error; // this will only work if the error is the response object.
});
};

Resources