Firestore database won't appear - javascript

I'm new with Firebase and I'm still learning how it works. I've created a login, signup and logout sections. The users appear registrated and are saved in the authentication section, but I also want to have their data in database when they register for the first time. I thought of using Firestore Database. The problem is that everything seems to work, but nothing appears in my database section. At first I thought that I was not passing any user auth to the function, so i created a condition to test if there's no user auth, then show a warning. However, there's no warning so it means that I passed it properly.
This is how the sign up function works:
export const SignUp = () => {
const [error, setError] = useState("");
const [loading, setLoading] = useState(false);
const displayName = useRef();
const email = useRef();
const password = useRef();
const passwordConfirmRef = useRef();
const handleSubmit = async e => {
e.preventDefault();
if (password.current.value !== passwordConfirmRef.current.value) {
return setError("Passwords do not match");
}
try {
setError("")
setLoading(true)
const { user } = await auth.createUserWithEmailAndPassword(email.current.value, password.current.value)
const userRef = await handleUserProfile(user, displayName.current.value)
console.log(userRef)
} catch {
setError("Failed to create an account")
}
setLoading(false)
}
I create the user with auth.createUserWithEmailAndPassword and then I pass the user to handleUserProfile
Here's handleUserProfile function:
export const handleUserProfile = async (userAuth, additionalData) => {
if (!userAuth) {
console.warn("No userAuth")
return
}
const { displayName, email } = userAuth;
const timestamp = new Date()
try {
return await firestore.collection("users").add({
displayName,
email,
timestamp,
...additionalData
})
} catch (err) {
console.log(err)
}
return null;
};
Then, nothing appears in my database and nothing gets added. I'm not sure what I'm doing wrong.

The firestore.collections().add function is adding objects (key: value pairs).
It looks like you're not passing an object into handleUserProfile:
const userRef = await handleUserProfile(user, displayName.current.value)
Passing an object into additionalData should solve your issue.

Related

Multiple uncaught reference errors in promise not defined while trying to add data into the firestore database, and function running multiple times

After user logs in, I am trying to display the data in firestore to the user. Upon logging in, the console sends out multiple uncaught (in promise) ReferenceError:l is not defined, le, is not defined, n is not defined.
Ignoring the error does not cause the program to break. Upon updating the document of the current user, the function runs itself multiple times rather than a single time. Can somebody please help me fix this problem. Thank you very much.
I am also getting an error:
"Uncaught (in promise) TypeError: Cannot read properties of undefined (reading 'ingredients')"
if it is a new user with no documents yet. how would I deal with this?
import { getAuth, onAuthStateChanged } from "firebase/auth";
import {
doc,
updateDoc,
getDoc,
arrayUnion,
} from "firebase/firestore";
import { db } from "../configs";
export default function Ingredients() {
const [form, setForm] = useState("");
const auth = getAuth();
const [imgArr, setImgArr] = useState([]);
useEffect(() => {
onAuthStateChanged(auth, (user) => {
if (user) {
const uid = auth.currentUser.uid;
const docRef = doc(db, "users", uid);
//loads the user's ingredients from firebase upon login
const getUsers = async () => {
const data = await getDoc(docRef);
setImgArr(data.data().ingredients);
};
getUsers();
} else {
//clear the ingredients array upon logout
setImgArr([]);
}
});
}, [auth]);
function handleChange(e) {
setForm(e.target.value);
}
async function getResponse() {
const params = new URLSearchParams({ q: form });
const response = await fetch(
`https://edamam-food-and-grocery-database.p.rapidapi.com/parser?ingr=${params}`,
{
method: "GET",
headers: {
"X-RapidAPI-Key":
"29a63a7413msh8378b61a2e11cf3p192e62jsn53d83f1651fe",
"X-RapidAPI-Host": "edamam-food-and-grocery-database.p.rapidapi.com",
},
}
);
const data = await response.json();
return {
label: data.parsed[0].food.label,
image: data.parsed[0].food.image,
id: Math.random(),
};
}
//upload data to firebase and update the array of ingredients to display
const clickHandler = async (e) => {
try {
setForm(e.target.value);
//get response from edamam api
const newImg = await getResponse();
//redefining uid and docRef because unable to figure out how to make them global
const uid = auth.currentUser.uid;
const docRef = doc(db, "users", uid);
//updates firebase with new ingredient
updateDoc(docRef, {
ingredients: arrayUnion({ name: form, image: newImg.image }),
});
setImgArr([...imgArr, newImg]);
} catch (err) {
console.error(err);
}
};
//returns array with image of ingredients
const thingsElements = imgArr.map((thing) => (
<div key={Math.random()}>
<img src={thing.image} alt={thing.name} />
</div>
));
return (
<div className={`${styles.container} px-5`}>
<Heading heading="Ingredients" info="Search by etc" />
<Form
label="Search Ingredients..."
onChange={handleChange}
value={form}
placeholder="Search Ingredients..."
clicked={clickHandler}
icon={faCamera}
/>
<div className="flex flex-wrap">{thingsElements}</div>
</div>
);
}

firebase Display Name is null

I'm trying to print firebase display name.
its showing after login. but after registrtion its showing null value. I'm using react-firebase-hook
const [userAuthenticate,loadingAuthenticate] = useAuthState(auth)
const [update,setUpdate] = useState(auth)
useEffect(()=>{
const tokenUpdate = async()=>{
if(userAuthenticate && update){
console.log(userAuthenticate.displayName); // Showing Null
navigate('/');
}
}
tokenUpdate();
},[userAuthenticate,update]);
const onSubmit = async(data) => {
const name = data.name;
const email = data.email;
const password = data.password;
await createUserWithEmailAndPassword(email, password);
await updateProfile({ displayName: name });
await sendEmailVerification(email)
setUpdate(true);
};
Updating the profile does not automatically refresh the profile in the current application. You'll need to reload the user's profile after the call to updateProfile completes.

my react function hook not returning data state inside a function?

this is my function hook:
const useSignIn = () => {
const [data, setData] = useState(null);
const [loading, setLoading] = useState(false);
const [error, setError] = useState("");
const signUp = useCallback(async ({ email, password, confirmPassword }) => {
try {
setLoading(true);
const response = await api.post("/auth/sign_up/", {
email,
password,
password_confirmation: confirmPassword,
});
setData(response.data);
console.log("signUp response", response.data);
} catch (error) {
if (
error.response &&
error.response.data &&
error.response.data.errors &&
error.response.data.errors.email
) {
setError(error.response.data.errors.email[0]);
} else setError("Something went wrong");
} finally {
setLoading(false);
}
}, []);
return { loading, signUp, error, data };
};
then i use it in my react hook component like this:
const { signUp, error: signUpError, loading, data } = useSignUp();
const onSubmit = async ({
email,
password,
confirmPassword,
}: InitialValues) => {
await signUp({ email, password, confirmPassword });
console.log("data 0 ", data);
but what happens after signUp is resolved is that data is null? why is it that data is null? my log has data in it but just not on my component
Because the data you're looking at (the one you've logged) is the one from the previous render.
Instead, use data when rendering (when loading isn't true) and your component will be called to re-render when data changes — whereupon it will get a new copy of data from useSignup.
You're never actually setting the data equal to SignUp, you're setting the data with your useState hook (setData) but never assign it to SignUp. You need a return function instead, or after the useState hook, such as return (response.data) .

Correct way to pass async eerror

I have a function which uses Firebase auth to update a user's email:
export const updateEmail = async (email) => {
const user = auth.currentUser;
return user.updateEmail(email);
};
It is used in a function which gets an email from a form (in React) and tries to update the email. If there is an error, we change the state to reflect that.
handleSave = (e) => {
const email = e.target.email.value;
updateEmail(email).catch((err) => {
this.setState({ didError: true, emailError: err.message });
});
};
However, when an error occurs, in the console I get:
My question is: why does this still say 'Uncaught'? Does the .catch() in handleSave not take care of that?
update
Link to relevant Firebase docs
Assuming updateEmail returns a prmise, I guess you can try:
export const updateEmail = (email) => { // no need for async here
const user = auth.currentUser;
return user.updateEmail(email);
};
handleSave = async (e) => {
const email = e.target.email.value;
try{
await updateEmail(email);
}catch(err){
this.setState({ didError: true, emailError: err.message });
}
};
I'm not quite sure since I don't know so much about Firebase, let me suggest something.
export const updateEmail = async (email) => {
const user = auth.currentUser;
const response = await user.updateEmail(email);
if ( response.error ) {
throw new Error( response.error );
}
return "something else";
};

How do I add a user to my Firebase DB with it's unique id when I first create a user for authentication

This may seem like an obvious question, but i'm having trouble creating a user inside of my Firebase db. I'm very new to firebase and coding for that matter.
How I understand it to be is when a user clicks the sign up button, a user with the newly authenticated uid will be created under 'object/users". However the user is always null. In the google documentation it says that sometimes the user is null because it hasn't finished initializing the user. And to put it inside of onAuthStateChanged. This works, however, if I did this a user would be created/overwritten every time they log in or log out.
I suppose what I'm looking for is some solution to create a user inside of my firebase db when a user first signs up with valid information.
Here is my code:
function LoginCtrl($scope) {
$scope.txtEmail = document.getElementById('txtEmail');
$scope.txtPassword = document.getElementById('txtPassword');
$scope.btnLogin = document.getElementById('btnLogin');
$scope.btnSignUp = document.getElementById('btnSignUp');
$scope.btnLogout = document.getElementById('btnLogout');
btnLogin.addEventListener('click', e => {
const email = txtEmail.value;
const pass = txtPassword.value;
const auth = firebase.auth();
const promise = auth.signInWithEmailAndPassword(email, pass);
promise.catch(e => console.log(e.message));
});
btnSignUp.addEventListener('click', e => {
const email = txtEmail.value;
const pass = txtPassword.value;
const auth = firebase.auth();
const promise = auth.createUserWithEmailAndPassword(email, pass);
promise.catch(e => console.log(e.message));
createUser();
});
function createUser() {
var user = firebase.auth().currentUser;
if (user != null) {
const dbRefObject = firebase.database().ref().child('object');
const dbRefList = dbRefObject.child("users/" + user.uid);
dbRefList.set({
name: "jim",
});
}
}
btnLogout.addEventListener('click', e => {
firebase.auth().signOut();
});
firebase.auth().onAuthStateChanged(firebaseUser => {
if (firebaseUser) {
console.log(firebaseUser);
btnLogout.classList.remove('hide');
btnLogin.classList.add('hide');
} else {
console.log('not logged in');
btnLogout.classList.add('hide');
btnLogin.classList.remove('hide');
}
})
}
The culprit is in these three lines:
const promise = auth.createUserWithEmailAndPassword(email, pass);
promise.catch(e => console.log(e.message));
createUser();
You are firing off createUser() too soon. In the above code fragment, this happens right after starting the (asynchronous) registration process – the SDK never had a chance to actually create the user in the auth database!
The createUserWithEmailAndPassword returns a promise, as reflected in your local variable. What you need to do here is chaining the two calls, i.e. start the database manipulation after the promise is fulfilled.
Try this:
// inside the click handler
btnSignUp.addEventListener('click', e => {
const email = txtEmail.value;
const pass = txtPassword.value;
const auth = firebase.auth();
auth.createUserWithEmailAndPassword(email, pass)
.then(user => createUser(user)) // <-- important!
.catch(e => console.log(e.message));
});
function createUser(user) {
// no need for currentUser if you pass it in as an argument
if (user) {
...
}
}

Categories