import React, { useEffect, useMemo } from 'react'; import { useSocialStore } from '../../stores/socialStore'; import { useUIStore } from '../../stores/uiStore'; import { useActivityStore } from '../../stores/activityStore'; import { Avatar } from '../ui/Avatar'; import { Username } from '../ui/Username'; import { ActivityCard, hasRichActivity, getActivityAccentClass } from '../ui/ActivityCard'; import type { Friend } from '@backspace/shared'; import { getPrimaryActivity } from '@backspace/shared/src/activities.js'; import { parseFederatedUsername } from '../../utils/identity'; export function ActivityPanel() { const friends = useSocialStore((s) => s.friends); const loadFriends = useSocialStore((s) => s.loadFriends); const memberListOpen = useUIStore((s) => s.memberListOpen); const openUserProfile = useUIStore((s) => s.openUserProfile); const userActivities = useActivityStore((s) => s.userActivities); useEffect(() => { loadFriends(); }, [loadFriends]); const { activeFriends, onlineFriends, offlineFriends } = useMemo(() => { const active: Friend[] = []; const online: Friend[] = []; const offline: Friend[] = []; for (const f of friends) { if (f.status === 'offline') { offline.push(f); continue; } const activities = userActivities.get(f.homeUserId ?? f.id) ?? []; const primary = getPrimaryActivity(activities); // Active = has a non-custom activity (playing, listening, watching, streaming) if (primary && primary.type !== 'custom') { active.push(f); } else { online.push(f); } } return { activeFriends: active, onlineFriends: online, offlineFriends: offline }; }, [friends, userActivities]); if (!memberListOpen) return null; const handleFriendClick = (e: React.MouseEvent, friend: Friend) => { e.stopPropagation(); const rect = e.currentTarget.getBoundingClientRect(); openUserProfile( { id: friend.id, username: friend.username, displayName: friend.displayName, avatar: friend.avatar, banner: friend.banner, accentColor: friend.accentColor, avatarColor: friend.avatarColor, bio: friend.bio, status: friend.status, customStatus: friend.customStatus, createdAt: friend.createdAt, homeUserId: friend.homeUserId, homeInstance: friend.homeInstance, isAdmin: false, replicatedInstances: [], }, { top: Math.min(rect.top, window.innerHeight - 450), left: rect.left - 316, } ); }; const renderFriend = (friend: Friend, isOffline = false) => { const { baseName, domain } = parseFederatedUsername(friend.username); const friendDisplayName = friend.displayName ?? baseName; const activities = userActivities.get(friend.homeUserId ?? friend.id) ?? []; const isRichActivity = !isOffline && hasRichActivity(activities); const primary = getPrimaryActivity(activities); const accentClass = primary ? getActivityAccentClass(primary.type) : ''; const rowClass = isRichActivity ? `flex items-center gap-2.5 px-2.5 py-2 rounded-[10px] mb-1 cursor-pointer transition-colors glass-pill border-l-2 ${accentClass}` : 'flex items-center gap-2.5 px-2 py-1.5 rounded-[4px] hover:bg-interactive-hover cursor-pointer group transition-colors'; return (