+
+ { t('participantsPane.headings.visitors', { count: visitorsCount })}
+ { requests.length > 0
+ && t('participantsPane.headings.visitorRequests', { count: requests.length }) }
+
+ {
+ requests.length > 1
+ &&
{t('participantsPane.actions.admitAll')}
+ }
+
+
+ {
+ requests.map(r => (
+ )
+ )
+ }
+
+ >
+ );
+}
diff --git a/react/features/participants-pane/hooks.web.ts b/react/features/participants-pane/hooks.web.ts
index 0b3f47a4b8d0..6aedd2660bd4 100644
--- a/react/features/participants-pane/hooks.web.ts
+++ b/react/features/participants-pane/hooks.web.ts
@@ -24,16 +24,16 @@ export function useLobbyActions(participant?: IDrawerParticipant | null, closeDr
e.stopPropagation();
dispatch(approveKnockingParticipant(participant?.participantID ?? ''));
closeDrawer?.();
- }, [ dispatch, closeDrawer ]),
+ }, [ dispatch, closeDrawer, participant?.participantID ]),
useCallback(() => {
dispatch(rejectKnockingParticipant(participant?.participantID ?? ''));
closeDrawer?.();
- }, [ dispatch, closeDrawer ]),
+ }, [ dispatch, closeDrawer, participant?.participantID ]),
useCallback(() => {
dispatch(handleLobbyChatInitialized(participant?.participantID ?? ''));
- }, [ dispatch ])
+ }, [ dispatch, participant?.participantID ])
];
}
diff --git a/react/features/polls/middleware.ts b/react/features/polls/middleware.ts
index bcce701f8317..8205627057ce 100644
--- a/react/features/polls/middleware.ts
+++ b/react/features/polls/middleware.ts
@@ -63,13 +63,23 @@ MiddlewareRegistry.register(({ dispatch, getState }) => next => action => {
conference.on(JitsiConferenceEvents.ENDPOINT_MESSAGE_RECEIVED,
(user: any, data: any) => {
- data.type === COMMAND_NEW_POLL ? data.senderId = user._id : data.voterId = user._id;
- _handleReceivePollsMessage(data, dispatch);
+ const isNewPoll = data.type === COMMAND_NEW_POLL;
+
+ _handleReceivePollsMessage({
+ ...data,
+ senderId: isNewPoll ? user._id : undefined,
+ voterId: isNewPoll ? undefined : user._id
+ }, dispatch);
});
conference.on(JitsiConferenceEvents.NON_PARTICIPANT_MESSAGE_RECEIVED,
(id: any, data: any) => {
- data.type === COMMAND_NEW_POLL ? data.senderId = id : data.voterId = id;
- _handleReceivePollsMessage(data, dispatch);
+ const isNewPoll = data.type === COMMAND_NEW_POLL;
+
+ _handleReceivePollsMessage({
+ ...data,
+ senderId: isNewPoll ? id : undefined,
+ voterId: isNewPoll ? undefined : id
+ }, dispatch);
});
break;
diff --git a/react/features/visitors/actionTypes.ts b/react/features/visitors/actionTypes.ts
index c434d9d8d00d..999e520a3714 100644
--- a/react/features/visitors/actionTypes.ts
+++ b/react/features/visitors/actionTypes.ts
@@ -17,3 +17,24 @@ export const UPDATE_VISITORS_COUNT = 'UPDATE_VISITORS_COUNT';
* }
*/
export const I_AM_VISITOR_MODE = 'I_AM_VISITOR_MODE';
+
+/**
+ * The type of (redux) action which indicates that a promotion request was received from a visitor.
+ *
+ * {
+ * type: VISITOR_PROMOTION_REQUEST,
+ * nick: string,
+ * from: string
+ * }
+ */
+export const VISITOR_PROMOTION_REQUEST = 'VISITOR_PROMOTION_REQUEST';
+
+/**
+ * The type of (redux) action which indicates that a promotion response denied was received.
+ *
+ * {
+ * type: CLEAR_VISITOR_PROMOTION_REQUEST,
+ * request: IPromotionRequest
+ * }
+ */
+export const CLEAR_VISITOR_PROMOTION_REQUEST = 'CLEAR_VISITOR_PROMOTION_REQUEST';
diff --git a/react/features/visitors/actions.ts b/react/features/visitors/actions.ts
index 3ad9d28c1acc..13f58fe512df 100644
--- a/react/features/visitors/actions.ts
+++ b/react/features/visitors/actions.ts
@@ -1,4 +1,107 @@
-import { I_AM_VISITOR_MODE, UPDATE_VISITORS_COUNT } from './actionTypes';
+import { IStore } from '../app/types';
+import { getCurrentConference } from '../base/conference/functions';
+
+import {
+ CLEAR_VISITOR_PROMOTION_REQUEST,
+ I_AM_VISITOR_MODE,
+ UPDATE_VISITORS_COUNT,
+ VISITOR_PROMOTION_REQUEST
+} from './actionTypes';
+import { IPromotionRequest } from './types';
+
+/**
+ * Action used to admit multiple participants in the conference.
+ *
+ * @param {Array