import React, { useState, useEffect } from 'react'; import { useNavigate } from 'react-router-dom'; import { motion } from 'framer-motion'; import Navbar from './Navbar'; import Footer from './footer'; import './ProfilePage.css'; const ProfilePage = () => { const navigate = useNavigate(); const [isLoggedIn, setIsLoggedIn] = useState(false); const [isImageLoaded, setIsImageLoaded] = useState(false); const [newComment, setNewComment] = useState(''); const [userData, setUserData] = useState({ username: '', bio: 'No bio yet', profilePicture: '', posts: [], followers: [], following: [], postsCount: 0, }); const [showNewPostModal, setShowNewPostModal] = useState(false); const [showEditProfileModal, setShowEditProfileModal] = useState(false); const [showPostDetailModal, setShowPostDetailModal] = useState(false); const [selectedPost, setSelectedPost] = useState(null); const [likedPosts, setLikedPosts] = useState([]); const [showFollowModal, setShowFollowModal] = useState(false); const [followListType, setFollowListType] = useState(''); // 'followers' or 'following' const [followList, setFollowList] = useState([]); const [isLoadingFollowList, setIsLoadingFollowList] = useState(false); const [newPost, setNewPost] = useState({ image: null, description: '', tags: '', public: false, pin_id: null, likes: 0, comments: {}, }); const [editProfile, setEditProfile] = useState({ bio: '', profile_picture: null }); const [isUploading, setIsUploading] = useState(false); const [pins, setPins] = useState([]); // Default profile picture URL const defaultProfilePic = 'https://journeypoint-bucket.s3.us-east-2.amazonaws.com/uploads/default_profile_pic.jpg'; // Check login status and fetch data useEffect(() => { const storedUsername = localStorage.getItem('username'); const loginStatus = localStorage.getItem('login'); if (loginStatus === 'true' && storedUsername) { setIsLoggedIn(true); setUserData(prev => ({ ...prev, username: storedUsername, bio: 'No bio yet', profilePicture: defaultProfilePic })); fetchUserData(storedUsername); fetchUserPosts(storedUsername); fetchUserPins(storedUsername); } else { navigate('/login'); } }, [navigate]); // Handle post click const handlePostClick = (post) => { setSelectedPost(post); setShowPostDetailModal(true); }; // Fetch user profile data const fetchUserData = async (username) => { try { const response = await fetch(`https://jp-backend-kc80.onrender.com/api/getuser?username=${username}`); const user = await response.json(); if (user.length > 0) { setUserData(prev => ({ ...prev, username: user[0].username, bio: user[0].bio || 'No bio yet', profilePicture: user[0].profile_picture, followers: user[0].followers || [], following: user[0].following || [], })); } } catch (error) { console.error('Error fetching user data:', error); } }; // Fetch user posts const fetchUserPosts = async (username) => { try { const response = await fetch(`https://jp-backend-kc80.onrender.com/api/userposts?username=${username}`); const data = await response.json(); setUserData(prev => ({ ...prev, posts: Array.isArray(data) ? data : [], postsCount: Array.isArray(data) ? data.length : 0 })); } catch (error) { console.error('Error fetching user posts:', error); } }; // Fetch user pins const fetchUserPins = async (username) => { try { const response = await fetch(`https://jp-backend-kc80.onrender.com/api/pins?username=${username}`); const data = await response.json(); setPins(Array.isArray(data) ? data : []); } catch (error) { console.error('Error fetching pins:', error); } }; const showFollowList = async (type) => { setFollowListType(type); setIsLoadingFollowList(true); setShowFollowModal(true); try { // Get the appropriate list of usernames const usernames = type === 'followers' ? userData.followers : userData.following; // Fetch details for each user in parallel const usersData = await Promise.all( usernames.map(async (username) => { const response = await fetch(`https://jp-backend-kc80.onrender.com/api/getuser?username=${username}`); const user = await response.json(); return user[0]; // Assuming the API returns an array }) ); setFollowList(usersData.filter(user => user)); // Filter out any undefined users } catch (error) { console.error(`Error fetching ${type}:`, error); setFollowList([]); // Reset on error } finally { setIsLoadingFollowList(false); } }; // Upload image and return URL const uploadImage = async (file) => { const formData = new FormData(); formData.append('file', file); try { const response = await fetch('https://jp-backend-kc80.onrender.com/upload/', { method: 'POST', body: formData, }); const data = await response.json(); return data.image_url; } catch (error) { console.error('Error uploading image:', error); return null; } }; const handleDeletePost = async (postId) => { if (!window.confirm('Are you sure you want to delete this post?')) { return; } try { const response = await fetch(`https://jp-backend-kc80.onrender.com/api/userposts/${postId}/delete`, { method: 'DELETE', }); if (!response.ok) throw new Error('Failed to delete post'); // Remove the post from local state setUserData(prev => ({ ...prev, posts: prev.posts.filter(post => post.id !== postId), postsCount: prev.postsCount - 1 })); // Close the modal if open setShowPostDetailModal(false); alert('Post deleted successfully'); } catch (error) { console.error('Error deleting post:', error); alert('Failed to delete post. Please try again.'); } }; // Handle new post submission const handleNewPostSubmit = async (e) => { e.preventDefault(); if (!newPost.image || !userData.username) return; setIsUploading(true); try { const imageUrl = await uploadImage(newPost.image); if (!imageUrl) throw new Error('Image upload failed'); const postData = { username: userData.username, image_url: imageUrl, description: newPost.description, tags: newPost.tags, public: newPost.public }; if (newPost.pin_id) { postData.pin_id = newPost.pin_id; } const response = await fetch(`https://jp-backend-kc80.onrender.com/api/userposts?username=${userData.username}`, { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify(postData), }); if (!response.ok) throw new Error('Post creation failed' + response + postData.pin_id); await fetchUserPosts(userData.username); setShowNewPostModal(false); setNewPost({ image: null, description: '', tags: '', public: false, pin_id: null }); } catch (error) { console.error('Error creating post:', error); alert('Failed to create post. Please try again.' + error); } finally { setIsUploading(false); } }; // Handle input changes const handleInputChange = (e) => { const { name, value, type, checked, files } = e.target; setNewPost(prev => ({ ...prev, [name]: type === 'checkbox' ? checked : (type === 'file' ? files[0] : value) })); }; // Handle edit profile changes const handleEditProfileChange = (e) => { const { name, value, files } = e.target; setEditProfile(prev => ({ ...prev, [name]: name === 'profile_picture' ? files[0] : value })); }; // Handle edit profile submission const handleEditProfileSubmit = async (e) => { e.preventDefault(); if (!userData.username) return; //setIsUploading(true); try { //let profilePicUrl = userData.profilePicture === defaultProfilePic ? '' : userData.profilePicture; //if (editProfile.profile_picture) { //profilePicUrl = await uploadImage(editProfile.profile_picture); //if (!profilePicUrl) throw new Error('Profile picture upload failed'); //} const formData = new FormData(); if (editProfile.bio) { formData.append("bio", editProfile.bio); // profile_picture should be a File object } if (editProfile.profile_picture) { formData.append("profile_picture", editProfile.profile_picture); // profile_picture should be a File object } const response = await fetch(`https://jp-backend-kc80.onrender.com/api/userupdate/${userData.username}`, { method: 'PATCH', body: formData, }); if (!response.ok) throw new Error('Profile update failed' + response.status); await fetchUserData(userData.username); setShowEditProfileModal(false); } catch (error) { console.error('Error updating profile:', error); alert('Failed to update profile. Please try again.' + error); } finally { setIsUploading(false); } }; const handleAddComment = async (e) => { e.preventDefault(); if (!newComment.trim() || !selectedPost || !userData.username) return; try { const response = await fetch(`https://jp-backend-kc80.onrender.com/api/userposts/${selectedPost.id}/comment`, { method: 'PATCH', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ username: userData.username, comment: newComment }), }); if (!response.ok) throw new Error('Failed to add comment'); // Create the new comment entry const newCommentEntry = { [userData.username]: newComment }; // Update the selected post setSelectedPost(prev => ({ ...prev, comments: { ...(prev.comments || {}), ...newCommentEntry } })); // Update the post in the main posts list setUserData(prev => ({ ...prev, posts: prev.posts.map(post => post.id === selectedPost.id ? { ...post, comments: { ...(post.comments || {}), ...newCommentEntry } } : post ) })); setNewComment(''); } catch (error) { console.error('Error adding comment:', error); alert('Failed to add comment. Please try again.'); } }; const handleLikePost = async (postId) => { // Check if user already liked this post if (likedPosts.includes(postId)) { return; } try { const response = await fetch(`https://jp-backend-kc80.onrender.com/api/userposts/${postId}/like`, { method: 'PATCH', headers: { 'Content-Type': 'application/json', }, }); if (!response.ok) throw new Error('Failed to like post'); const result = await response.json(); // Update liked posts state setLikedPosts(prev => [...prev, postId]); // Update the selected post's like count setSelectedPost(prev => ({ ...prev, likes: result.likes })); // Also update the post in the main posts list setUserData(prev => ({ ...prev, posts: prev.posts.map(post => post.id === postId ? { ...post, likes: result.likes } : post ) })); } catch (error) { console.error('Error liking post:', error); alert('Failed to like post. Please try again.'); } }; // Open edit profile modal with current data const openEditProfileModal = () => { setEditProfile({ bio: userData.bio, profile_picture: null }); setShowEditProfileModal(true); }; return (
{/* Profile Header Section */}
Profile setIsImageLoaded(true)} onError={(e) => { e.target.onerror = null; e.target.src = defaultProfilePic; setIsImageLoaded(true); }} />
{userData.username}
{userData.postsCount} posts showFollowList('followers')} > {userData.followers.length} followers showFollowList('following')} > {userData.following.length} following
{userData.bio}
{/* Posts Grid Section */} {userData.posts.length > 0 ? (
{userData.posts.map((post, index) => (
handlePostClick(post)}> {`Post
❤️ {post.likes || 0} 💬 {Object.keys(post.comments || {}).length}
))}
) : (

Share Photos

When you share photos, they will appear on your profile.

)}
{/* Post Detail Modal */} {showPostDetailModal && selectedPost && (
setShowPostDetailModal(false)}> e.stopPropagation()} >
Post
Profile {userData.username}
{userData.username === selectedPost.username && ( )}

{selectedPost.description}

Tags: {selectedPost.tags || 'No tags'}
{selectedPost.pin_id && (
Location: {pins.find(pin => pin.id === selectedPost.pin_id)?.pin_name || 'Unknown location'}
)}
💬 {Object.keys(selectedPost.comments || {}).length} comments
{/* Comments section */}

Comments

{Object.keys(selectedPost.comments || {}).length > 0 ? (
{Object.entries(selectedPost.comments || {}).map(([username, comment]) => (
{username}: {comment}
))}
) : (

No comments yet

)}
setNewComment(e.target.value)} />
Posted on: {new Date(selectedPost.created_at).toLocaleDateString()}
)} {/* New Post Modal */} {showNewPostModal && (
!isUploading && setShowNewPostModal(false)}> e.stopPropagation()} >
{newPost.image ? ( Preview ) : (

Image preview will appear here

)}

Create Post