You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

NumbersList.web.js 6.5KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226
  1. /* @flow */
  2. import React, { Component } from 'react';
  3. import { translate } from '../../../base/i18n';
  4. type Props = {
  5. /**
  6. * Whether or not numbers should include links with the telephone protocol.
  7. */
  8. clickableNumbers: boolean,
  9. /**
  10. * The conference ID for dialing in.
  11. */
  12. conferenceID: number,
  13. /**
  14. * The phone numbers to display. Can be an array of number Objects or an
  15. * object with countries as keys and an array of numbers as values.
  16. */
  17. numbers: { [string]: Array<string> } | Array<Object>,
  18. /**
  19. * Invoked to obtain translated strings.
  20. */
  21. t: Function
  22. }
  23. /**
  24. * Displays a table with phone numbers to dial in to a conference.
  25. *
  26. * @extends Component
  27. */
  28. class NumbersList extends Component<Props> {
  29. /**
  30. * Implements React's {@link Component#render()}.
  31. *
  32. * @inheritdoc
  33. * @returns {ReactElement}
  34. */
  35. render() {
  36. const { numbers } = this.props;
  37. return this._renderWithCountries(numbers);
  38. }
  39. /**
  40. * Renders rows of countries and associated phone numbers.
  41. *
  42. * @param {Object|Array<Object>} numbersMapping - An object with country
  43. * names as keys and values as arrays of phone numbers.
  44. * @private
  45. * @returns {ReactElement[]}
  46. */
  47. _renderWithCountries(
  48. numbersMapping: { numbers: Array<string> } | Array<Object>) {
  49. const { t } = this.props;
  50. let hasFlags = false, numbers;
  51. if (Array.isArray(numbersMapping)) {
  52. hasFlags = true;
  53. numbers = numbersMapping.reduce(
  54. (resultNumbers, number) => {
  55. const countryName
  56. = t(`countries:countries.${number.countryCode}`);
  57. if (resultNumbers[countryName]) {
  58. resultNumbers[countryName].push(number);
  59. } else {
  60. resultNumbers[countryName] = [ number ];
  61. }
  62. return resultNumbers;
  63. }, {});
  64. } else {
  65. numbers = {};
  66. for (const [ country, numbersArray ]
  67. of Object.entries(numbersMapping.numbers)) {
  68. if (Array.isArray(numbersArray)) {
  69. /* eslint-disable arrow-body-style */
  70. const formattedNumbers = numbersArray.map(number => ({
  71. formattedNumber: number
  72. }));
  73. /* eslint-enable arrow-body-style */
  74. numbers[country] = formattedNumbers;
  75. }
  76. }
  77. }
  78. const rows = [];
  79. Object.keys(numbers).forEach((countryName: string) => {
  80. const numbersArray = numbers[countryName];
  81. rows.push(
  82. <tr
  83. className = 'number-group'
  84. key = { countryName }>
  85. { this._renderFlag(numbersArray[0].countryCode) }
  86. <td className = 'country' >{ countryName }</td>
  87. <td className = 'numbers-list-column'>
  88. { this._renderNumbersList(numbersArray) }
  89. </td>
  90. <td className = 'toll-free-list-column' >
  91. { this._renderNumbersTollFreeList(numbersArray) }
  92. </td>
  93. </tr>
  94. );
  95. });
  96. return (
  97. <table className = 'dial-in-numbers-list'>
  98. <thead>
  99. <tr>
  100. { hasFlags ? <th /> : null}
  101. <th>{ t('info.country') }</th>
  102. <th>{ t('info.numbers') }</th>
  103. <th />
  104. </tr>
  105. </thead>
  106. <tbody className = 'dial-in-numbers-body'>
  107. { rows }
  108. </tbody>
  109. </table>
  110. );
  111. }
  112. /**
  113. * Renders a div container for a flag for the country of the phone number.
  114. *
  115. * @param {string} countryCode - The country code flag to display.
  116. * @private
  117. * @returns {ReactElement}
  118. */
  119. _renderFlag(countryCode) {
  120. if (countryCode) {
  121. return (
  122. <td className = 'flag-cell'>
  123. <i className = { `flag iti-flag ${countryCode}` } />
  124. </td>);
  125. }
  126. return null;
  127. }
  128. /**
  129. * Renders a div container for a phone number.
  130. *
  131. * @param {Array} numbers - The phone number to display.
  132. * @private
  133. * @returns {ReactElement[]}
  134. */
  135. _renderNumbersList(numbers) {
  136. const numbersListItems = numbers.map(number =>
  137. (<li
  138. className = 'dial-in-number'
  139. key = { number.formattedNumber }>
  140. { this._renderNumberLink(number.formattedNumber) }
  141. </li>));
  142. return (
  143. <ul className = 'numbers-list'>
  144. { numbersListItems }
  145. </ul>
  146. );
  147. }
  148. /**
  149. * Renders list with a toll free text on the position where there is a
  150. * number marked as toll free.
  151. *
  152. * @param {Array} numbers - The phone number that are displayed.
  153. * @private
  154. * @returns {ReactElement[]}
  155. */
  156. _renderNumbersTollFreeList(numbers) {
  157. const { t } = this.props;
  158. const tollNumbersListItems = numbers.map(number =>
  159. (<li
  160. className = 'toll-free'
  161. key = { number.formattedNumber }>
  162. { number.tollFree ? t('info.dialInTollFree') : '' }
  163. </li>));
  164. return (
  165. <ul className = 'toll-free-list'>
  166. { tollNumbersListItems }
  167. </ul>
  168. );
  169. }
  170. /**
  171. * Renders a ReactElement for displaying a telephone number. If the
  172. * component prop {@code clickableNumbers} is true, then the number will
  173. * have a link with the telephone protocol.
  174. *
  175. * @param {string} number - The phone number to display.
  176. * @private
  177. * @returns {ReactElement}
  178. */
  179. _renderNumberLink(number) {
  180. if (this.props.clickableNumbers) {
  181. // Url encode # to %23, Android phone was cutting the # after
  182. // clicking it.
  183. // Seems that using ',' and '%23' works on iOS and Android.
  184. return (
  185. <a
  186. href = { `tel:${number},${this.props.conferenceID}%23` }
  187. key = { number } >
  188. { number }
  189. </a>
  190. );
  191. }
  192. return number;
  193. }
  194. }
  195. export default translate(NumbersList);