import React, { useState, useEffect, useRef } from 'react'; import toast from 'react-hot-toast'; import api from '../api'; import { useClickOutside } from '../hooks/useClickOutside'; import { useSocket } from '../SocketContext'; export default function Friends() { const [friends, setFriends] = useState([]); const [challengeFriends, setChallengeFriends] = useState([]); const [requests, setRequests] = useState([]); const [searchQuery, setSearchQuery] = useState(''); const [searchResults, setSearchResults] = useState([]); const [loading, setLoading] = useState(true); const [searchTimeout, setSearchTimeout] = useState(null); const [responding, setResponding] = useState(null); const [sending, setSending] = useState(null); const { socket } = useSocket(); const searchRef = useRef(null); useClickOutside(searchRef, () => setSearchResults([])); useEffect(() => { loadData(); }, []); // Listen for real-time friend request events useEffect(() => { if (!socket) return; const handleFriendRequest = (request) => { toast.success(`👋 ${request.from_username} sent you a friend request`); loadData(); // Refresh to show new request }; const handleFriendResponse = (response) => { if (response.status === 'accepted') { toast.success(`🎉 ${response.friend_username} accepted your friend request!`); loadData(); // Refresh friends list } else { toast(`${response.friend_username} declined your friend request`); } }; socket.on('friend:request', handleFriendRequest); socket.on('friend:response', handleFriendResponse); return () => { socket.off('friend:request', handleFriendRequest); socket.off('friend:response', handleFriendResponse); }; }, [socket]); const loadData = async () => { try { const [friendsData, requestsData] = await Promise.all([ api.getFriends(), api.getFriendRequests() ]); setFriends(friendsData.friends); setChallengeFriends(friendsData.challenge_friends || []); setRequests(requestsData.requests); } catch (err) { console.error('Failed to load data:', err); } finally { setLoading(false); } }; const handleSearch = (query) => { setSearchQuery(query); // Clear previous timeout if (searchTimeout) { clearTimeout(searchTimeout); } if (query.trim().length < 2) { setSearchResults([]); return; } // Debounce search by 1 second const timeout = setTimeout(async () => { try { const data = await api.searchUsers(query); setSearchResults(data.users); } catch (err) { console.error('Search failed:', err); } }, 1000); setSearchTimeout(timeout); }; const handleSendRequest = async (userId) => { setSending(userId); try { await api.sendFriendRequest(userId); setSearchQuery(''); setSearchResults([]); toast.success('Friend request sent!'); } catch (err) { toast.error('Failed to send request: ' + err.message); } finally { setSending(null); } }; const handleRespond = async (requestId, status) => { setResponding(requestId); try { await api.respondToFriendRequest(requestId, status); toast.success(status === 'accepted' ? 'Friend request accepted!' : 'Friend request declined'); await loadData(); } catch (err) { toast.error('Failed to respond: ' + err.message); } finally { setResponding(null); } }; if (loading) { return
No friends yet. Search above to add some!
) : (