import { useEffect } from 'react'; import { Room, RoomStateEvent, RoomStateEventHandlerMap } from 'matrix-js-sdk'; import { useMatrixClient } from './useMatrixClient'; import { useMediaAuthentication } from './useMediaAuthentication'; import { useForceUpdate } from './useForceUpdate'; import { getMemberName } from '../utils/room'; import { mxcUrlToHttp } from '../utils/matrix'; export type MemberAvatar = { name: string; avatarUrl: string | undefined; }; /** * Resolve a room member's display name and avatar http url, staying reactive to * that member's profile (name/avatar/membership) changes. * * Mirrors the reactivity pattern in ReadReceiptAvatars (N6): subscribe to * `RoomStateEvent.Members` filtered to this room + userId and force a re-render, * since `RoomMemberEvent` has no dedicated Avatar signal. */ export const useMemberAvatar = ( room: Room, userId: string, width = 32, height = 32, resizeMethod = 'crop', ): MemberAvatar => { const mx = useMatrixClient(); const useAuthentication = useMediaAuthentication(); const [, forceUpdate] = useForceUpdate(); useEffect(() => { const handleMembers: RoomStateEventHandlerMap[RoomStateEvent.Members] = ( event, _state, member, ) => { if (event.getRoomId() === room.roomId && member.userId === userId) { forceUpdate(); } }; mx.on(RoomStateEvent.Members, handleMembers); return () => { mx.removeListener(RoomStateEvent.Members, handleMembers); }; }, [mx, room.roomId, userId, forceUpdate]); const name = getMemberName(room, userId); const avatarMxc = room.getMember(userId)?.getMxcAvatarUrl(); const avatarUrl = avatarMxc ? (mxcUrlToHttp(mx, avatarMxc, useAuthentication, width, height, resizeMethod) ?? undefined) : undefined; return { name, avatarUrl }; };