Merge pull request #9184 from jitsi/tavram/invite-types
fix(invite) fix notifications for phone invites
This commit is contained in:
commit
6e91665987
|
@ -15,6 +15,7 @@ import {
|
||||||
UPDATE_DIAL_IN_NUMBERS_FAILED,
|
UPDATE_DIAL_IN_NUMBERS_FAILED,
|
||||||
UPDATE_DIAL_IN_NUMBERS_SUCCESS
|
UPDATE_DIAL_IN_NUMBERS_SUCCESS
|
||||||
} from './actionTypes';
|
} from './actionTypes';
|
||||||
|
import { INVITE_TYPES } from './constants';
|
||||||
import {
|
import {
|
||||||
getDialInConferenceID,
|
getDialInConferenceID,
|
||||||
getDialInNumbers,
|
getDialInNumbers,
|
||||||
|
@ -76,7 +77,7 @@ export function invite(
|
||||||
if (showCalleeInfo
|
if (showCalleeInfo
|
||||||
&& !calleeInfoVisible
|
&& !calleeInfoVisible
|
||||||
&& invitees.length === 1
|
&& invitees.length === 1
|
||||||
&& invitees[0].type === 'user'
|
&& invitees[0].type === INVITE_TYPES.USER
|
||||||
&& participants.length === 1) {
|
&& participants.length === 1) {
|
||||||
dispatch(setCalleeInfoVisible(true, invitees[0]));
|
dispatch(setCalleeInfoVisible(true, invitees[0]));
|
||||||
}
|
}
|
||||||
|
@ -110,7 +111,7 @@ export function invite(
|
||||||
|
|
||||||
// First create all promises for dialing out.
|
// First create all promises for dialing out.
|
||||||
const phoneNumbers
|
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
|
// For each number, dial out. On success, remove the number from
|
||||||
// {@link invitesLeftToSend}.
|
// {@link invitesLeftToSend}.
|
||||||
|
@ -131,7 +132,7 @@ export function invite(
|
||||||
|
|
||||||
const usersAndRooms
|
const usersAndRooms
|
||||||
= invitesLeftToSend.filter(
|
= invitesLeftToSend.filter(
|
||||||
({ type }) => type === 'user' || type === 'room');
|
({ type }) => [ INVITE_TYPES.USER, INVITE_TYPES.ROOM ].includes(type));
|
||||||
|
|
||||||
if (usersAndRooms.length) {
|
if (usersAndRooms.length) {
|
||||||
// Send a request to invite all the rooms and users. On success,
|
// Send a request to invite all the rooms and users. On success,
|
||||||
|
@ -146,7 +147,7 @@ export function invite(
|
||||||
.then(() => {
|
.then(() => {
|
||||||
invitesLeftToSend
|
invitesLeftToSend
|
||||||
= invitesLeftToSend.filter(
|
= invitesLeftToSend.filter(
|
||||||
({ type }) => type !== 'user' && type !== 'room');
|
({ type }) => ![ INVITE_TYPES.USER, INVITE_TYPES.ROOM ].includes(type));
|
||||||
})
|
})
|
||||||
.catch(error => {
|
.catch(error => {
|
||||||
dispatch(setCalleeInfoVisible(false));
|
dispatch(setCalleeInfoVisible(false));
|
||||||
|
@ -159,17 +160,17 @@ export function invite(
|
||||||
// Sipgw calls are fire and forget. Invite them to the conference, then
|
// Sipgw calls are fire and forget. Invite them to the conference, then
|
||||||
// immediately remove them from invitesLeftToSend.
|
// immediately remove them from invitesLeftToSend.
|
||||||
const vrooms
|
const vrooms
|
||||||
= invitesLeftToSend.filter(({ type }) => type === 'videosipgw');
|
= invitesLeftToSend.filter(({ type }) => type === INVITE_TYPES.VIDEO_ROOM);
|
||||||
|
|
||||||
conference
|
conference
|
||||||
&& vrooms.length > 0
|
&& vrooms.length > 0
|
||||||
&& dispatch(inviteVideoRooms(conference, vrooms));
|
&& dispatch(inviteVideoRooms(conference, vrooms));
|
||||||
|
|
||||||
invitesLeftToSend
|
invitesLeftToSend
|
||||||
= invitesLeftToSend.filter(({ type }) => type !== 'videosipgw');
|
= invitesLeftToSend.filter(({ type }) => type !== INVITE_TYPES.VIDEO_ROOM);
|
||||||
|
|
||||||
const sipEndpoints
|
const sipEndpoints
|
||||||
= invitesLeftToSend.filter(({ type }) => type === 'sip');
|
= invitesLeftToSend.filter(({ type }) => type === INVITE_TYPES.SIP);
|
||||||
|
|
||||||
conference && inviteSipEndpoints(
|
conference && inviteSipEndpoints(
|
||||||
sipEndpoints,
|
sipEndpoints,
|
||||||
|
@ -182,7 +183,7 @@ export function invite(
|
||||||
);
|
);
|
||||||
|
|
||||||
invitesLeftToSend
|
invitesLeftToSend
|
||||||
= invitesLeftToSend.filter(({ type }) => type !== 'sip');
|
= invitesLeftToSend.filter(({ type }) => type !== INVITE_TYPES.SIP);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
Promise.all(allInvitePromises)
|
Promise.all(allInvitePromises)
|
||||||
|
|
|
@ -8,6 +8,7 @@ import {
|
||||||
showNotification
|
showNotification
|
||||||
} from '../../../notifications';
|
} from '../../../notifications';
|
||||||
import { invite } from '../../actions';
|
import { invite } from '../../actions';
|
||||||
|
import { INVITE_TYPES } from '../../constants';
|
||||||
import {
|
import {
|
||||||
getInviteResultsForQuery,
|
getInviteResultsForQuery,
|
||||||
getInviteTypeCounts,
|
getInviteTypeCounts,
|
||||||
|
@ -100,6 +101,24 @@ export default class AbstractAddPeopleDialog<P: Props, S: State>
|
||||||
this._query = this._query.bind(this);
|
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
|
* Invite people and numbers to the conference. The logic works by inviting
|
||||||
* numbers, people/rooms, sip endpoints and videosipgw in parallel. All invitees are
|
* 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) {
|
if (invitedCount >= 3) {
|
||||||
notificationProps = {
|
notificationProps = {
|
||||||
titleArguments: {
|
titleArguments: {
|
||||||
name: invitees[0].name || invitees[0].address,
|
name: this._getDisplayName(invitees[0]),
|
||||||
count: invitedCount - 1
|
count: invitedCount - 1
|
||||||
},
|
},
|
||||||
titleKey: 'notify.invitedThreePlusMembers'
|
titleKey: 'notify.invitedThreePlusMembers'
|
||||||
|
@ -168,15 +187,15 @@ export default class AbstractAddPeopleDialog<P: Props, S: State>
|
||||||
} else if (invitedCount === 2) {
|
} else if (invitedCount === 2) {
|
||||||
notificationProps = {
|
notificationProps = {
|
||||||
titleArguments: {
|
titleArguments: {
|
||||||
first: invitees[0].name || invitees[0].address,
|
first: this._getDisplayName(invitees[0]),
|
||||||
second: invitees[1].name || invitees[1].address
|
second: this._getDisplayName(invitees[1])
|
||||||
},
|
},
|
||||||
titleKey: 'notify.invitedTwoMembers'
|
titleKey: 'notify.invitedTwoMembers'
|
||||||
};
|
};
|
||||||
} else if (invitedCount) {
|
} else if (invitedCount) {
|
||||||
notificationProps = {
|
notificationProps = {
|
||||||
titleArguments: {
|
titleArguments: {
|
||||||
name: invitees[0].name || invitees[0].address
|
name: this._getDisplayName(invitees[0])
|
||||||
},
|
},
|
||||||
titleKey: 'notify.invitedOneMember'
|
titleKey: 'notify.invitedOneMember'
|
||||||
};
|
};
|
||||||
|
|
|
@ -31,7 +31,7 @@ import {
|
||||||
} from '../../../../base/react';
|
} from '../../../../base/react';
|
||||||
import { connect } from '../../../../base/redux';
|
import { connect } from '../../../../base/redux';
|
||||||
import { beginShareRoom } from '../../../../share-room';
|
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, {
|
import AbstractAddPeopleDialog, {
|
||||||
type Props as AbstractProps,
|
type Props as AbstractProps,
|
||||||
type State as AbstractState,
|
type State as AbstractState,
|
||||||
|
@ -242,13 +242,13 @@ class AddPeopleDialog extends AbstractAddPeopleDialog<Props, State> {
|
||||||
const { item } = flatListItem;
|
const { item } = flatListItem;
|
||||||
|
|
||||||
switch (item.type) {
|
switch (item.type) {
|
||||||
case 'phone':
|
case INVITE_TYPES.PHONE:
|
||||||
return {
|
return {
|
||||||
avatar: IconPhone,
|
avatar: IconPhone,
|
||||||
key: item.number,
|
key: item.number,
|
||||||
title: item.number
|
title: item.number
|
||||||
};
|
};
|
||||||
case 'user':
|
case INVITE_TYPES.USER:
|
||||||
return {
|
return {
|
||||||
avatar: item.avatar,
|
avatar: item.avatar,
|
||||||
key: item.id || item.user_id,
|
key: item.id || item.user_id,
|
||||||
|
@ -273,7 +273,7 @@ class AddPeopleDialog extends AbstractAddPeopleDialog<Props, State> {
|
||||||
* @returns {string}
|
* @returns {string}
|
||||||
*/
|
*/
|
||||||
_keyExtractor(item) {
|
_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
|
_onClearField: () => void
|
||||||
|
@ -340,7 +340,7 @@ class AddPeopleDialog extends AbstractAddPeopleDialog<Props, State> {
|
||||||
_onPressItem(item) {
|
_onPressItem(item) {
|
||||||
return () => {
|
return () => {
|
||||||
const { inviteItems } = this.state;
|
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(
|
if (inviteItems.find(
|
||||||
_.matchesProperty(finderKey, item[finderKey]))) {
|
_.matchesProperty(finderKey, item[finderKey]))) {
|
||||||
|
@ -504,10 +504,10 @@ class AddPeopleDialog extends AbstractAddPeopleDialog<Props, State> {
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (item.type) {
|
switch (item.type) {
|
||||||
case 'phone':
|
case INVITE_TYPES.PHONE:
|
||||||
selected = inviteItems.find(_.matchesProperty('number', item.number));
|
selected = inviteItems.find(_.matchesProperty('number', item.number));
|
||||||
break;
|
break;
|
||||||
case 'user':
|
case INVITE_TYPES.USER:
|
||||||
selected = item.id
|
selected = item.id
|
||||||
? inviteItems.find(_.matchesProperty('id', item.id))
|
? inviteItems.find(_.matchesProperty('id', item.id))
|
||||||
: inviteItems.find(_.matchesProperty('user_id', item.user_id));
|
: inviteItems.find(_.matchesProperty('user_id', item.user_id));
|
||||||
|
|
|
@ -12,6 +12,7 @@ import { MultiSelectAutocomplete } from '../../../../base/react';
|
||||||
import { connect } from '../../../../base/redux';
|
import { connect } from '../../../../base/redux';
|
||||||
import { isVpaasMeeting } from '../../../../billing-counter/functions';
|
import { isVpaasMeeting } from '../../../../billing-counter/functions';
|
||||||
import { hideAddPeopleDialog } from '../../../actions';
|
import { hideAddPeopleDialog } from '../../../actions';
|
||||||
|
import { INVITE_TYPES } from '../../../constants';
|
||||||
import AbstractAddPeopleDialog, {
|
import AbstractAddPeopleDialog, {
|
||||||
type Props as AbstractProps,
|
type Props as AbstractProps,
|
||||||
type State,
|
type State,
|
||||||
|
@ -181,7 +182,7 @@ class InviteContactsForm extends AbstractAddPeopleDialog<Props, State> {
|
||||||
* @returns {Object} The item to display as selected in the input.
|
* @returns {Object} The item to display as selected in the input.
|
||||||
*/
|
*/
|
||||||
_onItemSelected(item) {
|
_onItemSelected(item) {
|
||||||
if (item.item.type === 'phone') {
|
if (item.item.type === INVITE_TYPES.PHONE) {
|
||||||
item.content = item.item.number;
|
item.content = item.item.number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -285,7 +286,7 @@ class InviteContactsForm extends AbstractAddPeopleDialog<Props, State> {
|
||||||
*/
|
*/
|
||||||
_parseQueryResults(response = []) {
|
_parseQueryResults(response = []) {
|
||||||
const { t, _dialOutEnabled } = this.props;
|
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 = [];
|
const userDisplayItems = [];
|
||||||
|
|
||||||
for (const user of users) {
|
for (const user of users) {
|
||||||
|
@ -309,7 +310,7 @@ class InviteContactsForm extends AbstractAddPeopleDialog<Props, State> {
|
||||||
content: `${phone} (${name})`,
|
content: `${phone} (${name})`,
|
||||||
elemBefore: elemAvatar,
|
elemBefore: elemAvatar,
|
||||||
item: {
|
item: {
|
||||||
type: 'phone',
|
type: INVITE_TYPES.PHONE,
|
||||||
number: phone
|
number: phone
|
||||||
},
|
},
|
||||||
tag: {
|
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 telephoneIcon = this._renderTelephoneIcon();
|
||||||
|
|
||||||
const numberDisplayItems = numbers.map(number => {
|
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 => {
|
const sipDisplayItems = sipAddresses.map(sip => {
|
||||||
return {
|
return {
|
||||||
|
|
|
@ -48,3 +48,14 @@ export const OUTGOING_CALL_START_SOUND_ID = 'OUTGOING_CALL_START_SOUND_ID';
|
||||||
*/
|
*/
|
||||||
// eslint-disable-next-line max-len
|
// eslint-disable-next-line max-len
|
||||||
export const SIP_ADDRESS_REGEX = /^[a-zA-Z]+(?:([^\s>:@]+)(?::([^\s@>]+))?@)?([\w\-.]+)(?::(\d+))?((?:;[^\s=?>;]+(?:=[^\s?;]+)?)*)(?:\?(([^\s&=>]+=[^\s&=>]+)(&[^\s&=>]+=[^\s&=>]+)*))?$/;
|
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'
|
||||||
|
};
|
||||||
|
|
|
@ -10,7 +10,7 @@ import { toState } from '../base/redux';
|
||||||
import { doGetJSON, parseURIString } from '../base/util';
|
import { doGetJSON, parseURIString } from '../base/util';
|
||||||
import { isVpaasMeeting } from '../billing-counter/functions';
|
import { isVpaasMeeting } from '../billing-counter/functions';
|
||||||
|
|
||||||
import { SIP_ADDRESS_REGEX } from './constants';
|
import { INVITE_TYPES, SIP_ADDRESS_REGEX } from './constants';
|
||||||
import logger from './logger';
|
import logger from './logger';
|
||||||
|
|
||||||
declare var $: Function;
|
declare var $: Function;
|
||||||
|
@ -227,13 +227,13 @@ export function getInviteResultsForQuery(
|
||||||
* the phone number can then be cleaned up when convenient.
|
* the phone number can then be cleaned up when convenient.
|
||||||
*/
|
*/
|
||||||
const hasPhoneResult
|
const hasPhoneResult
|
||||||
= peopleResults.find(result => result.type === 'phone');
|
= peopleResults.find(result => result.type === INVITE_TYPES.PHONE);
|
||||||
|
|
||||||
if (!hasPhoneResult && typeof phoneResults.allow === 'boolean') {
|
if (!hasPhoneResult && typeof phoneResults.allow === 'boolean') {
|
||||||
results.push({
|
results.push({
|
||||||
allowed: phoneResults.allow,
|
allowed: phoneResults.allow,
|
||||||
country: phoneResults.country,
|
country: phoneResults.country,
|
||||||
type: 'phone',
|
type: INVITE_TYPES.PHONE,
|
||||||
number: phoneResults.phone,
|
number: phoneResults.phone,
|
||||||
originalEntry: text,
|
originalEntry: text,
|
||||||
showCountryCodeReminder: !hasCountryCode
|
showCountryCodeReminder: !hasCountryCode
|
||||||
|
@ -242,7 +242,7 @@ export function getInviteResultsForQuery(
|
||||||
|
|
||||||
if (sipInviteEnabled && isASipAddress(text)) {
|
if (sipInviteEnabled && isASipAddress(text)) {
|
||||||
results.push({
|
results.push({
|
||||||
type: 'sip',
|
type: INVITE_TYPES.SIP,
|
||||||
address: text
|
address: text
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue