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

AbstractWelcomePage.js 7.9KB

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