您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

NumbersList.js 6.6KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228
  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. // The i18n-iso-countries package insists on upper case.
  56. const countryCode = number.countryCode.toUpperCase();
  57. const countryName
  58. = t(`countries:countries.${countryCode}`);
  59. if (resultNumbers[countryName]) {
  60. resultNumbers[countryName].push(number);
  61. } else {
  62. resultNumbers[countryName] = [ number ];
  63. }
  64. return resultNumbers;
  65. }, {});
  66. } else {
  67. numbers = {};
  68. for (const [ country, numbersArray ]
  69. of Object.entries(numbersMapping.numbers)) {
  70. if (Array.isArray(numbersArray)) {
  71. /* eslint-disable arrow-body-style */
  72. const formattedNumbers = numbersArray.map(number => ({
  73. formattedNumber: number
  74. }));
  75. /* eslint-enable arrow-body-style */
  76. numbers[country] = formattedNumbers;
  77. }
  78. }
  79. }
  80. const rows = [];
  81. Object.keys(numbers).forEach((countryName: string) => {
  82. const numbersArray = numbers[countryName];
  83. rows.push(
  84. <tr
  85. className = 'number-group'
  86. key = { countryName }>
  87. { this._renderFlag(numbersArray[0].countryCode) }
  88. <td className = 'country' >{ countryName }</td>
  89. <td className = 'numbers-list-column'>
  90. { this._renderNumbersList(numbersArray) }
  91. </td>
  92. <td className = 'toll-free-list-column' >
  93. { this._renderNumbersTollFreeList(numbersArray) }
  94. </td>
  95. </tr>
  96. );
  97. });
  98. return (
  99. <table className = 'dial-in-numbers-list'>
  100. <thead>
  101. <tr>
  102. { hasFlags ? <th /> : null}
  103. <th>{ t('info.country') }</th>
  104. <th>{ t('info.numbers') }</th>
  105. <th />
  106. </tr>
  107. </thead>
  108. <tbody className = 'dial-in-numbers-body'>
  109. { rows }
  110. </tbody>
  111. </table>
  112. );
  113. }
  114. /**
  115. * Renders a div container for a flag for the country of the phone number.
  116. *
  117. * @param {string} countryCode - The country code flag to display.
  118. * @private
  119. * @returns {ReactElement}
  120. */
  121. _renderFlag(countryCode) {
  122. if (countryCode) {
  123. return (
  124. <td className = 'flag-cell'>
  125. <i className = { `flag iti-flag ${countryCode}` } />
  126. </td>);
  127. }
  128. return null;
  129. }
  130. /**
  131. * Renders a div container for a phone number.
  132. *
  133. * @param {Array} numbers - The phone number to display.
  134. * @private
  135. * @returns {ReactElement[]}
  136. */
  137. _renderNumbersList(numbers) {
  138. const numbersListItems = numbers.map(number =>
  139. (<li
  140. className = 'dial-in-number'
  141. key = { number.formattedNumber }>
  142. { this._renderNumberLink(number.formattedNumber) }
  143. </li>));
  144. return (
  145. <ul className = 'numbers-list'>
  146. { numbersListItems }
  147. </ul>
  148. );
  149. }
  150. /**
  151. * Renders list with a toll free text on the position where there is a
  152. * number marked as toll free.
  153. *
  154. * @param {Array} numbers - The phone number that are displayed.
  155. * @private
  156. * @returns {ReactElement[]}
  157. */
  158. _renderNumbersTollFreeList(numbers) {
  159. const { t } = this.props;
  160. const tollNumbersListItems = numbers.map(number =>
  161. (<li
  162. className = 'toll-free'
  163. key = { number.formattedNumber }>
  164. { number.tollFree ? t('info.dialInTollFree') : '' }
  165. </li>));
  166. return (
  167. <ul className = 'toll-free-list'>
  168. { tollNumbersListItems }
  169. </ul>
  170. );
  171. }
  172. /**
  173. * Renders a ReactElement for displaying a telephone number. If the
  174. * component prop {@code clickableNumbers} is true, then the number will
  175. * have a link with the telephone protocol.
  176. *
  177. * @param {string} number - The phone number to display.
  178. * @private
  179. * @returns {ReactElement}
  180. */
  181. _renderNumberLink(number) {
  182. if (this.props.clickableNumbers) {
  183. // Url encode # to %23, Android phone was cutting the # after
  184. // clicking it.
  185. // Seems that using ',' and '%23' works on iOS and Android.
  186. return (
  187. <a
  188. href = { `tel:${number},${this.props.conferenceID}%23` }
  189. key = { number } >
  190. { number }
  191. </a>
  192. );
  193. }
  194. return number;
  195. }
  196. }
  197. export default translate(NumbersList);