fix(calls): sidebar voice-channel join respects the voice limit

channelFull was computed only in the prescreen; a second click on the
channel in the room nav joined a full channel. Extract
useVoiceChannelFull, use it in both places, and refuse with a
"Channel full (N/N)" toast.

Fixes #30

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PPmy3tPq869XDW4njjVaKA
This commit is contained in:
2026-09-12 19:46:06 -04:00
co-authored by Claude Opus 5
parent fc68e0a769
commit 26c70f5a1d
3 changed files with 60 additions and 9 deletions
+34
View File
@@ -0,0 +1,34 @@
import { Room } from 'matrix-js-sdk';
import { useMemo } from 'react';
import { useStateEvent } from './useStateEvent';
import { StateEvent } from '../../types/matrix/room';
import { VoiceLimitContent } from '../features/common-settings/general/RoomVoiceLimit';
import { useCallMembers, useCallSession } from './useCall';
import { useMatrixClient } from './useMatrixClient';
export type VoiceChannelFull = {
channelFull: boolean;
current: number;
max: number;
};
/**
* [Gitea #30] Voice channel user limit (`io.lotus.voice_limit`), shared between
* `CallPrescreen` and any other join path (e.g. the room-nav second-click join)
* so they agree on when a channel is full. 0/absent `max_users` means no limit.
*/
export const useVoiceChannelFull = (room: Room): VoiceChannelFull => {
const mx = useMatrixClient();
const callSession = useCallSession(room);
const callMembers = useCallMembers(callSession);
const limitEvent = useStateEvent(room, StateEvent.LotusVoiceLimit);
return useMemo(() => {
const maxUsers = limitEvent?.getContent<VoiceLimitContent>().max_users ?? 0;
// A user already counted in the session is rejoining and should not be blocked.
const alreadyMember = callMembers.some((m) => m.sender === mx.getSafeUserId());
const channelFull = maxUsers > 0 && !alreadyMember && callMembers.length >= maxUsers;
return { channelFull, current: callMembers.length, max: maxUsers };
}, [limitEvent, callMembers, mx]);
};