diff --git a/backend/Controllers/UserController.js b/backend/Controllers/UserController.js index 82a8aaae..e151d084 100644 --- a/backend/Controllers/UserController.js +++ b/backend/Controllers/UserController.js @@ -353,10 +353,69 @@ const deleteUserById = async (req, res) => { }; +const toggleFollowUser = async (req, res) => { + const { userId, username: followerUsername } = req.body; + try { + // Check if the target user exists + const targetUser = await User.findById(userId); + if (!targetUser) { + return res.status(404).json({ message: "User not found" }); + } + + // Find the logged-in user by their username + const loggedInUser = await User.findOne({ username: followerUsername }); + + if (!loggedInUser) { + return res.status(404).json({ message: "Logged-in user not found" }); + } + + // Check if already following + const isFollowing = targetUser.followers.includes(loggedInUser._id); + + if (isFollowing) { + // Unfollow: Remove the target user from logged-in user's following and vice versa + targetUser.followers = targetUser.followers.filter( + (followerId) => followerId.toString() !== loggedInUser._id.toString() + ); + loggedInUser.following = loggedInUser.following.filter( + (followingId) => followingId.toString() !== targetUser._id.toString() + ); + await targetUser.save(); + await loggedInUser.save(); + + return res.status(200).json({ + message: `Successfully unfollowed ${targetUser.username}`, + username: targetUser.username, + followingCount: loggedInUser.following.length, + followersCount: targetUser.followers.length, + }); + } else { + // Follow: Add the target user to logged-in user's following and vice versa + targetUser.followers.push(loggedInUser._id); + loggedInUser.following.push(targetUser._id); + await targetUser.save(); + await loggedInUser.save(); + + return res.status(200).json({ + message: `Successfully followed ${targetUser.username}`, + username: targetUser.username, + followingCount: loggedInUser.following.length, + followersCount: targetUser.followers.length, + }); + } + } catch (error) { + console.error("Error toggling follow status:", error); + res.status(500).json({ message: "Internal server error" }); + } +}; + + + const UserController = { Signup, Login, getAllUserName, + toggleFollowUser, deleteUserById, verifyUserByToken, forgotPassword, diff --git a/backend/routes/web.js b/backend/routes/web.js index 28d5a666..b0182c62 100644 --- a/backend/routes/web.js +++ b/backend/routes/web.js @@ -16,6 +16,7 @@ router.get("/recipe/getcomments/:recipeId", RecipeController.getComments); router.post("/signup", UserController.Signup); router.post("/login", UserController.Login); router.post("/submitFeedback", UserController.submitFeedback); +router.post("/follow", UserController.toggleFollowUser); router.get('/feedback', UserController.getAllFeedback); router.get('/feedback/:id', UserController.getFeedbackByUserId); router.post("/feedback/delete", UserController.deleteFeedbackById); diff --git a/frontend/src/Pages/Dashboard.jsx b/frontend/src/Pages/Dashboard.jsx index 0149e810..b011b0e9 100644 --- a/frontend/src/Pages/Dashboard.jsx +++ b/frontend/src/Pages/Dashboard.jsx @@ -13,6 +13,8 @@ const Dashboard = () => { const backendURL = import.meta.env.VITE_BACKEND_URL; const token = JSON.parse(localStorage.getItem("tastytoken")); const user = useLocation().state.user; + const [userData, setUserData] = useState(null) + const path = useLocation().pathname; const [loading, setLoading] = useState(true); const [isModalOpen, setModalOpen] = useState(false); const [recipes, setRecipes] = useState([]); @@ -29,7 +31,28 @@ const Dashboard = () => { }; const [viewingState, setViewingState] = useState(ViewState.RECIPE); const inputFile = useRef(null); // for redirecting click to open input file - + useEffect(() => { + let token = localStorage.getItem("tastytoken"); + if (token) { + token = JSON.parse(token); + axios + .get(`${backendURL}/api/token`, { + headers: { + Authorization: `Bearer ${token}`, + }, + }) + .then((res) => { + if (res.data.success) { + setUserData(res.data); + } + }) + .catch((err) => { + console.log(err); + }); + } else { + setUserData(null); + } + }, [path]); // form to send image change request const [form, setForm] = useState({ id: user._id, @@ -153,7 +176,7 @@ const Dashboard = () => { setError("User data is not available."); } }, [user._id]); - + console.log(user) const handleDelete = (id) => { const val = confirm("Are you sure you want to delete this recipe?"); if (val) { @@ -371,10 +394,13 @@ const Dashboard = () => {
Meggings kinfolk echo park stumptown DIY, kale chips beard diff --git a/frontend/src/Pages/Profile.jsx b/frontend/src/Pages/Profile.jsx index b930e4b4..365cdbda 100644 --- a/frontend/src/Pages/Profile.jsx +++ b/frontend/src/Pages/Profile.jsx @@ -1,12 +1,12 @@ import { useState, useEffect } from 'react' -import { useParams } from 'react-router-dom' +import { useParams, useLocation } from 'react-router-dom' import axios from 'axios' export default function UserProfile() { const { id } = useParams() // Get the user ID from the URL params const backendURL = import.meta.env.VITE_BACKEND_URL const token = JSON.parse(localStorage.getItem("tastytoken")) // Token still comes from local storage for authentication - + const [user, setUser] = useState(null) const [username, setUsername] = useState("ChefJulia") const [bio, setBio] = useState("Passionate about creating delicious, healthy recipes that anyone can make!") const [imagePreview, setImagePreview] = useState("/placeholder.svg?height=128&width=128") @@ -18,6 +18,30 @@ export default function UserProfile() { const [activeTab, setActiveTab] = useState('recipes') const [loading, setLoading] = useState(false) const [error, setError] = useState(null) + const path = useLocation().pathname; + useEffect(() => { + let token = localStorage.getItem("tastytoken"); + if (token) { + token = JSON.parse(token); + axios + .get(`${backendURL}/api/token`, { + headers: { + Authorization: `Bearer ${token}`, + }, + }) + .then((res) => { + if (res.data.success) { + setUser(res.data); + } + }) + .catch((err) => { + console.log(err); + }); + } else { + setUser(null); + } + }, [path]); + useEffect(() => { // Fetch user information @@ -34,6 +58,8 @@ export default function UserProfile() { setImagePreview(res.data.profile) setFollowingCount(res.data.following.length) setFollowers(res.data.followers.length) + console.log(user) + setFollowing(res.data.followers.includes(user.user._id)) }) .catch((err) => { console.error("Error fetching user data", err) @@ -82,12 +108,20 @@ export default function UserProfile() { fetchUserImage() fetchRecipes() fetchLikedRecipes() // Call the fetchLikedRecipes function to get liked recipes - }, [id, backendURL, token]) // Use id, backendURL, and token in dependencies + }, [id, backendURL, token, user]) // Use id, backendURL, and token in dependencies - const handleFollow = () => { - setFollowing(!following) - setFollowers(followers + (following ? -1 : 1)) - } + const handleFollow = async () => { + try { + await axios.post(`${backendURL}/api/follow`, + { username: JSON.parse(localStorage.getItem("username")), userId: id }, + { headers: { Authorization: `Bearer ${token}` }} + ); + setFollowing(!following); + setFollowers(followers + (following ? -1 : 1)); + } catch (err) { + console.error("Error updating follow status", err); + } + }; return (