Unsupported field value: undefined,Function addDoc() called with invalid data - reactjs

so here I want to store the array of image URL from the firebase storage in firestore. I am getting an error of undefined as my ImageUrl is undefined. please help me to solve this.The images are stored on cloud storage.
The code below shows my onSubmit function where a copy of the formdata is created.I have tried with and without '.then' and both gives me this error
const onSubmit = async (e) => {
e.preventDefault();
setLoading(true);
if (discountedPrice >= regularPrice) {
setLoading(false);
toast.error("Discounted price should be less than regular price");
}
console.log(formData);
if (images.length > 6) {
setLoading(false);
toast.error("Max of 6 images");
}
let geolocation = {};
let location;
// if (address != null) {
try {
const response = await fetch(
`https://maps.googleapis.com/maps/api/geocode/json?address=${address}&key=${process.env.React_App_YOUR_GOOGLE_API_KEY}`
);
const data = await response.json();
console.log(data);
geolocation.lat = data.results[0].geometry.location.lat;
geolocation.lng = data.results[0].geometry.location.lng;
console.log(
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
);
console.log(geolocation.lat);
console.log(data.status);
location =
data.status == "ZERO_RESULTS"
? undefined
: data.results[0].formatted_address;
if (location == undefined || location.includes("undefined")) {
setLoading(false);
toast.error("area does not match");
}
} catch (error) {
toast.error("area does not match");
}
//s store image to firebase
const storeImage = async (image) => {
return new Promise((resolve, reject) => {
const storage = getStorage();
const fileName = `${auth.currentUser.uid}-${image.name}-${uuidv4()}`;
const storageRef = ref(storage, "images/" + fileName);
const uploadTask = uploadBytesResumable(storageRef, image);
uploadTask.on(
"state_changed",
(snapshot) => {
// Observe state change events such as progress, pause, and resume
// Get task progress, including the number of bytes uploaded and the total number of bytes to be uploaded
const progress =
(snapshot.bytesTransferred / snapshot.totalBytes) * 100;
console.log("Upload is " + progress + "% done");
switch (snapshot.state) {
case "paused":
console.log("Upload is paused");
break;
case "running":
console.log("Upload is running");
break;
}
},
(error) => {
// Handle unsuccessful uploads
reject(error);
},
() => {
// Handle successful uploads on complete
// For instance, get the download URL: https://firebasestorage.googleapis.com/...
getDownloadURL(uploadTask.snapshot.ref).then((downloadURL) => {
resolve(downloadURL);
console.log("File available at", downloadURL);
});
}
);
});
};
const imageUrls = await Promise.all(
[...images].map((image) => {
storeImage(image);
})
)
.then(() => {
console.log("urlready " + imageUrls);
uploadingListings(imageUrls);
})
.catch((error) => {
console.log(error);
setLoading(false);
toast.error("Couldn't upload image");
return;
});
const uploadingListings = async (imageUrls) => {
console.log(imageUrls);
const formDataCopy = {
...formData,
imageUrls,
geolocation,
timestamp: serverTimestamp(),
};
formDataCopy.location = address;
delete formDataCopy.address;
delete formDataCopy.images;
!formDataCopy.offer && delete formDataCopy.discountedPrice;
console.log("this is" + formDataCopy);
const docRef = await addDoc(
collection(db, "listings"),
formDataCopy
setLoading(false);
toast.success("Created a listing");
navigate(`/category/${formDataCopy.type}/${docRef.id}`);
});
};

This is how I fixed it.
Realized I wasn't returning the url to imageUrls.
And also found it not helpful using the .then with imageUrls.
const imageUrls = await Promise.all(
[...images].map((image) => {
return storeImage(image);
})
)
// .then(() => {
// console.log("urlready " + imageUrls);
// return uploadingListings(imageUrls);
// })
.catch((error) => {
console.log(error);
setLoading(false);
toast.error("Couldn't upload listing");
return;
});
console.log("urlready " + imageUrls);
const formDataCopy = {
...formData,
imageUrls,
geolocation,
timestamp: serverTimestamp(),
};
console.log(formDataCopy);
formDataCopy.location = address;
delete formDataCopy.address;
delete formDataCopy.images;
!formDataCopy.offer && delete formDataCopy.discountedPrice;
console.log("this is" + formDataCopy);
const docRef = await addDoc(
collection(db, "listings"),
formDataCopy
)
console.log(docRef);
setLoading(false);
toast.success("Created a listing");
navigate(`/category/${formDataCopy.type}/${docRef.id}`);
};

Related

I am trying to upload multiple photos on firebase storage and then add to the firestore using url

after clicking add button it creates as many firestore documents as photos selected
so if I add 2 photos it will make 2 documents with these photos
imageUpload // this is a state
It looks like your post is mostly code; please add some more details.
stack overflow gives me this error so this is a dummy text
const addProduct = () => {
const collRef = collection(db, "products");
try {
const imageUrl = [];
if (imageUpload.length > 0) {
for (let i = 0; i < imageUpload.length; i++) {
const name = imageUpload[i].name + Date.now();
const storageRef = ref(storage, `img/${name}`);
const uploadTask = uploadBytesResumable(storageRef, imageUpload[i]);
uploadTask.on(
"state_changed",
(snapshot) => {
const progress =
Math.round(
(snapshot.bytesTransferred / snapshot.totalBytes) * 1000
) / 10;
console.log(`Upload #${i + 1} is ${progress}% done`);
},
(error) => {
console.log("error", error);
},
() => {
getDownloadURL(uploadTask.snapshot.ref)
.then(async (url) => {
imageUrl.push({ src: url });
await addDoc(collRef, {
title,
image: imageUrl,
});
})
.catch((error) => {
console.log(error);
});
}
);
}
}else{
console.log("Photo is not selected");
}
} catch (error) {
console.log("catch", error.message);
}
};

Uncaught (in promise) FirebaseError: Function addDoc() called with invalid data. Unsupported field value: undefined (found in field imgUrls )

when I submit the form to store the data on the firestore db I got this error message:
image 1
the value of images on the state is showen like this :
image 2
I find the same question posted by others but all the answers there is not working
for me
Here is my code :
const storeImage = async (image) => {
return new Promise((resolve, reject) => {
const storage = getStorage()
const fileName = `${auth.currentUser.uid}-${image.name}-${uuidv4()}`
const storageRef = ref(storage, 'images/' + fileName)
const uploadTask = uploadBytesResumable(storageRef, image)
uploadTask.on(
'state_changed',
(snapshot) => {
const progress =
(snapshot.bytesTransferred / snapshot.totalBytes) * 100
console.log('Upload is ' + progress + '% done')
switch (snapshot.state) {
case 'paused':
console.log('Upload is paused')
break
case 'running':
console.log('Upload is running')
break
default:
break
}
},
(error) => {
reject(error)
},
() => {
// Handle successful uploads on complete
// For instance, get the download URL: https://firebasestorage.googleapis.com/...
getDownloadURL(uploadTask.snapshot.ref).then((downloadURL) => {
resolve(downloadURL)
})
}
)
})
}
const imgUrls = await Promise.all(
[...images].map((image) => storeImage(image))
).catch(() => {
setLoading(false)
toast.error('Images not uploaded')
return
})
const formDataCopy = {
...formData,
imgUrls,
geolocation,
timestamp: serverTimestamp(),
}
formDataCopy.location = address
delete formDataCopy.images
delete formDataCopy.address
!formDataCopy.offer && delete formDataCopy.discountedPrice
const docRef = await addDoc(collection(db, 'listings'), formDataCopy)
setLoading(false)
toast.success('Listing saved')
navigate(`/category/${formDataCopy.type}/${docRef.id}`)
}

How do I upload a base64 image to firebase using Busboy (React)?

I am having trouble uploading an image to the db after cropping. I am able to upload the file on Postman, but can't figure out how to do it after cropping and getting it returned as a base64.
Here is my route that works with uploading a raw file, but not the base64:
exports.uploadProfileMedia = (req, res) => {
const BusBoy = require("busboy")
const path = require("path")
const os = require("os")
const fs = require("fs")
let mediaFileName
let mediaToBeUploaded = {}
let generatedToken = uuidv4()
const busboy = new BusBoy({ headers: req.headers })
busboy.on("file", (fieldname, file, filename, encoding, mimetype) => {
console.log(file, "before")
if (
mimetype !== "image/jpeg" &&
mimetype !== "image/png" &&
mimetype !== "image/heic"
) {
return res.status(400).json({ error: "Wrong file type submitted" })
}
const mediaExtension = filename.split(".")[
filename.split(".").length - 1
]
mediaFileName = `${Math.round(
Math.random() * 100000000000
).toString()}.${mediaExtension}`
const filepath = path.join(os.tmpdir(), mediaFileName)
mediaToBeUploaded = { filepath, mimetype }
file.pipe(fs.createWriteStream(filepath))
console.log(file, "after")
})
busboy.on("finish", () => {
admin
.storage()
.bucket()
.upload(mediaToBeUploaded.filepath, {
resumable: false,
metadata: {
metadata: {
contentType: mediaToBeUploaded.mimetype,
firebaseStorageDownloadTokens: generatedToken
}
}
})
.then(() => {
const mediaUrl = `https://firebasestorage.googleapis.com/v0/b/${firebaseConfig.storageBucket}/o/${mediaFileName}?alt=media&token=${generatedToken}`
return db
.doc(`/users/${req.user.username}`)
.update({ mediaUrl })
})
.then(() => {
return res
.status(201)
.json({ message: "Media uploaded successfully" })
})
.catch((err) => {
console.error(err)
return res.status(500).json({ error: err.code })
})
})
busboy.end(req.rawBody)
}
Here is where I pass in a base64 after cropping:
const uploadProfileMedia = (formData) => {
axios.defaults.headers.common["Authorization"] = localStorage.getItem(
"FBIdToken"
)
axios
.post("/api/user/media", formData)
.then((res) => {})
.catch((err) => console.log(err))
console.log(formData, "form")
}
Here is a snippet of the above console.log():
data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAMCAgICAgMCAgIDAwMDBAYEBAQEBAgGBgUGCQgKCgkICQkKDA8MCgsOCwkJDREN
Here is the function which calls the uploadProfileMedia():
const showCroppedImage = useCallback(async () => {
console.log(imageSrc, "imgsrc")
try {
const croppedImage = await getCroppedImg(
imageSrc,
croppedAreaPixels
)
setCroppedImage(croppedImage)
uploadProfileMedia(croppedImage)
console.log(croppedImage, "showcroppedImage")
} catch (e) {
console.error(e)
}
}, [imageSrc, croppedAreaPixels])

How to make Async Await Function in React Native?

I want to create a function that is about uploading photo to Firebase Storage with react-native-fetch-blob. I'm using Redux and you can find action functions below:
My problem is that uploadImage function is not running like asynchronous. Firebase function is running before uploadImage, so application give me an error.
I think i can't make a asynchronous function. How can i fix it ?
uploadImage() function:
const uploadImage = async (imageSource, whereToUpload) => {
let imageURL = '';
const mime = 'image/jpg';
const { Blob } = RNFetchBlob.polyfill;
const { fs } = RNFetchBlob;
window.XMLHttpRequest = RNFetchBlob.polyfill.XMLHttpRequest;
window.Blob = Blob;
console.log('URI =>', imageSource.uri);
let imgUri = imageSource.uri;
let uploadBlob = null;
const imageRef = firebase.storage().ref(whereToUpload + '/' + imageSource.fileName);
const uploadUri = Platform.OS === 'ios' ? imgUri.replace('file://', '') : imgUri;
await fs.readFile(uploadUri, 'base64')
.then((data) => Blob.build(data, { type: `${mime};BASE64` }))
.then((blob) => {
uploadBlob = blob;
return imageRef.put(blob, { contentType: mime });
})
.then(() => {
uploadBlob.close();
// eslint-disable-next-line no-return-assign
return imageURL = imageRef.getDownloadURL();
})
.catch((error) => {
console.log(error);
});
return imageURL;
};
and the main action is:
export const addProjectGroup = (
myUser,
groupName,
groupDescription,
groupProfilePic,
) => dispatch => {
const groupProfileFinalPic = async () => {
let finalGroupPicture = { landscape: '' };
if (_.isEmpty(groupProfilePic.src)) {
await uploadImage(groupProfilePic, 'groupPictures').then((imageURL) => {
console.log('İŞLEM TAMAM!');
console.log('SELECTED IMAGE URL =>', imageURL);
finalGroupPicture.landscape = imageURL;
});
} else {
finalGroupPicture.landscape = groupProfilePic.src.landscape;
}
return finalGroupPicture;
};
console.log("final group profile pic =>", groupProfileFinalPic());
// Önce grubu yaratalım..
// eslint-disable-next-line prefer-destructuring
const key = firebase
.database()
.ref()
.child('groups')
.push().key;
firebase
.database()
.ref('/groups/' + key)
.set({
admin: {
email: myUser.email,
name: myUser.name,
uid: myUser.uid,
},
groupName,
groupDescription,
groupProfilePic: groupProfileFinalPic(),
projects: '',
})
.then(() => {
console.log('Groups oluşturuldu.');
})
.catch(e => {
Alert.alert('Hata', 'Beklenmedik bir hata meydana geldi.');
console.log(e.message);
});
dispatch({
type: ADD_PROJECT_GROUP,
});
};
You are not awaiting groupProfileFinalPic(). This should be done before creating the action you want to dispatch.
groupProfileFinalPic().then(groupProfilePic => {
return firebase
.database()
.ref("/groups/" + key)
.set({
admin: {
email: myUser.email,
name: myUser.name,
uid: myUser.uid
},
groupName,
groupDescription,
groupProfilePic,
projects: ""
})
.then(() => {
console.log("Groups oluşturuldu.");
})
.catch(e => {
Alert.alert("Hata", "Beklenmedik bir hata meydana geldi.");
console.log(e.message);
});
});
I have no clue what the last dispatch is for, you might want to do that in one of the callbacks. Your code is to verbose for an SO question, but I hope this helps anyways.
You are using both await and then on the same call. To use await, you can arrange it something like
const uploadImage = async (imageSource, whereToUpload) => {
...
try {
let data = await RNFS.fs.readFile(uploadUri, 'base64')
let uploadBlob = await Blob.build(data, { type: `${mime};BASE64` }))
...etc...
return finalResult
catch (e) {
// handle error
}
}

firestore array not storing last value

I have a Registration form which has many fields for submission.Form submission is working fine, saving all the details to firestore. I have input file upload, user can select multiple files, on submit, uploadin all the files to firebase storage ans saving the upload link in an array(FileURLs).
For Example if I have selected 3 files on submit when i do console.log of state I can see the FileURLs with 3 data but In firestore last value is not getting saved.
Code
handleSubmit = (e) => {
e.preventDefault();
const promises = [];
const {fileURLs,sp_License}=this.state;
let files=[];
let orgFile='';
let err = this.validate();
if (!err) {
this.setState({ loading: true,disChecked:false })
// this.fileupload();
// this.MultifileuploadHandler();
const Lfilename = this.state.sp_Name + '_' + new Date().getTime();
const uploadTask = storage.ref('License/' + Lfilename).put(sp_License);
promises.push(uploadTask);
uploadTask
.then(uploadTaskSnapshot => {
return uploadTaskSnapshot.ref.getDownloadURL();
})
.then(url => {
// orgFile.push({url});
// this.setState({sp_License:url})
orgFile=url
// console.log(orgFile)
},()=>{
console.log(sp_License)
});
//multi pilots file
const storageRef = storage.ref();
this.state.sp_PilotsLicense.forEach((file) => {
const uploadTask= storageRef
.child(`License/${file.name}`).put(file)
promises.push(uploadTask);
uploadTask.then((snapshot) => {
return snapshot.ref.getDownloadURL();
}).then(url =>{
files.push({url});
})
});
Promise.all(promises).then(tasks => {
console.log('all uploads complete');
console.log(this.state)
if(this._mounted)
{
console.log(orgFile)
this.setState({
fileURLs: files,
sp_License:orgFile,
},()=>{
console.log(this.state)
});
}
this.saveData();
});
}
}
saveData=()=>{
let uid = this.props.auth.uid;
let keysToRemove = ["loading", "checked", "disChecked", "open", "message"]
let newState = Object.entries({...this.state}).reduce((obj, [key, value]) => {
if(!keysToRemove.includes(key)){
obj[key] = value
}
return obj
}, {})
console.log(newState)
this.props.UpdateUserDetails(uid, newState,this.successMessage)
}
Action
export const UpdateUserDetails= (id, droneSPDetails,func) => {
console.log(droneSPDetails)
console.log(func)
return (dispatch, getState, { getFirestore }) => {
const firestore = getFirestore()
firestore.collection('users')
.doc(id)
.set({
...droneSPDetails,
sp_RegisteredOn: new Date(),
sp_Status:"pending",
sp_ActiveFlag:"1",
},{ merge: true })
.then(() => {
func();
dispatch({ type: 'CREATE_DRONESP', droneSPDetails });
})
.catch((error) => {
console.error("Error adding document: ", error);
});
}
}
This is the value passed to store on firestore (from console.log)
fileURLs: Array(3)
0: {url: "https://firebasestorage.googleapis.com/v0/b/dronew…=media&token=084bc59a-8087-43de-afdb-05d4192ec4d2"}
1: {url: "https://firebasestorage.googleapis.com/v0/b/dronew…=media&token=3d427621-6a8b-4ed7-b6ce-5c3940fe7ee6"}
2: {url: "https://firebasestorage.googleapis.com/v0/b/dronew…=media&token=e24a5bab-e584-4a95-bb70-4d6c9f7fed7c"}
length: 3
but I can see only these 2 values getting saved.

Resources