0
votes

Background

I'm trying to upload images to firebase storage manually (using the upload file button in the web page), however I have no clue how to later link them to a firestore document. What I have come up with (I'm unsure if it works) is copying the url for the image in the storage bucket and adding it to a string type field in the document called profilePicture. The reason I'm unable to get this to work is that I'm really new to React Native and I don't know how to properly require the images other than typing in the specific local route. Mind you also, the way I'm requiring user data such as a profile name is after logging in with email/password auth I pass the data as a param to react navigation and require it as extraData.

What I have tried

Once I've copied the image url and pasted it in the firestore document I'm doing this:

const profilePicture = props.extraData.profilePicture;

<Image source={require({profilePicture})}/>

I have also tried using backticks but that isn't working either. The error message I'm getting is:

TransformError src\screens\Profile\ProfileScreen.js: src\screens\Profile\ProfileScreen.js:Invalid call at line 27: require({
  profilePicture: profilePicture
})

Note: this is an expo managed project.

Question

Is the problem in the code or in the way I'm linking both images? Maybe both? Should I require the document rather than relying on the data passed previously?

Thanks a lot in advance!

Edit 1:

I'm trying to get all info from the current user signed in, after a little research I've come to know about requiring images in this manner:

const ref = firebase.storage().ref('path/to/image.jpg'); const url = await ref.getDownloadURL();

and then I'd require the image as in <Image source={{uri: url}}/>

I get that this could be useful for something static, but I don't get how to update the ref for every single different user.

Edit 2:

Tried using the method mentioned in Edit 1, just to see what would happen, however It doesn't seem to work, the image just does not show up. Maybe because my component is a function component rather than a class component (?

1

1 Answers

1
votes

I understand that your goal is to generate, for each image that is uploaded to Cloud Storage, a Firestore document which contains a download URL.

If this is correct, one way is to use a Cloud Function that is triggered each time a new file is added to Cloud Storage. The following Cloud Function code does exactly that. You may adapt it to your exact requirements.

exports.generateFileURL = functions.storage.object().onFinalize(async object => {

    try {
        const bucket = admin.storage().bucket(object.bucket);
        const file = bucket.file(object.name);

        // You can check that the file is an image

        const signedURLconfig = { action: 'read', expires: '08-12-2025' };  // Adapt as follows

        const signedURLArray = await file.getSignedUrl(signedURLconfig);
        const url = signedURLArray[0];

        await admin.firestore().collection('profilePictures').add({ fileName: object.name, signedURL: url }) // Adapt the fields list as desired 
        return null;

    } catch (error) {
        console.log(error);
        return null;
    }

});

More info on the getSignedUrl() method of the Admin SDK here.

Also note that you could assign the Firestore document ID yourself, instead of having Firestore generating it as shown in the above code (with the add() method). For example, you can add to the image metadata the uid of the user and, in the Cloud Function,get this value and use this value as the Document ID.

Another possibility is to name the profile image with the user's uid.