2022-11-23 09:12:26 +00:00
|
|
|
import { IStore } from '../app/types';
|
|
|
|
import { conferenceWillJoin, setPassword } from '../base/conference/actions';
|
|
|
|
import { getCurrentConference, sendLocalParticipant } from '../base/conference/functions';
|
|
|
|
import { getLocalParticipant } from '../base/participants/functions';
|
|
|
|
import { IParticipant } from '../base/participants/types';
|
2022-03-03 17:29:38 +00:00
|
|
|
import { onLobbyChatInitialized, removeLobbyChatParticipant, sendMessage } from '../chat/actions.any';
|
|
|
|
import { LOBBY_CHAT_MESSAGE } from '../chat/constants';
|
|
|
|
import { handleLobbyMessageReceived } from '../chat/middleware';
|
2022-11-23 09:12:26 +00:00
|
|
|
import { hideNotification, showNotification } from '../notifications/actions';
|
|
|
|
import { LOBBY_NOTIFICATION_ID } from '../notifications/constants';
|
2021-04-09 12:30:25 +00:00
|
|
|
|
2021-09-23 09:12:31 +00:00
|
|
|
import {
|
|
|
|
KNOCKING_PARTICIPANT_ARRIVED_OR_UPDATED,
|
|
|
|
KNOCKING_PARTICIPANT_LEFT,
|
2022-09-27 07:10:28 +00:00
|
|
|
REMOVE_LOBBY_CHAT_WITH_MODERATOR,
|
2021-09-23 09:12:31 +00:00
|
|
|
SET_KNOCKING_STATE,
|
|
|
|
SET_LOBBY_MODE_ENABLED,
|
2022-03-03 17:29:38 +00:00
|
|
|
SET_LOBBY_PARTICIPANT_CHAT_STATE,
|
2022-09-27 07:10:28 +00:00
|
|
|
SET_LOBBY_VISIBILITY,
|
|
|
|
SET_PASSWORD_JOIN_FAILED
|
2021-09-23 09:12:31 +00:00
|
|
|
} from './actionTypes';
|
2022-03-03 17:29:38 +00:00
|
|
|
import { LOBBY_CHAT_INITIALIZED, MODERATOR_IN_CHAT_WITH_LEFT } from './constants';
|
|
|
|
import { getKnockingParticipants, getLobbyEnabled } from './functions';
|
2022-11-23 09:12:26 +00:00
|
|
|
import { IKnockingParticipant } from './types';
|
2021-09-23 09:12:31 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Tries to join with a preset password.
|
|
|
|
*
|
|
|
|
* @param {string} password - The password to join with.
|
|
|
|
* @returns {Function}
|
|
|
|
*/
|
|
|
|
export function joinWithPassword(password: string) {
|
2022-11-23 09:12:26 +00:00
|
|
|
return async (dispatch: IStore['dispatch'], getState: IStore['getState']) => {
|
2021-09-23 09:12:31 +00:00
|
|
|
const conference = getCurrentConference(getState);
|
|
|
|
|
|
|
|
dispatch(setPassword(conference, conference.join, password));
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Action to be dispatched when a knocking poarticipant leaves before any response.
|
|
|
|
*
|
|
|
|
* @param {string} id - The ID of the participant.
|
|
|
|
* @returns {{
|
|
|
|
* id: string,
|
|
|
|
* type: KNOCKING_PARTICIPANT_LEFT
|
|
|
|
* }}
|
|
|
|
*/
|
|
|
|
export function knockingParticipantLeft(id: string) {
|
|
|
|
return {
|
|
|
|
id,
|
|
|
|
type: KNOCKING_PARTICIPANT_LEFT
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Action to be executed when a participant starts knocking or an already knocking participant gets updated.
|
|
|
|
*
|
|
|
|
* @param {Object} participant - The knocking participant.
|
|
|
|
* @returns {{
|
|
|
|
* participant: Object,
|
|
|
|
* type: KNOCKING_PARTICIPANT_ARRIVED_OR_UPDATED
|
|
|
|
* }}
|
|
|
|
*/
|
2022-11-23 09:12:26 +00:00
|
|
|
export function participantIsKnockingOrUpdated(participant: IKnockingParticipant | Object) {
|
2021-09-23 09:12:31 +00:00
|
|
|
return {
|
|
|
|
participant,
|
|
|
|
type: KNOCKING_PARTICIPANT_ARRIVED_OR_UPDATED
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2022-03-01 12:17:06 +00:00
|
|
|
/**
|
|
|
|
* Handles a knocking participant and dismisses the notification.
|
|
|
|
*
|
|
|
|
* @param {string} id - The id of the knocking participant.
|
|
|
|
* @param {boolean} approved - True if the participant is approved, false otherwise.
|
|
|
|
* @returns {Function}
|
|
|
|
*/
|
|
|
|
export function answerKnockingParticipant(id: string, approved: boolean) {
|
2022-11-23 09:12:26 +00:00
|
|
|
return async (dispatch: IStore['dispatch']) => {
|
2022-03-01 12:17:06 +00:00
|
|
|
dispatch(setKnockingParticipantApproval(id, approved));
|
|
|
|
dispatch(hideNotification(LOBBY_NOTIFICATION_ID));
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2021-09-23 09:12:31 +00:00
|
|
|
/**
|
|
|
|
* Approves (lets in) or rejects a knocking participant.
|
|
|
|
*
|
|
|
|
* @param {string} id - The id of the knocking participant.
|
|
|
|
* @param {boolean} approved - True if the participant is approved, false otherwise.
|
|
|
|
* @returns {Function}
|
|
|
|
*/
|
|
|
|
export function setKnockingParticipantApproval(id: string, approved: boolean) {
|
2022-11-23 09:12:26 +00:00
|
|
|
return async (dispatch: IStore['dispatch'], getState: IStore['getState']) => {
|
2021-09-23 09:12:31 +00:00
|
|
|
const conference = getCurrentConference(getState);
|
|
|
|
|
|
|
|
if (conference) {
|
|
|
|
if (approved) {
|
|
|
|
conference.lobbyApproveAccess(id);
|
|
|
|
} else {
|
|
|
|
conference.lobbyDenyAccess(id);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Action used to admit multiple participants in the conference.
|
|
|
|
*
|
|
|
|
* @param {Array<Object>} participants - A list of knocking participants.
|
|
|
|
* @returns {void}
|
|
|
|
*/
|
2022-11-23 09:12:26 +00:00
|
|
|
export function admitMultiple(participants: Array<IKnockingParticipant>) {
|
|
|
|
return (dispatch: IStore['dispatch'], getState: IStore['getState']) => {
|
2021-09-23 09:12:31 +00:00
|
|
|
const conference = getCurrentConference(getState);
|
|
|
|
|
|
|
|
participants.forEach(p => {
|
|
|
|
conference.lobbyApproveAccess(p.id);
|
|
|
|
});
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Approves the request of a knocking participant to join the meeting.
|
|
|
|
*
|
|
|
|
* @param {string} id - The id of the knocking participant.
|
|
|
|
* @returns {Function}
|
|
|
|
*/
|
|
|
|
export function approveKnockingParticipant(id: string) {
|
2022-11-23 09:12:26 +00:00
|
|
|
return (dispatch: IStore['dispatch'], getState: IStore['getState']) => {
|
2021-09-23 09:12:31 +00:00
|
|
|
const conference = getCurrentConference(getState);
|
|
|
|
|
2022-11-23 09:12:26 +00:00
|
|
|
conference?.lobbyApproveAccess(id);
|
2021-09-23 09:12:31 +00:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Denies the request of a knocking participant to join the meeting.
|
|
|
|
*
|
|
|
|
* @param {string} id - The id of the knocking participant.
|
|
|
|
* @returns {Function}
|
|
|
|
*/
|
|
|
|
export function rejectKnockingParticipant(id: string) {
|
2022-11-23 09:12:26 +00:00
|
|
|
return (dispatch: IStore['dispatch'], getState: IStore['getState']) => {
|
2021-09-23 09:12:31 +00:00
|
|
|
const conference = getCurrentConference(getState);
|
|
|
|
|
2022-11-23 09:12:26 +00:00
|
|
|
conference?.lobbyDenyAccess(id);
|
2021-09-23 09:12:31 +00:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Action to set the knocking state of the participant.
|
|
|
|
*
|
|
|
|
* @param {boolean} knocking - The new state.
|
|
|
|
* @returns {{
|
|
|
|
* state: boolean,
|
|
|
|
* type: SET_KNOCKING_STATE
|
|
|
|
* }}
|
|
|
|
*/
|
|
|
|
export function setKnockingState(knocking: boolean) {
|
|
|
|
return {
|
|
|
|
knocking,
|
|
|
|
type: SET_KNOCKING_STATE
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Action to set the new state of the lobby mode.
|
|
|
|
*
|
|
|
|
* @param {boolean} enabled - The new state to set.
|
|
|
|
* @returns {{
|
|
|
|
* enabled: boolean,
|
|
|
|
* type: SET_LOBBY_MODE_ENABLED
|
|
|
|
* }}
|
|
|
|
*/
|
|
|
|
export function setLobbyModeEnabled(enabled: boolean) {
|
|
|
|
return {
|
|
|
|
enabled,
|
|
|
|
type: SET_LOBBY_MODE_ENABLED
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Action to be dispatched when we failed to join with a password.
|
|
|
|
*
|
|
|
|
* @param {boolean} failed - True of recent password join failed.
|
|
|
|
* @returns {{
|
|
|
|
* failed: boolean,
|
|
|
|
* type: SET_PASSWORD_JOIN_FAILED
|
|
|
|
* }}
|
|
|
|
*/
|
|
|
|
export function setPasswordJoinFailed(failed: boolean) {
|
|
|
|
return {
|
|
|
|
failed,
|
|
|
|
type: SET_PASSWORD_JOIN_FAILED
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Starts knocking and waiting for approval.
|
|
|
|
*
|
|
|
|
* @returns {Function}
|
|
|
|
*/
|
|
|
|
export function startKnocking() {
|
2022-11-23 09:12:26 +00:00
|
|
|
return async (dispatch: IStore['dispatch'], getState: IStore['getState']) => {
|
2021-09-23 09:12:31 +00:00
|
|
|
const state = getState();
|
|
|
|
const { membersOnly } = state['features/base/conference'];
|
|
|
|
const localParticipant = getLocalParticipant(state);
|
|
|
|
|
2022-11-23 09:12:26 +00:00
|
|
|
// @ts-ignore
|
2021-09-23 09:12:31 +00:00
|
|
|
dispatch(conferenceWillJoin(membersOnly));
|
|
|
|
|
|
|
|
// We need to update the conference object with the current display name, if approved
|
|
|
|
// we want to send that display name, it was not updated in case when pre-join is disabled
|
2022-11-23 09:12:26 +00:00
|
|
|
// @ts-ignore
|
2021-09-23 09:12:31 +00:00
|
|
|
sendLocalParticipant(state, membersOnly);
|
|
|
|
|
2022-11-23 09:12:26 +00:00
|
|
|
membersOnly?.joinLobby(localParticipant?.name, localParticipant?.email);
|
2022-03-03 17:29:38 +00:00
|
|
|
dispatch(setLobbyMessageListener());
|
2021-09-23 09:12:31 +00:00
|
|
|
dispatch(setKnockingState(true));
|
|
|
|
};
|
|
|
|
}
|
2021-08-20 08:53:11 +00:00
|
|
|
|
2021-04-09 12:30:25 +00:00
|
|
|
/**
|
|
|
|
* Action to toggle lobby mode on or off.
|
|
|
|
*
|
|
|
|
* @param {boolean} enabled - The desired (new) state of the lobby mode.
|
|
|
|
* @returns {Function}
|
|
|
|
*/
|
|
|
|
export function toggleLobbyMode(enabled: boolean) {
|
2022-11-23 09:12:26 +00:00
|
|
|
return async (dispatch: IStore['dispatch'], getState: IStore['getState']) => {
|
2021-04-09 12:30:25 +00:00
|
|
|
const conference = getCurrentConference(getState);
|
|
|
|
|
|
|
|
if (enabled) {
|
|
|
|
conference.enableLobby();
|
|
|
|
} else {
|
|
|
|
conference.disableLobby();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
2021-08-20 08:53:11 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Action to open the lobby screen.
|
|
|
|
*
|
|
|
|
* @returns {openDialog}
|
|
|
|
*/
|
|
|
|
export function openLobbyScreen() {
|
|
|
|
return {
|
|
|
|
type: SET_LOBBY_VISIBILITY,
|
|
|
|
visible: true
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Action to hide the lobby screen.
|
|
|
|
*
|
|
|
|
* @returns {hideDialog}
|
|
|
|
*/
|
|
|
|
export function hideLobbyScreen() {
|
|
|
|
return {
|
|
|
|
type: SET_LOBBY_VISIBILITY,
|
|
|
|
visible: false
|
|
|
|
};
|
|
|
|
}
|
2022-03-03 17:29:38 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Action to handle chat initialized in the lobby room.
|
|
|
|
*
|
|
|
|
* @param {Object} payload - The payload received,
|
|
|
|
* contains the information about the two participants
|
|
|
|
* that will chat with each other in the lobby room.
|
|
|
|
*
|
|
|
|
* @returns {Promise<void>}
|
|
|
|
*/
|
2022-11-23 09:12:26 +00:00
|
|
|
export function handleLobbyChatInitialized(payload: { attendee: IParticipant; moderator: IParticipant; }) {
|
|
|
|
return async (dispatch: IStore['dispatch'], getState: IStore['getState']) => {
|
2022-03-03 17:29:38 +00:00
|
|
|
const state = getState();
|
|
|
|
const conference = getCurrentConference(state);
|
|
|
|
|
|
|
|
const id = conference.myLobbyUserId();
|
|
|
|
|
|
|
|
dispatch({
|
|
|
|
type: SET_LOBBY_PARTICIPANT_CHAT_STATE,
|
|
|
|
participant: payload.attendee,
|
|
|
|
moderator: payload.moderator
|
|
|
|
});
|
|
|
|
|
|
|
|
dispatch(onLobbyChatInitialized(payload));
|
|
|
|
|
|
|
|
const attendeeIsKnocking = getKnockingParticipants(state).some(p => p.id === payload.attendee.id);
|
|
|
|
|
|
|
|
if (attendeeIsKnocking && conference.getRole() === 'moderator' && payload.moderator.id !== id) {
|
|
|
|
dispatch(showNotification({
|
|
|
|
titleKey: 'lobby.lobbyChatStartedNotification',
|
|
|
|
titleArguments: {
|
2022-11-23 09:12:26 +00:00
|
|
|
moderator: payload.moderator.name ?? '',
|
|
|
|
attendee: payload.attendee.name ?? ''
|
2022-03-03 17:29:38 +00:00
|
|
|
}
|
|
|
|
}));
|
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Action to send message to the moderator.
|
|
|
|
*
|
|
|
|
* @param {string} message - The message to be sent.
|
|
|
|
*
|
|
|
|
* @returns {Promise<void>}
|
|
|
|
*/
|
|
|
|
export function onSendMessage(message: string) {
|
2022-11-23 09:12:26 +00:00
|
|
|
return async (dispatch: IStore['dispatch']) => {
|
2022-03-03 17:29:38 +00:00
|
|
|
dispatch(sendMessage(message));
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Action to send lobby message to every participant. Only allowed for moderators.
|
|
|
|
*
|
|
|
|
* @param {Object} message - The message to be sent.
|
|
|
|
*
|
|
|
|
* @returns {Promise<void>}
|
|
|
|
*/
|
|
|
|
export function sendLobbyChatMessage(message: Object) {
|
2022-11-23 09:12:26 +00:00
|
|
|
return async (dispatch: IStore['dispatch'], getState: IStore['getState']) => {
|
2022-03-03 17:29:38 +00:00
|
|
|
const conference = getCurrentConference(getState);
|
|
|
|
|
|
|
|
conference.sendLobbyMessage(message);
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Sets lobby listeners if lobby has been enabled.
|
|
|
|
*
|
|
|
|
* @returns {Function}
|
|
|
|
*/
|
|
|
|
export function maybeSetLobbyChatMessageListener() {
|
2022-11-23 09:12:26 +00:00
|
|
|
return async (dispatch: IStore['dispatch'], getState: IStore['getState']) => {
|
2022-03-03 17:29:38 +00:00
|
|
|
const state = getState();
|
|
|
|
const lobbyEnabled = getLobbyEnabled(state);
|
|
|
|
|
|
|
|
if (lobbyEnabled) {
|
|
|
|
dispatch(setLobbyMessageListener());
|
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Action to handle the event when a moderator leaves during lobby chat.
|
|
|
|
*
|
|
|
|
* @param {string} participantId - The participant id of the moderator who left.
|
|
|
|
* @returns {Function}
|
|
|
|
*/
|
|
|
|
export function updateLobbyParticipantOnLeave(participantId: string) {
|
2022-11-23 09:12:26 +00:00
|
|
|
return async (dispatch: IStore['dispatch'], getState: IStore['getState']) => {
|
2022-03-03 17:29:38 +00:00
|
|
|
const state = getState();
|
|
|
|
const { knocking, knockingParticipants } = state['features/lobby'];
|
|
|
|
const { lobbyMessageRecipient } = state['features/chat'];
|
|
|
|
const { conference } = state['features/base/conference'];
|
|
|
|
|
|
|
|
if (knocking && lobbyMessageRecipient && lobbyMessageRecipient.id === participantId) {
|
|
|
|
return dispatch(removeLobbyChatParticipant(true));
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!knocking) {
|
|
|
|
// inform knocking participant when their moderator leaves
|
|
|
|
const participantToNotify = knockingParticipants.find(p => p.chattingWithModerator === participantId);
|
|
|
|
|
|
|
|
if (participantToNotify) {
|
2022-11-23 09:12:26 +00:00
|
|
|
conference?.sendLobbyMessage({
|
2022-03-03 17:29:38 +00:00
|
|
|
type: MODERATOR_IN_CHAT_WITH_LEFT,
|
|
|
|
moderatorId: participantToNotify.chattingWithModerator
|
|
|
|
}, participantToNotify.id);
|
|
|
|
}
|
|
|
|
dispatch({
|
|
|
|
type: REMOVE_LOBBY_CHAT_WITH_MODERATOR,
|
|
|
|
moderatorId: participantId
|
|
|
|
});
|
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Handles all messages received in the lobby room.
|
|
|
|
*
|
|
|
|
* @returns {Function}
|
|
|
|
*/
|
|
|
|
export function setLobbyMessageListener() {
|
2022-11-23 09:12:26 +00:00
|
|
|
return async (dispatch: IStore['dispatch'], getState: IStore['getState']) => {
|
2022-03-03 17:29:38 +00:00
|
|
|
const state = getState();
|
|
|
|
const conference = getCurrentConference(state);
|
|
|
|
const { enableLobbyChat = true } = state['features/base/config'];
|
|
|
|
|
|
|
|
if (!enableLobbyChat) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2022-11-23 09:12:26 +00:00
|
|
|
conference.addLobbyMessageListener((message: any, participantId: string) => {
|
2022-03-03 17:29:38 +00:00
|
|
|
if (message.type === LOBBY_CHAT_MESSAGE) {
|
|
|
|
return dispatch(handleLobbyMessageReceived(message.message, participantId));
|
|
|
|
}
|
|
|
|
if (message.type === LOBBY_CHAT_INITIALIZED) {
|
|
|
|
return dispatch(handleLobbyChatInitialized(message));
|
|
|
|
}
|
|
|
|
if (message.type === MODERATOR_IN_CHAT_WITH_LEFT) {
|
|
|
|
return dispatch(updateLobbyParticipantOnLeave(message.moderatorId));
|
|
|
|
}
|
|
|
|
});
|
|
|
|
};
|
|
|
|
}
|