From e08492236a46588cd2f55cb9ac07a76806eca0b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rados=C5=82aw=20Gierwia=C5=82o?= Date: Fri, 14 Nov 2025 18:04:10 +0100 Subject: [PATCH] feat: show all checked-in participants in event chat sidebar - Display all event participants (not just online users) - Add online/offline status indicator (green/gray dot) - Sort users: online first, then offline - Show participant count and online count separately - Load participants via /api/events/:slug/details endpoint - Users can see who's checked in and has declared heats even when offline This allows users to see the full picture of event participation, not just who's currently connected to the chat. --- frontend/src/pages/EventChatPage.jsx | 93 +++++++++++++++++++++------- 1 file changed, 70 insertions(+), 23 deletions(-) diff --git a/frontend/src/pages/EventChatPage.jsx b/frontend/src/pages/EventChatPage.jsx index c2e2c99..6db3194 100644 --- a/frontend/src/pages/EventChatPage.jsx +++ b/frontend/src/pages/EventChatPage.jsx @@ -17,6 +17,7 @@ const EventChatPage = () => { const [messages, setMessages] = useState([]); const [newMessage, setNewMessage] = useState(''); const [activeUsers, setActiveUsers] = useState([]); + const [checkedInUsers, setCheckedInUsers] = useState([]); const [isConnected, setIsConnected] = useState(false); const [loadingOlder, setLoadingOlder] = useState(false); const [hasMore, setHasMore] = useState(true); @@ -65,11 +66,11 @@ const EventChatPage = () => { fetchEvent(); }, [slug]); - // Load heats data + // Load heats data and checked-in users useEffect(() => { if (!event || !isParticipant) return; - const loadHeats = async () => { + const loadData = async () => { try { // Load my heats const myHeatsData = await heatsAPI.getMyHeats(slug); @@ -83,13 +84,28 @@ const EventChatPage = () => { heatsMap.set(userHeat.userId, userHeat.heats); }); setUserHeats(heatsMap); + + // Load all checked-in users (participants) + const eventDetails = await eventsAPI.getDetails(slug); + if (eventDetails.data && eventDetails.data.participants) { + const participants = eventDetails.data.participants + .map(p => ({ + userId: p.user.id, + username: p.user.username, + avatar: p.user.avatar || `https://api.dicebear.com/7.x/avataaars/svg?seed=${p.user.username}`, + firstName: p.user.firstName, + lastName: p.user.lastName, + })) + .filter(p => p.userId !== user.id); // Exclude current user + setCheckedInUsers(participants); + } } catch (error) { - console.error('Failed to load heats:', error); + console.error('Failed to load data:', error); } }; - loadHeats(); - }, [event, isParticipant, slug]); + loadData(); + }, [event, isParticipant, slug, user.id]); useEffect(() => { scrollToBottom(); @@ -279,6 +295,23 @@ const EventChatPage = () => { ); }; + // Combine checked-in users with online status + const getAllDisplayUsers = () => { + const activeUserIds = new Set(activeUsers.map(u => u.userId)); + + // Merge checked-in users with online status + const allUsers = checkedInUsers.map(user => ({ + ...user, + isOnline: activeUserIds.has(user.userId), + })); + + // Sort: online first, then offline + return allUsers.sort((a, b) => { + if (a.isOnline === b.isOnline) return 0; + return a.isOnline ? -1 : 1; + }); + }; + const handleLeaveEvent = async () => { try { setIsLeaving(true); @@ -428,12 +461,15 @@ const EventChatPage = () => { )}
- {/* Active Users Sidebar */} + {/* Participants Sidebar */}
-

- Active users ({activeUsers.filter(u => !shouldHideUser(u.userId)).length}) +

+ Participants ({getAllDisplayUsers().filter(u => !shouldHideUser(u.userId)).length})

+

+ {activeUsers.length} online +

{/* Filter Checkbox */} {myHeats.length > 0 && ( @@ -450,30 +486,41 @@ const EventChatPage = () => { )}
- {activeUsers.filter(u => !shouldHideUser(u.userId)).length === 0 && ( -

No other users online

+ {getAllDisplayUsers().filter(u => !shouldHideUser(u.userId)).length === 0 && ( +

No other participants

)}
- {activeUsers - .filter((activeUser) => !shouldHideUser(activeUser.userId)) - .map((activeUser) => { - const thisUserHeats = userHeats.get(activeUser.userId) || []; + {getAllDisplayUsers() + .filter((displayUser) => !shouldHideUser(displayUser.userId)) + .map((displayUser) => { + const thisUserHeats = userHeats.get(displayUser.userId) || []; const hasHeats = thisUserHeats.length > 0; return (
- {activeUser.username} +
+ {displayUser.username} + {/* Online/Offline indicator */} +
+
-

- {activeUser.username} +

+ {displayUser.username}

{/* Heat Badges */} {hasHeats && ( @@ -496,7 +543,7 @@ const EventChatPage = () => {