How to upload SVG images on firebase storage? - reactjs

I am having issue to upload an SVG image to firebase storage.
The upload seems to work correctly how when I am trying to click on the link. It returns the error file empty as per screenshot below.
Please see below my upload function
import { getStorage, ref, uploadBytesResumable, getDownloadURL } from "firebase/storage"
export const uploadToFirebase = async (file) => {
const storage = getStorage()
const storageRef = ref(storage, "images/avatar.svg")
const metadata = {
contentType: "image/svg+xml",
}
const uploadTask = uploadBytesResumable(storageRef, file, metadata)
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
}
},
(error) => {
// A full list of error codes is available at
// https://firebase.google.com/docs/storage/web/handle-errors
switch (error.code) {
case "storage/unauthorized":
// User doesn't have permission to access the object
break
case "storage/canceled":
// User canceled the upload
break
// ...
case "storage/unknown":
// Unknown error occurred, inspect error.serverResponse
break
}
},
() => {
// Upload completed successfully, now we can get the download URL
getDownloadURL(uploadTask.snapshot.ref).then((downloadURL) => {
console.log("File available at", downloadURL)
})
}
)
}
i am calling this function in my home component as fellow
useEffect(() => {
uploadToFirebase("../public/avatar.svg")
}, [])
Can someone help me underytand what is wrong with my code,please?

You pass a String to your uploadToFirebase() method which results in calling the uploadBytesResumable() method with a String as second argument.
As explained in the doc (above link), this second argument shall be a Blob, a Uint8Array or an ArrayBuffer.
Following our below comments: I'm not verse in reactjs but you need to get the image from your public folder as a Blob Object (or as a File Object, which is "a specific kind of Blob") and pass it to your uploadToFirebase() method. The following SO question & answers give several ways to do that (untested).

Related

Express + React | Googleapis - download a file

Im so new on React components and I try to download files from my google drive folder, after a long time currently I have working my API to upload, and get files. My question is, how should I pass the data to download the file on my front end?
How can I get the files from my google drive, and download on react component?
Thanks in advance, and sorry for my explication, I dont know what I currently doing with the file.
Note: This code is just as example to download an image, I want to pass a fileID to download anything, pdfs, docs, png, etc.
Update: After triying differents solutions my api function was completed like this:
google_Ctrl.getDownload = async(req, res) => {
console.log(req.params);
let Google = await drive.files.get(
{fileId: req.params.id,
alt: 'media'},
{ responseType: 'stream' }
).then((request) => {
console.log(request);
fileType = request.headers['content-type'];
fileName = ( "file" + '.' + fileType );
fileData = request.data;
res.set(request.headers)
// res.set("Content-Type", fileType);
// res.set("Content-Disposition", "attachment; filename='archivo.png'");
fileData.pipe(res)
});
}
My function its currently working, when I using api.rest to send a GET Request they provide me my files. But now my problem is on React Component, I read a lot of posts but I did not found the solution, I currently using downloadjs trying this solution, unsuccessfully.
const DownloadFile = () => {
axios.get(process.env.REACT_APP_API_URL + 'google/download/' + "1YtDWD9hNEgCUi8YGQPjV98sULhyM5m8C")
.then((res) => {
console.log(res);
// res.blob()
// fileDownload(res.data, 'filename.png');
download(res.data, "file.png", res.headers['content-type']);
}).catch((error) =>{
console.error(error);
message.error('upload failed.');
});
}
This is my download function on React component, my .txt files works, but when I try to download pdf's, docs, xlsx, etc, dosent work, what can I do?
With Api.rest I tested my api function and it's working, I can download my files from api.rest, but my react functions apparently its badly formatted, I guess.
Okey, after a long time checking the code I found my error on the React Function, if someone is in the same position, here the code working:
API Google:
google_Ctrl.getDownload = async(req, res) => {
console.log(req.params);
console.log(req.body);
let Google = await drive.files.get(
{fileId: req.params.id,
alt: 'media'},
{ responseType: 'stream' }
).then((request) => {
console.log(request);
fileType = request.headers['content-type'];
fileName = ( "file" + '.' + fileType );
fileData = request.data;
// res.set(request.headers)
console.log(fileType);
res.set("Content-Type", fileType);
res.set("Content-Disposition", "attachment; filename='archivo.png'");
fileData.pipe(res)
});
}
React Component:
const DownloadFile = () => {
axios.get(process.env.REACT_APP_API_URL + 'google/download/' + "1YtDWD9hNEgCUi8YGQPjV98sULhyM5m8C",
{responseType: 'blob'})
.then((res) => {
console.log(res);
// res.blob()
fileDownload(res.data, 'filename.png');
// download(res.data, "file.pdf", res.headers['content-type']);
}).catch((error) =>{
console.error(error);
message.error('upload failed.');
});
}
The next step is send the FileID, Filename with the extention and when you recive use that name/extension to save correctly the file :D.

How to get onUploadProgress value in an await function from axios?

I'm relatively new to react and having trouble getting the progress value "progressEvent" of axios in the onUploadProgress callback,
I have two files, one for the api call and one for my react component:
Here is a sample of my api.js
function uploadImage(file) {
return axios.post('/api/media_objects', file, {
onUploadProgress: progressEvent => {
let percentComplete = progressEvent.loaded / progressEvent.total
percentComplete = parseInt(percentComplete * 100);
console.log(percentComplete);
}
}).then(response => response.data.id);
}
and my try/catch from the component
try {
const upload = await xxxAPI.uploadImage(formData);
} catch (error) {
console.log(error);
}
How can i retrieve in the "try" the "percentComplete" ?
Thanks !
Generally, I'd advise using some kind of state management (redux/mobx) for controlling this flow. Not to handle it directly from a React component. So the component will trigger a kind of action and the upload process will be handled outside.
But, for a very simple solution, you'd need something like this:
function uploadImage(file, updateProgress) {
return axios.post('/api/media_objects', file, {
onUploadProgress: progressEvent => {
let percentComplete = progressEvent.loaded / progressEvent.total
percentComplete = parseInt(percentComplete * 100);
console.log(percentComplete);
updateProgress(percentComplete);
}
}).then(response => response.data.id);
}
const MyComponent = () => {
const [progress, setProgress] = useState(0);
const onUpload = useCallback(() => {
myApi.uploadImage(data, setProgress);
},[]);
return <div>
<span>Uploaded: {progress}</span>
<button onClick={onUpload}>Upload</button>
</div>;
};
the progress value is stored in the component's state so it can be updated and rendered.
I would also put the try/catch in the API method rather than in the component.
On a more general note. I'd advise using a library such as react-uploady to manage the upload for you. There's are a lot of edge cases and functionality you need to handle typically when uploading files and a small 3rd party like Uploady takes care of it for you: Preview with progress for file uploading in React

Can't retrieve download url from firebase storage

I'm trying to retrieve download url so i can pass it down in promise in the function i'm calling.
In the storage image is uploaded but somehow i'm getting error on the line where i console.log - 404 error like it does not exist ( but it does )
uploadFile = (file, metadata) => {
const pathToUpload = this.state.channel.id;
const ref = this.props.messagesRef;
const filePath = `chat/public/${uuidv4()}.jpg`; // uuid is a function that creates random string
this.setState({
uploadState: 'uploading',
uploadTask: this.state.storageRef.child(filePath).put(file,metadata)
},
() => {
this.state.uploadTask.on('state_changed', snap => {
const percentUploaded = Math.round((snap.bytesTransferred / snap.totalBytes) * 100)
this.setState({percentUploaded})
},
err => {
console.error(err)
this.setState({
errors: this.state.errors.concat(err),
uploadState: 'error',
uploadTask: null
})
})
},
() => {
this.state.uploadTask.snapshot.ref.getDownloadURL().then(downloadUrl => {
console.log(downloadUrl) // get error
this.sendFileMessage(downloadUrl, ref, pathToUpload)
})
.catch(err => {
console.error(err)
this.setState({
errors: this.state.errors.concat(err),
uploadState: 'error',
uploadTask: null
})
})
}
)
};
If you need more code let me know, but on this point where i log error it's where the problem is.
Simply url of posted image in the DB can't be retrieved, i tried with storage rules but there everything looks fine.
EDIT: With state_changed listener state doesn't change - whole time it stays at 'uploading' while image is being stored in storage
It looks like you're not waiting for the upload to fully complete before requesting the download URL. This is usually what a 404 means with this sort of code. You're going to have to use the promise returned by storageRef.child(filePath).put(file,metadata) in order to know when the upload is complete, and only then will you be able to call getDownloadURL() successfully on its reference.

Value of state variable is lost - React

I want to build a CRUD in React with Laravel and Firebase. Everything is perfect when I'm working with text, but I got trouble when I try to upload an image to Firebase Storage. I can save it but I can't get its URL.
I wrote 2 "console.log". In the first one the URL is there, but the second one (when I try to get the URL from the state variable) doesn't return anything.
handleSubmit = event =>{
event.preventDefault();
const {imagen} = this.state;
if(imagen!=null){
const uploadTask = storage.ref(`imagenes/${imagen.name}`).put(imagen);
uploadTask.on('state_changed',
(snapshot) => {
const progress = Math.round((snapshot.bytesTransferred / snapshot.totalBytes) * 100);
this.setState({progress});
},
(error) => {
console.log(error);
},
() => {
storage.ref('imagenes').child(imagen.name).getDownloadURL().then(url => {
this.setState({url});
console.log(this.state.url); //<<<<<<<<<<<<<SHOW URL (IT'S OK!)
})
});
}
var direccion = null;
const form = event.target;
let data = new FormData(form);
data.append('url', this.state.url);
console.log(this.state.url); //<<<<<<<DOESN'T SHOW URL !! (HERE'S THE TROUBLE)
If you want to check the entire file:
https://github.com/AndresVasquezPUCE/project/blob/master/pelicula
I'm not a professional, so please don't be rude :D
this.setState is asynchronous
If you want to get the updated state value, add a callback and access the new state there like
this.setState({ url: 'some url'}, () => {
conosle.log(this.state.url);
});
Data is loaded from Firebase asynchronously. By the time your console.log(this.state.url); //<<<<<<<DOESN'T SHOW URL !! (HERE'S THE TROUBLE) the data hasn't been loaded from Firebase yet, and the then hasn't been called yet.
Any code that needs the data from Firebase needs to either be inside the then() callback (such as console.log(this.state.url); //<<<<<<<<<<<<<SHOW URL (IT'S OK!)) or be called from there (such as this.setState({url})).

React Redux Firebase Upload File Object

Trying to pass the file object to redux action and perform the function inside of an redux action, not sure its the correct way? but basically i want back downloadURL from firebase upload complete so I can show image front end.
createLocation(event) {
event.preventDefault();
const fileObject = this.state.file;
const test = {
fileObject
}
this.props.uploadImage_func(test);
}
and action function:
export function uploadImage_func(fileObject) {
return dispatch => {
const fileName = 'myimage';
const storageRef = firebase.storage().ref('test/' + fileName);
const task = storageRef.put(fileObject);
task.on('state_changed',
function complete(snapshot) {
const downloadURL = task.snapshot.downloadURL;
},
).then(function () {
dispatch(attemptLogin({
...downloadURL
}));
});
}
}
error:
As you can see you have got an error Invalid argument in 'put' at index 0: Expected Blob or File. So first of all you need path exactly File or Blob. If you did right in you createLocation and got file object than you need not to wrap it in const test object more. That action causes unnecessary nesting, so just path fileObject as it is. And more. When you subscribe for firebase UploadTask on event you need to path callback functions and do it in a right order, so try to use next:
uploadTask.on('state_changed',
(snapshot) => {
// here you could log loading information in percents but uploading is not finished yes
console.log((snapshot.bytesTransferred / snapshot.totalBytes) * 100);
},
(error) => console.log(error),
() => {
// And after uploading is complete you could get your download url
console.log('Call save img', uploadTask.snapshot.downloadURL);
}
);
For more information read documentation for Firebase Storage (Upload files)

Resources