Here is my code.
import FirebaseKeys from "./config";
import firebase from 'firebase/app';
class Fire {
constructor() {
firebase.initializeApp(FirebaseKeys);
}
addPost = async ({text, localUri}) => {
const remoteUri = await this.uploadPhotoAsync(localUri)
return new Promise((res, rej) => {
this.firestore.collection("posts").add({
text,
uid: this.uid,
timestamp: this.timestamp,
image: remoteUri
})
.then(ref => {
res(ref)
})
.catch(error => {
rej(error)
});
});
};
uploadPhotoAsync = async uri => {
const path = `photos/${this.uid}/${Date.now()}.jpg`
return new Promise(async (res, rej) => {
const response = await fetch(uri)
const file = await response.blob()
let upload = firebase.storage().ref(path).put(file)
upload.on(
"state_changed",
snapshot => {},
err => {
rej(err)
},
async () => {
const url = await upload.snapshot.ref.getDownloadURL();
res(url);
}
);
});
};
What I have noticed is there is no problem uploading image on uploadImageAsync but when it comes to addPost method it does not create a collection named "post".
what should I do with this? thankyou in advance. btw I am not using expo on this.
First of all, the collection that your addPost method is trying to create is called "posts", not "post". When it comes to Firestore, always check that your security rules allow for this user to write to that path.
It would also be nice to see the usage of addPost, and see what its res and rej return.
Related
I wanna add multiple photo to db by Array.map() and after that add Array with url storage to collection.
I have problem with async function, because i should wait for this function await addImages() but something is not good.
const addImages = async () => {
image.map(async (imagePhoto) => {
const childPath = `post/${firebase.auth().currentUser.uid}/${Math.random().toString(36)}`;
const response = await fetch(imagePhoto);
const blob = await response.blob();
const task = firebase
.storage()
.ref()
.child(childPath)
.put(blob);
const taskProgress = snapshot => {
console.log(`transferred: ${snapshot.bytesTransferred}`)
}
const taskCompleted = () => {
task.snapshot.ref.getDownloadURL().then((snapshot) => {
imageDB.push(snapshot)
})
}
const taskError = snapshot => {
console.log(snapshot)
}
task.on("state_changed", taskProgress, taskError, taskCompleted);
})
}
const addToDbServices = async () => {
await addImages();
firebase.firestore().collection("services")
.doc(firebase.auth().currentUser.uid)
.collection("userServices")
.add({
nameService,
errorCode,
description,
imageDB,
status,
creation: firebase.firestore.FieldValue.serverTimestamp()
}).then(() => {
Alert.alert('Serwis', 'Twoje zgłoszenie zostało pomyślnie dodane'),
navigation.goBack()
})
}
image.map(async (imagePhoto) => {...})
This creates an array of promises. These are executed but not awaited by default, so code execution continues regardless whether the operations are finished or not. If you want to await all these promises you can use Promis.all() like that:
const addImages = async () => {
const pendingOperations = image.map(async (imagePhoto) => {...});
// wait until all images are processed
return Promise.all(pendingOperations); // or await Promise.all(pendingOperations);
}
const addToDbServices = async () => {
await addImages();
...
}
Can someone assist me with revising the code so it will wait for the upload to finish then save the image urls to firestore? I'm new to async and await and can't seem to figure it out. The fileDownloadUrl is still empty even if I do the saving to firestore inside the Promise.all(promises).then():
cxonst promises = [];
const fileDownloadUrl = [];
pictures.forEach(file => {
const uploadTask =
firebase
.storage()
.ref()
.child(`img/upl/${file.data.name}`)
.put(file.uploadTask);
promises.push(uploadTask);
uploadTask.on(
firebase.storage.TaskEvent.STATE_CHANGED,
snapshot => {
const progress = Math.round((snapshot.bytesTransferred /
snapshot.totalBytes) * 100);
if (snapshot.state === firebase.storage.TaskState.RUNNING) {
console.log(`Progress: ${progress}%`);
}
},
error => console.log(error.code),
async () => {
const downloadURL = await
uploadTask.snapshot.ref.getDownloadURL();
fileDownloadUrl.push(downloadURL);
}
);
});
Promise.all(promises)
.then(() => {
db
.collection("properties")
.add({
timestamp: firebase.firestore.FieldValue.serverTimestamp(),
title: title,
description: description,
pictures: fileDownloadUrl,
user: user.uid
})
})
.catch(err => console.log(err));
While you are waiting for the promises of the put calls to complete, you're then using the uploadTask.on() to determine the download URL. Since this on is not part of the promise, there is no guarantee they're in sync.
A simpler and working approach should be:
const promises = pictures.map(file => {
const ref = firebase.storage().ref().child(`img/upl/${file.data.name}`);
return ref
.put(file.uploadTask)
.then(() => ref.getDownloadURL())
});
Promise.all(promises)
.then((fileDownloadUrls) => {
db
.collection("properties")
.add({
timestamp: firebase.firestore.FieldValue.serverTimestamp(),
title: title,
description: description,
pictures: fileDownloadUrls,
user: user.uid
})
})
.catch(err => console.log(err));
I am trying to send the validation email upon the account registration, using firebase. The registration is being done successfully but whenever I try to code email verification it gives me an error. Probably because I don't know where to place it. All my firebase methods are on Fire.js, which are the following:
import firebaseKeys from './Config';
import firebase from 'firebase';
require("firebase/firestore");
class Fire {
constructor() {
if (!firebase.apps.length) {
firebase.initializeApp(firebaseKeys);
}
}
addPost = async ({ text, localUri }) => {
const remoteUri = await this.uploadPhotoAsync(localUri, 'photos/${this.uid}/${Date.now()}');
return new Promise((res, rej) => {
this.firestore.collection('posts').add({
text,
uid: this.uid,
timestamp: this.timestamp,
image: remoteUri
})
.then(ref => {
res(ref);
})
.catch(error => {
rej(error);
});
});
}
uploadPhotoAsync = async (uri, filename) => {
return new Promise(async (res, rej) => {
const response = await fetch(uri);
const file = await response.blob();
let upload = firebase
.storage()
.ref(filename)
.put(file);
upload.on(
"state_changed",
snapshot => {},
err => {
rej(err);
},
async () => {
const url = await upload.snapshot.ref.getDownloadURL();
res(url);
}
);
});
}
createUser = async user => {
let remoteUri = null
try {
await firebase.auth().createUserWithEmailAndPassword(user.email, user.password)
//I tried to code it here with user.sendEmailVerification();
let db = this.firestore.collection("users").doc(this.uid)
db.set({
name: user.name,
email: user.email,
avatar: null
})
if (user.avatar) {
remoteUri = await this.uploadPhotoAsync(user.avatar, 'avatars/${this.uid}')
db.set({avatar: remoteUri}, {merge: true});
}
} catch (error) {
alert("Error: ", error);
}
};
get firestore() {
return firebase.firestore();
}
get uid() {
return (firebase.auth().currentUser || {}).uid;
}
get timestamp() {
return Date.now();
}
}
Fire.shared = new Fire();
export default Fire;
The createUserWithEmailAndPassword() method returns a Promise which resolves with a UserCredential AND (as the the doc indicates) "on successful creation of the user account, this user will also be signed in to your application."
So you can easily get the signed in user by using the user property of the UserCredential, and call the sendEmailVerification() method, as follows:
try {
const userCredential = await firebase.auth().createUserWithEmailAndPassword(user.email, user.password);
await userCredential.user.sendEmailVerification();
//In the next line, you should most probably use userCredential.user.uid as the ID of the Firestore document (instead of this.uid)
cont db = this.firestore.collection("users").doc(this.uid);
//...
} catch (...)
Note that you may pass an ActionCodeSettings object to the sendEmailVerification() method, see the doc.
I am trying to upload an image to Firebase storage. The problem is that since the user has not signed up yet, I don't have their uid.
I depend on onAuthStateChanged to get the user id and upload an image to their bucket, but so far it hasn't turned out well.
const { userObject } = useContext(Context) //trying to get the uid from here
onSubmit={(values, { setSubmitting }) => {
async function writeToFirebase() {
firebaseService.auth.createUserWithEmailAndPassword(values.email, values.password)
await firebaseService.firestore.collection('businessesPendingAdminApproval').add(values)
}
writeToFirebase()
async function sendToFirebaseImageBucket(photo, uid) {
const businessRef = await firebaseService.firestore.doc(
`businessesPendingAdminApproval/${uid}`,
)
firebaseService.storage
.ref()
.child('businesses')
.child(uid)
.child('avatar-image')
.put(photo)
.then(response => response.ref.getDownloadURL())
.then(photoURL => businessRef.update({ avatarImage: photoURL })) //try to update avatarImage
}
const uid = userObject.uid //undefined, can't get uid
sendToFirebaseImageBucket(values.avatarImage, uid) //uid gets passed as undefined
}}>
The way I am setting the userObject which is where I'm trying to get the uid from.
Setting the userObject eventually works but maybe not fast enought for me to be able to pass it to a function (as in the code above).
useEffect(() => {
firebaseService.auth.onAuthStateChanged(async function (userAuth) {
if (userAuth) {
const user = await firebaseService.createUserProfileDocument(userAuth)
setUserObject(user) //set userObject which has an uid field.
} else {
console.log('no one signed in')
}
})
}, [])
Just add your image to cloud storage right after you have logged in and was able to get uid. the following code can help you, it works for me as well. put the following code inside useEffect.
const unsubscribe = auth().onAuthStateChanged(user => {
if (user.uid){
const ref = storage.ref(`images/${user.uid}`);
const task = ref.putFile(_image, { contentType: 'image/jpeg' });
task.on(firebase.storage.TaskEvent.STATE_CHANGED, snap => {
setState({ type: 'cents', value: snap.bytesTransferred / snap.totalBytes * 100 });
}, err => { console.log('Error in help:persisAppState: ', err) }, async () => {
const image = await ref.getDownloadURL();
if (image) await db.collection("imagelinks").doc(user.id).set({ image });
});
}
});
this is my react native + firebase project and i have got 2 questions:
How do you suggest to pass the id from one CV ?
How do i fetch only one CV from firebase, cause if i try this it gives me this error:
TypeError: undefined is not an object (evaluating 'querySnapshot.docs.map')]
fetching all the documents from the collection is fine
getCv: () => {
const id = "eccc137b-88be-470d-a0b8-c90b58a6473a"
return firebase
.firestore()
.collection('cvs')
.doc(id)
.get()
.then(function(querySnapshot) {
let cvs = querySnapshot.docs.map(doc => doc.data())
// console.log(doc.data())
return cvs
})
.catch(function(error) {
console.log('Error getting documents: ', error)
})
}
This is my fetchCV method
fetchCvs = async () => {
try {
const cvs = await this.props.firebase.getCv()
//const cvs = await this.props.firebase.getCvs()
//console.log(cvs)
this.setState({ DATA: cvs, isRefreshing: false })
} catch (e) {
console.error(e)
}
}
This is how i add one CV
onSubmit = async () => {
try {
const cv = {
photo: this.state.image,
title: this.state.title,
description: this.state.description,
salary: this.state.salary,
createdAt: new Date().toISOString()
}
this.props.firebase.uploadCv(cv)
this.setState({
image: null,
title: '',
description: '',
salary: '',
createdAt: ''
})
} catch (e) {
console.error(e)
}
}
uploadCv: cv => {
const id = uuid.v4()
const uploadData = {
id: id,
cvPhoto: cv.photo,
cvTitle: cv.title,
cvDescription: cv.description,
cvSalary: cv.salary,
cvCreatedAt: cv.createdAt
}
return firebase
.firestore()
.collection('cvs')
.doc(id)
.set(uploadData)
},
and This is how i implemented the deleteCv method
onDelete = async () => {
const cvId = {
id: this.state.title
}
//this.props.firebase.deleteItem(cv);
const deleteId = this.props.firebase.deleteItem(cv);
console.log(deleteId)
}
I have different error, when I try similar code in nodejs, but I think its the same reason. In line:
let cvs = querySnapshot.docs.map(doc => doc.data())
As you are using get on DocumentReference querySnapshot is instance of DocumentSnapshot which does not have property docs. I think you should use querySnapshot.data() first and than manipulate on data returned.
Or maybe you wanted to use get on collection, not on document, and than you will get QuerySnapshot object and .doc array will be available.