feat(invite): send DTMF tones if specified as part of phone number text
If phone number to be invited into the conference ends with a comma then the following part will be stored in redux state and sent later as DTMF tones after Jigasi connects to the conference.
This commit is contained in:
parent
8dc0f30a49
commit
bc54a87f2e
|
@ -61,6 +61,15 @@ export const SET_DIAL_IN_SUMMARY_VISIBLE = 'SET_DIAL_IN_SUMMARY_VISIBLE';
|
|||
*/
|
||||
export const SET_INVITE_DIALOG_VISIBLE = 'SET_INVITE_DIALOG_VISIBLE';
|
||||
|
||||
/**
|
||||
* The type of Redux action which stores pending dtmf. Check out the {@link storePendingDTMF} action for more details.
|
||||
* {
|
||||
* type: STORE_PENDING_DTMF,
|
||||
* pendingDtmf: ?string
|
||||
* }
|
||||
*/
|
||||
export const STORE_PENDING_DTMF = 'STORE_PENDING_DTMF';
|
||||
|
||||
/**
|
||||
* The type of the action which signals an error occurred while requesting dial-
|
||||
* in numbers.
|
||||
|
|
|
@ -13,13 +13,15 @@ import {
|
|||
SET_CALLEE_INFO_VISIBLE,
|
||||
SET_DIAL_IN_SUMMARY_VISIBLE,
|
||||
SET_INVITE_DIALOG_VISIBLE,
|
||||
STORE_PENDING_DTMF,
|
||||
UPDATE_DIAL_IN_NUMBERS_FAILED,
|
||||
UPDATE_DIAL_IN_NUMBERS_SUCCESS
|
||||
} from './actionTypes';
|
||||
import {
|
||||
getDialInConferenceID,
|
||||
getDialInNumbers,
|
||||
invitePeopleAndChatRooms
|
||||
invitePeopleAndChatRooms,
|
||||
splitPhoneNumberAndDTMF
|
||||
} from './functions';
|
||||
import logger from './logger';
|
||||
|
||||
|
@ -98,7 +100,12 @@ export function invite(
|
|||
// For each number, dial out. On success, remove the number from
|
||||
// {@link invitesLeftToSend}.
|
||||
const phoneInvitePromises = phoneNumbers.map(item => {
|
||||
const numberToInvite = item.number;
|
||||
const {
|
||||
dtmf,
|
||||
phoneNumber: numberToInvite
|
||||
} = splitPhoneNumberAndDTMF(item.number);
|
||||
|
||||
dtmf && dispatch(storePendingDTMF(dtmf));
|
||||
|
||||
return conference.dial(numberToInvite)
|
||||
.then(() => {
|
||||
|
@ -157,6 +164,25 @@ export function invite(
|
|||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores pending DTMF tones to be sent after a phone connection is established. If more than one phone numbers are
|
||||
* invited into the conference then weird things may happen, as there's no way to match participant with the invited
|
||||
* phone number.
|
||||
*
|
||||
* @param {string} pendingDtmf - A string with digits and dtmf characters that will be sent after Jigasi participant
|
||||
* joins the conference and enters the {@link CONNECTED_USER} state.
|
||||
* @returns {{
|
||||
* pendingDtmf: ?string,
|
||||
* type: STORE_PENDING_DTMF
|
||||
* }}
|
||||
*/
|
||||
export function storePendingDTMF(pendingDtmf: ?string) {
|
||||
return {
|
||||
type: STORE_PENDING_DTMF,
|
||||
pendingDtmf
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends AJAX requests for dial-in numbers and conference ID.
|
||||
*
|
||||
|
|
|
@ -340,7 +340,9 @@ function isMaybeAPhoneNumber(text: string): boolean {
|
|||
* @returns {RegExp}
|
||||
*/
|
||||
function isPhoneNumberRegex(): RegExp {
|
||||
let regexString = '^[0-9+()-\\s]*$';
|
||||
// The ',' '*' '#' characters are allowed to be able to specify pending DTMF tones to be dialed just after the phone
|
||||
// connection is established.
|
||||
let regexString = '^[0-9+()-\\s,*#]*$';
|
||||
|
||||
if (typeof interfaceConfig !== 'undefined') {
|
||||
regexString = interfaceConfig.PHONE_NUMBER_REGEX || regexString;
|
||||
|
@ -349,6 +351,37 @@ function isPhoneNumberRegex(): RegExp {
|
|||
return new RegExp(regexString);
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts the DTMF part out of the phone number text. The DTMF is to be specified after a comma and must contain
|
||||
* only DTMF tone characters for example: "+12223334444,23,4*9#".
|
||||
*
|
||||
* @param {string} phoneNumberText - See the text above.
|
||||
* @returns {{
|
||||
* phoneNumber: string,
|
||||
* dtmf: ?string
|
||||
* }}
|
||||
*/
|
||||
export function splitPhoneNumberAndDTMF(phoneNumberText: string) {
|
||||
const firstCommaIdx = phoneNumberText.indexOf(',');
|
||||
let dtmf, phoneNumber = phoneNumberText;
|
||||
|
||||
if (firstCommaIdx !== -1) {
|
||||
dtmf = phoneNumberText.substr(firstCommaIdx);
|
||||
|
||||
phoneNumber = phoneNumberText.substr(0, firstCommaIdx);
|
||||
|
||||
// There's no point in playing just commas, so clear the dtmf var
|
||||
if (!dtmf.replace(',', '').length) {
|
||||
dtmf = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
phoneNumber,
|
||||
dtmf
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends an ajax request to a directory service.
|
||||
*
|
||||
|
|
|
@ -4,3 +4,4 @@ export * from './functions';
|
|||
|
||||
import './reducer';
|
||||
import './middleware';
|
||||
import './pendingDtmfMiddleware';
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
import { CONNECTED_USER } from '../presence-status';
|
||||
|
||||
import { getCurrentConference } from '../base/conference';
|
||||
import { StateListenerRegistry } from '../base/redux';
|
||||
|
||||
import { storePendingDTMF } from './actions';
|
||||
import logger from './logger';
|
||||
import { getPendingDtmf } from './selectors';
|
||||
|
||||
StateListenerRegistry.register(
|
||||
state => {
|
||||
const jigasiParticipantId
|
||||
= state['features/base/participants']
|
||||
.find(p => p.isJigasi && p.presence?.toLowerCase() === CONNECTED_USER)
|
||||
?.id;
|
||||
|
||||
return jigasiParticipantId;
|
||||
},
|
||||
(jigasiParticipantId, { getState, dispatch }) => {
|
||||
const state = getState();
|
||||
const pendingDtmf = jigasiParticipantId && getPendingDtmf(state);
|
||||
const conference = getCurrentConference(state);
|
||||
|
||||
if (conference && pendingDtmf) {
|
||||
logger.info('Sending pending DTMF tones');
|
||||
conference.sendTones(pendingDtmf);
|
||||
dispatch(storePendingDTMF(undefined));
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
StateListenerRegistry.register(
|
||||
state => getCurrentConference(state),
|
||||
(conference, { dispatch }, prevConference) => {
|
||||
if (prevConference && conference !== prevConference) {
|
||||
dispatch(storePendingDTMF(undefined));
|
||||
}
|
||||
}
|
||||
);
|
|
@ -8,6 +8,7 @@ import {
|
|||
SET_CALLEE_INFO_VISIBLE,
|
||||
SET_DIAL_IN_SUMMARY_VISIBLE,
|
||||
SET_INVITE_DIALOG_VISIBLE,
|
||||
STORE_PENDING_DTMF,
|
||||
UPDATE_DIAL_IN_NUMBERS_FAILED,
|
||||
UPDATE_DIAL_IN_NUMBERS_SUCCESS
|
||||
} from './actionTypes';
|
||||
|
@ -23,6 +24,13 @@ const DEFAULT_STATE = {
|
|||
calleeInfoVisible: false,
|
||||
inviteDialogVisible: false,
|
||||
numbersEnabled: true,
|
||||
|
||||
/**
|
||||
* Pending DTMF tones. See {@link storePendingDTMF} for more info.
|
||||
*
|
||||
* @type {string|undefined}
|
||||
*/
|
||||
pendingDtmf: undefined,
|
||||
pendingInviteRequests: []
|
||||
};
|
||||
|
||||
|
@ -62,6 +70,12 @@ ReducerRegistry.register('features/invite', (state = DEFAULT_STATE, action) => {
|
|||
inviteDialogVisible: action.visible
|
||||
};
|
||||
|
||||
case STORE_PENDING_DTMF:
|
||||
return {
|
||||
...state,
|
||||
pendingDtmf: action.pendingDtmf
|
||||
};
|
||||
|
||||
case UPDATE_DIAL_IN_NUMBERS_FAILED:
|
||||
return {
|
||||
...state,
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
/**
|
||||
* Retrieves pending DTMF tones if any. See {@link storePendingDTMF} for more info.
|
||||
*
|
||||
* @param {Object} state - The Redux state.
|
||||
* @returns {string}
|
||||
*/
|
||||
export function getPendingDtmf(state) {
|
||||
return state['features/invite'].pendingDtmf;
|
||||
}
|
Loading…
Reference in New Issue