diff --git a/src/components/viewmodels/memberlist/MemberListViewModel.tsx b/src/components/viewmodels/memberlist/MemberListViewModel.tsx index a03f703511..41233a4d6f 100644 --- a/src/components/viewmodels/memberlist/MemberListViewModel.tsx +++ b/src/components/viewmodels/memberlist/MemberListViewModel.tsx @@ -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(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( diff --git a/src/components/views/rooms/RoomHeader/RoomHeader.tsx b/src/components/views/rooms/RoomHeader/RoomHeader.tsx index 5a8bd77cf8..7f6e5ce29b 100644 --- a/src/components/views/rooms/RoomHeader/RoomHeader.tsx +++ b/src/components/views/rooms/RoomHeader/RoomHeader.tsx @@ -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, diff --git a/src/hooks/useRoomMembers.ts b/src/hooks/useRoomMembers.ts index 14448ba307..44007c82e1 100644 --- a/src/hooks/useRoomMembers.ts +++ b/src/hooks/useRoomMembers.ts @@ -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(room.getJoinedMemberCount()); + const [count, setCount] = useState( + 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); diff --git a/test/unit-tests/components/views/rooms/memberlist/common.tsx b/test/unit-tests/components/views/rooms/memberlist/common.tsx index 592155841f..30ea7e9c81 100644 --- a/test/unit-tests/components/views/rooms/memberlist/common.tsx +++ b/test/unit-tests/components/views/rooms/memberlist/common.tsx @@ -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;