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.

PageReloadDialog.tsx 5.7KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221
  1. // @ts-expect-error
  2. import { randomInt } from '@jitsi/js-utils/random';
  3. import React, { Component } from 'react';
  4. import { WithTranslation } from 'react-i18next';
  5. import { connect } from 'react-redux';
  6. import { appNavigate, reloadNow } from '../../../../app/actions.native';
  7. import { IReduxState, IStore } from '../../../../app/types';
  8. import { translate } from '../../../i18n/functions';
  9. import { isFatalJitsiConnectionError } from '../../../lib-jitsi-meet/functions.native';
  10. import { hideDialog } from '../../actions';
  11. import logger from '../../logger';
  12. import ConfirmDialog from './ConfirmDialog';
  13. /**
  14. * The type of the React {@code Component} props of
  15. * {@link PageReloadDialog}.
  16. */
  17. interface IProps extends WithTranslation {
  18. conferenceError?: Error;
  19. configError?: Error;
  20. connectionError?: Error;
  21. dispatch: IStore['dispatch'];
  22. isNetworkFailure: boolean;
  23. reason?: string;
  24. }
  25. /**
  26. * The type of the React {@code Component} state of
  27. * {@link PageReloadDialog}.
  28. */
  29. interface IPageReloadDialogState {
  30. timeLeft: number;
  31. }
  32. /**
  33. * Implements a React Component that is shown before the
  34. * conference is reloaded.
  35. * Shows a warning message and counts down towards the re-load.
  36. */
  37. class PageReloadDialog extends Component<IProps, IPageReloadDialogState> {
  38. _interval?: number;
  39. _timeoutSeconds: number;
  40. /**
  41. * Initializes a new PageReloadOverlay instance.
  42. *
  43. * @param {Object} props - The read-only properties with which the new
  44. * instance is to be initialized.
  45. * @public
  46. */
  47. constructor(props: IProps) {
  48. super(props);
  49. this._timeoutSeconds = 10 + randomInt(0, 20);
  50. this.state = {
  51. timeLeft: this._timeoutSeconds
  52. };
  53. this._onCancel = this._onCancel.bind(this);
  54. this._onReloadNow = this._onReloadNow.bind(this);
  55. this._onReconnecting = this._onReconnecting.bind(this);
  56. }
  57. /**
  58. * React Component method that executes once component is mounted.
  59. *
  60. * @inheritdoc
  61. * @returns {void}
  62. */
  63. componentDidMount() {
  64. const { timeLeft } = this.state;
  65. logger.info(
  66. `The conference will be reloaded after ${timeLeft} seconds.`
  67. );
  68. this._interval = setInterval(() =>
  69. this._onReconnecting(), 1000);
  70. }
  71. /**
  72. * Clears the timer interval.
  73. *
  74. * @inheritdoc
  75. * @returns {void}
  76. */
  77. componentWillUnmount() {
  78. if (this._interval) {
  79. clearInterval(this._interval);
  80. this._interval = undefined;
  81. }
  82. }
  83. /**
  84. * Handle clicking of the "Cancel" button. It will navigate back to the
  85. * welcome page.
  86. *
  87. * @private
  88. * @returns {boolean}
  89. */
  90. _onCancel() {
  91. const { dispatch } = this.props;
  92. clearInterval(this._interval ?? 0);
  93. dispatch(appNavigate(undefined));
  94. return true;
  95. }
  96. /**
  97. * Handles automatic reconnection.
  98. *
  99. * @private
  100. * @returns {void}
  101. */
  102. _onReconnecting() {
  103. const { dispatch } = this.props;
  104. const { timeLeft } = this.state;
  105. if (timeLeft === 0) {
  106. if (this._interval) {
  107. dispatch(hideDialog());
  108. this._onReloadNow();
  109. this._interval = undefined;
  110. }
  111. }
  112. this.setState({
  113. timeLeft: timeLeft - 1
  114. });
  115. }
  116. /**
  117. * Handle clicking on the "Reload Now" button. It will navigate to the same
  118. * conference URL as before immediately, without waiting for the timer to
  119. * kick in.
  120. *
  121. * @private
  122. * @returns {boolean}
  123. */
  124. _onReloadNow() {
  125. const { dispatch } = this.props;
  126. clearInterval(this._interval ?? 0);
  127. dispatch(reloadNow());
  128. return true;
  129. }
  130. /**
  131. * Implements React's {@link Component#render()}.
  132. *
  133. * @inheritdoc
  134. * @returns {ReactElement}
  135. */
  136. render() {
  137. const { isNetworkFailure, t } = this.props;
  138. const { timeLeft } = this.state;
  139. let message, title;
  140. if (isNetworkFailure) {
  141. title = 'dialog.conferenceDisconnectTitle';
  142. message = 'dialog.conferenceDisconnectMsg';
  143. } else {
  144. title = 'dialog.conferenceReloadTitle';
  145. message = 'dialog.conferenceReloadMsg';
  146. }
  147. return (
  148. <ConfirmDialog
  149. cancelLabel = 'dialog.Cancel'
  150. confirmLabel = 'dialog.rejoinNow'
  151. descriptionKey = { `${t(message, { seconds: timeLeft })}` }
  152. onCancel = { this._onCancel }
  153. onSubmit = { this._onReloadNow }
  154. title = { title } />
  155. );
  156. }
  157. }
  158. /**
  159. * Maps (parts of) the redux state to the associated component's props.
  160. *
  161. * @param {Object} state - The redux state.
  162. * @param {IProps} ownProps - The own props of the component.
  163. * @protected
  164. * @returns {{
  165. * isNetworkFailure: boolean,
  166. * reason: string
  167. * }}
  168. */
  169. function mapStateToProps(state: IReduxState, ownProps: IProps) {
  170. const { conferenceError, configError, connectionError } = ownProps;
  171. const fatalConnectionError
  172. = connectionError && isFatalJitsiConnectionError(connectionError);
  173. const isNetworkFailure = Boolean(configError || fatalConnectionError);
  174. let reason;
  175. if (conferenceError) {
  176. reason = `error.conference.${conferenceError.name}`;
  177. } else if (connectionError) {
  178. reason = `error.conference.${connectionError.name}`;
  179. } else if (configError) {
  180. reason = `error.config.${configError.name}`;
  181. } else {
  182. logger.error('No reload reason defined!');
  183. }
  184. return {
  185. isNetworkFailure,
  186. reason
  187. };
  188. }
  189. export default translate(connect(mapStateToProps)(PageReloadDialog));