diff --git a/backend/Controllers/UserController.js b/backend/Controllers/UserController.js index a1defd1..eeae297 100644 --- a/backend/Controllers/UserController.js +++ b/backend/Controllers/UserController.js @@ -465,11 +465,55 @@ const toggleFollowUser = async (req, res) => { + +import mongoose from "mongoose"; + +const getFollowerAndFollowingList = async (req, res) => { + const { id } = req.params; // Get the user ID from route params + + // Check if the user ID is valid (mongoose checks for ObjectId format) + if (!mongoose.Types.ObjectId.isValid(id)) { + return res.status(400).json({ message: "Invalid user ID" }); + } + + try { + // Find the user with the provided ID + const user = await User.findById(id); + + if (!user) { + return res.status(404).json({ message: "User not found" }); + } + + // Fetch the followers' details + const followers = await User.find({ '_id': { $in: user.followers } }) + .select('firstName lastName username profile'); // Only select necessary fields + + // Fetch the following details + const following = await User.find({ '_id': { $in: user.following } }) + .select('firstName lastName username profile'); // Only select necessary fields + + // Return the followers and following data + return res.json({ + followers, + following, + }); + } catch (err) { + console.error("Error fetching followers and following", err); + return res.status(500).json({ message: "Server error" }); + } +}; + +export { getFollowerAndFollowingList }; + + + + const UserController = { Signup, Login, getAllUserName, toggleFollowUser, + getFollowerAndFollowingList, deleteUserById, verifyUserByToken, forgotPassword, diff --git a/backend/routes/web.js b/backend/routes/web.js index 9c94815..5fe6703 100644 --- a/backend/routes/web.js +++ b/backend/routes/web.js @@ -20,6 +20,7 @@ router.get("/verify-account", VerificationController.verifyEmail); router.post("/reverify-account", VerificationController.resendVerificationEmail); router.post("/login", UserController.Login); +router.get("/user/:id/followers-following", UserController.getFollowerAndFollowingList); router.post("/submitFeedback", UserController.submitFeedback); router.post("/follow", UserController.toggleFollowUser); router.get('/feedback', UserController.getAllFeedback); diff --git a/frontend/src/Components/FollowerModal.jsx b/frontend/src/Components/FollowerModal.jsx new file mode 100644 index 0000000..b5abf94 --- /dev/null +++ b/frontend/src/Components/FollowerModal.jsx @@ -0,0 +1,67 @@ +// FollowModal.js +import React from 'react'; + +export default function FollowModal({ isOpen, onClose, followers, following, activeTab, setActiveTab }) { + console.log(following) + if (!isOpen) return null; + + return ( +
+
+
+

Followers & Following

+ +
+ + {/* Tab Header */} +
+ + +
+ + {/* Tab Content */} +
+ {activeTab === 'followers' ? ( + followers.length > 0 ? ( + followers.map((follower) => ( +
+ {follower.username} +
+ @{follower.username} + {follower.firstName} {follower.lastName} +
+
+ )) + ) : ( +

No followers found.

+ ) + ) : ( + following.length > 0 ? ( + following.map((followedUser) => ( +
+ {followedUser.username} +
+ @{followedUser.username} + {followedUser.firstName} {followedUser.lastName} +
+
+ )) + ) : ( +

No following users found.

+ ) + )} +
+
+
+ ); +} diff --git a/frontend/src/Pages/Profile.jsx b/frontend/src/Pages/Profile.jsx index 083caa5..faf1b5b 100644 --- a/frontend/src/Pages/Profile.jsx +++ b/frontend/src/Pages/Profile.jsx @@ -1,6 +1,6 @@ import { useState, useEffect } from 'react' import { useParams, useLocation } from 'react-router-dom' - +import FollowModal from '../Components/FollowerModal' import axios from 'axios' export default function UserProfile() { @@ -9,7 +9,8 @@ export default function UserProfile() { const token = JSON.parse(localStorage.getItem("tastytoken")) // Token still comes from local storage for authentication const [user, setUser] = useState(null) - +const [followingList, setFollowingList] = useState(null) + const [followersList, setFollowersList] = 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") @@ -48,6 +49,7 @@ export default function UserProfile() { useEffect(() => { + if (user) { // Fetch user information const fetchUserImage = () => { axios @@ -113,8 +115,8 @@ export default function UserProfile() { fetchUserImage() fetchRecipes() fetchLikedRecipes() // Call the fetchLikedRecipes function to get liked recipes - - }, [id, backendURL, token, user]) // Use id, backendURL, and token in dependencies + } + }, [user]) const handleFollow = async () => { try { @@ -128,8 +130,34 @@ export default function UserProfile() { console.error("Error updating follow status", err); } }; + useEffect(() => { + if(user){ + const fetchFollowersFollowing = async () => { + try { + const response = await axios.get(`${backendURL}/api/user/${id}/followers-following`); + setFollowersList(response.data.followers); + setFollowingList(response.data.following); + console.log(response) + setLoading(false); + } catch (err) { + setError("Error fetching data"); + setLoading(false); + } + }; + + fetchFollowersFollowing(); + } + }, [user]); + const [isModalOpen, setIsModalOpen] = useState(false); + const [activeModalTab, setActiveModalTab] = useState('followers'); // Tracks which tab to show in modal + const handleOpenModal = (tab) => { + setActiveModalTab(tab); + setIsModalOpen(true); + }; + + const handleCloseModal = () => setIsModalOpen(false); return (
{/* Banner and Profile Picture */} @@ -155,23 +183,31 @@ export default function UserProfile() {

{username}

{bio}

+ {(user && (user.user._id !== id)) && + className={`px-4 py-2 rounded-full ${ + following + ? 'bg-white text-red-700 border border-red-700 hover:bg-red-50' + : 'bg-red-700 text-white hover:bg-red-800' + }`} + onClick={handleFollow} + > + {following ? 'Following' : 'Follow'} + } + {/* User Stats */}
{recipes.length} Recipes - {followers} Followers - {followingCount} Following + + + +
@@ -252,6 +288,14 @@ export default function UserProfile() { )} + ) }