Profile.jsx
const Profile = () => {
const [auth, setAuth] = useAuth()
const [name, setName] = useState("")
const [email, setEmail] = useState("");
const [password, setPassword] = useState("");
const [phone, setPhone] = useState("");
const [address, setAddress] = useState("");
const [photo, setPhoto] = useState("")
const navigate = useNavigate()
console.log(photo.path)
useEffect(() => {
const { name, email, phone, address, photo } = auth?.user
setName(name);
setPhone(phone);
setEmail(email);
setAddress(address);
setPhoto(photo)
}, [auth?.user])
const handleSubmit = async(e) => {
e.preventDefault()
const data = new FormData()
data.append("name", name)
data.append("email", email)
data.append("password", password)
data.append("phone", phone)
data.append("address", address)
if(photo){
data.append("photo", photo)
}
try{
const res = await axios.put("http://localhost:4000/api/auth/profile", data)
if(res.data.success) {
toast(res.data.message,{type: "success", draggable:false})
navigate("/")
} else {
toast(res.data.message,{type: "error", draggable:false})
}
} catch(error){
console.log(error);
toast("Something Went Wrong",{type: "error", draggable:false})
}
}
return (
<form onSubmit={handleSubmit}>
<div className='input-photo'>
{photo && (
<div>
{/* <img src={photo.path} alt='Profile photo' /> */}
<img src={URL.createObjectURL(photo)} alt='Profile photo' />
</div>
)}
<div className="">
<label>
{photo ? photo.name : "Upload Photo"}
<input type='file' name='photo' accept='image/*'
onChange={(e) => setPhoto(e.target.files[0])} hidden />
</label>
</div>
</div>
</form>
)
)
controllers/auth.js
export const updateProfileController = async(req,res) => {
try{
const { name, email, password, address, phone } = req.body
const photo = req.files[0]
const user = await userModel.findById(req.user._id)
if(password && password.length < 6){
return res.json({ error: "Password required and 6 characters long"})
}
const hashedPassword = password ? await hashPassword(password) : undefined
console.log(photo)
const updatedUser = await userModel.findByIdAndUpdate(req.user._id,
{
name: name || user.name,
email: email || user.email,
password: hashedPassword || user.password,
phone: phone || user.phone,
address: address || user.address,
photo: photo || user.photo
},
{ new: true }
)
res.status(200).send({
success: true,
message: "Profile updated successfully",
updatedUser,
});
} catch(error){
console.log(error);
res.status(400).send({
success: false,
message: "Error while updating profile",
error,
});
}
}
models/user.js
photo: {
type: {},
},
I am trying to display the photo that has been saved in MongoDB and since because I used URL.createObjectURL to display so the user can change the profile photo. May I ask how to have the photo first displayed the original ones then when the user clicks on the input field then the photo can be shown as well?
>Solution :
It seems like you’re trying to display a user’s profile photo in your React application, where the photo is initially fetched from MongoDB, and then updated using a file input. You’re currently using URL.createObjectURL to create a temporary URL for previewing the photo, but you need a mechanism to first display the existing photo from the server and then show the updated photo when the user selects a new one.
To achieve this, you should handle the photo URL differently for the initial load (where you display the photo stored in MongoDB) and when the user selects a new photo.
Here’s how you can modify your code:
Display the initial photo from MongoDB: When you fetch the user’s profile, the photo field should contain information about the photo stored in MongoDB. If you store the photo as a path or URL in MongoDB, you can directly use this path/URL to display the image.
Update photo preview on selection: When the user selects a new photo, you can use URL.createObjectURL to create a temporary URL for previewing the new photo.
Here’s an adjustment to your Profile.jsx component:
const Profile = () => {
// ... other states
const [photo, setPhoto] = useState("");
const [photoPreview, setPhotoPreview] = useState("");
useEffect(() => {
const { name, email, phone, address, photo } = auth?.user;
setName(name);
setEmail(email);
setPhone(phone);
setAddress(address);
setPhoto(photo);
// Set initial photo preview from MongoDB
if (photo) {
// Assuming 'photo' contains a URL or path
setPhotoPreview(photo);
}
}, [auth?.user]);
const handlePhotoChange = (e) => {
const file = e.target.files[0];
setPhoto(file);
setPhotoPreview(URL.createObjectURL(file));
};
// ... handleSubmit remains the same
return (
<form onSubmit={handleSubmit}>
{/* ... other form fields */}
<div className='input-photo'>
{photoPreview && (
<div>
<img src={photoPreview} alt='Profile photo' />
</div>
)}
<div>
<label>
{photo ? photo.name : "Upload Photo"}
<input type='file' name='photo' accept='image/*'
onChange={handlePhotoChange} hidden />
</label>
</div>
</div>
</form>
);
}
In this modification, photoPreview is used to handle the display of the photo. Initially, it is set to the photo URL/path from MongoDB. When the user selects a new photo, handlePhotoChange updates photoPreview to the new photo’s temporary URL.
Note: Ensure that the server correctly handles the photo update in the updateProfileController and that the path/URL stored in MongoDB points to a location where the photo is accessible to the client.