Adds dial in default number and pin to the text for calendar/share. (#3421)
* Adds dial in default number and pin to the text for calendar/share. * Handles fail to fetch numbers or conference id.
This commit is contained in:
parent
1d128e027a
commit
7674e90d4d
|
@ -430,7 +430,7 @@
|
||||||
"share":
|
"share":
|
||||||
{
|
{
|
||||||
"mainText": "Click the following link to join the meeting:\n__roomUrl__",
|
"mainText": "Click the following link to join the meeting:\n__roomUrl__",
|
||||||
"dialInfoText": "\n\n=====\n\nJust want to dial in on your phone?\n\nClick this link to see the dial in phone numbers for this meetings\n__dialInfoPageUrl__"
|
"dialInfoText": "\n\n=====\n\nJust want to dial in on your phone?\n\n__defaultDialInNumber__Click this link to see the dial in phone numbers for this meeting\n__dialInfoPageUrl__"
|
||||||
},
|
},
|
||||||
"connection":
|
"connection":
|
||||||
{
|
{
|
||||||
|
|
|
@ -329,36 +329,35 @@ export const microsoftCalendarApi = {
|
||||||
return Promise.reject('Not authorized, please sign in!');
|
return Promise.reject('Not authorized, please sign in!');
|
||||||
}
|
}
|
||||||
|
|
||||||
const { dialInNumbersUrl } = getState()['features/base/config'];
|
return getShareInfoText(getState(), location, true/* use html */)
|
||||||
const text = getShareInfoText(
|
.then(text => {
|
||||||
location, dialInNumbersUrl !== undefined, true/* use html */);
|
const client = Client.init({
|
||||||
|
authProvider: done => done(null, token)
|
||||||
|
});
|
||||||
const client = Client.init({
|
|
||||||
authProvider: done => done(null, token)
|
|
||||||
});
|
|
||||||
|
|
||||||
return client
|
|
||||||
.api(`/me/events/${id}`)
|
|
||||||
.get()
|
|
||||||
.then(description => {
|
|
||||||
const body = description.body;
|
|
||||||
|
|
||||||
if (description.bodyPreview) {
|
|
||||||
body.content = `${description.bodyPreview}<br><br>`;
|
|
||||||
}
|
|
||||||
|
|
||||||
// replace all new lines from the text with html <br>
|
|
||||||
// to make it pretty
|
|
||||||
body.content += text.split('\n').join('<br>');
|
|
||||||
|
|
||||||
return client
|
return client
|
||||||
.api(`/me/calendar/events/${id}`)
|
.api(`/me/events/${id}`)
|
||||||
.patch({
|
.get()
|
||||||
body,
|
.then(description => {
|
||||||
location: {
|
const body = description.body;
|
||||||
'displayName': location
|
|
||||||
|
if (description.bodyPreview) {
|
||||||
|
body.content
|
||||||
|
= `${description.bodyPreview}<br><br>`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// replace all new lines from the text with html
|
||||||
|
// <br> to make it pretty
|
||||||
|
body.content += text.split('\n').join('<br>');
|
||||||
|
|
||||||
|
return client
|
||||||
|
.api(`/me/calendar/events/${id}`)
|
||||||
|
.patch({
|
||||||
|
body,
|
||||||
|
location: {
|
||||||
|
'displayName': location
|
||||||
|
}
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
|
@ -211,13 +211,8 @@ export function updateProfile() {
|
||||||
*/
|
*/
|
||||||
export function updateCalendarEvent(
|
export function updateCalendarEvent(
|
||||||
id: string, calendarId: string, location: string) {
|
id: string, calendarId: string, location: string) {
|
||||||
return (dispatch: Dispatch<*>, getState: Function) => {
|
return (dispatch: Dispatch<*>, getState: Function) =>
|
||||||
|
getShareInfoText(getState(), location)
|
||||||
const { dialInNumbersUrl } = getState()['features/base/config'];
|
.then(text =>
|
||||||
const text = getShareInfoText(location, dialInNumbersUrl !== undefined);
|
|
||||||
|
|
||||||
return googleApi.get()
|
|
||||||
.then(() =>
|
|
||||||
googleApi._updateCalendarEntry(id, calendarId, location, text));
|
googleApi._updateCalendarEntry(id, calendarId, location, text));
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,8 +10,7 @@ import { DialInSummary } from '../dial-in-summary';
|
||||||
import NoRoomError from './NoRoomError';
|
import NoRoomError from './NoRoomError';
|
||||||
|
|
||||||
document.addEventListener('DOMContentLoaded', () => {
|
document.addEventListener('DOMContentLoaded', () => {
|
||||||
const params = parseURLParams(window.location, true, 'search');
|
const { room } = parseURLParams(window.location, true, 'search');
|
||||||
const { room } = params;
|
|
||||||
|
|
||||||
ReactDOM.render(
|
ReactDOM.render(
|
||||||
<I18nextProvider i18n = { i18next }>
|
<I18nextProvider i18n = { i18next }>
|
||||||
|
@ -19,7 +18,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||||
? <DialInSummary
|
? <DialInSummary
|
||||||
className = 'dial-in-page'
|
className = 'dial-in-page'
|
||||||
clickableNumbers = { false }
|
clickableNumbers = { false }
|
||||||
room = { params.room } />
|
room = { room } />
|
||||||
: <NoRoomError className = 'dial-in-page' /> }
|
: <NoRoomError className = 'dial-in-page' /> }
|
||||||
</I18nextProvider>,
|
</I18nextProvider>,
|
||||||
document.getElementById('react')
|
document.getElementById('react')
|
||||||
|
|
|
@ -7,7 +7,7 @@ import { getInviteURL } from '../../../base/connection';
|
||||||
import { translate } from '../../../base/i18n';
|
import { translate } from '../../../base/i18n';
|
||||||
import { isLocalParticipantModerator } from '../../../base/participants';
|
import { isLocalParticipantModerator } from '../../../base/participants';
|
||||||
|
|
||||||
import { getDialInfoPageURL } from '../../functions';
|
import { _getDefaultPhoneNumber, getDialInfoPageURL } from '../../functions';
|
||||||
import DialInNumber from './DialInNumber';
|
import DialInNumber from './DialInNumber';
|
||||||
import PasswordForm from './PasswordForm';
|
import PasswordForm from './PasswordForm';
|
||||||
|
|
||||||
|
@ -49,6 +49,11 @@ class InfoDialog extends Component {
|
||||||
*/
|
*/
|
||||||
_inviteURL: PropTypes.string,
|
_inviteURL: PropTypes.string,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The current location url of the conference.
|
||||||
|
*/
|
||||||
|
_locationURL: PropTypes.object,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The value for how the conference is locked (or undefined if not
|
* The value for how the conference is locked (or undefined if not
|
||||||
* locked) as defined by room-lock constants.
|
* locked) as defined by room-lock constants.
|
||||||
|
@ -118,7 +123,7 @@ class InfoDialog extends Component {
|
||||||
|
|
||||||
if (numbers) {
|
if (numbers) {
|
||||||
this.state.phoneNumber
|
this.state.phoneNumber
|
||||||
= this._getDefaultPhoneNumber(numbers, defaultCountry);
|
= _getDefaultPhoneNumber(numbers, defaultCountry);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -157,8 +162,7 @@ class InfoDialog extends Component {
|
||||||
const { defaultCountry, numbers } = nextProps.dialIn;
|
const { defaultCountry, numbers } = nextProps.dialIn;
|
||||||
|
|
||||||
this.setState({
|
this.setState({
|
||||||
phoneNumber:
|
phoneNumber: _getDefaultPhoneNumber(numbers, defaultCountry)
|
||||||
this._getDefaultPhoneNumber(numbers, defaultCountry)
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -231,35 +235,6 @@ class InfoDialog extends Component {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the internal state of which dial-in number to display.
|
|
||||||
*
|
|
||||||
* @param {Array<string>|Object} dialInNumbers - The array or object of
|
|
||||||
* numbers to choose a number from.
|
|
||||||
* @param {string} defaultCountry - The country code for the country
|
|
||||||
* whose phone number should display.
|
|
||||||
* @private
|
|
||||||
* @returns {string|null}
|
|
||||||
*/
|
|
||||||
_getDefaultPhoneNumber(dialInNumbers, defaultCountry = 'US') {
|
|
||||||
if (Array.isArray(dialInNumbers)) {
|
|
||||||
// Dumbly return the first number if an array.
|
|
||||||
return dialInNumbers[0];
|
|
||||||
} else if (Object.keys(dialInNumbers).length > 0) {
|
|
||||||
const defaultNumbers = dialInNumbers[defaultCountry];
|
|
||||||
|
|
||||||
if (defaultNumbers) {
|
|
||||||
return defaultNumbers[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
const firstRegion = Object.keys(dialInNumbers)[0];
|
|
||||||
|
|
||||||
return firstRegion && firstRegion[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generates the URL for the static dial in info page.
|
* Generates the URL for the static dial in info page.
|
||||||
*
|
*
|
||||||
|
@ -268,7 +243,8 @@ class InfoDialog extends Component {
|
||||||
*/
|
*/
|
||||||
_getDialInfoPageURL() {
|
_getDialInfoPageURL() {
|
||||||
return getDialInfoPageURL(
|
return getDialInfoPageURL(
|
||||||
encodeURIComponent(this.props._conferenceName));
|
encodeURIComponent(this.props._conferenceName),
|
||||||
|
this.props._locationURL);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -525,6 +501,7 @@ class InfoDialog extends Component {
|
||||||
* _conference: Object,
|
* _conference: Object,
|
||||||
* _conferenceName: string,
|
* _conferenceName: string,
|
||||||
* _inviteURL: string,
|
* _inviteURL: string,
|
||||||
|
* _locationURL: string,
|
||||||
* _locked: string,
|
* _locked: string,
|
||||||
* _password: string
|
* _password: string
|
||||||
* }}
|
* }}
|
||||||
|
@ -542,6 +519,7 @@ function _mapStateToProps(state) {
|
||||||
_conference: conference,
|
_conference: conference,
|
||||||
_conferenceName: room,
|
_conferenceName: room,
|
||||||
_inviteURL: getInviteURL(state),
|
_inviteURL: getInviteURL(state),
|
||||||
|
_locationURL: state['features/base/connection'].locationURL,
|
||||||
_locked: locked,
|
_locked: locked,
|
||||||
_password: password
|
_password: password
|
||||||
};
|
};
|
||||||
|
|
|
@ -403,15 +403,16 @@ export function searchDirectory( // eslint-disable-line max-params
|
||||||
* Returns descriptive text that can be used to invite participants to a meeting
|
* Returns descriptive text that can be used to invite participants to a meeting
|
||||||
* (share via mobile or use it for calendar event description).
|
* (share via mobile or use it for calendar event description).
|
||||||
*
|
*
|
||||||
|
* @param {Object} state - The current state.
|
||||||
* @param {string} inviteUrl - The conference/location URL.
|
* @param {string} inviteUrl - The conference/location URL.
|
||||||
* @param {boolean} includeDialInfo - Whether to include or not the dialing
|
|
||||||
* information link.
|
|
||||||
* @param {boolean} useHtml - Whether to return html text.
|
* @param {boolean} useHtml - Whether to return html text.
|
||||||
* @returns {string}
|
* @returns {Promise<string>} A {@code Promise} resolving with a
|
||||||
|
* descriptive text that can be used to invite participants to a meeting.
|
||||||
*/
|
*/
|
||||||
export function getShareInfoText(
|
export function getShareInfoText(
|
||||||
inviteUrl: string, includeDialInfo: boolean, useHtml: ?boolean) {
|
state: Object, inviteUrl: string, useHtml: ?boolean): Promise<string> {
|
||||||
let roomUrl = inviteUrl;
|
let roomUrl = inviteUrl;
|
||||||
|
const includeDialInfo = state['features/base/config'] !== undefined;
|
||||||
|
|
||||||
if (useHtml) {
|
if (useHtml) {
|
||||||
roomUrl = `<a href="${roomUrl}">${roomUrl}</a>`;
|
roomUrl = `<a href="${roomUrl}">${roomUrl}</a>`;
|
||||||
|
@ -421,29 +422,90 @@ export function getShareInfoText(
|
||||||
|
|
||||||
if (includeDialInfo) {
|
if (includeDialInfo) {
|
||||||
const { room } = parseURIString(inviteUrl);
|
const { room } = parseURIString(inviteUrl);
|
||||||
let dialInfoPageUrl = getDialInfoPageURL(room);
|
let numbersPromise;
|
||||||
|
|
||||||
if (useHtml) {
|
if (state['features/invite'].numbers
|
||||||
dialInfoPageUrl
|
&& state['features/invite'].conferenceID) {
|
||||||
= `<a href="${dialInfoPageUrl}">${dialInfoPageUrl}</a>`;
|
numbersPromise = Promise.resolve(state['features/invite']);
|
||||||
|
} else {
|
||||||
|
// we are requesting numbers and conferenceId directly
|
||||||
|
// not using updateDialInNumbers, because custom room
|
||||||
|
// is specified and we do not want to store the data
|
||||||
|
// in the state
|
||||||
|
const { dialInConfCodeUrl, dialInNumbersUrl, hosts }
|
||||||
|
= state['features/base/config'];
|
||||||
|
const mucURL = hosts && hosts.muc;
|
||||||
|
|
||||||
|
if (!dialInConfCodeUrl || !dialInNumbersUrl || !mucURL) {
|
||||||
|
// URLs for fetching dial in numbers not defined
|
||||||
|
return Promise.reject();
|
||||||
|
}
|
||||||
|
|
||||||
|
numbersPromise = Promise.all([
|
||||||
|
getDialInNumbers(dialInNumbersUrl),
|
||||||
|
getDialInConferenceID(dialInConfCodeUrl, room, mucURL)
|
||||||
|
]).then(([ { defaultCountry, numbers }, {
|
||||||
|
conference, id, message } ]) => {
|
||||||
|
|
||||||
|
if (!conference || !id) {
|
||||||
|
return Promise.reject(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
defaultCountry,
|
||||||
|
numbers,
|
||||||
|
conferenceID: id
|
||||||
|
};
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
infoText += i18next.t('share.dialInfoText', { dialInfoPageUrl });
|
return numbersPromise.then(
|
||||||
|
({ conferenceID, defaultCountry, numbers }) => {
|
||||||
|
const phoneNumber
|
||||||
|
= _getDefaultPhoneNumber(numbers, defaultCountry) || '';
|
||||||
|
|
||||||
|
return `${
|
||||||
|
i18next.t('info.dialInNumber')} ${
|
||||||
|
phoneNumber} ${
|
||||||
|
i18next.t('info.dialInConferenceID')} ${
|
||||||
|
conferenceID}#\n\n`;
|
||||||
|
})
|
||||||
|
.catch(error =>
|
||||||
|
logger.error('Error fetching numbers or conferenceID', error))
|
||||||
|
.then(defaultDialInNumber => {
|
||||||
|
let dialInfoPageUrl = getDialInfoPageURL(
|
||||||
|
room,
|
||||||
|
state['features/base/connection'].locationURL);
|
||||||
|
|
||||||
|
if (useHtml) {
|
||||||
|
dialInfoPageUrl
|
||||||
|
= `<a href="${dialInfoPageUrl}">${dialInfoPageUrl}</a>`;
|
||||||
|
}
|
||||||
|
|
||||||
|
infoText += i18next.t('share.dialInfoText', {
|
||||||
|
defaultDialInNumber,
|
||||||
|
dialInfoPageUrl });
|
||||||
|
|
||||||
|
return infoText;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return infoText;
|
return Promise.resolve(infoText);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generates the URL for the static dial in info page.
|
* Generates the URL for the static dial in info page.
|
||||||
*
|
*
|
||||||
* @param {string} conferenceName - The conference name.
|
* @param {string} conferenceName - The conference name.
|
||||||
* @private
|
* @param {Object} locationURL - The current location URL, the object coming
|
||||||
|
* from state ['features/base/connection'].locationURL.
|
||||||
* @returns {string}
|
* @returns {string}
|
||||||
*/
|
*/
|
||||||
export function getDialInfoPageURL(conferenceName: string) {
|
export function getDialInfoPageURL(
|
||||||
const origin = window.location.origin;
|
conferenceName: string,
|
||||||
const pathParts = window.location.pathname.split('/');
|
locationURL: Object) {
|
||||||
|
const origin = locationURL.origin;
|
||||||
|
const pathParts = locationURL.pathname.split('/');
|
||||||
|
|
||||||
pathParts.length = pathParts.length - 1;
|
pathParts.length = pathParts.length - 1;
|
||||||
|
|
||||||
|
@ -457,3 +519,34 @@ export function getDialInfoPageURL(conferenceName: string) {
|
||||||
|
|
||||||
return `${origin}${newPath}/static/dialInInfo.html?room=${conferenceName}`;
|
return `${origin}${newPath}/static/dialInInfo.html?room=${conferenceName}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the internal state of which dial-in number to display.
|
||||||
|
*
|
||||||
|
* @param {Array<string>|Object} dialInNumbers - The array or object of
|
||||||
|
* numbers to choose a number from.
|
||||||
|
* @param {string} defaultCountry - The country code for the country
|
||||||
|
* whose phone number should display.
|
||||||
|
* @private
|
||||||
|
* @returns {string|null}
|
||||||
|
*/
|
||||||
|
export function _getDefaultPhoneNumber(
|
||||||
|
dialInNumbers: Object,
|
||||||
|
defaultCountry: string = 'US') {
|
||||||
|
if (Array.isArray(dialInNumbers)) {
|
||||||
|
// Dumbly return the first number if an array.
|
||||||
|
return dialInNumbers[0];
|
||||||
|
} else if (Object.keys(dialInNumbers).length > 0) {
|
||||||
|
const defaultNumbers = dialInNumbers[defaultCountry];
|
||||||
|
|
||||||
|
if (defaultNumbers) {
|
||||||
|
return defaultNumbers[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
const firstRegion = Object.keys(dialInNumbers)[0];
|
||||||
|
|
||||||
|
return firstRegion && firstRegion[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
|
@ -19,9 +19,7 @@ export function beginShareRoom(roomURL: ?string): Function {
|
||||||
}
|
}
|
||||||
roomURL && dispatch({
|
roomURL && dispatch({
|
||||||
type: BEGIN_SHARE_ROOM,
|
type: BEGIN_SHARE_ROOM,
|
||||||
roomURL,
|
roomURL
|
||||||
includeDialInfo: getState()['features/base/config']
|
|
||||||
.dialInNumbersUrl !== undefined
|
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,7 +21,7 @@ const logger = require('jitsi-meet-logger').getLogger(__filename);
|
||||||
MiddlewareRegistry.register(store => next => action => {
|
MiddlewareRegistry.register(store => next => action => {
|
||||||
switch (action.type) {
|
switch (action.type) {
|
||||||
case BEGIN_SHARE_ROOM:
|
case BEGIN_SHARE_ROOM:
|
||||||
_shareRoom(action.roomURL, action.includeDialInfo, store.dispatch);
|
_shareRoom(action.roomURL, store);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -32,36 +32,35 @@ MiddlewareRegistry.register(store => next => action => {
|
||||||
* Open the native sheet for sharing a specific conference/room URL.
|
* Open the native sheet for sharing a specific conference/room URL.
|
||||||
*
|
*
|
||||||
* @param {string} roomURL - The URL of the conference/room to be shared.
|
* @param {string} roomURL - The URL of the conference/room to be shared.
|
||||||
* @param {boolean} includeDialInfo - Whether to include or not the dialing
|
* @param {Store} store - Redux store.
|
||||||
* information link.
|
|
||||||
* @param {Dispatch} dispatch - The Redux dispatch function.
|
|
||||||
* @private
|
* @private
|
||||||
* @returns {void}
|
* @returns {void}
|
||||||
*/
|
*/
|
||||||
function _shareRoom(
|
function _shareRoom(roomURL: string, { dispatch, getState }) {
|
||||||
roomURL: string, includeDialInfo: boolean, dispatch: Function) {
|
getShareInfoText(getState(), roomURL)
|
||||||
const message = getShareInfoText(roomURL, includeDialInfo);
|
.then(message => {
|
||||||
const title = `${getName()} Conference`;
|
const title = `${getName()} Conference`;
|
||||||
const onFulfilled
|
const onFulfilled
|
||||||
= (shared: boolean) => dispatch(endShareRoom(roomURL, shared));
|
= (shared: boolean) => dispatch(endShareRoom(roomURL, shared));
|
||||||
|
|
||||||
Share.share(
|
Share.share(
|
||||||
/* content */ {
|
/* content */ {
|
||||||
message,
|
message,
|
||||||
title
|
title
|
||||||
},
|
},
|
||||||
/* options */ {
|
/* options */ {
|
||||||
dialogTitle: title, // Android
|
dialogTitle: title, // Android
|
||||||
subject: title // iOS
|
subject: title // iOS
|
||||||
})
|
})
|
||||||
.then(
|
.then(
|
||||||
/* onFulfilled */ value => {
|
/* onFulfilled */ value => {
|
||||||
onFulfilled(value.action === Share.sharedAction);
|
onFulfilled(value.action === Share.sharedAction);
|
||||||
},
|
},
|
||||||
/* onRejected */ reason => {
|
/* onRejected */ reason => {
|
||||||
logger.error(
|
logger.error(
|
||||||
`Failed to share conference/room URL ${roomURL}:`,
|
`Failed to share conference/room URL ${roomURL}:`,
|
||||||
reason);
|
reason);
|
||||||
onFulfilled(false);
|
onFulfilled(false);
|
||||||
});
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue