The problem is that when I try to upload an image of size more than 2MB, it should show an error message under the tag but instead it shows uploading message first, following with "Image uploaded successfully" and at the end error message is displayed i.e., "Error uploading image (file size must be less than 2 MB)". This functionality works well but only the order of displaying error isn't working as expected when file size is 2MB+.
Tried to fix this for a while but doesn't seem to work anyway. The same code worked well in other project but it is not the same here.
In case error occurs while uploading, imageError state is changed to true which should display only error message in the UI.
---Profile.jsx---
import { useSelector } from "react-redux";
import { useRef, useState, useEffect } from "react";
import {
getDownloadURL,
getStorage,
ref,
uploadBytesResumable,
} from "firebase/storage";
import { app } from "../firebase";
const Profile = () => {
const fileRef = useRef(null);
const [image, setImage] = useState(undefined);
const [imagePercent, setImagePercent] = useState(0);
const [imageError, setImageError] = useState(false);
const [formData, setFormData] = useState({});
const { currentUser } = useSelector((state) => state.user);
useEffect(() => {
if (image) {
handleFileUpload(image);
}
}, [image]);
**const handleFileUpload = async (image) => {
const storage = getStorage(app);
const fileName = new Date().getTime() + image.name;
const storageRef = ref(storage, fileName);
const uploadTask = uploadBytesResumable(storageRef, image);
uploadTask.on(
"state_changed",
(snapshot) => {
const progress =
(snapshot.bytesTransferred / snapshot.totalBytes) * 100;
setImagePercent(Math.round(progress));
},
(error) => {
setImageError(true);
},
() => {
getDownloadURL(uploadTask.snapshot.ref).then((downloadURL) =>
setFormData({ ...formData, profilePicture: downloadURL })
);
}
);
};**
return (
<div className="p-3 max-w-lg mx-auto">
<h1 className="text-3xl font-semibold text-center my-7">Profile</h1>
<form className="flex flex-col gap-4">
<input
type="file"
ref={fileRef}
hidden
accept="image/*"
onChange={(ev) => {
setImage(ev.target.files[0]);
setImageError(false);
}}
/>
<img
src={currentUser.profilePicture}
alt="profile image"
className="h-24 w-24 self-center cursor-pointer rounded-full object-cover mt-2"
onClick={() => fileRef.current.click()}
/>
**<p className="text-sm self-center">
{imageError ? (
<span className="text-red-700">
Error uploading image (file size must be less than 2 MB)
</span>
) : imagePercent > 0 && imagePercent < 100 ? (
<span className="text-slate-700">{`Uploading: ${imagePercent} %`}</span>
) : imagePercent === 100 ? (
<span className="text-green-700">Image uploaded successfully</span>
) : (
""
)}
</p>**
<input
defaultValue={currentUser.username}
type="text"
id="username"
placeholder="Username"
className="bg-slate-100 rounded-lg p-3"
autoComplete="off"
/>
<input
defaultValue={currentUser.email}
type="email"
id="email"
placeholder="Email"
className="bg-slate-100 rounded-lg p-3"
autoComplete="off"
/>
<input
type="password"
id="password"
placeholder="Password"
className="bg-slate-100 rounded-lg p-3"
autoComplete="off"
/>
<button className="bg-slate-700 text-white p-3 rounded-lg uppercase hover:opacity-95 disabled:opacity-80">
Update
</button>
</form>
<div className="flex justify-between mt-5">
<span className="text-red-700 cursor-pointer">Delete Account</span>
<span className="text-red-700 cursor-pointer">Sign Out</span>
</div>
</div>
);
};
You (only) enforce the maximum file size in the security rules of Cloud Storage, and those rules are only applied once the upload has completed. To prevent uploading a file that is larger than you want, you should check its size in the client-side code before starting the upload, e.g. by checking its size
property.