fix(sip) allow sip invites to contain phone numbers
display sip address in invites hide lobby password for sip users tidy up invite placeholders
This commit is contained in:
parent
7396db71fd
commit
f7ddcbbbf3
|
@ -5,6 +5,7 @@
|
|||
"copyInvite": "Copy meeting invitation",
|
||||
"copyLink": "Copy meeting link",
|
||||
"copyStream": "Copy live streaming link",
|
||||
"contacts": "contacts",
|
||||
"countryNotSupported": "We do not support this destination yet.",
|
||||
"countryReminder": "Calling outside the US? Please make sure you start with the country code!",
|
||||
"defaultEmail": "Your Default Email",
|
||||
|
@ -16,19 +17,14 @@
|
|||
"inviteMoreMailSubject": "Join {{appName}} meeting",
|
||||
"inviteMorePrompt": "Invite more people",
|
||||
"linkCopied": "Link copied to clipboard",
|
||||
"loading": "Searching for people and phone numbers",
|
||||
"loadingNumber": "Validating phone number",
|
||||
"loadingPeople": "Searching for people to invite",
|
||||
"noResults": "No matching search results",
|
||||
"noValidNumbers": "Please enter a phone number",
|
||||
"outlookEmail": "Outlook Email",
|
||||
"searchNumbers": "Add phone numbers",
|
||||
"searchPeople": "Search for people",
|
||||
"searchPeopleAndNumbers": "Search for people or add their phone numbers",
|
||||
"phoneNumbers": "phone numbers",
|
||||
"searching": "Searching...",
|
||||
"shareInvite": "Share meeting invitation",
|
||||
"shareLink": "Share the meeting link to invite others",
|
||||
"shareStream": "Share the live streaming link",
|
||||
"sip": "SIP: {{address}}",
|
||||
"sipAddresses": "sip addresses",
|
||||
"telephone": "Telephone: {{number}}",
|
||||
"title": "Invite people to this meeting",
|
||||
"yahooEmail": "Yahoo Email"
|
||||
|
@ -379,6 +375,7 @@
|
|||
"inviteLiveStream": "To view the live stream of this meeting, click this link: {{url}}",
|
||||
"invitePhone": "To join by phone instead, tap this: {{number}},,{{conferenceID}}#\n",
|
||||
"invitePhoneAlternatives": "Looking for a different dial-in number?\nSee meeting dial-in numbers: {{url}}\n\n\nIf also dialing-in through a room phone, join without connecting to audio: {{silentUrl}}",
|
||||
"inviteSipEndpoint": "To join using the SIP address, enter this: {{sipUri}}",
|
||||
"inviteURLFirstPartGeneral": "You are invited to join a meeting.",
|
||||
"inviteURLFirstPartPersonal": "{{name}} is inviting you to a meeting.\n",
|
||||
"inviteURLSecondPart": "\nJoin the meeting:\n{{url}}\n",
|
||||
|
|
|
@ -215,7 +215,7 @@ export function updateDialInNumbers() {
|
|||
getDialInNumbers(dialInNumbersUrl, room, mucURL),
|
||||
getDialInConferenceID(dialInConfCodeUrl, room, mucURL)
|
||||
])
|
||||
.then(([ dialInNumbers, { conference, id, message } ]) => {
|
||||
.then(([ dialInNumbers, { conference, id, message, sipUri } ]) => {
|
||||
if (!conference || !id) {
|
||||
return Promise.reject(message);
|
||||
}
|
||||
|
@ -223,7 +223,8 @@ export function updateDialInNumbers() {
|
|||
dispatch({
|
||||
type: UPDATE_DIAL_IN_NUMBERS_SUCCESS,
|
||||
conferenceID: id,
|
||||
dialInNumbers
|
||||
dialInNumbers,
|
||||
sipUri
|
||||
});
|
||||
})
|
||||
.catch(error => {
|
||||
|
|
|
@ -57,6 +57,8 @@ class InviteContactsForm extends AbstractAddPeopleDialog<Props, State> {
|
|||
|
||||
_resourceClient: Object;
|
||||
|
||||
_translations: Object;
|
||||
|
||||
state = {
|
||||
addToCallError: false,
|
||||
addToCallInProgress: false,
|
||||
|
@ -86,6 +88,16 @@ class InviteContactsForm extends AbstractAddPeopleDialog<Props, State> {
|
|||
makeQuery: this._query,
|
||||
parseResults: this._parseQueryResults
|
||||
};
|
||||
|
||||
|
||||
const { t } = props;
|
||||
|
||||
this._translations = {
|
||||
_dialOutEnabled: t('addPeople.phoneNumbers'),
|
||||
_addPeopleEnabled: t('addPeople.contacts'),
|
||||
_sipInviteEnabled: t('addPeople.sipAddresses')
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -118,30 +130,29 @@ class InviteContactsForm extends AbstractAddPeopleDialog<Props, State> {
|
|||
_addPeopleEnabled,
|
||||
_dialOutEnabled,
|
||||
_isVpaas,
|
||||
_sipInviteEnabled,
|
||||
t
|
||||
} = this.props;
|
||||
const footerText = this._renderFooterText();
|
||||
let isMultiSelectDisabled = this.state.addToCallInProgress;
|
||||
let placeholder;
|
||||
let loadingMessage;
|
||||
let noMatches;
|
||||
const loadingMessage = 'addPeople.searching';
|
||||
const noMatches = 'addPeople.noResults';
|
||||
|
||||
if (_addPeopleEnabled && _dialOutEnabled) {
|
||||
loadingMessage = 'addPeople.loading';
|
||||
noMatches = 'addPeople.noResults';
|
||||
placeholder = 'addPeople.searchPeopleAndNumbers';
|
||||
} else if (_addPeopleEnabled) {
|
||||
loadingMessage = 'addPeople.loadingPeople';
|
||||
noMatches = 'addPeople.noResults';
|
||||
placeholder = 'addPeople.searchPeople';
|
||||
} else if (_dialOutEnabled) {
|
||||
loadingMessage = 'addPeople.loadingNumber';
|
||||
noMatches = 'addPeople.noValidNumbers';
|
||||
placeholder = 'addPeople.searchNumbers';
|
||||
} else {
|
||||
const features = {
|
||||
_dialOutEnabled,
|
||||
_addPeopleEnabled,
|
||||
_sipInviteEnabled
|
||||
};
|
||||
|
||||
const computedPlaceholder = Object.keys(features)
|
||||
.filter(v => Boolean(features[v]))
|
||||
.map(v => this._translations[v])
|
||||
.join(', ');
|
||||
|
||||
const placeholder = computedPlaceholder ? `${t('dialog.add')} ${computedPlaceholder}` : t('addPeople.disabled');
|
||||
|
||||
if (!computedPlaceholder) {
|
||||
isMultiSelectDisabled = true;
|
||||
noMatches = 'addPeople.noResults';
|
||||
placeholder = 'addPeople.disabled';
|
||||
}
|
||||
|
||||
return (
|
||||
|
@ -156,7 +167,7 @@ class InviteContactsForm extends AbstractAddPeopleDialog<Props, State> {
|
|||
noMatchesFound = { t(noMatches) }
|
||||
onItemSelected = { this._onItemSelected }
|
||||
onSelectionChange = { this._onSelectionChange }
|
||||
placeholder = { t(placeholder) }
|
||||
placeholder = { placeholder }
|
||||
ref = { this._setMultiSelectElement }
|
||||
resourceClient = { this._resourceClient }
|
||||
shouldFitContainer = { true }
|
||||
|
|
|
@ -47,7 +47,7 @@ export const OUTGOING_CALL_START_SOUND_ID = 'OUTGOING_CALL_START_SOUND_ID';
|
|||
* Regex for matching sip addresses.
|
||||
*/
|
||||
// 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-Z0-9]+(?:([^\s>:@]+)(?::([^\s@>]+))?@)?([\w\-.]+)(?::(\d+))?((?:;[^\s=?>;]+(?:=[^\s?;]+)?)*)(?:\?(([^\s&=>]+=[^\s&=>]+)(&[^\s&=>]+=[^\s&=>]+)*))?$/;
|
||||
|
||||
/**
|
||||
* Different invite types mapping
|
||||
|
|
|
@ -301,6 +301,14 @@ export function getInviteText({
|
|||
invite = `${invite}\n${dial}\n${moreNumbers}`;
|
||||
}
|
||||
|
||||
if (dialIn.sipUri) {
|
||||
const sipText = t('info.inviteSipEndpoint', {
|
||||
sipUri: dialIn.sipUri
|
||||
});
|
||||
|
||||
invite = `${invite}\n${sipText}`;
|
||||
}
|
||||
|
||||
return invite;
|
||||
}
|
||||
|
||||
|
|
|
@ -60,6 +60,7 @@ ReducerRegistry.register('features/invite', (state = DEFAULT_STATE, action) => {
|
|||
...state,
|
||||
conferenceID: action.conferenceID,
|
||||
numbers: action.dialInNumbers,
|
||||
sipUri: action.sipUri,
|
||||
numbersEnabled: true,
|
||||
numbersFetched: true
|
||||
};
|
||||
|
|
|
@ -46,6 +46,11 @@ export type Props = {
|
|||
*/
|
||||
_passwordJoinFailed: boolean,
|
||||
|
||||
/**
|
||||
* True if the password field should be available for lobby participants.
|
||||
*/
|
||||
_renderPassword: boolean,
|
||||
|
||||
/**
|
||||
* The Redux dispatch function.
|
||||
*/
|
||||
|
@ -365,6 +370,7 @@ export function _mapStateToProps(state: Object): $Shape<Props> {
|
|||
const localParticipant = getLocalParticipant(state);
|
||||
const participantId = localParticipant?.id;
|
||||
const { knocking, passwordJoinFailed } = state['features/lobby'];
|
||||
const { iAmSipGateway } = state['features/base/config'];
|
||||
|
||||
return {
|
||||
_knocking: knocking,
|
||||
|
@ -372,6 +378,7 @@ export function _mapStateToProps(state: Object): $Shape<Props> {
|
|||
_participantEmail: localParticipant?.email,
|
||||
_participantId: participantId,
|
||||
_participantName: localParticipant?.name,
|
||||
_passwordJoinFailed: passwordJoinFailed
|
||||
_passwordJoinFailed: passwordJoinFailed,
|
||||
_renderPassword: !iAmSipGateway
|
||||
};
|
||||
}
|
||||
|
|
|
@ -208,7 +208,7 @@ class LobbyScreen extends AbstractLobbyScreen {
|
|||
* @inheritdoc
|
||||
*/
|
||||
_renderStandardButtons() {
|
||||
const { _knocking, t } = this.props;
|
||||
const { _knocking, _renderPassword, t } = this.props;
|
||||
|
||||
return (
|
||||
<>
|
||||
|
@ -223,7 +223,7 @@ class LobbyScreen extends AbstractLobbyScreen {
|
|||
{ t('lobby.knockButton') }
|
||||
</Text>
|
||||
</TouchableOpacity> }
|
||||
<TouchableOpacity
|
||||
{ _renderPassword && <TouchableOpacity
|
||||
onPress = { this._onSwitchToPasswordMode }
|
||||
style = { [
|
||||
styles.button,
|
||||
|
@ -232,7 +232,7 @@ class LobbyScreen extends AbstractLobbyScreen {
|
|||
<Text>
|
||||
{ t('lobby.enterPasswordButton') }
|
||||
</Text>
|
||||
</TouchableOpacity>
|
||||
</TouchableOpacity> }
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -152,7 +152,7 @@ class LobbyScreen extends AbstractLobbyScreen {
|
|||
* @inheritdoc
|
||||
*/
|
||||
_renderStandardButtons() {
|
||||
const { _knocking, t } = this.props;
|
||||
const { _knocking, _renderPassword, t } = this.props;
|
||||
|
||||
return (
|
||||
<>
|
||||
|
@ -163,12 +163,12 @@ class LobbyScreen extends AbstractLobbyScreen {
|
|||
type = 'primary'>
|
||||
{ t('lobby.knockButton') }
|
||||
</ActionButton> }
|
||||
<ActionButton
|
||||
{_renderPassword && <ActionButton
|
||||
onClick = { this._onSwitchToPasswordMode }
|
||||
testId = 'lobby.enterPasswordButton'
|
||||
type = 'secondary'>
|
||||
{ t('lobby.enterPasswordButton') }
|
||||
</ActionButton>
|
||||
</ActionButton> }
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue