Adds new format of phoneList service and re-design dial in numbers page. (#3903)

* Adds new format of phoneList service and re-design dial in numbers page.

Adds flags and country names (with translations) for the numbers if using the new format.

* Fixes tests and fixes get default number.

* Updates swagger with new format.

* Moves html back yo table.

Fixes displaying on mobile and also the tel: URI generation. The tel: URI is tested on Android and iOS and seems to work (Android was not interpreting 'p', but both seems to like ',').

* Fixes a wrong return statement.

* Small fixes.
This commit is contained in:
Дамян Минков 2019-02-26 13:32:46 +00:00 committed by GitHub
parent d7eea8abbc
commit ea4d49f2a0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 351 additions and 138 deletions

View File

@ -28,7 +28,7 @@
max-width: 40em; max-width: 40em;
padding: 35px 0 40px 0; padding: 35px 0 40px 0;
text-align: center; text-align: center;
width: 75%; width: 90%;
a:active { a:active {
text-decoration: none; text-decoration: none;
@ -46,7 +46,7 @@
&__text, &__text,
.deep-linking-dial-in { .deep-linking-dial-in {
font-size: 1.2em; font-size: 1em;
line-height: em(29px, 21px); line-height: em(29px, 21px);
margin-bottom: 0.65em; margin-bottom: 0.65em;
@ -59,6 +59,26 @@
font-size: em(21, 18); font-size: em(21, 18);
} }
} }
table {
font-size: 1em;
}
.dial-in-conference-id {
margin: 10px 0 10px 0;
}
.dial-in-conference-description {
font-size: 0.8em;
}
.toll-free-list {
min-width: 80px;
}
.numbers-list {
min-width: 150px;
}
} }
&__href { &__href {

View File

@ -124,29 +124,75 @@
} }
} }
.dial-in-numbers-list {
margin-top: 20px;
font-size: 12px;
line-height: 24px;
border-collapse: separate;
border-spacing: 0 5px;
thead {
text-align: left;
}
td,
th {
border-bottom: 1px solid #d1dbe8;
}
.flag {
border-bottom-style: none;
width: 30px;
vertical-align: top;
}
.country {
font-weight: bold;
vertical-align: top;
padding: 0 20px 0 0;
}
ul {
padding: 0px 0px 0px 0px;
}
.numbers-list {
list-style: none;
padding: 0 20px 0 0;
}
.toll-free-list {
font-weight: bold;
list-style: none;
vertical-align: top;
}
}
.dial-in-page { .dial-in-page {
align-items: center; align-items: center;
box-sizing: border-box; box-sizing: border-box;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
font-size: 24px; font-size: 12px;
max-height: 100%; max-height: 100%;
overflow: auto; overflow: auto;
padding: 25px;
position: absolute; position: absolute;
transform: translateY(-50%); transform: translateY(-50%);
top: 50%; top: 50%;
width: 100%; width: 100%;
.dial-in-numbers-list {
font-size: 24px;
margin-top: 20px;
}
.dial-in-conference-id { .dial-in-conference-id {
text-align: center; text-align: center;
min-width: 200px; min-width: 200px;
width: 30%; }
.dial-in-conference-name,
.dial-in-conference-pin {
font-size: 18px;
}
.dial-in-conference-description {
margin: 12px;
} }
} }

12
debian/rules vendored
View File

@ -3,12 +3,22 @@
# Uncomment this to turn on verbose mode. # Uncomment this to turn on verbose mode.
#export DH_VERBOSE=1 #export DH_VERBOSE=1
LANGUAGES := $(shell node -p "Object.keys(require('./lang/languages.json')).join(' ')")
COUNTRIES_DIR := node_modules/i18n-iso-countries/langs
%: %:
dh $@ dh $@
# we skip making Makefile exists for updating browserify modules when developing # we skip making Makefile exists for updating browserify modules when developing
override_dh_auto_build: override_dh_auto_build:
override_dh_install: override_dh_install: $(LANGUAGES)
dh_installdirs dh_installdirs
dh_install -X/config.js -X/package.json dh_install -X/config.js -X/package.json
$(LANGUAGES):
if [ -f $(COUNTRIES_DIR)/$@.json ] ; \
then \
dh_install -pjitsi-meet-web $(COUNTRIES_DIR)/$@.json usr/share/jitsi-meet/lang/; \
mv debian/jitsi-meet-web/usr/share/jitsi-meet/lang/$@.json debian/jitsi-meet-web/usr/share/jitsi-meet/lang/countries-$@.json; \
fi;

View File

@ -71,7 +71,7 @@ paths:
$ref: "#/definitions/ConferenceMapperDetails" $ref: "#/definitions/ConferenceMapperDetails"
405: 405:
description: "Invalid input" description: "Invalid input"
/phoneNumberList: /phoneNumberList:
get: get:
tags: tags:
@ -96,7 +96,7 @@ securityDefinitions:
name: "Authorization" name: "Authorization"
in: "header" in: "header"
definitions: definitions:
ConferenceMapperRequest: ConferenceMapperRequest:
description: "Request to create or find a conference mapping" description: "Request to create or find a conference mapping"
type: "object" type: "object"
@ -114,7 +114,7 @@ definitions:
domain: domain:
type: "string" type: "string"
description: "Domain part of the conference. Used if 'conference' is not provided. Defaults to domain of the API endpoint. Used to generate a 'conference' value (search by conference)" description: "Domain part of the conference. Used if 'conference' is not provided. Defaults to domain of the API endpoint. Used to generate a 'conference' value (search by conference)"
ConferenceMapperDetails: ConferenceMapperDetails:
description: "Conference mapping between conference JID and numeric ID" description: "Conference mapping between conference JID and numeric ID"
type: "object" type: "object"
@ -126,22 +126,26 @@ definitions:
type: "string" type: "string"
format: "JID" format: "JID"
description: "Full JID for the conference OR boolean false if no conference was found (search by ID)" description: "Full JID for the conference OR boolean false if no conference was found (search by ID)"
PhoneNumberList: PhoneNumberList:
type: "object" description: "List of dial in numbers for the conference."
properties: type: "array"
numbersEnabled: items:
type: "boolean"
description: "Control flag for Jitsi Meet user interface. Must be set to true for Jitsi Meet to display phone-in UI elements"
numbers:
type: "object" type: "object"
description: "Keys are Country Names, each value is an array of phone numbers" properties:
additionalProperties: countryCode:
type: "array"
items:
type: "string" type: "string"
format: "phone" description: "ISO 3166-1 country code. Alpha-2 supported."
default:
type: "boolean"
description: "Whether this number is the default one to show. Optional."
formattedNumber:
type: "string"
description: "The formatted telephone number to show."
tollFree:
type: "boolean"
description: "Whether the number is toll free number."
externalDocs: externalDocs:
description: "Find out more about the Jitsi Cloud API" description: "Find out more about the Jitsi Cloud API"
url: "https://jitsi.org/CloudAPI" url: "https://jitsi.org/CloudAPI"

View File

@ -344,10 +344,11 @@
"cancelPassword": "Cancel password", "cancelPassword": "Cancel password",
"conferenceURL": "Link:", "conferenceURL": "Link:",
"country": "Country", "country": "Country",
"dialANumber": "To join your meeting, dial one of these numbers and then enter this PIN: __conferenceID__#", "dialANumber": "To join your meeting, dial one of these numbers and then enter the pin.",
"dialInConferenceID": "PIN:", "dialInConferenceID": "PIN:",
"dialInNotSupported": "Sorry, dialing in is currently not suppported.", "dialInNotSupported": "Sorry, dialing in is currently not supported.",
"dialInNumber": "Dial-in:", "dialInNumber": "Dial-in:",
"dialInTollFree": "Toll Free",
"genericError": "Whoops, something went wrong.", "genericError": "Whoops, something went wrong.",
"inviteLiveStream": "To view the live stream of this meeting, click this link: __url__", "inviteLiveStream": "To view the live stream of this meeting, click this link: __url__",
"invitePhone": "To join by phone, dial __number__ and enter this PIN: __conferenceID__#", "invitePhone": "To join by phone, dial __number__ and enter this PIN: __conferenceID__#",

5
package-lock.json generated
View File

@ -7494,6 +7494,11 @@
"integrity": "sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM=", "integrity": "sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM=",
"dev": true "dev": true
}, },
"i18n-iso-countries": {
"version": "3.7.8",
"resolved": "https://registry.npmjs.org/i18n-iso-countries/-/i18n-iso-countries-3.7.8.tgz",
"integrity": "sha512-NkT3lRiw7D4kKtSAVjVdHCvGlc2UOe0ALKa9IfEx0LkEDf0q3YgjP/veVk0d/OZ7yqUNzV8aJP4lJc6RPj++Gw=="
},
"i18next": { "i18next": {
"version": "8.4.3", "version": "8.4.3",
"resolved": "https://registry.npmjs.org/i18next/-/i18next-8.4.3.tgz", "resolved": "https://registry.npmjs.org/i18next/-/i18next-8.4.3.tgz",

View File

@ -37,6 +37,7 @@
"@webcomponents/url": "0.7.1", "@webcomponents/url": "0.7.1",
"amplitude-js": "4.5.2", "amplitude-js": "4.5.2",
"dropbox": "4.0.9", "dropbox": "4.0.9",
"i18n-iso-countries": "3.7.8",
"i18next": "8.4.3", "i18next": "8.4.3",
"i18next-browser-languagedetector": "2.0.0", "i18next-browser-languagedetector": "2.0.0",
"i18next-xhr-backend": "1.4.2", "i18next-xhr-backend": "1.4.2",

View File

@ -13,7 +13,7 @@ import { translate as reactI18nextTranslate } from 'react-i18next';
export function translate(component, options = { wait: true }) { export function translate(component, options = { wait: true }) {
// Use the default list of namespaces. // Use the default list of namespaces.
return ( return (
reactI18nextTranslate([ 'main', 'languages' ], options)( reactI18nextTranslate([ 'main', 'languages', 'countries' ], options)(
component)); component));
} }

View File

@ -3,6 +3,7 @@
import i18next from 'i18next'; import i18next from 'i18next';
import I18nextXHRBackend from 'i18next-xhr-backend'; import I18nextXHRBackend from 'i18next-xhr-backend';
import COUNTRIES_RESOURCES from 'i18n-iso-countries/langs/en.json';
import LANGUAGES_RESOURCES from '../../../../lang/languages.json'; import LANGUAGES_RESOURCES from '../../../../lang/languages.json';
import MAIN_RESOURCES from '../../../../lang/main.json'; import MAIN_RESOURCES from '../../../../lang/main.json';
@ -51,7 +52,7 @@ const options = {
load: 'unspecific', load: 'unspecific',
ns: { ns: {
defaultNs: 'main', defaultNs: 'main',
namespaces: [ 'main', 'languages' ] namespaces: [ 'main', 'languages', 'countries' ]
}, },
resGetPath: 'lang/__ns__-__lng__.json', resGetPath: 'lang/__ns__-__lng__.json',
useDataAttrOptions: true useDataAttrOptions: true
@ -68,6 +69,12 @@ i18next
.init(options); .init(options);
// Add default language which is preloaded from the source code. // Add default language which is preloaded from the source code.
i18next.addResourceBundle(
DEFAULT_LANGUAGE,
'countries',
COUNTRIES_RESOURCES,
/* deep */ true,
/* overwrite */ true);
i18next.addResourceBundle( i18next.addResourceBundle(
DEFAULT_LANGUAGE, DEFAULT_LANGUAGE,
'languages', 'languages',

View File

@ -14,6 +14,11 @@ type Props = {
*/ */
conferenceID: number, conferenceID: number,
/**
* The name of the conference.
*/
conferenceName: ?string,
/** /**
* Invoked to obtain translated strings. * Invoked to obtain translated strings.
*/ */
@ -33,11 +38,19 @@ class ConferenceID extends Component<Props> {
* @returns {ReactElement} * @returns {ReactElement}
*/ */
render() { render() {
const { conferenceID, t } = this.props; const { conferenceID, conferenceName, t } = this.props;
return ( return (
<div className = 'dial-in-conference-id'> <div className = 'dial-in-conference-id'>
{ t('info.dialANumber', { conferenceID }) } <div className = 'dial-in-conference-name'>
{ conferenceName }
</div>
<div className = 'dial-in-conference-description'>
{ t('info.dialANumber') }
</div>
<div className = 'dial-in-conference-pin'>
{ `${t('info.dialInConferenceID')} ${conferenceID}` }
</div>
</div> </div>
); );
} }

View File

@ -56,9 +56,9 @@ type State = {
loading: boolean, loading: boolean,
/** /**
* The dial-in numbers. entered by the local participant. * The dial-in numbers to be displayed.
*/ */
numbers: ?Array<Object>, numbers: ?Array<Object> | ?Object,
/** /**
* Whether or not dial-in is allowed. * Whether or not dial-in is allowed.
@ -143,6 +143,7 @@ class DialInSummary extends Component<Props, State> {
conferenceID conferenceID
? <ConferenceID ? <ConferenceID
conferenceID = { conferenceID } conferenceID = { conferenceID }
conferenceName = { this.props.room }
key = 'conferenceID' /> key = 'conferenceID' />
: null, : null,
<NumbersList <NumbersList
@ -238,17 +239,22 @@ class DialInSummary extends Component<Props, State> {
* Callback invoked when fetching dial-in numbers succeeds. Sets the * Callback invoked when fetching dial-in numbers succeeds. Sets the
* internal to show the numbers. * internal to show the numbers.
* *
* @param {Object} response - The response from fetching dial-in numbers. * @param {Array|Object} response - The response from fetching
* dial-in numbers.
* @param {Array|Object} response.numbers - The dial-in numbers. * @param {Array|Object} response.numbers - The dial-in numbers.
* @param {boolean} reponse.numbersEnabled - Whether or not dial-in is * @param {boolean} response.numbersEnabled - Whether or not dial-in is
* enabled. * enabled, old syntax that is deprecated.
* @private * @private
* @returns {void} * @returns {void}
*/ */
_onGetNumbersSuccess({ numbers, numbersEnabled }) { _onGetNumbersSuccess(
response: Array<Object> | { numbersEnabled?: boolean }) {
this.setState({ this.setState({
numbersEnabled, numbersEnabled:
numbers Array.isArray(response)
? response.length > 0 : response.numbersEnabled,
numbers: response
}); });
} }

View File

@ -17,10 +17,10 @@ type Props = {
conferenceID: number, conferenceID: number,
/** /**
* The phone numbers to display. Can be an array of numbers or an object * The phone numbers to display. Can be an array of number Objects or an
* with countries as keys and an array of numbers as values. * object with countries as keys and an array of numbers as values.
*/ */
numbers: { [string]: Array<string> } | Array<string>, numbers: { [string]: Array<string> } | Array<Object>,
/** /**
* Invoked to obtain translated strings. * Invoked to obtain translated strings.
@ -41,92 +41,165 @@ class NumbersList extends Component<Props> {
* @returns {ReactElement} * @returns {ReactElement}
*/ */
render() { render() {
const { numbers, t } = this.props; const { numbers } = this.props;
return ( return this._renderWithCountries(numbers);
<table className = 'dial-in-numbers-list'>
<thead>
<tr>
{ Array.isArray(numbers)
? null
: <th>{ t('info.country') }</th> }
<th>{ t('info.numbers') }</th>
</tr>
</thead>
<tbody className = 'dial-in-numbers-body'>
{ Array.isArray(numbers)
? numbers.map(this._renderNumberRow)
: this._renderWithCountries(numbers) }
</tbody>
</table>);
} }
/** /**
* Renders rows of countries and associated phone numbers. * Renders rows of countries and associated phone numbers.
* *
* @param {Object} numbersMapping - An object with country names as keys * @param {Object|Array<Object>} numbersMapping - An object with country
* and values as arrays of phone numbers. * names as keys and values as arrays of phone numbers.
* @private * @private
* @returns {ReactElement[]} * @returns {ReactElement[]}
*/ */
_renderWithCountries(numbersMapping: Object) { _renderWithCountries(
const rows = []; numbersMapping: { numbers: Array<string> } | Array<Object>) {
const { t } = this.props;
let hasFlags = false, numbers;
for (const [ country, numbers ] of Object.entries(numbersMapping)) { if (Array.isArray(numbersMapping)) {
if (!Array.isArray(numbers)) { hasFlags = true;
return; numbers = numbersMapping.reduce(
} (resultNumbers, number) => {
const countryName
= t(`countries:countries.${number.countryCode}`);
const formattedNumbers = numbers.map(number => { if (resultNumbers[countryName]) {
if (typeof number === 'string') { resultNumbers[countryName].push(number);
return this._renderNumberDiv(number); } else {
resultNumbers[countryName] = [ number ];
}
return resultNumbers;
}, {});
} else {
numbers = {};
for (const [ country, numbersArray ]
of Object.entries(numbersMapping.numbers)) {
if (Array.isArray(numbersArray)) {
/* eslint-disable arrow-body-style */
const formattedNumbers = numbersArray.map(number => ({
formattedNumber: number
}));
/* eslint-enable arrow-body-style */
numbers[country] = formattedNumbers;
} }
}
return null;
});
rows.push(
<tr key = { country }>
<td>{ country }</td>
<td className = 'dial-in-numbers'>{ formattedNumbers }</td>
</tr>
);
} }
return rows; const rows = [];
}
Object.keys(numbers).forEach((countryName: string) => {
const numbersArray = numbers[countryName];
rows.push(
<tr
className = 'number-group'
key = { countryName }>
{ this._renderFlag(numbersArray[0].countryCode) }
<td className = 'country' >{ countryName }</td>
<td className = 'numbers-list-column'>
{ this._renderNumbersList(numbersArray) }
</td>
<td className = 'toll-free-list-column' >
{ this._renderNumbersTollFreeList(numbersArray) }
</td>
</tr>
);
});
/**
* Renders a table row for a phone number.
*
* @param {string} number - The phone number to display.
* @private
* @returns {ReactElement[]}
*/
_renderNumberRow(number) {
return ( return (
<tr key = { number }> <table className = 'dial-in-numbers-list'>
<td className = 'dial-in-number'> <thead>
{ this._renderNumberLink(number) } <tr>
</td> { hasFlags ? <th /> : null}
</tr> <th>{ t('info.country') }</th>
<th>{ t('info.numbers') }</th>
<th />
</tr>
</thead>
<tbody className = 'dial-in-numbers-body'>
{ rows }
</tbody>
</table>
); );
} }
/** /**
* Renders a div container for a phone number. * Renders a div container for a phone number.
* *
* @param {string} number - The phone number to display. * @param {string} countryCode - The phone number to display.
* @private
* @returns {ReactElement}
*/
_renderFlag(countryCode) {
const OFFSET = 127397;
if (countryCode) {
// ensure country code is all caps
const cc = countryCode.toUpperCase();
// return the emoji flag corresponding to country_code or null
const countryFlag = /^[A-Z]{2}$/.test(cc)
? String.fromCodePoint(...[ ...cc ]
.map(c => c.charCodeAt() + OFFSET))
: null;
return <td className = 'flag'>{ countryFlag }</td>;
}
return null;
}
/**
* Renders a div container for a phone number.
*
* @param {Array} numbers - The phone number to display.
* @private * @private
* @returns {ReactElement[]} * @returns {ReactElement[]}
*/ */
_renderNumberDiv(number) { _renderNumbersList(numbers) {
return ( const numbersListItems = numbers.map(number =>
<div (<li
className = 'dial-in-number' className = 'dial-in-number'
key = { number }> key = { number.formattedNumber }>
{ this._renderNumberLink(number) } { this._renderNumberLink(number.formattedNumber) }
</div> </li>));
return (
<ul className = 'numbers-list'>
{ numbersListItems }
</ul>
);
}
/**
* Renders list with a toll free text on the position where there is a
* number marked as toll free.
*
* @param {Array} numbers - The phone number that are displayed.
* @private
* @returns {ReactElement[]}
*/
_renderNumbersTollFreeList(numbers) {
const { t } = this.props;
const tollNumbersListItems = numbers.map(number =>
(<li
className = 'toll-free'
key = { number.formattedNumber }>
{ number.tollFree ? t('info.dialInTollFree') : '' }
</li>));
return (
<ul className = 'toll-free-list'>
{ tollNumbersListItems }
</ul>
); );
} }
@ -141,9 +214,12 @@ class NumbersList extends Component<Props> {
*/ */
_renderNumberLink(number) { _renderNumberLink(number) {
if (this.props.clickableNumbers) { if (this.props.clickableNumbers) {
// Url encode # to %23, Android phone was cutting the # after
// clicking it.
// Seems that using ',' and '%23' works on iOS and Android.
return ( return (
<a <a
href = { `tel:${number}p${this.props.conferenceID}#` } href = { `tel:${number},${this.props.conferenceID}%23` }
key = { number } > key = { number } >
{ number } { number }
</a> </a>

View File

@ -121,9 +121,7 @@ class InfoDialog extends Component<Props, State> {
let phoneNumber = state.phoneNumber; let phoneNumber = state.phoneNumber;
if (!state.phoneNumber && props.dialIn.numbers) { if (!state.phoneNumber && props.dialIn.numbers) {
const { defaultCountry, numbers } = props.dialIn; phoneNumber = _getDefaultPhoneNumber(props.dialIn);
phoneNumber = _getDefaultPhoneNumber(numbers, defaultCountry);
} }
return { return {
@ -157,11 +155,9 @@ class InfoDialog extends Component<Props, State> {
constructor(props: Props) { constructor(props: Props) {
super(props); super(props);
const { defaultCountry, numbers } = props.dialIn; if (props.dialIn && props.dialIn.numbers) {
if (numbers) {
this.state.phoneNumber this.state.phoneNumber
= _getDefaultPhoneNumber(numbers, defaultCountry); = _getDefaultPhoneNumber(props.dialIn.numbers);
} }
/** /**

View File

@ -54,13 +54,14 @@ export function getDialInConferenceID(
/** /**
* Sends a GET request for phone numbers used to dial into a conference. * Sends a GET request for phone numbers used to dial into a conference.
* *
* @param {string} url - The service that returns confernce dial-in numbers. * @param {string} url - The service that returns conference dial-in numbers.
* @param {string} roomName - The conference name to find the associated * @param {string} roomName - The conference name to find the associated
* conference ID. * conference ID.
* @param {string} mucURL - In which MUC the conference exists. * @param {string} mucURL - In which MUC the conference exists.
* @returns {Promise} - The promise created by the request. The returned numbers * @returns {Promise} - The promise created by the request. The returned numbers
* may be an array of numbers or an object with countries as keys and arrays of * may be an array of Objects containing numbers, with keys countryCode,
* phone number strings. * tollFree, formattedNumber or an object with countries as keys and arrays of
* phone number strings, as the second one should not be used and is deprecated.
*/ */
export function getDialInNumbers( export function getDialInNumbers(
url: string, url: string,
@ -432,7 +433,7 @@ export function getShareInfoText(
numbersPromise = Promise.all([ numbersPromise = Promise.all([
getDialInNumbers(dialInNumbersUrl, room, mucURL), getDialInNumbers(dialInNumbersUrl, room, mucURL),
getDialInConferenceID(dialInConfCodeUrl, room, mucURL) getDialInConferenceID(dialInConfCodeUrl, room, mucURL)
]).then(([ { defaultCountry, numbers }, { ]).then(([ numbers, {
conference, id, message } ]) => { conference, id, message } ]) => {
if (!conference || !id) { if (!conference || !id) {
@ -440,7 +441,6 @@ export function getShareInfoText(
} }
return { return {
defaultCountry,
numbers, numbers,
conferenceID: id conferenceID: id
}; };
@ -448,9 +448,8 @@ export function getShareInfoText(
} }
return numbersPromise.then( return numbersPromise.then(
({ conferenceID, defaultCountry, numbers }) => { ({ conferenceID, numbers }) => {
const phoneNumber const phoneNumber = _getDefaultPhoneNumber(numbers) || '';
= _getDefaultPhoneNumber(numbers, defaultCountry) || '';
return `${ return `${
i18next.t('info.dialInNumber')} ${ i18next.t('info.dialInNumber')} ${
@ -513,27 +512,47 @@ export function getDialInfoPageURL(
* *
* @param {Array<string>|Object} dialInNumbers - The array or object of * @param {Array<string>|Object} dialInNumbers - The array or object of
* numbers to choose a number from. * numbers to choose a number from.
* @param {string} defaultCountry - The country code for the country
* whose phone number should display.
* @private * @private
* @returns {string|null} * @returns {string|null}
*/ */
export function _getDefaultPhoneNumber( export function _getDefaultPhoneNumber(
dialInNumbers: Object, dialInNumbers: Object): ?string {
defaultCountry: string = 'US'): ?string { const defValueForDefaultCountry = 'US';
if (Array.isArray(dialInNumbers)) { if (Array.isArray(dialInNumbers)) {
// Dumbly return the first number if an array. // new syntax follows
return dialInNumbers[0]; // find the default country inside dialInNumbers, US one
} else if (Object.keys(dialInNumbers).length > 0) { // or return the first one
const defaultNumbers = dialInNumbers[defaultCountry]; let defaultNumber = dialInNumbers.find(number => number.default);
if (!defaultNumber) {
defaultNumber = dialInNumbers.find(({ countryCode }) =>
countryCode === defValueForDefaultCountry);
}
if (defaultNumber) {
return defaultNumber.formattedNumber;
}
return dialInNumbers.length > 0
? dialInNumbers[0].formattedNumber : null;
}
const {
defaultCountry = defValueForDefaultCountry,
numbers } = dialInNumbers;
if (numbers && Object.keys(numbers).length > 0) {
// deprecated and will be removed
const defaultNumbers = numbers[defaultCountry];
if (defaultNumbers) { if (defaultNumbers) {
return defaultNumbers[0]; return defaultNumbers[0];
} }
const firstRegion = Object.keys(dialInNumbers)[0]; const firstRegion = Object.keys(numbers)[0];
return firstRegion && firstRegion[0]; return firstRegion && numbers[firstRegion][0];
} }
return null; return null;

View File

@ -10,6 +10,8 @@ import {
UPDATE_DIAL_IN_NUMBERS_SUCCESS UPDATE_DIAL_IN_NUMBERS_SUCCESS
} from './actionTypes'; } from './actionTypes';
const logger = require('jitsi-meet-logger').getLogger(__filename);
const DEFAULT_STATE = { const DEFAULT_STATE = {
/** /**
* The indicator which determines whether (the) {@code CalleeInfo} is * The indicator which determines whether (the) {@code CalleeInfo} is
@ -54,17 +56,24 @@ ReducerRegistry.register('features/invite', (state = DEFAULT_STATE, action) => {
}; };
case UPDATE_DIAL_IN_NUMBERS_SUCCESS: { case UPDATE_DIAL_IN_NUMBERS_SUCCESS: {
const { if (Array.isArray(action.dialInNumbers)) {
defaultCountry, return {
numbers, ...state,
numbersEnabled conferenceID: action.conferenceID,
} = action.dialInNumbers; numbers: action.dialInNumbers,
numbersEnabled: true
};
}
// this is the old format which is deprecated
logger.warn('Using deprecated API for retrieving phone numbers');
const { numbersEnabled } = action.dialInNumbers;
return { return {
...state, ...state,
conferenceID: action.conferenceID, conferenceID: action.conferenceID,
defaultCountry, numbers: action.dialInNumbers,
numbers,
numbersEnabled numbersEnabled
}; };
} }