mirror of
https://gitcode.com/GitHub_Trending/ji/jitsi-meet.git
synced 2026-05-21 08:07:46 +00:00
[RN] add support for inviting participants during a call on mobile
* Button conditionally shown based on if the feature is enabled and available * Hooks for launching the invite UI (delegates to the native layer) * Hooks for using the search and dial out checks from the native layer (calls back into JS) * Hooks for handling sending invites and passing any failures back to the native layer * Android and iOS handling for those hooks Author: Ryan Peck <rpeck@atlassian.com> Author: Eric Brynsvold <ebrynsvold@atlassian.com>
This commit is contained in:
committed by
Saúl Ibarra Corretgé
parent
4e36127dc7
commit
f64c13d4b7
@@ -14,18 +14,14 @@ import { MultiSelectAutocomplete } from '../../base/react';
|
||||
import { inviteVideoRooms } from '../../videosipgw';
|
||||
|
||||
import {
|
||||
checkDialNumber,
|
||||
invitePeopleAndChatRooms,
|
||||
searchDirectory
|
||||
sendInvitesForItems,
|
||||
getInviteResultsForQuery
|
||||
} from '../functions';
|
||||
|
||||
const logger = require('jitsi-meet-logger').getLogger(__filename);
|
||||
|
||||
declare var interfaceConfig: Object;
|
||||
|
||||
const isPhoneNumberRegex
|
||||
= new RegExp(interfaceConfig.PHONE_NUMBER_REGEX || '^[0-9+()-\\s]*$');
|
||||
|
||||
/**
|
||||
* The dialog that allows to invite people to the call.
|
||||
*/
|
||||
@@ -240,20 +236,6 @@ class AddPeopleDialog extends Component<*, *> {
|
||||
);
|
||||
}
|
||||
|
||||
_getDigitsOnly: (string) => string;
|
||||
|
||||
/**
|
||||
* Removes all non-numeric characters from a string.
|
||||
*
|
||||
* @param {string} text - The string from which to remove all characters
|
||||
* except numbers.
|
||||
* @private
|
||||
* @returns {string} A string with only numbers.
|
||||
*/
|
||||
_getDigitsOnly(text = '') {
|
||||
return text.replace(/\D/g, '');
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper for determining how many of each type of user is being invited.
|
||||
* Used for logging and sending analytics related to invites.
|
||||
@@ -294,27 +276,6 @@ class AddPeopleDialog extends Component<*, *> {
|
||||
|| this.state.addToCallInProgress;
|
||||
}
|
||||
|
||||
_isMaybeAPhoneNumber: (string) => boolean;
|
||||
|
||||
/**
|
||||
* Checks whether a string looks like it could be for a phone number.
|
||||
*
|
||||
* @param {string} text - The text to check whether or not it could be a
|
||||
* phone number.
|
||||
* @private
|
||||
* @returns {boolean} True if the string looks like it could be a phone
|
||||
* number.
|
||||
*/
|
||||
_isMaybeAPhoneNumber(text) {
|
||||
if (!isPhoneNumberRegex.test(text)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const digits = this._getDigitsOnly(text);
|
||||
|
||||
return Boolean(digits.length);
|
||||
}
|
||||
|
||||
_onItemSelected: (Object) => Object;
|
||||
|
||||
/**
|
||||
@@ -379,75 +340,26 @@ class AddPeopleDialog extends Component<*, *> {
|
||||
addToCallInProgress: true
|
||||
});
|
||||
|
||||
let allInvitePromises = [];
|
||||
let invitesLeftToSend = [
|
||||
...this.state.inviteItems
|
||||
];
|
||||
const {
|
||||
_conference,
|
||||
_inviteServiceUrl,
|
||||
_inviteUrl,
|
||||
_jwt
|
||||
} = this.props;
|
||||
|
||||
// First create all promises for dialing out.
|
||||
if (this.props.enableDialOut && this.props._conference) {
|
||||
const phoneNumbers = invitesLeftToSend.filter(
|
||||
({ item }) => item.type === 'phone');
|
||||
const inviteItems = this.state.inviteItems;
|
||||
const items = inviteItems.map(item => item.item);
|
||||
|
||||
// For each number, dial out. On success, remove the number from
|
||||
// {@link invitesLeftToSend}.
|
||||
const phoneInvitePromises = phoneNumbers.map(number => {
|
||||
const numberToInvite = this._getDigitsOnly(number.item.number);
|
||||
const options = {
|
||||
conference: _conference,
|
||||
inviteServiceUrl: _inviteServiceUrl,
|
||||
inviteUrl: _inviteUrl,
|
||||
inviteVideoRooms: this.props.inviteVideoRooms,
|
||||
jwt: _jwt
|
||||
};
|
||||
|
||||
return this.props._conference.dial(numberToInvite)
|
||||
.then(() => {
|
||||
invitesLeftToSend
|
||||
= invitesLeftToSend.filter(invite =>
|
||||
invite !== number);
|
||||
})
|
||||
.catch(error => logger.error(
|
||||
'Error inviting phone number:', error));
|
||||
|
||||
});
|
||||
|
||||
allInvitePromises = allInvitePromises.concat(phoneInvitePromises);
|
||||
}
|
||||
|
||||
if (this.props.enableAddPeople) {
|
||||
const usersAndRooms = invitesLeftToSend.filter(i =>
|
||||
i.item.type === 'user' || i.item.type === 'room')
|
||||
.map(i => i.item);
|
||||
|
||||
if (usersAndRooms.length) {
|
||||
// Send a request to invite all the rooms and users. On success,
|
||||
// filter all rooms and users from {@link invitesLeftToSend}.
|
||||
const peopleInvitePromise = invitePeopleAndChatRooms(
|
||||
this.props._inviteServiceUrl,
|
||||
this.props._inviteUrl,
|
||||
this.props._jwt,
|
||||
usersAndRooms)
|
||||
.then(() => {
|
||||
invitesLeftToSend = invitesLeftToSend.filter(i =>
|
||||
i.item.type !== 'user' && i.item.type !== 'room');
|
||||
})
|
||||
.catch(error => logger.error(
|
||||
'Error inviting people:', error));
|
||||
|
||||
allInvitePromises.push(peopleInvitePromise);
|
||||
}
|
||||
|
||||
// Sipgw calls are fire and forget. Invite them to the conference
|
||||
// then immediately remove them from {@link invitesLeftToSend}.
|
||||
const vrooms = invitesLeftToSend.filter(i =>
|
||||
i.item.type === 'videosipgw')
|
||||
.map(i => i.item);
|
||||
|
||||
this.props._conference
|
||||
&& vrooms.length > 0
|
||||
&& this.props.inviteVideoRooms(
|
||||
this.props._conference, vrooms);
|
||||
|
||||
invitesLeftToSend = invitesLeftToSend.filter(i =>
|
||||
i.item.type !== 'videosipgw');
|
||||
}
|
||||
|
||||
Promise.all(allInvitePromises)
|
||||
.then(() => {
|
||||
sendInvitesForItems(items, options)
|
||||
.then(invitesLeftToSend => {
|
||||
// If any invites are left that means something failed to send
|
||||
// so treat it as an error.
|
||||
if (invitesLeftToSend.length) {
|
||||
@@ -467,8 +379,18 @@ class AddPeopleDialog extends Component<*, *> {
|
||||
addToCallError: true
|
||||
});
|
||||
|
||||
const unsentInviteIDs = invitesLeftToSend.map(invite =>
|
||||
invite.id || invite.number
|
||||
);
|
||||
|
||||
const itemsToSelect = inviteItems.filter(invite =>
|
||||
unsentInviteIDs.includes(
|
||||
invite.item.id || invite.item.number
|
||||
)
|
||||
);
|
||||
|
||||
if (this._multiselect) {
|
||||
this._multiselect.setSelectedItems(invitesLeftToSend);
|
||||
this._multiselect.setSelectedItems(itemsToSelect);
|
||||
}
|
||||
|
||||
return;
|
||||
@@ -558,82 +480,25 @@ class AddPeopleDialog extends Component<*, *> {
|
||||
* @returns {Promise}
|
||||
*/
|
||||
_query(query = '') {
|
||||
const text = query.trim();
|
||||
const {
|
||||
enableAddPeople,
|
||||
enableDialOut,
|
||||
_dialOutAuthUrl,
|
||||
_jwt,
|
||||
_peopleSearchQueryTypes,
|
||||
_peopleSearchUrl
|
||||
} = this.props;
|
||||
|
||||
let peopleSearchPromise;
|
||||
const options = {
|
||||
dialOutAuthUrl: _dialOutAuthUrl,
|
||||
enableAddPeople,
|
||||
enableDialOut,
|
||||
jwt: _jwt,
|
||||
peopleSearchQueryTypes: _peopleSearchQueryTypes,
|
||||
peopleSearchUrl: _peopleSearchUrl
|
||||
};
|
||||
|
||||
if (this.props.enableAddPeople && text) {
|
||||
peopleSearchPromise = searchDirectory(
|
||||
_peopleSearchUrl,
|
||||
_jwt,
|
||||
text,
|
||||
_peopleSearchQueryTypes);
|
||||
} else {
|
||||
peopleSearchPromise = Promise.resolve([]);
|
||||
}
|
||||
|
||||
|
||||
const hasCountryCode = text.startsWith('+');
|
||||
let phoneNumberPromise;
|
||||
|
||||
if (this.props.enableDialOut && this._isMaybeAPhoneNumber(text)) {
|
||||
let numberToVerify = text;
|
||||
|
||||
// When the number to verify does not start with a +, we assume no
|
||||
// proper country code has been entered. In such a case, prepend 1
|
||||
// for the country code. The service currently takes care of
|
||||
// prepending the +.
|
||||
if (!hasCountryCode && !text.startsWith('1')) {
|
||||
numberToVerify = `1${numberToVerify}`;
|
||||
}
|
||||
|
||||
// The validation service works properly when the query is digits
|
||||
// only so ensure only digits get sent.
|
||||
numberToVerify = this._getDigitsOnly(numberToVerify);
|
||||
|
||||
phoneNumberPromise
|
||||
= checkDialNumber(numberToVerify, _dialOutAuthUrl);
|
||||
} else {
|
||||
phoneNumberPromise = Promise.resolve({});
|
||||
}
|
||||
|
||||
return Promise.all([ peopleSearchPromise, phoneNumberPromise ])
|
||||
.then(([ peopleResults, phoneResults ]) => {
|
||||
const results = [
|
||||
...peopleResults
|
||||
];
|
||||
|
||||
/**
|
||||
* This check for phone results is for the day the call to
|
||||
* searching people might return phone results as well. When
|
||||
* that day comes this check will make it so the server checks
|
||||
* are honored and the local appending of the number is not
|
||||
* done. The local appending of the phone number can then be
|
||||
* cleaned up when convenient.
|
||||
*/
|
||||
const hasPhoneResult = peopleResults.find(
|
||||
result => result.type === 'phone');
|
||||
|
||||
if (!hasPhoneResult
|
||||
&& typeof phoneResults.allow === 'boolean') {
|
||||
results.push({
|
||||
allowed: phoneResults.allow,
|
||||
country: phoneResults.country,
|
||||
type: 'phone',
|
||||
number: phoneResults.phone,
|
||||
originalEntry: text,
|
||||
showCountryCodeReminder: !hasCountryCode
|
||||
});
|
||||
}
|
||||
|
||||
return results;
|
||||
});
|
||||
return getInviteResultsForQuery(query, options);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
91
react/features/invite/components/InviteButton.native.js
Normal file
91
react/features/invite/components/InviteButton.native.js
Normal file
@@ -0,0 +1,91 @@
|
||||
// @flow
|
||||
|
||||
import React, { Component } from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
import { launchNativeInvite } from '../../mobile/invite-search';
|
||||
import { ToolbarButton } from '../../toolbox';
|
||||
|
||||
/**
|
||||
* The type of {@link EnterPictureInPictureToobarButton}'s React
|
||||
* {@code Component} props.
|
||||
*/
|
||||
type Props = {
|
||||
|
||||
/**
|
||||
* Indicates if the "Add to call" feature is available.
|
||||
*/
|
||||
enableAddPeople: boolean,
|
||||
|
||||
/**
|
||||
* Indicates if the "Dial out" feature is available.
|
||||
*/
|
||||
enableDialOut: boolean,
|
||||
|
||||
/**
|
||||
* Launches native invite dialog.
|
||||
*
|
||||
* @protected
|
||||
*/
|
||||
onLaunchNativeInvite: Function,
|
||||
};
|
||||
|
||||
/**
|
||||
* Implements a {@link ToolbarButton} to enter Picture-in-Picture.
|
||||
*/
|
||||
class InviteButton extends Component<Props> {
|
||||
|
||||
/**
|
||||
* Implements React's {@link Component#render()}.
|
||||
*
|
||||
* @inheritdoc
|
||||
* @returns {ReactElement}
|
||||
*/
|
||||
render() {
|
||||
const {
|
||||
enableAddPeople,
|
||||
enableDialOut,
|
||||
onLaunchNativeInvite,
|
||||
...props
|
||||
} = this.props;
|
||||
|
||||
if (!enableAddPeople && !enableDialOut) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<ToolbarButton
|
||||
iconName = { 'add' }
|
||||
onClick = { onLaunchNativeInvite }
|
||||
{ ...props } />
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Maps redux actions to {@link InviteButton}'s React
|
||||
* {@code Component} props.
|
||||
*
|
||||
* @param {Function} dispatch - The redux action {@code dispatch} function.
|
||||
* @returns {{
|
||||
* onLaunchNativeInvite
|
||||
* }}
|
||||
* @private
|
||||
*/
|
||||
function _mapDispatchToProps(dispatch) {
|
||||
return {
|
||||
|
||||
/**
|
||||
* Launches native invite dialog.
|
||||
*
|
||||
* @private
|
||||
* @returns {void}
|
||||
* @type {Function}
|
||||
*/
|
||||
onLaunchNativeInvite() {
|
||||
dispatch(launchNativeInvite());
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export default connect(undefined, _mapDispatchToProps)(InviteButton);
|
||||
@@ -1,5 +1,6 @@
|
||||
// @flow
|
||||
|
||||
import { getLocalParticipant, PARTICIPANT_ROLE } from '../base/participants';
|
||||
import { doGetJSON } from '../base/util';
|
||||
|
||||
declare var $: Function;
|
||||
@@ -50,7 +51,7 @@ export function getDialInNumbers(url: string): Promise<*> {
|
||||
* type items to invite.
|
||||
* @returns {Promise} - The promise created by the request.
|
||||
*/
|
||||
export function invitePeopleAndChatRooms( // eslint-disable-line max-params
|
||||
function invitePeopleAndChatRooms( // eslint-disable-line max-params
|
||||
inviteServiceUrl: string,
|
||||
inviteUrl: string,
|
||||
jwt: string,
|
||||
@@ -88,9 +89,10 @@ export function searchDirectory( // eslint-disable-line max-params
|
||||
text: string,
|
||||
queryTypes: Array<string> = [ 'conferenceRooms', 'user', 'room' ]
|
||||
): Promise<Array<Object>> {
|
||||
const queryTypesString = JSON.stringify(queryTypes);
|
||||
const query = encodeURIComponent(text);
|
||||
const queryTypesString = encodeURIComponent(JSON.stringify(queryTypes));
|
||||
|
||||
return fetch(`${serviceUrl}?query=${encodeURIComponent(text)}&queryTypes=${
|
||||
return fetch(`${serviceUrl}?query=${query}&queryTypes=${
|
||||
queryTypesString}&jwt=${jwt}`)
|
||||
.then(response => {
|
||||
const jsonify = response.json();
|
||||
@@ -110,6 +112,21 @@ export function searchDirectory( // eslint-disable-line max-params
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* RegExp to use to determine if some text might be a phone number.
|
||||
*
|
||||
* @returns {RegExp}
|
||||
*/
|
||||
function isPhoneNumberRegex(): RegExp {
|
||||
let regexString = '^[0-9+()-\\s]*$';
|
||||
|
||||
if (typeof interfaceConfig !== 'undefined') {
|
||||
regexString = interfaceConfig.PHONE_NUMBER_REGEX || regexString;
|
||||
}
|
||||
|
||||
return new RegExp(regexString);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends an ajax request to check if the phone number can be called.
|
||||
*
|
||||
@@ -137,3 +154,315 @@ export function checkDialNumber(
|
||||
.catch(reject);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes all non-numeric characters from a string.
|
||||
*
|
||||
* @param {string} text - The string from which to remove all characters
|
||||
* except numbers.
|
||||
* @private
|
||||
* @returns {string} A string with only numbers.
|
||||
*/
|
||||
function getDigitsOnly(text: string = ''): string {
|
||||
return text.replace(/\D/g, '');
|
||||
}
|
||||
|
||||
/**
|
||||
* Type of the options to use when sending a search query.
|
||||
*/
|
||||
export type GetInviteResultsOptions = {
|
||||
|
||||
/**
|
||||
* The endpoint to use for checking phone number validity.
|
||||
*/
|
||||
dialOutAuthUrl: string,
|
||||
|
||||
/**
|
||||
* Whether or not to search for people.
|
||||
*/
|
||||
enableAddPeople: boolean,
|
||||
|
||||
/**
|
||||
* Whether or not to check phone numbers.
|
||||
*/
|
||||
enableDialOut: boolean,
|
||||
|
||||
/**
|
||||
* Array with the query types that will be executed -
|
||||
* "conferenceRooms" | "user" | "room".
|
||||
*/
|
||||
peopleSearchQueryTypes: Array<string>,
|
||||
|
||||
/**
|
||||
* The url to query for people.
|
||||
*/
|
||||
peopleSearchUrl: string,
|
||||
|
||||
/**
|
||||
* The jwt token to pass to the search service.
|
||||
*/
|
||||
jwt: string
|
||||
};
|
||||
|
||||
/**
|
||||
* Combines directory search with phone number validation to produce a single
|
||||
* set of invite search results.
|
||||
*
|
||||
* @param {string} query - Text to search.
|
||||
* @param {GetInviteResultsOptions} options - Options to use when searching.
|
||||
* @returns {Promise<*>}
|
||||
*/
|
||||
export function getInviteResultsForQuery(
|
||||
query: string,
|
||||
options: GetInviteResultsOptions): Promise<*> {
|
||||
const text = query.trim();
|
||||
|
||||
const {
|
||||
dialOutAuthUrl,
|
||||
enableAddPeople,
|
||||
enableDialOut,
|
||||
peopleSearchQueryTypes,
|
||||
peopleSearchUrl,
|
||||
jwt
|
||||
} = options;
|
||||
|
||||
let peopleSearchPromise;
|
||||
|
||||
if (enableAddPeople && text) {
|
||||
peopleSearchPromise = searchDirectory(
|
||||
peopleSearchUrl,
|
||||
jwt,
|
||||
text,
|
||||
peopleSearchQueryTypes);
|
||||
} else {
|
||||
peopleSearchPromise = Promise.resolve([]);
|
||||
}
|
||||
|
||||
|
||||
const hasCountryCode = text.startsWith('+');
|
||||
let phoneNumberPromise;
|
||||
|
||||
if (enableDialOut && isMaybeAPhoneNumber(text)) {
|
||||
let numberToVerify = text;
|
||||
|
||||
// When the number to verify does not start with a +, we assume no
|
||||
// proper country code has been entered. In such a case, prepend 1
|
||||
// for the country code. The service currently takes care of
|
||||
// prepending the +.
|
||||
if (!hasCountryCode && !text.startsWith('1')) {
|
||||
numberToVerify = `1${numberToVerify}`;
|
||||
}
|
||||
|
||||
// The validation service works properly when the query is digits
|
||||
// only so ensure only digits get sent.
|
||||
numberToVerify = getDigitsOnly(numberToVerify);
|
||||
|
||||
phoneNumberPromise
|
||||
= checkDialNumber(numberToVerify, dialOutAuthUrl);
|
||||
} else {
|
||||
phoneNumberPromise = Promise.resolve({});
|
||||
}
|
||||
|
||||
return Promise.all([ peopleSearchPromise, phoneNumberPromise ])
|
||||
.then(([ peopleResults, phoneResults ]) => {
|
||||
const results = [
|
||||
...peopleResults
|
||||
];
|
||||
|
||||
/**
|
||||
* This check for phone results is for the day the call to
|
||||
* searching people might return phone results as well. When
|
||||
* that day comes this check will make it so the server checks
|
||||
* are honored and the local appending of the number is not
|
||||
* done. The local appending of the phone number can then be
|
||||
* cleaned up when convenient.
|
||||
*/
|
||||
const hasPhoneResult = peopleResults.find(
|
||||
result => result.type === 'phone');
|
||||
|
||||
if (!hasPhoneResult
|
||||
&& typeof phoneResults.allow === 'boolean') {
|
||||
results.push({
|
||||
allowed: phoneResults.allow,
|
||||
country: phoneResults.country,
|
||||
type: 'phone',
|
||||
number: phoneResults.phone,
|
||||
originalEntry: text,
|
||||
showCountryCodeReminder: !hasCountryCode
|
||||
});
|
||||
}
|
||||
|
||||
return results;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether a string looks like it could be for a phone number.
|
||||
*
|
||||
* @param {string} text - The text to check whether or not it could be a
|
||||
* phone number.
|
||||
* @private
|
||||
* @returns {boolean} True if the string looks like it could be a phone
|
||||
* number.
|
||||
*/
|
||||
function isMaybeAPhoneNumber(text: string): boolean {
|
||||
if (!isPhoneNumberRegex().test(text)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const digits = getDigitsOnly(text);
|
||||
|
||||
return Boolean(digits.length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Type of the options to use when sending invites.
|
||||
*/
|
||||
export type SendInvitesOptions = {
|
||||
|
||||
/**
|
||||
* Conference object used to dial out.
|
||||
*/
|
||||
conference: Object,
|
||||
|
||||
/**
|
||||
* The URL to send invites through.
|
||||
*/
|
||||
inviteServiceUrl: string,
|
||||
|
||||
/**
|
||||
* The URL sent with each invite.
|
||||
*/
|
||||
inviteUrl: string,
|
||||
|
||||
/**
|
||||
* The function to use to invite video rooms.
|
||||
*
|
||||
* @param {Object} The conference to which the video rooms should be
|
||||
* invited.
|
||||
* @param {Array<Object>} The list of rooms that should be invited.
|
||||
* @returns {void}
|
||||
*/
|
||||
inviteVideoRooms: (Object, Array<Object>) => void,
|
||||
|
||||
/**
|
||||
* The jwt token to pass to the invite service.
|
||||
*/
|
||||
jwt: string
|
||||
};
|
||||
|
||||
/**
|
||||
* Send invites for a list of items (may be a combination of users, rooms, phone
|
||||
* numbers, and video rooms).
|
||||
*
|
||||
* @param {Array<Object>} invites - Items for which invites should be sent.
|
||||
* @param {SendInvitesOptions} options - Options to use when sending the
|
||||
* provided invites.
|
||||
* @returns {Promise} Promise containing the list of invites that were not sent.
|
||||
*/
|
||||
export function sendInvitesForItems(
|
||||
invites: Array<Object>,
|
||||
options: SendInvitesOptions
|
||||
): Promise<Array<Object>> {
|
||||
|
||||
const {
|
||||
conference,
|
||||
inviteServiceUrl,
|
||||
inviteUrl,
|
||||
inviteVideoRooms,
|
||||
jwt
|
||||
} = options;
|
||||
|
||||
let allInvitePromises = [];
|
||||
let invitesLeftToSend = [ ...invites ];
|
||||
|
||||
// First create all promises for dialing out.
|
||||
if (conference) {
|
||||
const phoneNumbers = invitesLeftToSend.filter(
|
||||
item => item.type === 'phone');
|
||||
|
||||
// For each number, dial out. On success, remove the number from
|
||||
// {@link invitesLeftToSend}.
|
||||
const phoneInvitePromises = phoneNumbers.map(item => {
|
||||
const numberToInvite = getDigitsOnly(item.number);
|
||||
|
||||
return conference.dial(numberToInvite)
|
||||
.then(() => {
|
||||
invitesLeftToSend
|
||||
= invitesLeftToSend.filter(invite =>
|
||||
invite !== item);
|
||||
})
|
||||
.catch(error => logger.error(
|
||||
'Error inviting phone number:', error));
|
||||
|
||||
});
|
||||
|
||||
allInvitePromises = allInvitePromises.concat(phoneInvitePromises);
|
||||
}
|
||||
|
||||
const usersAndRooms = invitesLeftToSend.filter(item =>
|
||||
item.type === 'user' || item.type === 'room');
|
||||
|
||||
if (usersAndRooms.length) {
|
||||
// Send a request to invite all the rooms and users. On success,
|
||||
// filter all rooms and users from {@link invitesLeftToSend}.
|
||||
const peopleInvitePromise = invitePeopleAndChatRooms(
|
||||
inviteServiceUrl,
|
||||
inviteUrl,
|
||||
jwt,
|
||||
usersAndRooms)
|
||||
.then(() => {
|
||||
invitesLeftToSend = invitesLeftToSend.filter(item =>
|
||||
item.type !== 'user' && item.type !== 'room');
|
||||
})
|
||||
.catch(error => logger.error(
|
||||
'Error inviting people:', error));
|
||||
|
||||
allInvitePromises.push(peopleInvitePromise);
|
||||
}
|
||||
|
||||
// Sipgw calls are fire and forget. Invite them to the conference
|
||||
// then immediately remove them from {@link invitesLeftToSend}.
|
||||
const vrooms = invitesLeftToSend.filter(item =>
|
||||
item.type === 'videosipgw');
|
||||
|
||||
conference
|
||||
&& vrooms.length > 0
|
||||
&& inviteVideoRooms(conference, vrooms);
|
||||
|
||||
invitesLeftToSend = invitesLeftToSend.filter(item =>
|
||||
item.type !== 'videosipgw');
|
||||
|
||||
return Promise.all(allInvitePromises)
|
||||
.then(() => invitesLeftToSend);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if adding people is currently enabled.
|
||||
*
|
||||
* @param {boolean} state - Current state.
|
||||
* @returns {boolean} Indication of whether adding people is currently enabled.
|
||||
*/
|
||||
export function isAddPeopleEnabled(state: Object): boolean {
|
||||
const { app } = state['features/app'];
|
||||
const { isGuest } = state['features/base/jwt'];
|
||||
|
||||
return !isGuest && Boolean(app && app.props.addPeopleEnabled);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if dial out is currently enabled or not.
|
||||
*
|
||||
* @param {boolean} state - Current state.
|
||||
* @returns {boolean} Indication of whether dial out is currently enabled.
|
||||
*/
|
||||
export function isDialOutEnabled(state: Object): boolean {
|
||||
const { conference } = state['features/base/conference'];
|
||||
const { isGuest } = state['features/base/jwt'];
|
||||
const { enableUserRolesBasedOnToken } = state['features/base/config'];
|
||||
const participant = getLocalParticipant(state);
|
||||
|
||||
return participant && participant.role === PARTICIPANT_ROLE.MODERATOR
|
||||
&& conference && conference.isSIPCallingSupported()
|
||||
&& (!enableUserRolesBasedOnToken || !isGuest);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
export * from './actions';
|
||||
export * from './components';
|
||||
export * from './functions';
|
||||
|
||||
import './reducer';
|
||||
import './middleware';
|
||||
|
||||
Reference in New Issue
Block a user