Downloading Files from Firebase Storage - reactjs

I have a function that when clicked downloads a file from firebase storage. I have implemented the function as in the firebase documentation v8. I have also applied the cors policy to allow downloads but the problem is that file is still not being downloaded and I am not getting an error.
Kindly help on this.
Below is my download function.
const handleDownloadFile = async file => {
try {
const url = file.downloadURL;
console.log(file);
const xhr = new XMLHttpRequest();
xhr.responseType = 'blob';
xhr.onload = event => {
const blob = xhr.response;
};
xhr.open('GET', url);
xhr.send();
} catch (error) {
console.log(error.message);
}
};
The function accepts the details of the file. Below is a sample object that
{
name: 'Ndov network LOGO - 400.png',
downloadURL: 'https://firebasestorage.googleapis.com/v0/b/tkiā€¦=media&token=2680cc-4043-4676-992a-7e64fe8342f2',
uuid: '1b1c0a4b-80a5-42d4-a698-719a26e3f281'
}
kindly help me understand why I am not getting any errors and the still download, not working.

Easiest way to download file on url that comes from API is to
window.open(url,'_blank');
or you can use some library for downloading files in blob format like
https://www.npmjs.com/package/file-saver

This will open a window and ask the user where they want to save the file locally.
import { getStorage, ref, uploadBytes, getBlob } from 'firebase/storage'
export const downloadFile = (refToFile) => {
const storage = getStorage()
const fileRef = ref(storage, refToFile)
const blob = await getBlob(fileRef)
const blobUrl = URL.createObjectURL(blob)
const link = document.createElement('a')
link.href = blobUrl
link.download = 'myfilename.pdf'
link.click()
}

Related

Why my download button is not doing anything? Firebase, react

I'm following the firebase documentation for web to download the files related to a document in firestore. I practically pasted the code to achieve this, but when I click the element is not showing anything on console.
import { ref, getDownloadURL } from 'firebase/storage'
export const downloadMethod = (path) => {
getDownloadURL(ref(storage, path))
.then(url => {
const xhr = new XMLHttpRequest();
xhr.responseType = 'blob';
xhr.onload = (event) => {
const blob = xhr.response;
};
xhr.open('GET', url);
xhr.send();
})
.catch(error => {
throw error
})
}
Before this I was having cors error but I solved it using
[
{
"origin": ["*"],
"method": ["GET"],
"maxAgeSeconds": 3600
}
]
I want the website to download the requested file when I hit the button.
I guess you are missing the reference to the storage
import { getStorage, ref, getDownloadURL } from "firebase/storage";
const storage = getStorage();
...
Since the example in the documentation doesn't work, I looked for other methods in the documentation itself, and I managed to do exactly what I wanted by using getBlob()
This is my final function:
import { ref, getBlob } from 'firebase/storage'
import { storage } from '../firebase/firebase.config'
getBlob(ref(storage, 'files/MyFile.pdf'))
.then((blob) => {
const href = URL.createObjectURL(blob)
const a = Object.assign(document.createElement('a'), {
href,
style: 'display:none',
download: 'myFile.pdf' // This is where you set the name of the file you're about to download
})
a.click()
URL.revokeObjectURL(href)
a.remove()
}).catch((error)=>{
console.error(error)
})
If you feel there's something I can change, you can feel free to tell me

File Upload and download JavaScript

EDIT
Hope someone can clarify this issue I am having:
I want to store files in the backend inBinary format, and after get them and convert them into the original state of the file, I believe there is something wrong with my code, I am using HTML upload
this is how I send the binary data to backend:
const handleSubmit = async file => {
let formData = new FormData()
formData.append('file', file)
try {
const res = await postInvoice(uuid, formData)
console.log(res)
setLoadingInvoice(false)
setState({
fileList: [],
attachments: [],
filesConverted: [],
})
}
}
**edit with the api call, only missing hte url part which is in a different file**
export const postInvoice = async (id, data) => {
return await request
.post(BRattachments().post(id))
.send(data)
.set(getHeaders())
}
this is how I try to download te bianrry data:
const handleDownload = async value => {
try {
const res = await getInvoice(value.id)//api call
const file = new Blob([response], {
type: res.type,
})
saveAs(file, value.id + '.' + res.extension)//using save as to save import saveAs from 'file-saver'
}
}
**edited,this is the API CALL,I have them groued in a different file**
export const getInvoice = async ref => {
return await request
.get(BRattachments().getAll(ref))
.send()
.set(getHeaders())
.responseType('blob')
}
the problem is that every time I try to download any saved file, it gives me a problem, with XLS I only see null in the file, with PNG it says file not PNG, etc.
Hope someone can clarify how can I download binary file and convert it in a downloadable file.
thanks

How to add files using JSZip from remote URL in ReactJS?

I'm using the map function to loop files inside a folder of my zip files but the folder is always empty. The fetching of the main file is working though.
Here is my code:
getZip = async () => {
const zip = new JSZip();
const url = await svc.getMainFileURL(); // will return a downloadable url from s3
let response = await fetch(mcsURL); // will fetch the data from s3 blob
let data = await response.blob(); // and convert it into blob
zip.file(`MainFile.xlsx`, data); // add into the zip file
const otherFiles = zip.folder("files"); // create another folder inside the zip file
// Loop files from source data then insert it in the folder
const list = sourceData.map(async (item,index) => {
const fileUrl = await svc.getOtherFileUrl();
const response = await fetch(fileUrl);
const data = await response.blob();
console.log(data);
otherFiles.file(`${index}.xlsx`, data);
})
zip.generateAsync({type:"blob"})
.then(function(content) {
FileSaver.saveAs(content, `Zip File Name`);
});
}
The logging of data returns fine but when I download the zip file it has only the data of the main file with folder files. Here's a screenshot:
There may be a problem with me using async/await but I can't figure it out. Can anyone help me? Thanks in advance.
Nevermind, I already solved it using Promise.all(). The zip.generateAsync function returns the zip file even if the promises from the map function are not resolved. That's why the folder is always empty. Here is my altered code:
getZip = async () => {
const zip = new JSZip();
const url = await svc.getMainFileURL(); // will return a downloadable url from s3
let response = await fetch(mcsURL); // will fetch the data from s3 blob
let data = await response.blob(); // and convert it into blob
zip.file(`MainFile.xlsx`, data); // add into the zip file
const otherFiles = zip.folder("files"); // create another folder inside the zip file
// Loop files from source data then insert it in the folder
const list = sourceData.map(async (item,index) => {
const fileUrl = await svc.getOtherFileUrl();
const response = await fetch(fileUrl);
const data = await response.blob();
console.log(data);
otherFiles.file(`${index}.xlsx`, data);
return data;
})
// If all prmises are fullfilled it will call the zip
// function and download it using the FileSaver library
Promise.all(list).then(function() {
zip.generateAsync({type:"blob"})
.then(function(content) {
FileSaver.saveAs(content, `Zip File Name`);
});
});
}

Download a by ByteArray as pdf /handle error in React

I have an api called from react. it returns a pdf file. When i click the link as href, i can download the pdf.
Now, instead of an href, i am calling a function , on clicking and from that function, i call the api. But i am not able to download the file.
This is what i am doing:
fetch(<url>, {
method: "GET",
headers: {
Accept: "application/pdf",
"Content-Type": "application/pdf",
},
}).then(response => response.blob())
.then(response => {
var blob=response
var reader = new window.FileReader();
reader.readAsDataURL(blob);
reader.onloadend = function() {
var base64data = reader.result;
window.open(base64data);
}
})
.catch(error => {
console.error(error);
});
I am not able to download any file. The api (written in kotlin) returns a bytearray.
Also, if the api throws an exception instead of returning bytearray, i need to show a pop up ,
Any thoughts on this ?
To download the file you could use the file-saver npm package and use it as following:
import { saveAs } from 'file-saver';
const file = new Blob([blob]);
saveAs(file, 'fileName');
To open the file in your browser:
const file = new Blob([blob], {
type: 'application/pdf',
});
const fileURL = URL.createObjectURL(file);
window.open(fileURL);
You can create an invisible anchor tag somewhere in your component and use it. In my solution i created an invisible anchor tag with id invisible-link
async function download(payload) {
const response = await axios({
url: getFileLink(payload), responseType: 'blob'
})
if (response.status !== 200) {
// handle error
return
}
const anchor = document.getElementById('invisible-link')
const objectUrl = window.URL.createObjectURL(response.data)
anchor.href = objectUrl;
anchor.download = getDownloadFilename(response.headers)
anchor.click()
window.URL.revokeObjectURL(objectUrl)
}
function getDownloadFilename(headers = {}) {
const { 'content-disposition' : disposition = '' } = headers
const keyValue = disposition.split(';').find(e => e.includes('filename')) || ''
const [,filename] = keyValue.split('=')
return filename
}
here's a link of my code using this approach
// Function to download the file from byte array in REACT JS
const downloadPdfFromArrayBytes = (fileName = 'testFile.pdf', byteArrayResFromAPI) => {
const arr = new Uint8Array(array);
const blob = new Blob([arr]);
if (navigator.msSaveBlob) {
// IE 10+
navigator.msSaveBlob(blob, fileName);
} else {
const link = document.createElement('a');
// Browsers that support HTML5 download attribute
if (link.download !== undefined) {
const url = URL.createObjectURL(blob);
link.setAttribute('href', url);
link.setAttribute('download', fileName);
link.style.visibility = 'hidden';
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
}
}
};
// Example
// if you have api resp in byteArray as [10,12,30,20,34,49]
const fileName = 'myfileexample.pdf';
const apiResByteArr = [10,12,30,20,34,49];
downloadPdfFromArrayBytes(fileName ,apiResByteArr);

Google Cloud speech with React Native

I am trying to use Google Cloud Speech API so I can pass audio file and receive the translated text but I am stuck to the integration. I already have api key and everything needed but can't find how to use it from react native. In the documentation there is only explanation for node.js (from javascript part). Also there are several libraries out dated or supporting only the one OS. Someone succeeded in that?
The node.js example from the documentation:
// Imports the Google Cloud client library
const Speech = require('#google-cloud/speech');
// Your Google Cloud Platform project ID
const projectId = 'YOUR_PROJECT_ID';
// Instantiates a client
const speechClient = Speech({
projectId: projectId
});
// The name of the audio file to transcribe
const fileName = './resources/audio.raw';
// The audio file's encoding and sample rate
const options = {
encoding: 'LINEAR16',
sampleRate: 16000
};
// Detects speech in the audio file
speechClient.recognize(fileName, options)
.then((results) => {
const transcription = results[0];
console.log(`Transcription: ${transcription}`);
});
You could deploy the code using google app engine and make a post req from react-native.
Also need to configure and use google cloud storage to store the audio file for conversion.
Here is my server code.
const format = require('util').format;
const fs = require('fs');
const express = require('express');
const multer = require('multer');
const requestHttp = require('request');
const {Storage} = require('#google-cloud/storage');
// Instantiate a storage client
const storage = new Storage();
// const upload = multer();
const app = express();
// Imports the Google Cloud client library
const speech = require('#google-cloud/speech');
// Creates a client
const client = new speech.SpeechClient();
/**
* TODO(developer): Uncomment the following lines before running the sample.
*/
const encoding = 'LINEAR16';
const sampleRateHertz = 16000;
const languageCode = 'en-US';
const upload = multer({
storage: multer.memoryStorage(),
limits: {
fileSize: 5 * 1024 * 1024, // no larger than 5mb, you can change as needed.
},
});
const bucket = storage.bucket(process.env.GCLOUD_STORAGE_BUCKET);
app.post('/upload', upload.single('file') , async (req, res) => {
const file = await req.file
if (!file) {
const error = new Error('Please upload a file')
error.httpStatusCode = 400
return next(error)
}
// Create a new blob in the bucket and upload the file data.
const blob = bucket.file(req.file.originalname);
const blobStream = blob.createWriteStream({
resumable: false,
});
blobStream.on('error', err => {
next(err);
});
blobStream.on('finish', async () => {
// The public URL can be used to directly access the file via HTTP.
const publicUrl = await format(
`https://storage.googleapis.com/${bucket.name}/${blob.name}`
);
const request = {
config: {
encoding: encoding,
sampleRateHertz: sampleRateHertz,
languageCode: languageCode,
},
audio: {
uri: 'gs://YOUR-Bucket-Name/File-name.ext'
}
};
// Stream the audio to the Google Cloud Speech API
const [response] = await client.recognize(request);
const transcription = response.results
.map(result => result.alternatives[0].transcript)
.join('\n');
console.log(`Transcription: `, transcription);
res.status(200)
.send({
success: 'true',
message: 'Text retrieved successfully',
text: transcription
})
.end();
});
blobStream.end(req.file.buffer);
});
const PORT = process.env.PORT || 8080;
app.listen(PORT, () => {
console.log(`App listening on port ${PORT}`);
console.log('Press Ctrl+C to quit.');
});
deploy this server to Heroku then from your react native app send the post or get request to this server and get the result on your app.
To send post or get request use Axios library https://github.com/axios/axios

Resources