Преглед на файлове

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.
master
Дамян Минков преди 6 години
родител
ревизия
ea4d49f2a0
No account linked to committer's email address

+ 22
- 2
css/deep-linking/_mobile.scss Целия файл

@@ -28,7 +28,7 @@
28 28
         max-width: 40em;
29 29
         padding: 35px 0 40px 0;
30 30
         text-align: center;
31
-        width: 75%;
31
+        width: 90%;
32 32
 
33 33
         a:active {
34 34
             text-decoration: none;
@@ -46,7 +46,7 @@
46 46
 
47 47
     &__text,
48 48
     .deep-linking-dial-in  {
49
-        font-size: 1.2em;
49
+        font-size: 1em;
50 50
         line-height: em(29px, 21px);
51 51
         margin-bottom: 0.65em;
52 52
 
@@ -59,6 +59,26 @@
59 59
                 font-size: em(21, 18);
60 60
             }
61 61
         }
62
+
63
+        table {
64
+            font-size: 1em;
65
+        }
66
+
67
+        .dial-in-conference-id {
68
+            margin: 10px 0 10px 0;
69
+        }
70
+
71
+        .dial-in-conference-description {
72
+            font-size: 0.8em;
73
+        }
74
+
75
+        .toll-free-list {
76
+            min-width: 80px;
77
+        }
78
+
79
+        .numbers-list {
80
+            min-width: 150px;
81
+        }
62 82
     }
63 83
 
64 84
     &__href {

+ 54
- 8
css/modals/invite/_info.scss Целия файл

@@ -124,29 +124,75 @@
124 124
     }
125 125
 }
126 126
 
127
+.dial-in-numbers-list {
128
+    margin-top: 20px;
129
+    font-size: 12px;
130
+    line-height: 24px;
131
+    border-collapse: separate;
132
+    border-spacing: 0 5px;
133
+
134
+    thead {
135
+        text-align: left;
136
+    }
137
+
138
+    td,
139
+    th {
140
+        border-bottom: 1px solid #d1dbe8;
141
+    }
142
+
143
+    .flag {
144
+        border-bottom-style: none;
145
+        width: 30px;
146
+        vertical-align: top;
147
+    }
148
+
149
+    .country {
150
+        font-weight: bold;
151
+        vertical-align: top;
152
+        padding: 0 20px 0 0;
153
+    }
154
+
155
+    ul {
156
+        padding: 0px 0px 0px 0px;
157
+    }
158
+
159
+    .numbers-list {
160
+        list-style: none;
161
+        padding: 0 20px 0 0;
162
+    }
163
+
164
+    .toll-free-list {
165
+        font-weight: bold;
166
+        list-style: none;
167
+        vertical-align: top;
168
+    }
169
+}
170
+
127 171
 .dial-in-page {
128 172
     align-items: center;
129 173
     box-sizing: border-box;
130 174
     display: flex;
131 175
     flex-direction: column;
132
-    font-size: 24px;
176
+    font-size: 12px;
133 177
     max-height: 100%;
134 178
     overflow: auto;
135
-    padding: 25px;
136 179
     position: absolute;
137 180
     transform: translateY(-50%);
138 181
     top: 50%;
139 182
     width: 100%;
140 183
 
141
-    .dial-in-numbers-list {
142
-        font-size: 24px;
143
-        margin-top: 20px;
144
-    }
145
-
146 184
     .dial-in-conference-id {
147 185
         text-align: center;
148 186
         min-width: 200px;
149
-        width: 30%;
187
+    }
188
+
189
+    .dial-in-conference-name,
190
+    .dial-in-conference-pin {
191
+        font-size: 18px;
192
+    }
193
+
194
+    .dial-in-conference-description {
195
+        margin: 12px;
150 196
     }
151 197
 }
152 198
 

+ 11
- 1
debian/rules Целия файл

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

+ 21
- 17
doc/cloud-api.swagger Целия файл

@@ -71,7 +71,7 @@ paths:
71 71
             $ref: "#/definitions/ConferenceMapperDetails"
72 72
         405:
73 73
           description: "Invalid input"
74
- 
74
+
75 75
   /phoneNumberList:
76 76
     get:
77 77
       tags:
@@ -96,7 +96,7 @@ securityDefinitions:
96 96
     name: "Authorization"
97 97
     in: "header"
98 98
 definitions:
99
- 
99
+
100 100
   ConferenceMapperRequest:
101 101
     description: "Request to create or find a conference mapping"
102 102
     type: "object"
@@ -114,7 +114,7 @@ definitions:
114 114
       domain:
115 115
         type: "string"
116 116
         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)"
117
- 
117
+
118 118
   ConferenceMapperDetails:
119 119
     description: "Conference mapping between conference JID and numeric ID"
120 120
     type: "object"
@@ -126,22 +126,26 @@ definitions:
126 126
         type: "string"
127 127
         format: "JID"
128 128
         description: "Full JID for the conference OR boolean false if no conference was found (search by ID)"
129
- 
129
+
130 130
   PhoneNumberList:
131
-    type: "object"
132
-    properties:
133
-      numbersEnabled:
134
-        type: "boolean"
135
-        description: "Control flag for Jitsi Meet user interface.  Must be set to true for Jitsi Meet to display phone-in UI elements"
136
-      numbers:
131
+    description: "List of dial in numbers for the conference."
132
+    type: "array"
133
+    items:
137 134
         type: "object"
138
-        description: "Keys are Country Names, each value is an array of phone numbers"
139
-        additionalProperties:
140
-          type: "array"
141
-          items:
135
+        properties:
136
+          countryCode:
137
+            type: "string"
138
+            description: "ISO 3166-1 country code. Alpha-2 supported."
139
+          default:
140
+            type: "boolean"
141
+            description: "Whether this number is the default one to show. Optional."
142
+          formattedNumber:
142 143
             type: "string"
143
-            format: "phone"
144
- 
144
+            description: "The formatted telephone number to show."
145
+          tollFree:
146
+            type: "boolean"
147
+            description: "Whether the number is toll free number."
148
+
145 149
 externalDocs:
146 150
   description: "Find out more about the Jitsi Cloud API"
147
-  url: "https://jitsi.org/CloudAPI"
151
+  url: "https://jitsi.org/CloudAPI"

+ 3
- 2
lang/main.json Целия файл

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

+ 5
- 0
package-lock.json Целия файл

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

+ 1
- 0
package.json Целия файл

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

+ 1
- 1
react/features/base/i18n/functions.js Целия файл

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

+ 8
- 1
react/features/base/i18n/i18next.js Целия файл

@@ -3,6 +3,7 @@
3 3
 import i18next from 'i18next';
4 4
 import I18nextXHRBackend from 'i18next-xhr-backend';
5 5
 
6
+import COUNTRIES_RESOURCES from 'i18n-iso-countries/langs/en.json';
6 7
 import LANGUAGES_RESOURCES from '../../../../lang/languages.json';
7 8
 import MAIN_RESOURCES from '../../../../lang/main.json';
8 9
 
@@ -51,7 +52,7 @@ const options = {
51 52
     load: 'unspecific',
52 53
     ns: {
53 54
         defaultNs: 'main',
54
-        namespaces: [ 'main', 'languages' ]
55
+        namespaces: [ 'main', 'languages', 'countries' ]
55 56
     },
56 57
     resGetPath: 'lang/__ns__-__lng__.json',
57 58
     useDataAttrOptions: true
@@ -68,6 +69,12 @@ i18next
68 69
     .init(options);
69 70
 
70 71
 // Add default language which is preloaded from the source code.
72
+i18next.addResourceBundle(
73
+    DEFAULT_LANGUAGE,
74
+    'countries',
75
+    COUNTRIES_RESOURCES,
76
+    /* deep */ true,
77
+    /* overwrite */ true);
71 78
 i18next.addResourceBundle(
72 79
     DEFAULT_LANGUAGE,
73 80
     'languages',

+ 15
- 2
react/features/invite/components/dial-in-summary/ConferenceID.web.js Целия файл

@@ -14,6 +14,11 @@ type Props = {
14 14
      */
15 15
     conferenceID: number,
16 16
 
17
+    /**
18
+     * The name of the conference.
19
+     */
20
+    conferenceName: ?string,
21
+
17 22
     /**
18 23
      * Invoked to obtain translated strings.
19 24
      */
@@ -33,11 +38,19 @@ class ConferenceID extends Component<Props> {
33 38
      * @returns {ReactElement}
34 39
      */
35 40
     render() {
36
-        const { conferenceID, t } = this.props;
41
+        const { conferenceID, conferenceName, t } = this.props;
37 42
 
38 43
         return (
39 44
             <div className = 'dial-in-conference-id'>
40
-                { t('info.dialANumber', { conferenceID }) }
45
+                <div className = 'dial-in-conference-name'>
46
+                    { conferenceName }
47
+                </div>
48
+                <div className = 'dial-in-conference-description'>
49
+                    { t('info.dialANumber') }
50
+                </div>
51
+                <div className = 'dial-in-conference-pin'>
52
+                    { `${t('info.dialInConferenceID')} ${conferenceID}` }
53
+                </div>
41 54
             </div>
42 55
         );
43 56
     }

+ 14
- 8
react/features/invite/components/dial-in-summary/DialInSummary.web.js Целия файл

@@ -56,9 +56,9 @@ type State = {
56 56
     loading: boolean,
57 57
 
58 58
     /**
59
-     * The dial-in numbers. entered by the local participant.
59
+     * The dial-in numbers to be displayed.
60 60
      */
61
-    numbers: ?Array<Object>,
61
+    numbers: ?Array<Object> | ?Object,
62 62
 
63 63
     /**
64 64
      * Whether or not dial-in is allowed.
@@ -143,6 +143,7 @@ class DialInSummary extends Component<Props, State> {
143 143
                 conferenceID
144 144
                     ? <ConferenceID
145 145
                         conferenceID = { conferenceID }
146
+                        conferenceName = { this.props.room }
146 147
                         key = 'conferenceID' />
147 148
                     : null,
148 149
                 <NumbersList
@@ -238,17 +239,22 @@ class DialInSummary extends Component<Props, State> {
238 239
      * Callback invoked when fetching dial-in numbers succeeds. Sets the
239 240
      * internal to show the numbers.
240 241
      *
241
-     * @param {Object} response - The response from fetching dial-in numbers.
242
+     * @param {Array|Object} response - The response from fetching
243
+     * dial-in numbers.
242 244
      * @param {Array|Object} response.numbers - The dial-in numbers.
243
-     * @param {boolean} reponse.numbersEnabled - Whether or not dial-in is
244
-     * enabled.
245
+     * @param {boolean} response.numbersEnabled - Whether or not dial-in is
246
+     * enabled, old syntax that is deprecated.
245 247
      * @private
246 248
      * @returns {void}
247 249
      */
248
-    _onGetNumbersSuccess({ numbers, numbersEnabled }) {
250
+    _onGetNumbersSuccess(
251
+            response: Array<Object> | { numbersEnabled?: boolean }) {
252
+
249 253
         this.setState({
250
-            numbersEnabled,
251
-            numbers
254
+            numbersEnabled:
255
+                Array.isArray(response)
256
+                    ? response.length > 0 : response.numbersEnabled,
257
+            numbers: response
252 258
         });
253 259
     }
254 260
 

+ 128
- 52
react/features/invite/components/dial-in-summary/NumbersList.web.js Целия файл

@@ -17,10 +17,10 @@ type Props = {
17 17
     conferenceID: number,
18 18
 
19 19
     /**
20
-     * The phone numbers to display. Can be an array of numbers or an object
21
-     * with countries as keys and an array of numbers as values.
20
+     * The phone numbers to display. Can be an array of number Objects or an
21
+     * object with countries as keys and an array of numbers as values.
22 22
      */
23
-    numbers: { [string]: Array<string> } | Array<string>,
23
+    numbers: { [string]: Array<string> } | Array<Object>,
24 24
 
25 25
     /**
26 26
      * Invoked to obtain translated strings.
@@ -41,92 +41,165 @@ class NumbersList extends Component<Props> {
41 41
      * @returns {ReactElement}
42 42
      */
43 43
     render() {
44
-        const { numbers, t } = this.props;
44
+        const { numbers } = this.props;
45
+
46
+        return this._renderWithCountries(numbers);
47
+    }
48
+
49
+    /**
50
+     * Renders rows of countries and associated phone numbers.
51
+     *
52
+     * @param {Object|Array<Object>} numbersMapping - An object with country
53
+     * names as keys and values as arrays of phone numbers.
54
+     * @private
55
+     * @returns {ReactElement[]}
56
+     */
57
+    _renderWithCountries(
58
+            numbersMapping: { numbers: Array<string> } | Array<Object>) {
59
+        const { t } = this.props;
60
+        let hasFlags = false, numbers;
61
+
62
+        if (Array.isArray(numbersMapping)) {
63
+            hasFlags = true;
64
+            numbers = numbersMapping.reduce(
65
+                (resultNumbers, number) => {
66
+                    const countryName
67
+                        = t(`countries:countries.${number.countryCode}`);
68
+
69
+                    if (resultNumbers[countryName]) {
70
+                        resultNumbers[countryName].push(number);
71
+                    } else {
72
+                        resultNumbers[countryName] = [ number ];
73
+                    }
74
+
75
+                    return resultNumbers;
76
+                }, {});
77
+        } else {
78
+            numbers = {};
79
+
80
+            for (const [ country, numbersArray ]
81
+                of Object.entries(numbersMapping.numbers)) {
82
+
83
+                if (Array.isArray(numbersArray)) {
84
+                    /* eslint-disable arrow-body-style */
85
+                    const formattedNumbers = numbersArray.map(number => ({
86
+                        formattedNumber: number
87
+                    }));
88
+                    /* eslint-enable arrow-body-style */
89
+
90
+                    numbers[country] = formattedNumbers;
91
+                }
92
+            }
93
+        }
94
+
95
+        const rows = [];
96
+
97
+        Object.keys(numbers).forEach((countryName: string) => {
98
+            const numbersArray = numbers[countryName];
99
+
100
+            rows.push(
101
+                <tr
102
+                    className = 'number-group'
103
+                    key = { countryName }>
104
+                    { this._renderFlag(numbersArray[0].countryCode) }
105
+                    <td className = 'country' >{ countryName }</td>
106
+                    <td className = 'numbers-list-column'>
107
+                        { this._renderNumbersList(numbersArray) }
108
+                    </td>
109
+                    <td className = 'toll-free-list-column' >
110
+                        { this._renderNumbersTollFreeList(numbersArray) }
111
+                    </td>
112
+                </tr>
113
+            );
114
+        });
45 115
 
46 116
         return (
47 117
             <table className = 'dial-in-numbers-list'>
48 118
                 <thead>
49 119
                     <tr>
50
-                        { Array.isArray(numbers)
51
-                            ? null
52
-                            : <th>{ t('info.country') }</th> }
120
+                        { hasFlags ? <th /> : null}
121
+                        <th>{ t('info.country') }</th>
53 122
                         <th>{ t('info.numbers') }</th>
123
+                        <th />
54 124
                     </tr>
55 125
                 </thead>
56 126
                 <tbody className = 'dial-in-numbers-body'>
57
-                    { Array.isArray(numbers)
58
-                        ? numbers.map(this._renderNumberRow)
59
-                        : this._renderWithCountries(numbers) }
127
+                    { rows }
60 128
                 </tbody>
61
-            </table>);
129
+            </table>
130
+        );
62 131
     }
63 132
 
64 133
     /**
65
-     * Renders rows of countries and associated phone numbers.
134
+     * Renders a div container for a phone number.
66 135
      *
67
-     * @param {Object} numbersMapping - An object with country names as keys
68
-     * and values as arrays of phone numbers.
136
+     * @param {string} countryCode - The phone number to display.
69 137
      * @private
70
-     * @returns {ReactElement[]}
138
+     * @returns {ReactElement}
71 139
      */
72
-    _renderWithCountries(numbersMapping: Object) {
73
-        const rows = [];
140
+    _renderFlag(countryCode) {
141
+        const OFFSET = 127397;
74 142
 
75
-        for (const [ country, numbers ] of Object.entries(numbersMapping)) {
76
-            if (!Array.isArray(numbers)) {
77
-                return;
78
-            }
79
-
80
-            const formattedNumbers = numbers.map(number => {
81
-                if (typeof number === 'string') {
82
-                    return this._renderNumberDiv(number);
83
-                }
143
+        if (countryCode) {
144
+            // ensure country code is all caps
145
+            const cc = countryCode.toUpperCase();
84 146
 
85
-                return null;
86
-            });
147
+            // return the emoji flag corresponding to country_code or null
148
+            const countryFlag = /^[A-Z]{2}$/.test(cc)
149
+                ? String.fromCodePoint(...[ ...cc ]
150
+                    .map(c => c.charCodeAt() + OFFSET))
151
+                : null;
87 152
 
88
-            rows.push(
89
-                <tr key = { country }>
90
-                    <td>{ country }</td>
91
-                    <td className = 'dial-in-numbers'>{ formattedNumbers }</td>
92
-                </tr>
93
-            );
153
+            return <td className = 'flag'>{ countryFlag }</td>;
94 154
         }
95 155
 
96
-        return rows;
156
+        return null;
97 157
     }
98 158
 
99 159
     /**
100
-     * Renders a table row for a phone number.
160
+     * Renders a div container for a phone number.
101 161
      *
102
-     * @param {string} number - The phone number to display.
162
+     * @param {Array} numbers - The phone number to display.
103 163
      * @private
104 164
      * @returns {ReactElement[]}
105 165
      */
106
-    _renderNumberRow(number) {
166
+    _renderNumbersList(numbers) {
167
+        const numbersListItems = numbers.map(number =>
168
+            (<li
169
+                className = 'dial-in-number'
170
+                key = { number.formattedNumber }>
171
+                { this._renderNumberLink(number.formattedNumber) }
172
+            </li>));
173
+
107 174
         return (
108
-            <tr key = { number }>
109
-                <td className = 'dial-in-number'>
110
-                    { this._renderNumberLink(number) }
111
-                </td>
112
-            </tr>
175
+            <ul className = 'numbers-list'>
176
+                { numbersListItems }
177
+            </ul>
113 178
         );
114 179
     }
115 180
 
116 181
     /**
117
-     * Renders a div container for a phone number.
182
+     * Renders list with a toll free text on the position where there is a
183
+     * number marked as toll free.
118 184
      *
119
-     * @param {string} number - The phone number to display.
185
+     * @param {Array} numbers - The phone number that are displayed.
120 186
      * @private
121 187
      * @returns {ReactElement[]}
122 188
      */
123
-    _renderNumberDiv(number) {
189
+    _renderNumbersTollFreeList(numbers) {
190
+        const { t } = this.props;
191
+
192
+        const tollNumbersListItems = numbers.map(number =>
193
+            (<li
194
+                className = 'toll-free'
195
+                key = { number.formattedNumber }>
196
+                { number.tollFree ? t('info.dialInTollFree') : '' }
197
+            </li>));
198
+
124 199
         return (
125
-            <div
126
-                className = 'dial-in-number'
127
-                key = { number }>
128
-                { this._renderNumberLink(number) }
129
-            </div>
200
+            <ul className = 'toll-free-list'>
201
+                { tollNumbersListItems }
202
+            </ul>
130 203
         );
131 204
     }
132 205
 
@@ -141,9 +214,12 @@ class NumbersList extends Component<Props> {
141 214
      */
142 215
     _renderNumberLink(number) {
143 216
         if (this.props.clickableNumbers) {
217
+            // Url encode # to %23, Android phone was cutting the # after
218
+            // clicking it.
219
+            // Seems that using ',' and '%23' works on iOS and Android.
144 220
             return (
145 221
                 <a
146
-                    href = { `tel:${number}p${this.props.conferenceID}#` }
222
+                    href = { `tel:${number},${this.props.conferenceID}%23` }
147 223
                     key = { number } >
148 224
                     { number }
149 225
                 </a>

+ 3
- 7
react/features/invite/components/info-dialog/InfoDialog.web.js Целия файл

@@ -121,9 +121,7 @@ class InfoDialog extends Component<Props, State> {
121 121
         let phoneNumber = state.phoneNumber;
122 122
 
123 123
         if (!state.phoneNumber && props.dialIn.numbers) {
124
-            const { defaultCountry, numbers } = props.dialIn;
125
-
126
-            phoneNumber = _getDefaultPhoneNumber(numbers, defaultCountry);
124
+            phoneNumber = _getDefaultPhoneNumber(props.dialIn);
127 125
         }
128 126
 
129 127
         return {
@@ -157,11 +155,9 @@ class InfoDialog extends Component<Props, State> {
157 155
     constructor(props: Props) {
158 156
         super(props);
159 157
 
160
-        const { defaultCountry, numbers } = props.dialIn;
161
-
162
-        if (numbers) {
158
+        if (props.dialIn && props.dialIn.numbers) {
163 159
             this.state.phoneNumber
164
-                = _getDefaultPhoneNumber(numbers, defaultCountry);
160
+                = _getDefaultPhoneNumber(props.dialIn.numbers);
165 161
         }
166 162
 
167 163
         /**

+ 37
- 18
react/features/invite/functions.js Целия файл

@@ -54,13 +54,14 @@ export function getDialInConferenceID(
54 54
 /**
55 55
  * Sends a GET request for phone numbers used to dial into a conference.
56 56
  *
57
- * @param {string} url - The service that returns confernce dial-in numbers.
57
+ * @param {string} url - The service that returns conference dial-in numbers.
58 58
  * @param {string} roomName - The conference name to find the associated
59 59
  * conference ID.
60 60
  * @param {string} mucURL - In which MUC the conference exists.
61 61
  * @returns {Promise} - The promise created by the request. The returned numbers
62
- * may be an array of numbers or an object with countries as keys and arrays of
63
- * phone number strings.
62
+ * may be an array of Objects containing numbers, with keys countryCode,
63
+ * tollFree, formattedNumber or an object with countries as keys and arrays of
64
+ * phone number strings, as the second one should not be used and is deprecated.
64 65
  */
65 66
 export function getDialInNumbers(
66 67
         url: string,
@@ -432,7 +433,7 @@ export function getShareInfoText(
432 433
             numbersPromise = Promise.all([
433 434
                 getDialInNumbers(dialInNumbersUrl, room, mucURL),
434 435
                 getDialInConferenceID(dialInConfCodeUrl, room, mucURL)
435
-            ]).then(([ { defaultCountry, numbers }, {
436
+            ]).then(([ numbers, {
436 437
                 conference, id, message } ]) => {
437 438
 
438 439
                 if (!conference || !id) {
@@ -440,7 +441,6 @@ export function getShareInfoText(
440 441
                 }
441 442
 
442 443
                 return {
443
-                    defaultCountry,
444 444
                     numbers,
445 445
                     conferenceID: id
446 446
                 };
@@ -448,9 +448,8 @@ export function getShareInfoText(
448 448
         }
449 449
 
450 450
         return numbersPromise.then(
451
-            ({ conferenceID, defaultCountry, numbers }) => {
452
-                const phoneNumber
453
-                    = _getDefaultPhoneNumber(numbers, defaultCountry) || '';
451
+            ({ conferenceID, numbers }) => {
452
+                const phoneNumber = _getDefaultPhoneNumber(numbers) || '';
454 453
 
455 454
                 return `${
456 455
                     i18next.t('info.dialInNumber')} ${
@@ -513,27 +512,47 @@ export function getDialInfoPageURL(
513 512
  *
514 513
  * @param {Array<string>|Object} dialInNumbers - The array or object of
515 514
  * numbers to choose a number from.
516
- * @param {string} defaultCountry - The country code for the country
517
- * whose phone number should display.
518 515
  * @private
519 516
  * @returns {string|null}
520 517
  */
521 518
 export function _getDefaultPhoneNumber(
522
-        dialInNumbers: Object,
523
-        defaultCountry: string = 'US'): ?string {
519
+        dialInNumbers: Object): ?string {
520
+    const defValueForDefaultCountry = 'US';
521
+
524 522
     if (Array.isArray(dialInNumbers)) {
525
-        // Dumbly return the first number if an array.
526
-        return dialInNumbers[0];
527
-    } else if (Object.keys(dialInNumbers).length > 0) {
528
-        const defaultNumbers = dialInNumbers[defaultCountry];
523
+        // new syntax follows
524
+        // find the default country inside dialInNumbers, US one
525
+        // or return the first one
526
+        let defaultNumber = dialInNumbers.find(number => number.default);
527
+
528
+        if (!defaultNumber) {
529
+            defaultNumber = dialInNumbers.find(({ countryCode }) =>
530
+                countryCode === defValueForDefaultCountry);
531
+        }
532
+
533
+        if (defaultNumber) {
534
+            return defaultNumber.formattedNumber;
535
+        }
536
+
537
+        return dialInNumbers.length > 0
538
+            ? dialInNumbers[0].formattedNumber : null;
539
+    }
540
+
541
+    const {
542
+        defaultCountry = defValueForDefaultCountry,
543
+        numbers } = dialInNumbers;
544
+
545
+    if (numbers && Object.keys(numbers).length > 0) {
546
+        // deprecated and will be removed
547
+        const defaultNumbers = numbers[defaultCountry];
529 548
 
530 549
         if (defaultNumbers) {
531 550
             return defaultNumbers[0];
532 551
         }
533 552
 
534
-        const firstRegion = Object.keys(dialInNumbers)[0];
553
+        const firstRegion = Object.keys(numbers)[0];
535 554
 
536
-        return firstRegion && firstRegion[0];
555
+        return firstRegion && numbers[firstRegion][0];
537 556
     }
538 557
 
539 558
     return null;

+ 16
- 7
react/features/invite/reducer.js Целия файл

@@ -10,6 +10,8 @@ import {
10 10
     UPDATE_DIAL_IN_NUMBERS_SUCCESS
11 11
 } from './actionTypes';
12 12
 
13
+const logger = require('jitsi-meet-logger').getLogger(__filename);
14
+
13 15
 const DEFAULT_STATE = {
14 16
     /**
15 17
      * The indicator which determines whether (the) {@code CalleeInfo} is
@@ -54,17 +56,24 @@ ReducerRegistry.register('features/invite', (state = DEFAULT_STATE, action) => {
54 56
         };
55 57
 
56 58
     case UPDATE_DIAL_IN_NUMBERS_SUCCESS: {
57
-        const {
58
-            defaultCountry,
59
-            numbers,
60
-            numbersEnabled
61
-        } = action.dialInNumbers;
59
+        if (Array.isArray(action.dialInNumbers)) {
60
+            return {
61
+                ...state,
62
+                conferenceID: action.conferenceID,
63
+                numbers: action.dialInNumbers,
64
+                numbersEnabled: true
65
+            };
66
+        }
67
+
68
+        // this is the old format which is deprecated
69
+        logger.warn('Using deprecated API for retrieving phone numbers');
70
+
71
+        const { numbersEnabled } = action.dialInNumbers;
62 72
 
63 73
         return {
64 74
             ...state,
65 75
             conferenceID: action.conferenceID,
66
-            defaultCountry,
67
-            numbers,
76
+            numbers: action.dialInNumbers,
68 77
             numbersEnabled
69 78
         };
70 79
     }

Loading…
Отказ
Запис