Download multiple files from Firebase in ReactJS - javascript

I have several folders in firebase storage that contain images (each folder corresponds to an entity).https://i.stack.imgur.com/s9ZpX.png
When I want to download the url of each entity, what firebase does is bring me all the images that it has in the storage even if it does the forEach to each entity.
useEffect(() => {
setLoading(true);
Promise.all([getRooms(), getLocation()])
.then((values) => {
const roomsSnapshot = values[0];
const rooms = [];
const pUrl = [];
roomsSnapshot.forEach((doc) => {
const splitAddress = doc.data().address.split(", ");
formatedAddress.current = splitAddress[1] + " " + splitAddress[0];
//Download from storage//
storage
.ref(`${doc.data().roomPhotoId}/`)
.list()
.then(function (result) {
result.items.forEach((imageRef) => {
imageRef.getDownloadURL().then((url) => {
console.log(url)
roomItems.push(url)
});
});
setRoomsImagesCounter(roomsImagesCounter + 1);
// no photos scenario
if (result.items.length === 0) {
setLoading(false);
}
});
//pushing entity data//
rooms.push({
...doc.data(),
id: doc.id,
photosURL: roomItems,
shortAddress: formatedAddress.current,
coordsAddress: coords.current,
});
});
console.log(rooms);
setRooms(rooms);
// getPhotos(rooms);
setLoading(false);
})
.catch((err) => {
console.log("Error getting getting rooms or user role", err);
});
// eslint-disable-next-line react-hooks/exhaustive-deps }, []);
I don't know why firebase brings me all the images instead of bringing me the images separately for each entity.
I hope you have understood and I await your answers or any questions you have.
Thanks!
UPDATE
This is the console.log(rooms) https://i.stack.imgur.com/rQkoB.png

Can you try to create the storage ref like this:
// Create a reference under which you want to list
var listRef = storage.ref().child(`${doc.data().roomPhotoId}/`);
// Find all the prefixes and items.
listRef.listAll()
.then((res) => {
res.prefixes.forEach((folderRef) => {
// All the prefixes under listRef.
// You may call listAll() recursively on them.
});
res.items.forEach((itemRef) => {
// All the items under listRef.
});
}).catch((error) => {
// Uh-oh, an error occurred!
});
Make sure to use listAll.
Be aware that:
root.child('images').listAll() will return /images/uid as a prefix.
root.child('images/uid').listAll() will return the file as an item.
You can find more about it here.
Your code with grouping the downloadURLS:
useEffect(() => {
setLoading(true);
Promise.all([getRooms(), getLocation()])
.then((values) => {
const roomsSnapshot = values[0];
const rooms = [];
const pUrl = [];
roomsSnapshot.forEach((doc) => {
const splitAddress = doc.data().address.split(", ");
formatedAddress.current = splitAddress[1] + " " + splitAddress[0];
//Download from storage//
rooms[`${doc.data().roomPhotoId}`]=[]
storage
.ref(`${doc.data().roomPhotoId}/`)
.list()
.then(function (result) {
result.items.forEach((imageRef) => {
imageRef.getDownloadURL().then((url) => {
console.log(url)
roomItems.push(url)
});
});
setRoomsImagesCounter(roomsImagesCounter + 1);
// no photos scenario
if (result.items.length === 0) {
setLoading(false);
}
});
//pushing entity data//
rooms[`${doc.data().roomPhotoId}`].push({
...doc.data(),
id: doc.id,
photosURL: roomItems,
shortAddress: formatedAddress.current,
coordsAddress: coords.current,
});
});
console.log(rooms);
setRooms(rooms);
// getPhotos(rooms);
setLoading(false);
})
.catch((err) => {
console.log("Error getting getting rooms or user role", err);
});
// eslint-disable-next-line react-hooks/exhaustive-deps }, []);

Related

How to get image filename from Firebase Storage?

I am using the following:
const [allImages, setImages] = useState([]);
const getFromFirebase = () => {
//1.
let storageRef = storage.ref(user1);
//2.
storageRef.listAll().then(function (res) {
//3.
res.items.forEach((imageRef) => {
console.log(imageRef);
imageRef.getDownloadURL().then((url) => {
//4.
setImages((allImages) => [...allImages, url]);
});
});
})
.catch(function (error) {
console.log(error);
});
console.log(allImages);
};
and then displaying via:
<button onClick={getFromFirebase}>Show</button><br/><br/>
<div id="photos">
{allImages.map((image) => {
return (
<div key={image} className="image">
<img className="uploadedfile" src={image} alt="" />
<button className="buttondelete" onClick={() => deleteFromFirebase(image)}>
Delete
</button>
</div>
I realise this is returning the getDownloadURL for the image URL, but how do I also return the image filename?
To get the filename you can use getMetadata:
imageRef.getMetadata().then(metadata => {
// do something with metadata.name
});
You can use the 'getMetaData' method.
import { getStorage, ref, getMetadata } from "firebase/storage";
// Create a reference to the file whose metadata we want to retrieve
const storage = getStorage();
const forestRef = ref(storage, 'images/forest.jpg');
// Get metadata properties
getMetadata(forestRef)
.then((metadata) => {
// Metadata now contains the metadata for 'images/forest.jpg'
})
.catch((error) => {
// Uh-oh, an error occurred!
});
You can refer Firebase Docs - File Metadata for a better understanding
To get the file name and url or download link of the videos or files from the firebase storage you can use these two functions in react and javascript
// function to fetch videos/files from firebase storage
const fetchVideos = async () => {
const storageRef = firebase.storage().ref("storage folder name");
const videos = [];
await storageRef
.listAll()
.then(async function (result) {
result.items.forEach(async function (videoRef) {
// getting the name of the file
const videoName = videoRef.name;
//getting the url of the file -> calling another function for this
const videoUrl = await getVideoUrl(videoRef);
// creating the object with name and url
const videoObj = {
videoName,
videoUrl,
};
console.log("video obj", videoObj);
videos.push(videoObj);
});
})
.catch(function (error) {
// Handle any errors
return [];
});
}
// function to get download url
const getVideoUrl = (imageRef) => {
const videoLink = imageRef
.getDownloadURL()
.then(function (videoUrl) {
// console.log("videoUrl", videoUrl);
return videoUrl;
})
.catch(function (error) {
// Handle any errors
return "";
});
return videoLink;
};

Paginating firestore data with realtime additions on top of the result

I want to load my data into chunks of 10 in react. I am listening for document addition using onSnapshot() firestore method. I want to paginate data and at the same time allow the recent addition to come to the top. How to apply this in the code below -
db.collection('palettes').orderBy("createdAt").onSnapshot(snapshot => {
snapshot.docChanges().forEach(change => {
if (change.type === "added") {
setPalette( prevPalette => ([
{ id: change.doc.id, ...change.doc.data() },
...prevPalette
]))
setIsLoading(false)
}
})
})
I think you should save state of last document for pagination and realtime updates
Example
const getPalettes = (pageSize, lastDocument) => new Promise((resolve, reject) => {
let query = db.collection('palettes')
.orderBy("createdAt")
if(lastDocument) {
query = query.startAt(lastDocument)
}
query = query.limit(pageSize);
return query.onSnapshot(query => {
const docs = query.docs.map(pr => ({pr.id, ...pr.data()}))
resolve(docs);
});
})
let unsubscribe = getPalettes(10).then(newPalettes => {
setPalette(palettes => [...palettes, newPalettes]);
lastPalette = newPalettes[newPalettes.length -1];
setLastPalette(lastPalette);
unsubscribe();
})
unsubscribe = getPalettes(10, lastPalette).then(newPalettes => {
setPalette(palettes => [...palettes, newPalettes]);
lastPalette = newPalettes[newPalettes.length -1];
setLastPalette(lastPalette);
unsubscribe();
})
const listenForLatestPalettes = (lastDocument, callback) => {
return db.collection('palettes')
.orderBy("createdAt")
.startAt(lastDocument)
.onSnapshot(callback);
}
const callback = snapshot => {
for(let change of snapshot.docChanges()) {
if (change.type === "added") {
setPalette(palettes => {
const palette = { id: change.doc.id, ...change.doc.data() };
return [...palettes.filter(pal => pal.id !== id], palette];
})
}
}
}
unsubscribe = listenForLatestPalettes(lastDocument, callback);

Upload data to firebase storage and Firebase database from array in react native

I have an array that contains the local location of some images as shown below.
imagePath=
["file:///data/user/0/com.app.taamoutlet/cache/react-native-image-crop-picker/22536474236950.png","file:///data/user/0/com.app.taamoutlet/cache/react-native-image-crop-picker/22583225016770.png
"]
I have done uploading for a single image.
As per the code you have seen below I want to upload the images to firebase storage. I want to upload each image in the array to a single folder. And then collect the downloadable URL and each image and store that information under a single product as you see
() => {
const fs = RNFetchBlob.fs
const uid = "flyers/" + this.state.productUid;
const imageRef = firebase.storage().ref(uid).child(Math.random()+".jpg") //string "dp1.jpg"
let mime = 'image/jpg'
//------------------------------------------------
// coverting to base64
fs.readFile(this.state.imagePath, 'base64')
.then((data) => {
//console.log('data='+data);
return Blob.build(data, { type: `${mime};BASE64` })
})
.then((blob) => {
//uplaoding Image
uploadBlob = blob
return imageRef.put(blob, { contentType: mime })
})
.then(() => {
uploadBlob.close()
//getting url
return imageRef.getDownloadURL()
})
.then((url) => {
urls = url;
console.log('urls=' + urls)
//================================
try {
alert("Uploading Flyer" + this.state.title)
//-------------------------------------------
//----------Inserting Data to Database--------
usersTable = 'flyers/' + this.state.productUid,
console.log(usersTable)
firebase.database().ref(usersTable).set(
{
title: this.state.title,
description: this.state.description,
imageUrls: url,
storename: this.state.storename,
user: asyncValue,
longitude: this.state.longitude,
latitutde: this.state.latitutde
}
).then(
alert(this.state.title + " flyer sucessfully uploaded")
)
//--------------------------------------------
}
catch (error) {
this.setState({ loading: false })
this.setState({ disabled: false })
console.log(error.toString())
alert(error.toString())
}
//================================
})
}
As mentioned by Renaud, you have to use Promise.all. Please check out this example:
const promises = [fs.readFile(this.state.imagePath, 'base64'),...];
return Promise.all(promises).then((arrayOfResults) => {
const furtherPromises = [...]
return Promise.all(furtherPromises)
.then((uploadedFiles) => {
// action required
})
.catch((error) => {
// action required
});
}).catch((error) => {
// action required
});

error while fetching data from firebase push notification

I'm new to react native and I'm working on firebase push notification. I'm getting the notification, but the problem is I'm not able to fetch data and display it in flatlist. Notification are shown perfectly. But the problem is why I can't fetch data. I want this event data to be fteched in my notification list which i have added below image.
componentWillMount() {
const firebase = require("firebase");
if (!firebase.apps.length) {
firebase.initializeApp(db);
}
this.fetchEventsList()
}
// Fetch events list
fetchEventsList = () => {
Preference.set('userPhoneCheck', '+917508060520');
let phone = Preference.get('userPhoneCheck');
firebase.database().ref('/users').child(phone).child('/events').once('value').then((snapshot) => {
let data = snapshot.val();
let items = Object.values(data);
this.setState({
userEventsList: items
});
// this.deleteOldEvents();
this.initAllEventList();
}).then((data) => {}).catch((error) => {
//error callback
console.log('error ', error)
})
}
//fetch the friends list according to group name
initAllEventList = () => {
//let groupName='G1';
let eventId = '';
let userEventsList = [...this.state.userEventsList];
for (var i = 0; i < userEventsList.length; i++) {
eventId = userEventsList[i].eventId;
ToastAndroid.show("eventId>" + eventId, ToastAndroid.SHORT);
if (eventId != '') {
this.fetchFriendsList(eventId);
}
}
}
//app users remove that not in contacts
fetchFriendsList = (eventId) => {
let allEventsList = [...this.state.allEventsList];
firebase.database().ref('/events').child(eventId).once('value').then((snapshot) => {
let data = snapshot.val();
let items = Object.values(data);
allEventsList.push(items);
this.setState({
allEventsList: allEventsList
});
ToastAndroid.show("kk>" + allEventsList.length, ToastAndroid.SHORT);
}).then((data) => {
}).catch((error) => {
//error callback
console.log('error ', error)
})
}

React-native-fbsdk ShareDialog. How to share with prefilled message and photos content together?

I have react-native 0.44.0 and react-native-fbsdk 0.5.0. ShareDialog component work fine, but due to lack of docs explanation had been totally stuck. I have app with own API. I make API call fetch sharing template with photos array.
.then((responseData) => {
console.log("Facebook Share Api Test")
console.log(responseData)
// After receiving result checking Platform
// If this is iOS we should let our result image links be fetched to encode it in Base64.
if(Platform.OS !== 'android'){
console.log("Not Andro!d!")
let imgUrl
let sharePhotoContent
let iteratePhotos = function (data) {
var photoInfo = [];
var ready = Promise.resolve(null)
data.forEach(function (value, i) {
let iconURL = API.SERVER_URL + API.SERVICE_PORT + API.HEAD_ICON_RES_URL + value.photo_id + 'S'
ready = ready.then(function () {
return RNFetchBlob
.fetch('GET', iconURL)
.then(res => res.data)
.then(resData => {
imgUrl = 'data:image/jpeg;base64,' + resData
console.log(imgUrl)
return imgUrl
})
.then(img => {
console.log(img)
let res = {
imageUrl: img,
userGenerated: true,
caption: value.comment
}
return res
})
.catch(err => {
console.log(err)
})
}).then(function (resData) {
photoInfo[i] = resData;
});
});
return ready.then(function () { return photoInfo; });
}
iteratePhotos(responseData.photos).then((res) => {
console.log('res', res)
if(res.length > 0){
sharePhotoContent = {
contentType: 'photo',
contentDescription: 'Wow, check out this great site!',
photos: res
}
} else {
sharePhotoContent = {
contentType: 'link',
contentUrl: 'some url',
message: responseData.message
}
}
ShareDialog.canShow(sharePhotoContent)
.then((canShow) => {
if (canShow) {
return ShareDialog.show(sharePhotoContent);
}
})
.then((result) => {
this.setState({isshowIndicator: false})
if(!result.isCancelled){
this.setState({isFacebookShared: true})
setTimeout(() => alert("Success!"), 100)
}
})
.catch(error => {
this.setState({isshowIndicator: false})
console.log(error)
setTimeout(() => alert('Share fail with error: ' + error), 100)
}
)
})
} else {
let photoInfo = responseData.photos.map(value => {
return {
imageUrl: API.SERVER_URL + API.SERVICE_PORT + API.HEAD_ICON_RES_URL + value.photo_id + 'S',
...value
}
})
console.log(photoInfo, "It IS ANDROID")
if(responseData.photos.length > 0){
var sharePhotoContent = {
contentType: 'photo',
photos: photoInfo
}
} else {
var sharePhotoContent = {
contentType: 'link',
contentUrl: 'some url',
message: responseData.message
}
}
ShareDialog.canShow(sharePhotoContent)
.then((canShow) => {
if (canShow) {
return ShareDialog.show(sharePhotoContent);
}
})
.then((result) => {
this.setState({isshowIndicator: false})
if(!result.isCancelled){
this.setState({isFacebookShared: true})
setTimeout(() => alert("Success!"), 100)
}
})
.catch(error => {
this.setState({isshowIndicator: false})
setTimeout(() => alert('Share fail with error: ' + error), 100)
})
}
})
When I tap share, sharedialog opens and photos that I want are pasted but message line waits to be filled
But I need into ShareDialog opened:
Photos needed to be attached;
Message to be prefilled according that one I received from my API.
Is this possible? Please help this is prerelease feature needed to be implemented very fast and I havent any idea how((
Attaching screenshots that describes 1. what is going now here? 2. What i want to do.
some social network like facebook does not support pre-filling the message for users as seen in their Policy: https://developers.facebook.com/policy/#socialplugins

Categories

Resources