Below is the my profile page code I thinking I should use a callback along with another useEffect function but I’m not sure please help. You ignore all the code involving deleting, saving, and handling ingredients I just working on the profile card for right now plus those already work. I really just don’t want the user to have to refresh the page every time they upload a new image to see it. Unless you all have other fun way of getting around this or suggest i just make another modal telling the user to refresh the page or any other creative way to make this feature seem less bad and unprofessional. I’m a beginner and would really appreciate some help with this!
import React, { useEffect, useState, useCallback } from "react";
import Axios from "axios";
import Cookies from "js-cookie";
import Footer from "./Footer";
import Header from "./Header";
import "./Profile.css";
const Profile = () => {
const [userData, setUserData] = useState({});
const [savedIngredients, setSavedIngredients] = useState([]);
const [ingredientName, setIngredientName] = useState("");
const [ingredientQuantity, setIngredientQuantity] = useState("");
const [selectedFile, setSelectedFile] = useState(null);
const [showUploadModal, setShowUploadModal] = useState(false);
const [previewImage, setPreviewImage] = useState(null);
const [profilePictureURL, setProfilePictureURL] = useState(userData.profilePicture);
const API = "http://localhost:3000"
const handleFileChange = (event) => {
const file = event.target.files[0];
setSelectedFile(file);
const previewImageURL = file ? URL.createObjectURL(file) : null;
setPreviewImage(previewImageURL);
};
// Fetch email and username
useEffect(() => {
const authToken = Cookies.get("userToken");
Axios.get(
API+"/users/profile",
{
withCredentials: true,
headers: {
Authorization: `Bearer ${authToken}`,
},
}
)
.then((response) => {
console.log("Profile response:", response.data);
setUserData({
username: response.data.username,
email: response.data.email,
profilePicture: response.data.profilePicture,
});
setProfilePictureURL(response.data.profilePicture)
})
.catch((error) => {
console.error(error);
});
}, []);
// Fetch and display saved ingredients
const fetchSavedIngredients = useCallback(async () => {
try {
const response = await Axios.get(
API+"/users/saved_ingredients",
{
withCredentials: true,
headers: {
Authorization: `Bearer ${Cookies.get("userToken")}`,
},
}
);
console.log("Response Data:", response.data);
setSavedIngredients(response.data.savedIngredients);
setIngredientName("");
setIngredientQuantity("");
} catch (error) {
console.error(error);
}
}, []);
const { username = "", email = "" } = userData || {};
// insert ingredients into the fridge table
const handleSaveIngredients = async () => {
try {
console.log("Input Ingredient Name:", ingredientName);
const trimmedIngredientName = ingredientName.toLowerCase().trim();
console.log("trimmedIngredientName:" + trimmedIngredientName);
if (!trimmedIngredientName) {
console.error("Ingredient name cannot be empty.");
return;
}
if (!ingredientQuantity) {
console.error("Quantity cannot be empty.");
return;
}
const response = await Axios.post(
API+"/users/profile_ingredient_list",
{
name: trimmedIngredientName,
quantity: ingredientQuantity,
},
{
withCredentials: true,
headers: {
Authorization: `Bearer ${Cookies.get("userToken")}`,
},
}
);
console.log(response.data);
// Only fetch ingredients after a successful save
fetchSavedIngredients();
setIngredientName("");
setIngredientQuantity("");
} catch (error) {
console.error(error);
}
};
useEffect(() => {
fetchSavedIngredients();
}, []);
const handleDeleteIngredient = async (ingredientName) => {
try {
const response = await Axios.delete(
"http://localhost:3001/users/delete_ingredient",
{
withCredentials: true,
headers: {
Authorization: `Bearer ${Cookies.get("userToken")}`,
},
data: {
name: ingredientName,
},
}
);
setSavedIngredients(response.data.savedIngredients);
} catch (error) {
console.error(error);
}
};
const handleProfilePictureUpload = async () => {
try {
if (selectedFile) {
const formData = new FormData();
formData.append("profilePicture", selectedFile);
const response = await Axios.post(
API + "/users/upload_profile_picture",
formData,
{
withCredentials: true,
headers: {
Authorization: `Bearer ${Cookies.get("userToken")}`,
"Content-Type": "multipart/form-data",
},
}
);
// Update the user data with the new profile picture file name
setUserData((prevUserData) => ({
...prevUserData,
profilePicture: response.data.filePath.split('/').pop(),
}));
// Update the profile picture URL to trigger a re-render
setProfilePictureURL(response.data.filePath.split('/').pop());
setShowUploadModal(false);
}
} catch (error) {
console.error(error);
}
};
// console.log("Profile Picture File Name:", userData.profilePicture);
return (
<div>
<Header />
<div className="Profile-Card">
<div className="Profile-Picture">
<div className="picture-icon" onClick={() => setShowUploadModal(true)}>
<img
className="pic-icon"
src="./images/photo_icon.png"
alt="Add Photo"
/>
</div>
{userData.profilePicture ? (
<img
className="profile-pic"
src={`http://localhost:3000/uploads/${userData.profilePicture}`}
alt="Profile"
/>
) : (
<img
className="default"
src="./images/profile_pic.jpg"
alt="Default Profile"
/>
)}
</div>
<div className="card-content">
<h1>Profile</h1>
<p>Username: {username}</p>
<p>Email: {email}</p>
</div>
</div>
{showUploadModal && (
<div className="upload-modal">
<div className="upload-modal-content">
<input
type="file"
accept="image/jpg, image/png, image/jpeg"
id="file"
onChange={handleFileChange}
style={{ display: 'none' }}
/>
<label htmlFor="file" className="file-input-button">
Change Profile Picture
</label>
{previewImage && (
<img
className="preview-image"
src={previewImage}
alt="Preview"
/>
)}
<button type="button" className="pic-upload" onClick={() => handleProfilePictureUpload()}>
Upload Picture
</button>
<button type="button" className="pic-cancel" onClick={() => setShowUploadModal(false)}>
Cancel
</button>
</div>
</div>
)}
{/* <form>
<h3>Ingredients:</h3>
<input
type="text"
value={ingredientName}
onChange={(e) => setIngredientName(e.target.value)}
placeholder="Ingredient Name"
/>
<input
type="text"
value={ingredientQuantity}
onChange={(e) => setIngredientQuantity(e.target.value)}
placeholder="Quantity"
/>
<button type="button" onClick={handleSaveIngredients}>
Save
</button>
</form> */}
{/* <div>
<h3>Saved Ingredients:</h3>
<ul>
{savedIngredients &&
savedIngredients.map((ingredient, index) => (
<li key={index}>
{ingredient.name} - {ingredient.quantity}
<button onClick={() => handleDeleteIngredient(ingredient.name)}>
Delete
</button>
</li>
))}
</ul>
</div> */}
<Footer />
</div>
);
};
export default Profile;
2
Answers
You can achieve this by doing the following:
useEffect
into a functionAfter which you can now call the function inside the
useEffect
handleProfilePictureUpload
callgetUserData
after the profile picture has been successfully uploaded.There is a possibility you issue is cache please replace
with
if it works out then it is cache; you can now create a variable for ${new Date().getTime()} or use number that change in every time the component reload in other to keep a clean code