feat(visitors-list): Add to participant pane.

This commit is contained in:
Hristo Terezov
2025-06-27 19:17:32 -05:00
parent 7bed0b36bd
commit 877fc98eef
14 changed files with 461 additions and 5 deletions

View File

@@ -5,6 +5,7 @@ import { IStore } from '../app/types';
import { IStateful } from '../base/app/types';
import {
CONFERENCE_JOINED,
CONFERENCE_WILL_LEAVE,
ENDPOINT_MESSAGE_RECEIVED,
UPDATE_CONFERENCE_METADATA
} from '../base/conference/actionTypes';
@@ -35,7 +36,7 @@ import { INotificationProps } from '../notifications/types';
import { open as openParticipantsPane } from '../participants-pane/actions';
import { joinConference } from '../prejoin/actions';
import { UPDATE_VISITORS_IN_QUEUE_COUNT } from './actionTypes';
import { SUBSCRIBE_VISITORS_LIST, UPDATE_VISITORS_IN_QUEUE_COUNT } from './actionTypes';
import {
approveRequest,
clearPromotionRequest,
@@ -45,10 +46,11 @@ import {
setInVisitorsQueue,
setVisitorDemoteActor,
setVisitorsSupported,
updateVisitorsInQueueCount
updateVisitorsInQueueCount,
updateVisitorsList
} from './actions';
import { JoinMeetingDialog } from './components';
import { getPromotionRequests, getVisitorsInQueueCount } from './functions';
import { getPromotionRequests, getVisitorsInQueueCount, isVisitorsListEnabled } from './functions';
import logger from './logger';
import { WebsocketClient } from './websocket-client';
@@ -135,6 +137,16 @@ MiddlewareRegistry.register(({ dispatch, getState }) => next => action => {
break;
}
case CONFERENCE_WILL_LEAVE: {
WebsocketClient.getInstance().disconnect();
break;
}
case SUBSCRIBE_VISITORS_LIST: {
if (isVisitorsListEnabled(getState()) && !WebsocketClient.getInstance().isActive()) {
_subscribeVisitorsList(getState, dispatch);
}
break;
}
case ENDPOINT_MESSAGE_RECEIVED: {
const { data } = action;
@@ -314,6 +326,63 @@ function _subscribeQueueStats(stateful: IStateful, dispatch: IStore['dispatch'])
toState(stateful)['features/base/jwt'].jwt);
}
function _subscribeVisitorsList(getState: IStore['getState'], dispatch: IStore['dispatch']) {
const state = getState();
const { visitors: visitorsConfig } = state['features/base/config'];
const conference = state['features/base/conference'].conference;
const meetingId = conference?.getMeetingUniqueId();
const localParticipant = getLocalParticipant(state);
const participantId = localParticipant?.id;
if (!visitorsConfig?.queueService || !meetingId || !participantId) {
logger.warn(`Missing required data for visitors list subscription', ${JSON.stringify({
queueService: visitorsConfig?.queueService,
meetingId,
participantId: participantId ? 'participantId present' : 'participantId missing'
})}`);
return;
}
const queueEndpoint = `/secured/conference/visitors-list/queue/${meetingId}/${participantId}`;
const topicEndpoint = `/secured/conference/visitors-list/topic/${meetingId}`;
logger.debug('Starting visitors list subscription');
WebsocketClient.getInstance()
.connectVisitorsListWithInitial(
`wss://${visitorsConfig.queueService}/visitors-list/websocket`,
queueEndpoint,
topicEndpoint,
// Initial list callback - replace entire list
initialVisitors => {
const visitors = initialVisitors.map(v => ({ id: v.r, name: v.n }));
dispatch(updateVisitorsList(visitors));
},
// Delta updates callback - apply incremental changes
updates => {
let visitors = [ ...(getState()['features/visitors'].visitors ?? []) ];
updates.forEach(u => {
if (u.s === 'j') {
const index = visitors.findIndex(v => v.id === u.r);
if (index === -1) {
visitors.push({ id: u.r, name: u.n });
} else {
visitors[index] = { id: u.r, name: u.n };
}
} else if (u.s === 'l') {
visitors = visitors.filter(v => v.id !== u.r);
}
});
dispatch(updateVisitorsList(visitors));
},
getState()['features/base/jwt'].jwt);
}
/**
* Function to handle the promotion notification.
*