Retrieving/Handling Image URL From Firestore - React Native - firebase

I am new to React Native and Firebase (Firestore) and I'm developing an app where I have to retrieve posts to my feed.
I can retrieve all data I need, but I don't know how to display the image in the frontend. The post document has a field image which is saved as an URL and stored in the Firebase storage.
Does anyone know how can I get the image displayed? I am using a to sort the data.
This is my retrieveData() and it prints the correct URL:
retrieveData() {
var that = this;
let postRef = firebase
.firestore()
.collection("posts")
.orderBy("timestamp", "desc")
.limit(10);
let allPosts = postRef
.get()
.then((snapshot) => {
snapshot.forEach((doc) => {
var post = that.state.posts;
const data = (doc.id, "=>", doc.data());
that.setState({ posts: post });
console.log(data.image);
post.push({
id: data.id,
title: data.title,
description: data.description,
expireDate: data.expireDate,
timestamp: data.timestamp,
image: data.image,
});
});
})
.catch((err) => {
console.log("Error getting documents", err);
});
}
And this is how I am calling the image in the flatlist:
<Image
source={post.image}
style={styles.postImage}
/>
Can anyone help me with that?
Thanks in advance.

Can you share the image url ? And preferred way is to store image on the firebase storage and get the downloadUrl then store that url in the firestore document.
fileref.put(file)
.then(snapshot => {
return snapshot.ref.getDownloadURL(); // Will return a promise with the download
link
})
.then(downloadURL => {
console.log(`Successfully uploaded file and got download link - ${downloadURL}`);
return downloadURL;
})
.catch(error => {
// Use to signal error if something goes wrong.
console.log(`Failed to upload file and get link - ${error}`);
});

Related

Registration token(s) provided to sendToDevice() must be a non-empty string or a non-empty array. (Firebase cloud functions)

I am making a chat application where I am trying to send push notifications to when one user sends a message to the other user.
I am using firebase cloud functions with JavaScript and in the firebase functions log I can see that it's able to get the user who sends the message and the user who receives the message. But for some reason It's showing me that the token is empty.
Even though I have a token and I am able to print it in the log(The screenshot of firebase cloud functions log where you can see that token is being printed and I have partially marked over it).
For more reference I am also attaching the screenshot of my two collections in firebase -
All the users collection where the push token is being saved.(The structure is users>uid>{user_info}).
The chat collection screenshot where you can see the structure of chats.(The structure here is chatroom>chatid>chats>{chat_documents}).
My index.js file in functions folder for firebase is below-
const functions = require('firebase-functions')
const admin = require('firebase-admin')
admin.initializeApp()
exports.sendNotification = functions.firestore
.document('chatroom/{chatId}/chats/{message}')
.onCreate((snap) => {
console.log('----------------start function--------------------')
const doc = snap.data()
console.log(doc)
const idFrom = doc.idFrom
const idTo = doc.idTo
const contentMessage = doc.mesaage
console.log(`Starting to push token`)
// Get push token user to (receive)
admin
.firestore()
.collection('users')
.where('uid', '==', idTo)
.get()
.then(querySnapshot => {
querySnapshot.forEach(userTo => {
console.log(`Found user to: ${userTo.data().name}`)
console.log(`Found user to: ${userTo.data().pushtoken}`)
try {
// Get info of the user who is sending the message
admin
.firestore()
.collection('users')
.where('uid', '==', idFrom)
.get()
.then(querySnapshot2 => {
querySnapshot2.forEach(userFrom => {
console.log(`Found user from: ${userFrom.data().name}`)
const payload = {
notification: {
title: `"${userFrom.data().name}"`,
body: contentMessage,
badge: '1',
sound: 'default'
}
}
// Lets push to the target device
admin
.messaging()
.sendToDevice(payload,userTo.data().pushtoken)
.then(response => {
console.log('Successfully sent message:', response)
})
.catch(error => {
console.log('Error sending message:', error)
})
})
})
} catch(e){
console.log('Can not find pushToken target user')
}
})
})
return null
})
What might be the problem here as I am not able to figure it out? Your help would be really appreciated. Also kindly let me know if you want any more information regarding the same.

How to get downloadUrl after uploadString in firebase v9?

There is no documentation on firebase docs as to how to get UploadTask after uploadString is done in firebase v9.
const message4 = 'data:text/plain;base64,5b6p5Y+344GX44G+44GX44Gf77yB44GK44KB44Gn44Go44GG77yB';
uploadString(storageRef, message4, 'data_url').then((snapshot) => {
console.log('Uploaded a data_url string!');
});
or how can I get the downloadUrl after the uploadString is completed?
I got the answer.
uploadString(storageRef, uri, 'data_url').then((snapshot) => {
getDownloadURL(snapshot.ref).then(async (url) => {
// Url
})
})

How to get values of object in firestore

Im trying to implement code in Firestore which will get the values of a specific object inside a doc in firestore, unfortunently i couldnt find the way to do it.
This is my query code:
useEffect(() => {
firebase
.firestore()
.collection("users")
.doc(uid)
.collection("confirmed-appointments")
.get()
.then((snapshot) => {
let service = [];
snapshot.forEach((doc) => {
service.push(doc.data());
});
console.log("Services: ", service[0].servicesSelected); //Checking if i can get the serviceSelected Obj
});
}, []);
This is a image of the firestore:
What i want is to get the data of the Red circle object, move it to a local object in the code and then present its data inside the app.
any suggestions?
As far as I can tell from the above images, document 10 contains an array, which means that you will need to index into that array in order to get its elements. You can leverage the following code to fetch the servicesSelected object fields:
import firestore from '#react-native-firebase/firestore';
firestore()
.collection('users')
.doc(uid)
.collection("confirmed-appointments")
.get()
.then(querySnapshot => {
//let service = [];
console.log('Total confirmed appointments: ', querySnapshot.size);
querySnapshot.forEach(documentSnapshot => {
console.log("Services Selected: ", documentSnapshot.data().YOUR_ARRAY[1].servicesSelected);
//service.push(documentSnapshot.data());
//console.log('Appointment ID: ', documentSnapshot.id, documentSnapshot.data());
});
});
Note that I assume that servicesSelected lives at index 1 of YOUR_ARRAY (replace YOUR_ARRAY with its actual name).
You can refer to the officially recommended documentation for more details about React Native for Firebase.

google places api returns a string, how do I parse to JSON object?

In a small webshop that I am trying to setup, I need to update the opening hours in the background with firebase functions and google place details when a user creates a shoppingcart.
I can succesfully sent a GET request with POSTMAN to retrieve the opening hours of a shop using the following instructions:
https://developers.google.com/places/web-service/details
But I cannot access the response from the GET request as I usually do with JSON responses.
I tried also:response.result.opening_hours.json()
Can someone tell me what I am doing wrong?
export const mapGooglePlaces = functions.database
.ref('/shopping-carts/{shoppingCartId}/shippingManner')
.onWrite(event => {
const shippingManner = event.data.val();
const optionsAPI = {
method: 'GET',
uri: 'https://maps.googleapis.com/maps/api/place/details/json?placeid=ChIJN1t_tDeuEmsRUsoyG83frY4&key=YOUR_API_KEY',
};
return request(optionsAPI)
.then(response => {
const openingHours = response.result.opening_hours;
console.log(openingHours);
return;
})
.catch(function (err) {
console.log(err);
});
});
The response is not a JSON object. It is JSON formatted text and must be parsed to create an object. Modify the code as follows:
return request(optionsAPI)
.then(response => {
const responseObject = JSON.parse(response);
const openingHours = responseObject.result.opening_hours;
console.log(openingHours);
return;
})
.catch(function (err) {
console.log(err);
});
Also, before using the opening_hours or any other property of result, you should test responseObject.status === 'OK' to confirm that a place was found and at least one result was returned.

Uploading Image to Firebase in React Native

I have two image paths in my component state
I try to upload one of the images inside of a function but get an error:
Firebase Storage: Invalid argument in 'put' at index 0: Expected Blob or file
and my function
submitImages = () => {
// Upload images to Firebase storage
let user = firebaseAuth.currentUser;
let imagesRef = storageRef.child('productImages/' + user.uid);
imagesRef.put(this.state.imageFront).then(snapshot => {
console.log('Uploaded ' + this.state.imageFront);
});
}
What should I be doing instead to get these images up to Firebase. Thanks!
What the error says is that you need to use a blob. You can use react-native-fetch-blob: https://github.com/wkh237/react-native-fetch-blob
Check out this example: https://github.com/dailydrip/react-native-firebase-storage/blob/master/src/App.js#L43-L69
I am posting my code since this was a bit frustrating for me:
To upload images to firebase.storage you need to upload the images as Blobs. If you don't know what Blobs are, don't worry: BLOB stands for Binary Large OBject.
Step 1.
npm install --save react-native-fetch-blob
Step 2.
// copy and paste this code where you will handle the file upload
import RNFetchBlob from 'react-native-fetch-blob'
const Blob = RNFetchBlob.polyfill.Blob;
const fs = RNFetchBlob.fs;
window.XMLHttpRequest = RNFetchBlob.polyfill.XMLHttpRequest;
window.Blob = Blob;
Step 3.
// The uploadImage function that you are going to use:
function uploadImage(uri, mime = 'image/jpeg', name) {
return new Promise((resolve, reject) => {
let imgUri = uri; let uploadBlob = null;
const uploadUri = Platform.OS === 'ios' ? imgUri.replace('file://', '') : imgUri;
const { currentUser } = firebase.auth();
const imageRef = firebase.storage().ref(`/jobs/${currentUser.uid}`)
fs.readFile(uploadUri, 'base64')
.then(data => {
return Blob.build(data, { type: `${mime};BASE64` });
})
.then(blob => {
uploadBlob = blob;
return imageRef.put(blob, { contentType: mime, name: name });
})
.then(() => {
uploadBlob.close()
return imageRef.getDownloadURL();
})
.then(url => {
resolve(url);
})
.catch(error => {
reject(error)
})
})
}
So how do you call this function?
Pass the URI of the image as the first argument. In my case img1, img2, img3 where variables that pointed to the URIs of the images, that I wanted to upload which were on my phone. They looked something like '/Phone/Pics/imageToUpload.jpeg', etc.
As the second argument you can pass 'image/jpeg' and the last argument is the name that you want to give the image. Chose the name that you like.
But what if I have several images and want to upload them and want to handle the upload correctly. What if one upload succeeds and the other does not?
Do this then:
let imgPromises = [];
imgPromises.push(uploadImage(img1, 'image/jpeg', 'imageOne'));
imgPromises.push(uploadImage(img2, 'image/jpeg', 'imageTwo'));
imgPromises.push(uploadImage(img3, 'image/jpeg', 'imageOne'));
Promise.all(imgPromises).then(urls => {
// ALL IMAGES SUCCEEDED and you will get an array of URIS that you can save to your database for later use!
}).catch(error => {
// One OR many images failed the upload. Give feedback to someone.
})
You can use react-native-firebase to upload image to storge https://rnfirebase.io/
const storage = firebase.storage();
const sessionId = new Date().getTime();
const imageRef = storage.ref('images').child(`${sessionId}`);
return imageRef.putFile(uri);
So far this is the best method I found to upload a file/image to a Firebase Storage with React Native. This method does not use any third party libraries except for the Expo SDK.
Get the File URI of the image to upload. To do this we will need to use Expo ImagePicker. The best place to include this code block is on to a button with an onPress handler.
ImagePicker.launchImageLibraryAsync({
mediaTypes: "Images"
}).then((result)=>{
if (!result.cancelled) {
// User picked an image
const {height, width, type, uri} = result;
return uriToBlob(uri); // will follow later
}
})
Generate a BLOB from the image URI. There are a lot of third party libraries to help do this. But if you don't want to install a library, then you can use XMLHttpRequest. The React Native docs recommends we use the Fetch API, but right now we can't use it because it will throw an error that we can only fetch https:// urls, but our URI is a file://. There is a way to get pass this, but using XMLHttpRequest will make things a lot simpler.
uriToBlob = (uri) => {
return new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest();
xhr.onload = function() {
// return the blob
resolve(xhr.response);
};
xhr.onerror = function() {
// something went wrong
reject(new Error('uriToBlob failed'));
};
// this helps us get a blob
xhr.responseType = 'blob';
xhr.open('GET', uri, true);
xhr.send(null);
});
}
We have our BLOB, let's upload it to Firebase. This part is pretty straightforward as explained in the Firebase Docs.
uploadToFirebase = (blob) => {
return new Promise((resolve, reject)=>{
var storageRef = firebase.storage().ref();
storageRef.child('uploads/photo.jpg').put(blob, {
contentType: 'image/jpeg'
}).then((snapshot)=>{
blob.close(); // let's free up the blob
resolve(snapshot);
}).catch((error)=>{
reject(error);
});
});
}
That's it, you can now upload a file to Firebase Storage. The key part to this is getting a File URI and converting it to a BLOB. You can read more about this method here.
For some time I used the Firebase JS SDK with React Native. Using this library, as referred in this thread you need to use a library like rn-fetch-blob (react-native-fetch-blob is not maintained anymore) in order to provide a blob to Firebase Storage put() method.
Recently I started using React Native Firebase. As they say in their website "Using the native Firebase SDKs with React Native Firebase allows you to consume device SDKs which don't exist on the Firebase JS SDK".
Using React-Native-Firebase you don't need any extra library to upload images to Firebase Storage, and your code gets much cleaner:
export const uploadImage = (path, mime = 'application/octet-stream') => {
return new Promise((resolve, reject) => {
const imageRef = firebase.storage().ref('images').child('filename.jpg');
return imageRef.put(path, { contentType: mime })
.then(() => {
return imageRef.getDownloadURL();
})
.then(url => {
resolve(url);
})
.catch(error => {
reject(error);
console.log('Error uploading image: ', error);
});
});
};
if you don’t mind using cloudinary, I show how to upload and then get the uploaded url to save to firebase
https://medium.com/#ifeoluwaking24/how-to-upload-an-image-in-expo-react-native-to-firebase-using-cloudinary-24aac981c87
Also you can try it snack but make sure you add your cloud_name and upload_preset
https://snack.expo.io/#ifeking/upload-to-cloudinary

Resources