React FirebaseError DocumentReference.set() - javascript

Please can someone help me. I think the way I am handling the promise is wrong and really need someone to help me.
I am letting the user upload a picture . When the user presses submit the image is uploaded to firebase-storage. However I don't think I am handling the wait period to upload the image and setting the data to firebase-database. What I mean is when I press submit I get the error FireBase Function DocumentReference.set() called with invalid data Because it is setting the image to undefined
However if I wait a couple of seconds I get the console.log("File available at" + downloadUrl) which means the image was uploaded.
Basically I just need to add a waiting period to my code between when the image is uploaded and when to send the data to the firebase-database
This is my code any help will be much appreciated !!!!!
const uploadImage = async (uri, imageName) => {
const response = await fetch(uri)
const blob = await response.blob()
var ref = firebase.storage().ref().child(`images/${imageName}`)
ref.put(blob)
.then(()=>{
// Upload completed successfully, now we can get the download URL
var storageRef = firebase.storage().ref('images/' + imageName)
storageRef.getDownloadURL().then((downloadUrl)=>{
console.log(`File available at ${downloadUrl}`)
setDownload(JSON.stringify(downloadUrl))
})
})
.catch(error => {
setRefreshing(false) // false isRefreshing flag for disable pull to refresh
Alert.alert("An error occured", "Please try again later")
});
}
const handleSubmit = useCallback(() => {
if (postImage !== undefined) {
const fileExtention = postImage[0].split('.').pop()
const fileName = `${uniqid}.${fileExtention}`
uploadImage(postImage, fileName)
firebase.firestore()
.collection('Posts')
.doc(uniqid)
.set({
id: currentUser,
name: postName[0],
image: downloadImage,
})
}
})
Thank you in advance for all your help!!!!!

To use await inside useCallback you can try to wrap the code inside it in a self invoking function like this:
const handleSubmit = useCallback(() => {
(async () =>{ if (postImage !== undefined) {
const fileExtention = postImage[0].split('.').pop()
const fileName = `${uniqid}.${fileExtention}`
uploadImage(postImage, fileName)
await firebase.firestore()
.collection('Posts')
.doc(uniqid)
.set({
id: currentUser,
name: postName[0],
image: downloadImage,
})
}
})()
})

Related

Downloading an mp3 file from S3 and manipulating it results in bad file

I did a script that downloads a MP3 file from my S3 bucket and then manipulates in before download (Adding ID3 Tags).
It's working and the tags are injected properly, but the files corrupts as it seems and unplayable.
I still can see my tags trough MP3tag so it has data in it, but no audio is playing trough the file.
Heres my code,
Trying to figure it what went wrong
const downloadFileWithID3 = async (filename, downloadName, injectedEmail) => {
try {
const data = await s3Client.send(
new GetObjectCommand({
Bucket: "BUCKETNAME",
Key: filename,
})
);
const fileStream = streamSaver.createWriteStream(downloadName);
const writer = fileStream.getWriter();
const reader = data.Body.getReader();
const pump = () =>
reader.read().then(({ value, done }) => {
if (done) writer.close();
else {
const arrayBuffer = value;
const writerID3 = new browserId3Writer(arrayBuffer);
const titleAndArtist = downloadName.split("-");
const [artist, title] = titleAndArtist;
writerID3.setFrame("TIT2", title.slice(0, -4));
writerID3.setFrame("TPE1", [artist]);
writerID3.setFrame("TCOM", [injectedEmail]);
writerID3.addTag();
let taggedFile = new Uint8Array(writerID3.arrayBuffer);
writer.write(taggedFile).then(pump);
}
});
await pump()
.then(() => console.log("Closed the stream, Done writing"))
.catch((err) => console.log(err));
} catch (err) {
console.log(err);
}
};
Hope you can help me solve this wierd bug,
Thanks in advance!
Ok so i've figured it out, instead of using chunks of the stream itself i've used getSignedUrl from the s3 bucket it works.
Thanks everyone for trying to help out!

Upload image in firebase expo react native

i have an issue, i trying solve a several hours but white not success, my issue consists in create an upload to firestorage in firebase and show your respective uri in a variable i called image, but i don't know what wrong in my code, why he save my image like this
and don't show you uri in my variable
bellow is my code
This is a create user i set here in imageUri a uploadImage who i called in my variable image
const createUser = async () => {
const imageUri = uploadImage()
await addDoc(
usersCollectionRef,
{
name: name || null,
cep: cep || null,
logradouro: logradouro || null,
numero: numero || null,
bairro: bairro || null,
uf: uf || null,
image: imageUri || null,
},
navigation.navigate("HomeScreen")
);
};
here is a code i pick image and my upload function to set a image in firestore (i follow the docs)
const pickImage = async () => {
let result = await ImagePicker.launchImageLibraryAsync({
mediaTypes: ImagePicker.MediaTypeOptions.All,
allowsEditing: true,
aspect: [4, 3],
quality: 1,
});
console.log(result);
if (!result.cancelled) {
setImage(result);
}
};
const uploadImage = () => {
const storageRef = ref(storage, `images/${image.name}`);
uploadBytes(storageRef, image).then((snapshot) => {
console.log(snapshot);
});
};
i really need some help for solve this issue i appreciate every tryed of help, any more questions about my code please comment if need i send my repository.
There are some mistakes in your code.
First, the ImagePicker returns an object like that (docs) :
{
"cancelled":false,
"height":1611,
"width":2148,
"uri":"file:///data/user/0/host.exp.exponent/cache/cropped1814158652.jpg"
}
There is no "name" field, that's why you see that undefined, because you access ${image.name}.
Second, as far as ImagePicker returns an object, you can't use it on uploadBytes pretending it is a Blob or similar. You should create a Blob from the uri image:
const response = await fetch(imageUri)
const blobFile = await response.blob()
Definetely, this is a function I suggest you to use for uploading an image on firebase storage
export async function uploadImage(imageUri) {
try {
const response = await fetch(imageUri)
const blobFile = await response.blob()
const reference = ref(storage, "your_name.jpg")
const result = await uploadBytes(reference, blobFile)
const url = await getDownloadURL(result.ref)
return url
} catch (err) {
return Promise.reject(err)
}
}

react firebase image post 400 error on uploading

I am trying to upload an image to a cloud storage and received an post 400 error
The file is in initialize in another component.
Thanks for help
const projectStorage = getStorage();
useEffect(() => {
const storageRef = ref(projectStorage, file.name);
uploadBytes(storageRef, file).then((snap) => {
let percentage = (snap.bytesTransferred / snap.totalBytes) * 100;
setProgress(percentage);
console.log('File Uploaded');
}, (err) => {
setError(err);
}, async () => {
//this url doesnt change the setstate url becuase it is in seperate score
const url = await storageRef.getDownloadURL();
setUrl(url);
})
}, [file]);
I created a new project on firebase and then change the permissions on the storage rules and its works.

Why does app crash when page starts to load due to useEffect hook with firebase upload in React Native

I'm trying to upload a photo to firebase storage in my post screen/page. I thought I was supposed to use an useEffect hook when calling api's so I did that and put in a dependency array for the two states that had to change for rerender. When I delete the useEffect and just have the uploadImage function and then I run the uploadImage function in the imagePicker function after confirming the event wasn't cancelled, it works but I can't seem to get the folder/imagename right. I can only call it something and then it continues to overwrite.
the workflow should be render the two buttons on screen, when the photo picker button is pressed, run the chooseFromLibrary function which will set the state for imageFilename and imageSelected(uri). That should tell the dependency array to run the effect of calling the uploadImage function with the variables for imageSelected and imageFilename. I want the ref in the uploadImage function to create/put in the folder for user.username (this is from context) and then the image name to be be imageFilename but it doesn't seem to be working.
What am I doing wrong?
const [user] = useContext(UserContext);
const [imageSelected, setImageSelected] = useState("");
const [imageFilename, setImageFilename] = useState("");
useEffect(() => {
uploadImage(imageSelected, imageFilename)
.then(() => {
Alert.alert("Success");
})
.catch((error) => {
Alert.alert(error);
});
}, [imageFilename, imageSelected]);
const uploadImage = async (uri, name) => {
const response = await fetch(uri);
const blob = await response.blob();
var ref = firebase
.storage()
.ref()
.child(`${user.username}` + name);
return ref.put(blob);
};
const chooseFromLibrary = async () => {
let result = await ImagePicker.launchImageLibraryAsync({
mediaTypes: ImagePicker.MediaTypeOptions.All,
allowsEditing: true,
aspect: [4, 3],
quality: 1,
});
if (!result.cancelled) {
let fileArray = result.uri.split("/");
let name = fileArray.pop();
setImageFilename(name);
setImageSelected(result.uri);
}
}
I had to run an if statement returning the effect if an image hadn't been selected yet.
if (!imageSelected) {
return;
}

Expand my image upload from 1 to 5 photos; map/foreach?

I am creating an app in which you can upload a photo, with some other data, to Firebase. The uploading part worked perfect with one picture. However I have now added a multiple-image picture (select 1 to 5 pictures) and would like my image upload function to upload the 5 pictures in stead of the 1.
The image upload works with 1 image provided, so how can I rearrange my code to upload the x-amount of photos in the array?
The pictures are added in the photos array with the following data (output shown below is a console.log from the images fetched);
Array [
Object {
"exists": true,
"file": "ph://8905951D-1D94-483A-8864-BBFDC4FAD202/L0/001",
"isDirectory": false,
"md5": "f9ebcab5aa0706847235887c1a7e4740",
"modificationTime": 1574493667.505371,
"size": 104533,
"uri": "ph://8905951D-1D94-483A-8864-BBFDC4FAD202/L0/001",
},
With this didFocus I check if the fethedImages param is set and set the photos array to the fetched images (So all the data that is shown above)
const didFocusSubscription = props.navigation.addListener(
'didFocus', () => {
let fetchedImages = props.navigation.getParam('fetchedImages')
console.log(fetchedImages)
setPhotos(fetchedImages)
setImageValid(true)
calculateImageDimensions()
}
);
When I save the page and start dispatching the data I run the following command the uploadImage function is ran and returns an uploadurl, this is then saved later on in the dispatch function to the Firebase Database to be fetched later;
uploadurl = await uploadImageAsync(photos)
SO the uploadImageAsync starts with the photos array forwarded. How can I make sure the function below is started for every photo.uri in the array? Can I use .map of for each for this, and in what context should I be using this?
Also I am not quite sure how I can send back an array of URLs to be saved together with the rest of the information.
async function uploadImageAsync(photos) {
console.log('uploadImage is gestart')
// Why are we using XMLHttpRequest? See:
// https://github.com/expo/expo/issues/2402#issuecomment-443726662
const blob = await new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest();
xhr.onload = function () {
resolve(xhr.response);
};
xhr.onerror = function (e) {
console.log(e);
reject(new TypeError('Network request failed'));
};
xhr.responseType = 'blob';
xhr.open('GET', photos, true);
xhr.send(null);
});
const ref = firebase
.storage()
.ref()
.child(uuid.v4());
const snapshot = await ref.put(blob);
// We're done with the blob, close and release it
blob.close();
return await snapshot.ref.getDownloadURL();
}
==============edited because of progress with uploading====================
Once again I am a little bit further. However the image upload function is now running, and because of is being multiple images I would like to await the response of all the images before continuing.
try {
uploadurl = await uploadImageAsync()
address = await getAddress(selectedLocation)
console.log(uploadurl)
if (!uploadurl.lenght) {
Alert.alert('Upload error', 'Something went wrong uploading the photo, plase try again', [
{ text: 'Okay' }
]);
return;
}
dispatch(
At this moment when I start the uploadImageAsync function. With he help of console.log I see it uploading the images, they also show up online. But while the pictures are uploading the upload url already returns with 0 and shows the Alert and stops the function.
uploadImageAsync = async () => {
const provider = firebase.database().ref(`providers/${uid}`);
let imagesArray = [];
try {
await photos.map(img => {
let file = img.data;
const path = "Img_" + uuid.v4();
const ref = firebase
.storage()
.ref(`/${uid}/${path}`);
ref.putString(file).then(() => {
ref
.getDownloadURL()
.then(images => {
imagesArray.push({
uri: images
});
console.log("Out-imgArray", imagesArray);
})
return imagesArray <== this return imagesArray is fired to early and starts the rest of my upload function.
} catch (e) {
console.error(e);
}
};
So a Discord chat pointed me in the way of a promise.all function for this to work. I tried that, but opened another stack overflow topic for getting this to work.
await response of image upload before continue function
The solution for my image upload function is in the topic above;
uploadImages = () => {
const provider = firebase.database().ref(`providers/${uid}`);
// CHANGED: removed 'let imagesArray = [];', no longer needed
return Promise.all(photos) // CHANGED: return the promise chain
.then(photoarray => {
console.log('all responses are resolved successfully');
// take each photo, upload it and then return it's download URL
return Promise.all(photoarray.map((photo) => { // CHANGED: used Promise.all(someArray.map(...)) idiom
let file = photo.data;
const path = "Img_" + uuid.v4();
const storageRef = firebase // CHANGED: renamed 'ref' to 'storageRef'
.storage()
.ref(`/${uid}/${path}`);
let metadata = {
contentType: 'image/jpeg',
};
// upload current photo and get it's download URL
return storageRef.putString(file, 'base64', metadata) // CHANGED: return the promise chain
.then(() => {
console.log(`${path} was uploaded successfully.`);
return storageRef.getDownloadURL() // CHANGED: return the promise chain
.then(fileUrl => ({uri: fileUrl}));
});
}));
})
.then((imagesArray) => { // These lines can
console.log("Out-imgArray: ", imagesArray) // safely be removed.
return imagesArray; // They are just
}) // for logging.
.catch((err) => {
console.error(err);
});
};

Categories

Resources