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

AbstractWelcomePage.js 7.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284
  1. // @flow
  2. import { generateRoomWithoutSeparator } from '@jitsi/js-utils/random';
  3. import { Component } from 'react';
  4. import type { Dispatch } from 'redux';
  5. import { createWelcomePageEvent, sendAnalytics } from '../../analytics';
  6. import { appNavigate } from '../../app/actions';
  7. import { IDeeplinkingConfig } from '../../base/config/configType';
  8. import isInsecureRoomName from '../../base/util/isInsecureRoomName';
  9. import { isCalendarEnabled } from '../../calendar-sync';
  10. import { isRecentListEnabled } from '../../recent-list/functions';
  11. /**
  12. * {@code AbstractWelcomePage}'s React {@code Component} prop types.
  13. */
  14. export type Props = {
  15. /**
  16. * Whether the calendar functionality is enabled or not.
  17. */
  18. _calendarEnabled: boolean,
  19. /**
  20. * The deeplinking config.
  21. */
  22. _deeplinkingCfg: IDeeplinkingConfig,
  23. /**
  24. * Whether the insecure room name functionality is enabled or not.
  25. */
  26. _enableInsecureRoomNameWarning: boolean,
  27. /**
  28. * URL for the moderated rooms microservice, if available.
  29. */
  30. _moderatedRoomServiceUrl: ?string,
  31. /**
  32. * Whether the recent list is enabled.
  33. */
  34. _recentListEnabled: Boolean,
  35. /**
  36. * Room name to join to.
  37. */
  38. _room: string,
  39. /**
  40. * The current settings.
  41. */
  42. _settings: Object,
  43. /**
  44. * The Redux dispatch Function.
  45. */
  46. dispatch: Dispatch<any>
  47. };
  48. /**
  49. * Base (abstract) class for container component rendering the welcome page.
  50. *
  51. * @abstract
  52. */
  53. export class AbstractWelcomePage<P: Props> extends Component<P, *> {
  54. _mounted: ?boolean;
  55. /**
  56. * Save room name into component's local state.
  57. *
  58. * @type {Object}
  59. * @property {number|null} animateTimeoutId - Identifier of the letter
  60. * animation timeout.
  61. * @property {string} generatedRoomname - Automatically generated room name.
  62. * @property {string} room - Room name.
  63. * @property {string} roomPlaceholder - Room placeholder that's used as a
  64. * placeholder for input.
  65. * @property {number|null} updateTimeoutId - Identifier of the timeout
  66. * updating the generated room name.
  67. */
  68. state = {
  69. animateTimeoutId: undefined,
  70. generatedRoomname: '',
  71. insecureRoomName: false,
  72. joining: false,
  73. room: '',
  74. roomPlaceholder: '',
  75. updateTimeoutId: undefined
  76. };
  77. /**
  78. * Initializes a new {@code AbstractWelcomePage} instance.
  79. *
  80. * @param {Props} props - The React {@code Component} props to initialize
  81. * the new {@code AbstractWelcomePage} instance with.
  82. */
  83. constructor(props: P) {
  84. super(props);
  85. // Bind event handlers so they are only bound once per instance.
  86. this._animateRoomnameChanging
  87. = this._animateRoomnameChanging.bind(this);
  88. this._onJoin = this._onJoin.bind(this);
  89. this._onRoomChange = this._onRoomChange.bind(this);
  90. this._renderInsecureRoomNameWarning = this._renderInsecureRoomNameWarning.bind(this);
  91. this._updateRoomname = this._updateRoomname.bind(this);
  92. }
  93. /**
  94. * Implements React's {@link Component#componentDidMount()}. Invoked
  95. * immediately after mounting occurs.
  96. *
  97. * @inheritdoc
  98. */
  99. componentDidMount() {
  100. this._mounted = true;
  101. sendAnalytics(createWelcomePageEvent('viewed', undefined, { value: 1 }));
  102. }
  103. /**
  104. * Implements React's {@link Component#componentWillUnmount()}. Invoked
  105. * immediately before this component is unmounted and destroyed.
  106. *
  107. * @inheritdoc
  108. */
  109. componentWillUnmount() {
  110. this._clearTimeouts();
  111. this._mounted = false;
  112. }
  113. _animateRoomnameChanging: (string) => void;
  114. /**
  115. * Animates the changing of the room name.
  116. *
  117. * @param {string} word - The part of room name that should be added to
  118. * placeholder.
  119. * @private
  120. * @returns {void}
  121. */
  122. _animateRoomnameChanging(word: string) {
  123. let animateTimeoutId;
  124. const roomPlaceholder = this.state.roomPlaceholder + word.substr(0, 1);
  125. if (word.length > 1) {
  126. animateTimeoutId
  127. = setTimeout(
  128. () => {
  129. this._animateRoomnameChanging(
  130. word.substring(1, word.length));
  131. },
  132. 70);
  133. }
  134. this.setState({
  135. animateTimeoutId,
  136. roomPlaceholder
  137. });
  138. }
  139. /**
  140. * Method that clears timeouts for animations and updates of room name.
  141. *
  142. * @private
  143. * @returns {void}
  144. */
  145. _clearTimeouts() {
  146. clearTimeout(this.state.animateTimeoutId);
  147. clearTimeout(this.state.updateTimeoutId);
  148. }
  149. /**
  150. * Renders the insecure room name warning.
  151. *
  152. * @returns {ReactElement}
  153. */
  154. _doRenderInsecureRoomNameWarning: () => React$Component<any>;
  155. _onJoin: () => void;
  156. /**
  157. * Handles joining. Either by clicking on 'Join' button
  158. * or by pressing 'Enter' in room name input field.
  159. *
  160. * @protected
  161. * @returns {void}
  162. */
  163. _onJoin() {
  164. const room = this.state.room || this.state.generatedRoomname;
  165. sendAnalytics(
  166. createWelcomePageEvent('clicked', 'joinButton', {
  167. isGenerated: !this.state.room,
  168. room
  169. }));
  170. if (room) {
  171. this.setState({ joining: true });
  172. // By the time the Promise of appNavigate settles, this component
  173. // may have already been unmounted.
  174. const onAppNavigateSettled
  175. = () => this._mounted && this.setState({ joining: false });
  176. this.props.dispatch(appNavigate(room))
  177. .then(onAppNavigateSettled, onAppNavigateSettled);
  178. }
  179. }
  180. _onRoomChange: (string) => void;
  181. /**
  182. * Handles 'change' event for the room name text input field.
  183. *
  184. * @param {string} value - The text typed into the respective text input
  185. * field.
  186. * @protected
  187. * @returns {void}
  188. */
  189. _onRoomChange(value: string) {
  190. this.setState({
  191. room: value,
  192. insecureRoomName: this.props._enableInsecureRoomNameWarning && value && isInsecureRoomName(value)
  193. });
  194. }
  195. _renderInsecureRoomNameWarning: () => React$Component<any>;
  196. /**
  197. * Renders the insecure room name warning if needed.
  198. *
  199. * @returns {ReactElement}
  200. */
  201. _renderInsecureRoomNameWarning() {
  202. if (this.props._enableInsecureRoomNameWarning && this.state.insecureRoomName) {
  203. return this._doRenderInsecureRoomNameWarning();
  204. }
  205. return null;
  206. }
  207. _updateRoomname: () => void;
  208. /**
  209. * Triggers the generation of a new room name and initiates an animation of
  210. * its changing.
  211. *
  212. * @protected
  213. * @returns {void}
  214. */
  215. _updateRoomname() {
  216. const generatedRoomname = generateRoomWithoutSeparator();
  217. const roomPlaceholder = '';
  218. const updateTimeoutId = setTimeout(this._updateRoomname, 10000);
  219. this._clearTimeouts();
  220. this.setState(
  221. {
  222. generatedRoomname,
  223. roomPlaceholder,
  224. updateTimeoutId
  225. },
  226. () => this._animateRoomnameChanging(generatedRoomname));
  227. }
  228. }
  229. /**
  230. * Maps (parts of) the redux state to the React {@code Component} props of
  231. * {@code AbstractWelcomePage}.
  232. *
  233. * @param {Object} state - The redux state.
  234. * @protected
  235. * @returns {Props}
  236. */
  237. export function _mapStateToProps(state: Object) {
  238. return {
  239. _calendarEnabled: isCalendarEnabled(state),
  240. _deeplinkingCfg: state['features/base/config'].deeplinking || {},
  241. _enableInsecureRoomNameWarning: state['features/base/config'].enableInsecureRoomNameWarning || false,
  242. _moderatedRoomServiceUrl: state['features/base/config'].moderatedRoomServiceUrl,
  243. _recentListEnabled: isRecentListEnabled(),
  244. _room: state['features/base/conference'].room,
  245. _settings: state['features/base/settings']
  246. };
  247. }