Files
cinny/src/app/hooks/useUserPresence.ts
T

67 lines
2.2 KiB
TypeScript
Raw Normal View History

2025-08-09 17:46:10 +05:30
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+.
2025-08-09 17:46:10 +05:30
const updatePresence: UserEventHandlerMap[UserEvent.Presence] = (event, u) => {
if (u.userId === user?.userId) {
setPresence(getUserPresence(u));
2025-08-09 17:46:10 +05:30
}
};
mx.on(UserEvent.Presence, updatePresence);
mx.on(UserEvent.CurrentlyActive, updatePresence);
mx.on(UserEvent.LastPresenceTs, updatePresence);
2025-08-09 17:46:10 +05:30
return () => {
mx.removeListener(UserEvent.Presence, updatePresence);
mx.removeListener(UserEvent.CurrentlyActive, updatePresence);
mx.removeListener(UserEvent.LastPresenceTs, updatePresence);
2025-08-09 17:46:10 +05:30
};
}, [mx, user]);
2025-08-09 17:46:10 +05:30
return presence;
};
export const usePresenceLabel = (): Record<Presence, string> =>
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.
2025-08-09 17:46:10 +05:30
() => ({
[Presence.Online]: 'Online',
[Presence.Unavailable]: 'Idle',
[Presence.Offline]: 'Offline',
2025-08-09 17:46:10 +05:30
}),
[],
2025-08-09 17:46:10 +05:30
);