Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.

LoginDialog.js 8.1KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313
  1. // @flow
  2. import { FieldTextStateless as TextField } from '@atlaskit/field-text';
  3. import React, { Component } from 'react';
  4. import type { Dispatch } from 'redux';
  5. import { connect } from '../../../../../connection';
  6. import { toJid } from '../../../base/connection/functions';
  7. import { Dialog } from '../../../base/dialog';
  8. import { translate, translateToHTML } from '../../../base/i18n';
  9. import { JitsiConnectionErrors } from '../../../base/lib-jitsi-meet';
  10. import { connect as reduxConnect } from '../../../base/redux';
  11. import { authenticateAndUpgradeRole } from '../../actions.native';
  12. import { cancelLogin } from '../../actions.web';
  13. /**
  14. * The type of the React {@code Component} props of {@link LoginDialog}.
  15. */
  16. type Props = {
  17. /**
  18. * {@link JitsiConference} that needs authentication - will hold a valid
  19. * value in XMPP login + guest access mode.
  20. */
  21. _conference: Object,
  22. /**
  23. * The server hosts specified in the global config.
  24. */
  25. _configHosts: Object,
  26. /**
  27. * Indicates if the dialog should display "connecting" status message.
  28. */
  29. _connecting: boolean,
  30. /**
  31. * The error which occurred during login/authentication.
  32. */
  33. _error: Object,
  34. /**
  35. * The progress in the floating range between 0 and 1 of the authenticating
  36. * and upgrading the role of the local participant/user.
  37. */
  38. _progress: number,
  39. /**
  40. * Redux store dispatch method.
  41. */
  42. dispatch: Dispatch<any>,
  43. /**
  44. * Invoked when username and password are submitted.
  45. */
  46. onSuccess: Function,
  47. /**
  48. * Conference room name.
  49. */
  50. roomName: string,
  51. /**
  52. * Invoked to obtain translated strings.
  53. */
  54. t: Function
  55. }
  56. /**
  57. * The type of the React {@code Component} state of {@link LoginDialog}.
  58. */
  59. type State = {
  60. /**
  61. * The user entered password for the conference.
  62. */
  63. password: string,
  64. /**
  65. * The user entered local participant name.
  66. */
  67. username: string,
  68. /**
  69. * Authentication process starts before joining the conference room.
  70. */
  71. loginStarted: boolean
  72. }
  73. /**
  74. * Component that renders the login in conference dialog.
  75. *
  76. * @returns {React$Element<any>}
  77. */
  78. class LoginDialog extends Component<Props, State> {
  79. /**
  80. * Initializes a new {@code LoginDialog} instance.
  81. *
  82. * @inheritdoc
  83. */
  84. constructor(props: Props) {
  85. super(props);
  86. this.state = {
  87. username: '',
  88. password: '',
  89. loginStarted: false
  90. };
  91. this._onCancelLogin = this._onCancelLogin.bind(this);
  92. this._onLogin = this._onLogin.bind(this);
  93. this._onChange = this._onChange.bind(this);
  94. }
  95. _onCancelLogin: () => void;
  96. /**
  97. * Called when the cancel button is clicked.
  98. *
  99. * @private
  100. * @returns {void}
  101. */
  102. _onCancelLogin() {
  103. const { dispatch } = this.props;
  104. dispatch(cancelLogin());
  105. }
  106. _onLogin: () => void;
  107. /**
  108. * Notifies this LoginDialog that the login button (OK) has been pressed by
  109. * the user.
  110. *
  111. * @private
  112. * @returns {void}
  113. */
  114. _onLogin() {
  115. const {
  116. _conference: conference,
  117. _configHosts: configHosts,
  118. roomName,
  119. onSuccess,
  120. dispatch
  121. } = this.props;
  122. const { password, username } = this.state;
  123. const jid = toJid(username, configHosts);
  124. if (conference) {
  125. dispatch(authenticateAndUpgradeRole(jid, password, conference));
  126. } else {
  127. this.setState({
  128. loginStarted: true
  129. });
  130. connect(jid, password, roomName)
  131. .then(connection => {
  132. onSuccess && onSuccess(connection);
  133. })
  134. .catch(() => {
  135. this.setState({
  136. loginStarted: false
  137. });
  138. });
  139. }
  140. }
  141. _onChange: Object => void;
  142. /**
  143. * Callback for the onChange event of the field.
  144. *
  145. * @param {Object} evt - The static event.
  146. * @returns {void}
  147. */
  148. _onChange(evt: Object) {
  149. this.setState({
  150. [evt.target.name]: evt.target.value
  151. });
  152. }
  153. /**
  154. * Renders an optional message, if applicable.
  155. *
  156. * @returns {ReactElement}
  157. * @private
  158. */
  159. renderMessage() {
  160. const {
  161. _configHosts: configHosts,
  162. _connecting: connecting,
  163. _error: error,
  164. _progress: progress,
  165. t
  166. } = this.props;
  167. const { username, password } = this.state;
  168. const messageOptions = {};
  169. let messageKey;
  170. if (progress && progress >= 0.5) {
  171. messageKey = t('connection.FETCH_SESSION_ID');
  172. } else if (error) {
  173. const { name } = error;
  174. if (name === JitsiConnectionErrors.PASSWORD_REQUIRED) {
  175. const { credentials } = error;
  176. if (credentials
  177. && credentials.jid === toJid(username, configHosts)
  178. && credentials.password === password) {
  179. messageKey = t('dialog.incorrectPassword');
  180. }
  181. } else if (name) {
  182. messageKey = t('dialog.connectErrorWithMsg');
  183. messageOptions.msg = `${name} ${error.message}`;
  184. }
  185. } else if (connecting) {
  186. messageKey = t('connection.CONNECTING');
  187. }
  188. if (messageKey) {
  189. return (
  190. <span>
  191. { translateToHTML(t, messageKey, messageOptions) }
  192. </span>
  193. );
  194. }
  195. return null;
  196. }
  197. /**
  198. * Implements {@Component#render}.
  199. *
  200. * @inheritdoc
  201. */
  202. render() {
  203. const {
  204. _connecting: connecting,
  205. t
  206. } = this.props;
  207. const { password, loginStarted, username } = this.state;
  208. return (
  209. <Dialog
  210. okDisabled = {
  211. connecting
  212. || loginStarted
  213. || !password
  214. || !username
  215. }
  216. okKey = { t('dialog.login') }
  217. onCancel = { this._onCancelLogin }
  218. onSubmit = { this._onLogin }
  219. titleKey = { t('dialog.authenticationRequired') }
  220. width = { 'small' }>
  221. <TextField
  222. autoFocus = { true }
  223. className = 'input-control'
  224. compact = { false }
  225. label = { t('dialog.user') }
  226. name = 'username'
  227. onChange = { this._onChange }
  228. placeholder = { t('dialog.userIdentifier') }
  229. shouldFitContainer = { true }
  230. type = 'text'
  231. value = { username } />
  232. <TextField
  233. className = 'input-control'
  234. compact = { false }
  235. label = { t('dialog.userPassword') }
  236. name = 'password'
  237. onChange = { this._onChange }
  238. shouldFitContainer = { true }
  239. type = 'password'
  240. value = { password } />
  241. { this.renderMessage() }
  242. </Dialog>
  243. );
  244. }
  245. }
  246. /**
  247. * Maps (parts of) the Redux state to the associated props for the
  248. * {@code LoginDialog} component.
  249. *
  250. * @param {Object} state - The Redux state.
  251. * @private
  252. * @returns {Props}
  253. */
  254. function mapStateToProps(state) {
  255. const {
  256. error: authenticateAndUpgradeRoleError,
  257. progress,
  258. thenableWithCancel
  259. } = state['features/authentication'];
  260. const { authRequired } = state['features/base/conference'];
  261. const { hosts: configHosts } = state['features/base/config'];
  262. const {
  263. connecting,
  264. error: connectionError
  265. } = state['features/base/connection'];
  266. return {
  267. _conference: authRequired,
  268. _configHosts: configHosts,
  269. _connecting: connecting || thenableWithCancel,
  270. _error: connectionError || authenticateAndUpgradeRoleError,
  271. _progress: progress
  272. };
  273. }
  274. export default translate(reduxConnect(mapStateToProps)(LoginDialog));