Why is user data not storing into firebase firestore? - javascript

I have functions that Sign up users but i can't seemed why it is not storing the users information in firebase firestore.
My Sign Up user functions:
//Signing up the user
export function* signUpUser({ payload: { displayName, surname, email, password, cellphone, address, province, tcCheckbox} }) {
try {
const user = yield auth.createUserWithEmailAndPassword(email, password);
const additionalData = { displayName, surname, cellphone, address, province, tcCheckbox};
yield getSnapshotFromUserAuth(user, additionalData);
} catch(err) {
console.log(err);
}
};
From my Sign up user function I get 'getSnapshotFromUserAuth'
export function* getSnapshotFromUserAuth(user, additionalData = {}) {
try {
const userRef = yield call(handleUserProfile, { userAuth: user, additionalData });
const snapshot = yield userRef.get();
yield put(signInSuccess({
id: snapshot.id,
...snapshot.data()
}))
} catch(err) {
console.log(err);
}
};
Which calls handleUserProfile in my firebase utils.js
export const auth = firebase.auth();
export const firestore = firebase.firestore();
export const handleUserProfile = async ({ userAuth, additionalData }) => {
if (!userAuth) return;
const { uid } = userAuth;
const userRef = firestore.doc(`users/${uid}`);
const snapshot = await userRef.get();
if (!snapshot.exists) {
const { displayName, surname, email } = userAuth;
const timestamp = new Date();
const userRoles = ['user'];
try {
await userRef.set({
displayName,
email,
surname,
createdDate: timestamp,
userRoles,
...additionalData
});
} catch(err) {
console.log(err);
}
}
return userRef;
};
The code is signing up the user but not storing all the additional data that i want to store with the user

I would think this is related with createUserWithEmailAndPassword. This method returns object UserCredential. Please check the reference and example.
So in the code there is user assignment and I think this should be corrected to:
const user = yield auth.createUserWithEmailAndPassword(email, password).user;
More or less like in the example. I do not have a playground to test it, so please share the result.

const { displayName, email, surname, cellphone, address, province, tcCheckbox } = userAuth;
did you mean additionalData instead of userAuth?

Related

Firebase get UID from account create

On Creation of an account I need to make 2 collections 1 for Users 1 for Companies.
Within each one, I need to capture the UID. I just cant seem to grab it. I keep getting undefined when console.log it.
component
const handleSubmit = async (e) => {
e.preventDefault()
setError('')
try {
await createUser(email, password).then(() => {
if (false) throw Error('Error')
//NEED Get UserID
addDoc(collection(db, 'Companies'), {
name: company,
//owner: userID,
users: [],
assets: []
}).then((docRef) => {
let companyID = docRef.id
addDoc(collection(db, 'Users'), {
name: name,
email: email,
company: [company],
companyID: [companyID]
//UserID: UserID
})
})
})
authContext
export const AuthContextProvider = ({ children }) => {
const [user, setUser] = useState({})
const createUser = (email, password) => {
return createUserWithEmailAndPassword(auth, email, password)
}
I have tried everything in the firebase documentation but I believe since I am using context it may process data a bit differently.
The createUser() function is returning a UserCredential object. You can read the user's UID from it. Try refactoring the code as shown below:
const handleSubmit = async (e) => {
e.preventDefault()
setError('')
const { user } = await createUser(email, password)
const docRef = await addDoc(collection(db, 'Companies'), {
name: company,
owner: user.uid,
users: [],
assets: []
})
await addDoc(collection(db, 'Users'), {
name: name,
email: email,
company: [company],
companyID: [docRef.id]
UserID: user.uid
})
}

Login data is not being saved in the realtime database when I add window.location.replace

I'm still new to programming and especially Firebase so there probably will some obvious stuff I missed.
This is supposed to be login/register page. When the user type's in the needed info and click one of the buttons that corresponds to there field. Tt's supposed to load another page. Save that data in a Firebase realtime database and also in authentication.
It's doing the ladder and first but not the second. So I'm stuck with the code I have displayed under this. I read something about needing to give sometime for the data to be send out.
import { firebaseConfig } from "./database.mjs";
import { initializeApp } from "https://www.gstatic.com/firebasejs/9.15.0/firebase-app.js";
import { getAuth, createUserWithEmailAndPassword,
signInWithEmailAndPassword, onAuthStateChanged,
signOut } from "https://www.gstatic.com/firebasejs/9.15.0/firebase-auth.js";
import {getDatabase, ref, get, set, child, update, remove, push} from "https://www.gstatic.com/firebasejs/9.15.0/firebase-database.js";
const app = initializeApp(firebaseConfig);
const auth = getAuth();
const db = getDatabase();
const UserRegistration = () => {
const Username = document.getElementById('username').value
const Email = document.getElementById("email-signup").value;
const Passwd = document.getElementById("passwd-signup").value;
createUserWithEmailAndPassword(auth, Email, Passwd)
.then((userCredential) => {
const user = userCredential.user;
const loginTime = new Date()
set(ref(db, 'users/' + user.uid),{
user_email: Email,
user_username: Username,
last_login: `${loginTime}`
})
console.log(user, "User Created");
}).then(StatusMonitor())
.catch((error) => {
const errorCode = error.code;
const errorMessage = error.message;
console.log(error.message)
});
}
const UserLogIn = () => {
const Email = document.getElementById("email-signup").value;
const Passwd = document.getElementById("passwd-signup").value;
const auth = getAuth();
signInWithEmailAndPassword(auth, Email, Passwd)
.then((userCredential) => {
const user = userCredential.user;
const loginTime = new Date()
update(ref(db, 'users/' + user.uid), {
last_login: loginTime
});
console.log(user, "Login Successfull");
})
.catch((error) => {
const errorCode = error.code;
const errorMessage = error.message;
console.log(error.message);
});
StatusMonitor()
}
//Login checker
const StatusMonitor = () => { //This part specifically
onAuthStateChanged(auth, (user) => {
if (user) {
const uid = user.uid;
console.log("User is active");
window.location.replace("./product.html")
}
else {
console.log("User is inactive");
}
})
}
document.getElementById("signup").addEventListener("click", UserRegistration);
document.getElementById('login').addEventListener("click", UserLogIn);
I was able to get it to work with setTimeout but this created it's own problems such as small freezes whenever the thing got triggered and of course the extra time needed for it to load as I can't set to it change based on latency.
Tried to do it with async/await but personally couldn't get it to work.
Any help would be appreciated!

How to decipher between different Firebase errors in single Cloud Function catch block?

I have a Firebase Cloud Function that performs two async tasks (create user by Authentication and batch write by Firestore) with a single catch block for all errors. My question is how can I decipher if the error is thrown from Authentication or from Firestore in the catch block before I throw the HTTPS error to the client?
exports.createUser = functions.https.onCall((data, _context) => {
const email = data.email;
const password = data.password;
const birthday = data.birthday;
const name = data.name;
return admin.auth().createUser({
email: email,
password: password,
})
.then((userRecord) => {
const userId = userRecord.uid;
const db = admin.firestore();
const batch = db.batch();
const testDocRef1 = db.collection("test1").doc(userId);
const testDocRef2 = db.collection("test2").doc(userId);
batch.create(testDocRef1, {name: name, email: email});
batch.create(testDocRef2, {name: name, birthday: birthday});
return batch.commit().then(() => {
return Promise.resolve({"userId": userId});
});
})
.catch((error) => {
// how can I decipher which async task this error came from?
throw new functions.https.HttpsError("unknown", "Refer to details for error specifics.", error);
});
});

How do you create a subcollection in Firebase Firestore?

I'm having troulbe figuring out how to add a subcollection to a document in my React App. I'm also getting the error that db.collection() is not a function. I'm trying to add the subcollection in the registerWithEmailAndPassword function. The Firebase Firestore documentation does not specify how to create a subcollection. Any help would be greatly appreciated thank you. Firebase config has been ommited to protect my API key.
import { initializeApp } from "firebase/app";
import {
GoogleAuthProvider,
getAuth,
signInWithPopup,
signInWithEmailAndPassword,
createUserWithEmailAndPassword,
sendPasswordResetEmail,
signOut,
} from "firebase/auth";
import {
getFirestore,
query,
getDocs,
collection,
where,
addDoc,
Firestore,
doc,
DocumentReference,
setDoc
} from "firebase/firestore";
// TODO: Add SDKs for Firebase products that you want to use
// https://firebase.google.com/docs/web/setup#available-libraries
// Your web app's Firebase configuration
// For Firebase JS SDK v7.20.0 and later, measurementId is optional
// Initialize Firebase
const app = initializeApp(firebaseConfig);
const auth = getAuth(app);
const db = getFirestore(app);
const googleProvider = new GoogleAuthProvider();
const signInWithGoogle = async () => {
try {
const res = await signInWithPopup(auth, googleProvider);
const user = res.user;
const q = query(collection(db, "users"), where("uid", "==", user.uid));
const docs = await getDocs(q);
if (docs.docs.length === 0) {
await addDoc(collection(db, "users"), {
uid: user.uid,
name: user.displayName,
authProvider: "google",
email: user.email,
});
}
} catch (err) {
console.error(err);
alert(err.message);
}
};
const logInWithEmailAndPassword = async (email, password) => {
try {
await signInWithEmailAndPassword(auth, email, password);
} catch (err) {
console.error(err);
alert(err.message);
}
};
const registerWithEmailAndPassword = async (name, email, password) => {
try {
const res = await createUserWithEmailAndPassword(auth, email, password);
const user = res.user;
const userDoc = await addDoc(collection(db, "users"), {
uid: user.uid,
name,
authProvider: "local",
email,
});
db.collection("users").doc(userDoc.id).collection("test");
} catch (err) {
console.error(err);
alert(err.message);
}
};
const sendPasswordReset = async (email) => {
try {
await sendPasswordResetEmail(auth, email);
alert("Password reset link sent!");
} catch (err) {
console.error(err);
alert(err.message);
}
};
const logout = () => {
signOut(auth);
};
export {
auth,
db,
signInWithGoogle,
logInWithEmailAndPassword,
registerWithEmailAndPassword,
sendPasswordReset,
logout,
};
This code uses the classic, namespaced syntax of Firebase SDK version 8 and before:
db.collection("users").doc(userDoc.id).collection("test");
But the rest of your code uses the new modular syntax of Firebase SDK versions 9 and later. The equivalent there would be:
collection(doc(collection(db, "users"), userDoc.id), "test")
Or more concisely:
collection(db, "users", userDoc.id, "test")
The above creates a reference to the subcollection, but doesn't create the collection in the database yet. A collection is created once a document is written to it, and removed automatically once the last document is removed from it.
So you can create a document in test (and thus create test) with:
const testCollection = collection(db, "users", userDoc.id, "test");
addDoc(testCollection, { title: "hello world })

Firestore database won't appear

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.

Categories