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.

DialInSummary.js 6.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275
  1. // @flow
  2. import React, { Component } from 'react';
  3. import { translate } from '../../../../base/i18n';
  4. import { getDialInConferenceID, getDialInNumbers } from '../../../_utils';
  5. import ConferenceID from './ConferenceID';
  6. import NumbersList from './NumbersList';
  7. declare var config: Object;
  8. /**
  9. * The type of the React {@code Component} props of {@link DialInSummary}.
  10. */
  11. type Props = {
  12. /**
  13. * Additional CSS classnames to append to the root of the component.
  14. */
  15. className: string,
  16. /**
  17. * Whether or not numbers should include links with the telephone protocol.
  18. */
  19. clickableNumbers: boolean,
  20. /**
  21. * The name of the conference to show a conferenceID for.
  22. */
  23. room: string,
  24. /**
  25. * The url where we were loaded.
  26. */
  27. url: URL | string,
  28. /**
  29. * Invoked to obtain translated strings.
  30. */
  31. t: Function
  32. };
  33. /**
  34. * The type of the React {@code Component} state of {@link DialInSummary}.
  35. */
  36. type State = {
  37. /**
  38. * The numeric ID of the conference, used as a pin when dialing in.
  39. */
  40. conferenceID: ?string,
  41. /**
  42. * An error message to display.
  43. */
  44. error: string,
  45. /**
  46. * Whether or not the app is fetching data.
  47. */
  48. loading: boolean,
  49. /**
  50. * The dial-in numbers to be displayed.
  51. */
  52. numbers: ?Array<Object> | ?Object,
  53. /**
  54. * Whether or not dial-in is allowed.
  55. */
  56. numbersEnabled: ?boolean
  57. }
  58. /**
  59. * Displays a page listing numbers for dialing into a conference and pin to
  60. * the a specific conference.
  61. *
  62. * @augments Component
  63. */
  64. class DialInSummary extends Component<Props, State> {
  65. state = {
  66. conferenceID: null,
  67. error: '',
  68. loading: true,
  69. numbers: null,
  70. numbersEnabled: null
  71. };
  72. /**
  73. * Initializes a new {@code DialInSummary} instance.
  74. *
  75. * @param {Object} props - The read-only properties with which the new
  76. * instance is to be initialized.
  77. */
  78. constructor(props: Props) {
  79. super(props);
  80. // Bind event handlers so they are only bound once for every instance.
  81. this._onGetNumbersSuccess = this._onGetNumbersSuccess.bind(this);
  82. this._onGetConferenceIDSuccess
  83. = this._onGetConferenceIDSuccess.bind(this);
  84. this._setErrorMessage = this._setErrorMessage.bind(this);
  85. }
  86. /**
  87. * Implements {@link Component#componentDidMount()}. Invoked immediately
  88. * after this component is mounted.
  89. *
  90. * @inheritdoc
  91. * @returns {void}
  92. */
  93. componentDidMount() {
  94. const getNumbers = this._getNumbers()
  95. .then(this._onGetNumbersSuccess)
  96. .catch(this._setErrorMessage);
  97. const getID = this._getConferenceID()
  98. .then(this._onGetConferenceIDSuccess)
  99. .catch(this._setErrorMessage);
  100. Promise.all([ getNumbers, getID ])
  101. .then(() => {
  102. this.setState({ loading: false });
  103. });
  104. }
  105. /**
  106. * Implements React's {@link Component#render()}.
  107. *
  108. * @inheritdoc
  109. * @returns {ReactElement}
  110. */
  111. render() {
  112. let className = '';
  113. let contents;
  114. const { conferenceID, error, loading, numbersEnabled } = this.state;
  115. if (loading) {
  116. contents = '';
  117. } else if (numbersEnabled === false) {
  118. contents = this.props.t('info.dialInNotSupported');
  119. } else if (error) {
  120. contents = error;
  121. } else {
  122. className = 'has-numbers';
  123. contents = [
  124. conferenceID
  125. ? <ConferenceID
  126. conferenceID = { conferenceID }
  127. conferenceName = { this.props.room }
  128. key = 'conferenceID' />
  129. : null,
  130. <NumbersList
  131. clickableNumbers = { this.props.clickableNumbers }
  132. conferenceID = { conferenceID }
  133. key = 'numbers'
  134. numbers = { this.state.numbers } />
  135. ];
  136. }
  137. return (
  138. <div className = { `${this.props.className} ${className}` }>
  139. { contents }
  140. </div>
  141. );
  142. }
  143. /**
  144. * Creates an AJAX request for the conference ID.
  145. *
  146. * @private
  147. * @returns {Promise}
  148. */
  149. _getConferenceID() {
  150. const { room } = this.props;
  151. const { dialInConfCodeUrl, hosts } = config;
  152. const mucURL = hosts && hosts.muc;
  153. if (!dialInConfCodeUrl || !mucURL || !room) {
  154. return Promise.resolve();
  155. }
  156. let url = this.props.url || {};
  157. if (typeof url === 'string' || url instanceof String) {
  158. url = new URL(url);
  159. }
  160. return getDialInConferenceID(dialInConfCodeUrl, room, mucURL, url)
  161. .catch(() => Promise.reject(this.props.t('info.genericError')));
  162. }
  163. /**
  164. * Creates an AJAX request for dial-in numbers.
  165. *
  166. * @private
  167. * @returns {Promise}
  168. */
  169. _getNumbers() {
  170. const { room } = this.props;
  171. const { dialInNumbersUrl, hosts } = config;
  172. const mucURL = hosts && hosts.muc;
  173. if (!dialInNumbersUrl) {
  174. return Promise.reject(this.props.t('info.dialInNotSupported'));
  175. }
  176. return getDialInNumbers(dialInNumbersUrl, room, mucURL)
  177. .catch(() => Promise.reject(this.props.t('info.genericError')));
  178. }
  179. _onGetConferenceIDSuccess: (Object) => void;
  180. /**
  181. * Callback invoked when fetching the conference ID succeeds.
  182. *
  183. * @param {Object} response - The response from fetching the conference ID.
  184. * @private
  185. * @returns {void}
  186. */
  187. _onGetConferenceIDSuccess(response = {}) {
  188. const { conference, id } = response;
  189. if (!conference || !id) {
  190. return;
  191. }
  192. this.setState({ conferenceID: id });
  193. }
  194. _onGetNumbersSuccess: (Object) => void;
  195. /**
  196. * Callback invoked when fetching dial-in numbers succeeds. Sets the
  197. * internal to show the numbers.
  198. *
  199. * @param {Array|Object} response - The response from fetching
  200. * dial-in numbers.
  201. * @param {Array|Object} response.numbers - The dial-in numbers.
  202. * @param {boolean} response.numbersEnabled - Whether or not dial-in is
  203. * enabled, old syntax that is deprecated.
  204. * @private
  205. * @returns {void}
  206. */
  207. _onGetNumbersSuccess(
  208. response: Array<Object> | { numbersEnabled?: boolean }) {
  209. this.setState({
  210. numbersEnabled:
  211. Array.isArray(response)
  212. ? response.length > 0 : response.numbersEnabled,
  213. numbers: response
  214. });
  215. }
  216. _setErrorMessage: (string) => void;
  217. /**
  218. * Sets an error message to display on the page instead of content.
  219. *
  220. * @param {string} error - The error message to display.
  221. * @private
  222. * @returns {void}
  223. */
  224. _setErrorMessage(error) {
  225. this.setState({
  226. error
  227. });
  228. }
  229. }
  230. export default translate(DialInSummary);