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.js 6.8KB

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