import { useEffect, useMemo, useState } from 'react'; import { User, UserEvent, UserEventHandlerMap } from 'matrix-js-sdk'; import { useMatrixClient } from './useMatrixClient'; export enum Presence { Online = 'online', Unavailable = 'unavailable', Offline = 'offline', } export type UserPresence = { presence: Presence; status?: string; active: boolean; lastActiveTs?: number; }; const getUserPresence = (user: User): UserPresence => ({ presence: user.presence as Presence, status: user.presenceStatusMsg, active: user.currentlyActive, lastActiveTs: user.getLastActiveTs(), }); export const useUserPresence = (userId: string): UserPresence | undefined => { const mx = useMatrixClient(); const user = mx.getUser(userId); const [presence, setPresence] = useState(() => (user ? getUserPresence(user) : undefined)); useEffect(() => { // Subscribe on mx (MatrixClient) rather than on individual User objects. // User objects have a default 10-listener limit; the same user can appear // in many components simultaneously (avatars, member list, etc.) and // per-user subscription causes MaxListenersExceededWarning at 11+. const updatePresence: UserEventHandlerMap[UserEvent.Presence] = (event, u) => { if (u.userId === user?.userId) { setPresence(getUserPresence(u)); } }; mx.on(UserEvent.Presence, updatePresence); mx.on(UserEvent.CurrentlyActive, updatePresence); mx.on(UserEvent.LastPresenceTs, updatePresence); return () => { mx.removeListener(UserEvent.Presence, updatePresence); mx.removeListener(UserEvent.CurrentlyActive, updatePresence); mx.removeListener(UserEvent.LastPresenceTs, updatePresence); }; }, [mx, user]); return presence; }; export const usePresenceLabel = (): Record => useMemo( // Keep this vocabulary aligned with the status setter (PresencePicker in // SettingsTab.tsx): online -> "Online", unavailable -> "Idle". Previously // these read "Active"/"Busy"/"Away", so a user who set "Idle" showed as // "Busy" to others. () => ({ [Presence.Online]: 'Online', [Presence.Unavailable]: 'Idle', [Presence.Offline]: 'Offline', }), [], );