Merge pull request #9184 from jitsi/tavram/invite-types

fix(invite) fix notifications for phone invites
This commit is contained in:
Avram Tudor 2021-05-11 16:23:20 +03:00 committed by GitHub
commit 6e91665987
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 60 additions and 28 deletions

View File

@ -15,6 +15,7 @@ import {
UPDATE_DIAL_IN_NUMBERS_FAILED,
UPDATE_DIAL_IN_NUMBERS_SUCCESS
} from './actionTypes';
import { INVITE_TYPES } from './constants';
import {
getDialInConferenceID,
getDialInNumbers,
@ -76,7 +77,7 @@ export function invite(
if (showCalleeInfo
&& !calleeInfoVisible
&& invitees.length === 1
&& invitees[0].type === 'user'
&& invitees[0].type === INVITE_TYPES.USER
&& participants.length === 1) {
dispatch(setCalleeInfoVisible(true, invitees[0]));
}
@ -110,7 +111,7 @@ export function invite(
// First create all promises for dialing out.
const phoneNumbers
= invitesLeftToSend.filter(({ type }) => type === 'phone');
= invitesLeftToSend.filter(({ type }) => type === INVITE_TYPES.PHONE);
// For each number, dial out. On success, remove the number from
// {@link invitesLeftToSend}.
@ -131,7 +132,7 @@ export function invite(
const usersAndRooms
= invitesLeftToSend.filter(
({ type }) => type === 'user' || type === 'room');
({ type }) => [ INVITE_TYPES.USER, INVITE_TYPES.ROOM ].includes(type));
if (usersAndRooms.length) {
// Send a request to invite all the rooms and users. On success,
@ -146,7 +147,7 @@ export function invite(
.then(() => {
invitesLeftToSend
= invitesLeftToSend.filter(
({ type }) => type !== 'user' && type !== 'room');
({ type }) => ![ INVITE_TYPES.USER, INVITE_TYPES.ROOM ].includes(type));
})
.catch(error => {
dispatch(setCalleeInfoVisible(false));
@ -159,17 +160,17 @@ export function invite(
// Sipgw calls are fire and forget. Invite them to the conference, then
// immediately remove them from invitesLeftToSend.
const vrooms
= invitesLeftToSend.filter(({ type }) => type === 'videosipgw');
= invitesLeftToSend.filter(({ type }) => type === INVITE_TYPES.VIDEO_ROOM);
conference
&& vrooms.length > 0
&& dispatch(inviteVideoRooms(conference, vrooms));
invitesLeftToSend
= invitesLeftToSend.filter(({ type }) => type !== 'videosipgw');
= invitesLeftToSend.filter(({ type }) => type !== INVITE_TYPES.VIDEO_ROOM);
const sipEndpoints
= invitesLeftToSend.filter(({ type }) => type === 'sip');
= invitesLeftToSend.filter(({ type }) => type === INVITE_TYPES.SIP);
conference && inviteSipEndpoints(
sipEndpoints,
@ -182,7 +183,7 @@ export function invite(
);
invitesLeftToSend
= invitesLeftToSend.filter(({ type }) => type !== 'sip');
= invitesLeftToSend.filter(({ type }) => type !== INVITE_TYPES.SIP);
return (
Promise.all(allInvitePromises)

View File

@ -8,6 +8,7 @@ import {
showNotification
} from '../../../notifications';
import { invite } from '../../actions';
import { INVITE_TYPES } from '../../constants';
import {
getInviteResultsForQuery,
getInviteTypeCounts,
@ -100,6 +101,24 @@ export default class AbstractAddPeopleDialog<P: Props, S: State>
this._query = this._query.bind(this);
}
/**
* Retrieves the notification display name for the invitee.
*
* @param {Object} invitee - The invitee object.
* @returns {string}
*/
_getDisplayName(invitee) {
if (invitee.type === INVITE_TYPES.PHONE) {
return invitee.number;
}
if (invitee.type === INVITE_TYPES.SIP) {
return invitee.address;
}
return invitee.name;
}
/**
* Invite people and numbers to the conference. The logic works by inviting
* numbers, people/rooms, sip endpoints and videosipgw in parallel. All invitees are
@ -160,7 +179,7 @@ export default class AbstractAddPeopleDialog<P: Props, S: State>
if (invitedCount >= 3) {
notificationProps = {
titleArguments: {
name: invitees[0].name || invitees[0].address,
name: this._getDisplayName(invitees[0]),
count: invitedCount - 1
},
titleKey: 'notify.invitedThreePlusMembers'
@ -168,15 +187,15 @@ export default class AbstractAddPeopleDialog<P: Props, S: State>
} else if (invitedCount === 2) {
notificationProps = {
titleArguments: {
first: invitees[0].name || invitees[0].address,
second: invitees[1].name || invitees[1].address
first: this._getDisplayName(invitees[0]),
second: this._getDisplayName(invitees[1])
},
titleKey: 'notify.invitedTwoMembers'
};
} else if (invitedCount) {
notificationProps = {
titleArguments: {
name: invitees[0].name || invitees[0].address
name: this._getDisplayName(invitees[0])
},
titleKey: 'notify.invitedOneMember'
};

View File

@ -31,7 +31,7 @@ import {
} from '../../../../base/react';
import { connect } from '../../../../base/redux';
import { beginShareRoom } from '../../../../share-room';
import { ADD_PEOPLE_DIALOG_VIEW_ID } from '../../../constants';
import { ADD_PEOPLE_DIALOG_VIEW_ID, INVITE_TYPES } from '../../../constants';
import AbstractAddPeopleDialog, {
type Props as AbstractProps,
type State as AbstractState,
@ -242,13 +242,13 @@ class AddPeopleDialog extends AbstractAddPeopleDialog<Props, State> {
const { item } = flatListItem;
switch (item.type) {
case 'phone':
case INVITE_TYPES.PHONE:
return {
avatar: IconPhone,
key: item.number,
title: item.number
};
case 'user':
case INVITE_TYPES.USER:
return {
avatar: item.avatar,
key: item.id || item.user_id,
@ -273,7 +273,7 @@ class AddPeopleDialog extends AbstractAddPeopleDialog<Props, State> {
* @returns {string}
*/
_keyExtractor(item) {
return item.type === 'user' ? item.id || item.user_id : item.number;
return item.type === INVITE_TYPES.USER ? item.id || item.user_id : item.number;
}
_onClearField: () => void
@ -340,7 +340,7 @@ class AddPeopleDialog extends AbstractAddPeopleDialog<Props, State> {
_onPressItem(item) {
return () => {
const { inviteItems } = this.state;
const finderKey = item.type === 'phone' ? 'number' : 'user_id';
const finderKey = item.type === INVITE_TYPES.PHONE ? 'number' : 'user_id';
if (inviteItems.find(
_.matchesProperty(finderKey, item[finderKey]))) {
@ -504,10 +504,10 @@ class AddPeopleDialog extends AbstractAddPeopleDialog<Props, State> {
}
switch (item.type) {
case 'phone':
case INVITE_TYPES.PHONE:
selected = inviteItems.find(_.matchesProperty('number', item.number));
break;
case 'user':
case INVITE_TYPES.USER:
selected = item.id
? inviteItems.find(_.matchesProperty('id', item.id))
: inviteItems.find(_.matchesProperty('user_id', item.user_id));

View File

@ -12,6 +12,7 @@ import { MultiSelectAutocomplete } from '../../../../base/react';
import { connect } from '../../../../base/redux';
import { isVpaasMeeting } from '../../../../billing-counter/functions';
import { hideAddPeopleDialog } from '../../../actions';
import { INVITE_TYPES } from '../../../constants';
import AbstractAddPeopleDialog, {
type Props as AbstractProps,
type State,
@ -181,7 +182,7 @@ class InviteContactsForm extends AbstractAddPeopleDialog<Props, State> {
* @returns {Object} The item to display as selected in the input.
*/
_onItemSelected(item) {
if (item.item.type === 'phone') {
if (item.item.type === INVITE_TYPES.PHONE) {
item.content = item.item.number;
}
@ -285,7 +286,7 @@ class InviteContactsForm extends AbstractAddPeopleDialog<Props, State> {
*/
_parseQueryResults(response = []) {
const { t, _dialOutEnabled } = this.props;
const users = response.filter(item => item.type !== 'phone' && item.type !== 'sip');
const users = response.filter(item => item.type === INVITE_TYPES.USER);
const userDisplayItems = [];
for (const user of users) {
@ -309,7 +310,7 @@ class InviteContactsForm extends AbstractAddPeopleDialog<Props, State> {
content: `${phone} (${name})`,
elemBefore: elemAvatar,
item: {
type: 'phone',
type: INVITE_TYPES.PHONE,
number: phone
},
tag: {
@ -320,7 +321,7 @@ class InviteContactsForm extends AbstractAddPeopleDialog<Props, State> {
}
}
const numbers = response.filter(item => item.type === 'phone');
const numbers = response.filter(item => item.type === INVITE_TYPES.PHONE);
const telephoneIcon = this._renderTelephoneIcon();
const numberDisplayItems = numbers.map(number => {
@ -349,7 +350,7 @@ class InviteContactsForm extends AbstractAddPeopleDialog<Props, State> {
});
const sipAddresses = response.filter(item => item.type === 'sip');
const sipAddresses = response.filter(item => item.type === INVITE_TYPES.SIP);
const sipDisplayItems = sipAddresses.map(sip => {
return {

View File

@ -48,3 +48,14 @@ export const OUTGOING_CALL_START_SOUND_ID = 'OUTGOING_CALL_START_SOUND_ID';
*/
// eslint-disable-next-line max-len
export const SIP_ADDRESS_REGEX = /^[a-zA-Z]+(?:([^\s>:@]+)(?::([^\s@>]+))?@)?([\w\-.]+)(?::(\d+))?((?:;[^\s=?>;]+(?:=[^\s?;]+)?)*)(?:\?(([^\s&=>]+=[^\s&=>]+)(&[^\s&=>]+=[^\s&=>]+)*))?$/;
/**
* Different invite types mapping
*/
export const INVITE_TYPES = {
PHONE: 'phone',
ROOM: 'room',
SIP: 'sip',
USER: 'user',
VIDEO_ROOM: 'videosipgw'
};

View File

@ -10,7 +10,7 @@ import { toState } from '../base/redux';
import { doGetJSON, parseURIString } from '../base/util';
import { isVpaasMeeting } from '../billing-counter/functions';
import { SIP_ADDRESS_REGEX } from './constants';
import { INVITE_TYPES, SIP_ADDRESS_REGEX } from './constants';
import logger from './logger';
declare var $: Function;
@ -227,13 +227,13 @@ export function getInviteResultsForQuery(
* the phone number can then be cleaned up when convenient.
*/
const hasPhoneResult
= peopleResults.find(result => result.type === 'phone');
= peopleResults.find(result => result.type === INVITE_TYPES.PHONE);
if (!hasPhoneResult && typeof phoneResults.allow === 'boolean') {
results.push({
allowed: phoneResults.allow,
country: phoneResults.country,
type: 'phone',
type: INVITE_TYPES.PHONE,
number: phoneResults.phone,
originalEntry: text,
showCountryCodeReminder: !hasCountryCode
@ -242,7 +242,7 @@ export function getInviteResultsForQuery(
if (sipInviteEnabled && isASipAddress(text)) {
results.push({
type: 'sip',
type: INVITE_TYPES.SIP,
address: text
});
}