Fix: member count in header and member list (#30982)

* fix: same member count in header and member list

* test: update test

* chore: use `useRoomMemberCount` to compute member count in member list

* test: add event emitter function on mocked `room.currentState`
This commit is contained in:
Florian Duros
2025-10-09 12:40:20 +02:00
committed by GitHub
parent b45488fc84
commit 3098eba4f2
4 changed files with 24 additions and 7 deletions

View File

@@ -38,6 +38,7 @@ import { isValid3pidInvite } from "../../../RoomInvite";
import { type ThreePIDInvite } from "../../../models/rooms/ThreePIDInvite";
import { type XOR } from "../../../@types/common";
import { useTypedEventEmitter } from "../../../hooks/useEventEmitter";
import { useRoomMemberCount } from "../../../hooks/useRoomMembers";
type Member = XOR<{ member: RoomMember }, { threePidInvite: ThreePIDInvite }>;
@@ -126,6 +127,9 @@ export function useMemberListViewModel(roomId: string): MemberListViewState {
const [isLoading, setIsLoading] = useState<boolean>(true);
// This is the last known total number of members in this room.
const [totalMemberCount, setTotalMemberCount] = useState(0);
const memberCountWithout3Pid = useRoomMemberCount(room, { includeInvited: true });
/**
* This is the current number of members in the list.
* This number will be less than the total number of members
@@ -168,7 +172,7 @@ export function useMemberListViewModel(roomId: string): MemberListViewState {
}
setMemberMap(newMemberMap);
setMemberCount(joinedSdk.length + invitedSdk.length + threePidInvited.length);
setMemberCount(memberCountWithout3Pid + threePidInvited.length);
if (!searchQuery) {
/**
* Since searching for members only gives you the relevant
@@ -180,7 +184,7 @@ export function useMemberListViewModel(roomId: string): MemberListViewState {
500,
{ leading: true, trailing: true },
),
[sdkContext.memberListStore, roomId, room],
[sdkContext.memberListStore, roomId, room, memberCountWithout3Pid],
);
const isPresenceEnabled = useMemo(

View File

@@ -71,7 +71,7 @@ export default function RoomHeader({
const joinRule = useRoomState(room, (state) => state.getJoinRule());
const members = useRoomMembers(room, 2500);
const memberCount = useRoomMemberCount(room, { throttleWait: 2500 });
const memberCount = useRoomMemberCount(room, { throttleWait: 2500, includeInvited: true });
const {
voiceCallDisabledReason,

View File

@@ -38,6 +38,11 @@ type RoomMemberCountOpts = {
* Wait time between room member count update
*/
throttleWait?: number;
/**
* Whether to include invited members in the count
* @default false
*/
includeInvited?: boolean;
};
/**
@@ -48,19 +53,21 @@ type RoomMemberCountOpts = {
*/
export const useRoomMemberCount = (
room: Room,
{ throttleWait }: RoomMemberCountOpts = { throttleWait: 250 },
{ throttleWait, includeInvited }: RoomMemberCountOpts = { throttleWait: 250, includeInvited: false },
): number => {
const [count, setCount] = useState<number>(room.getJoinedMemberCount());
const [count, setCount] = useState<number>(
includeInvited ? room.getInvitedAndJoinedMemberCount() : room.getJoinedMemberCount(),
);
const throttledUpdate = useMemo(
() =>
throttle(
() => {
setCount(room.getJoinedMemberCount());
setCount(includeInvited ? room.getInvitedAndJoinedMemberCount() : room.getJoinedMemberCount());
},
throttleWait,
{ leading: true, trailing: true },
),
[room, throttleWait],
[room, throttleWait, includeInvited],
);
useTypedEventEmitter(room.currentState, RoomStateEvent.Members, throttledUpdate);

View File

@@ -108,6 +108,12 @@ export async function renderMemberList(
members: {},
getMember: jest.fn(),
getStateEvents: ((eventType, stateKey) => (stateKey === undefined ? [] : null)) as RoomState["getStateEvents"], // ignore 3pid invites
getInvitedMemberCount: jest.fn().mockReturnValue(0),
getJoinedMemberCount: jest
.fn()
.mockReturnValue(adminUsers.length + moderatorUsers.length + defaultUsers.length),
on: jest.fn(),
off: jest.fn(),
} as unknown as RoomState;
for (const member of [...adminUsers, ...moderatorUsers, ...defaultUsers]) {
memberListRoom.currentState.members[member.userId] = member;