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.

InviteButton.web.js 6.8KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236
  1. import PropTypes from 'prop-types';
  2. import React, { Component } from 'react';
  3. import { connect } from 'react-redux';
  4. import Button from '@atlaskit/button';
  5. import DropdownMenu from '@atlaskit/dropdown-menu';
  6. import { translate } from '../../base/i18n';
  7. import { getLocalParticipant, PARTICIPANT_ROLE } from '../../base/participants';
  8. import { openDialog } from '../../base/dialog';
  9. import { AddPeopleDialog, InviteDialog } from '.';
  10. import { DialOutDialog } from '../../dial-out';
  11. import { isInviteOptionEnabled, getInviteOptionPosition } from '../functions';
  12. declare var interfaceConfig: Object;
  13. const SHARE_LINK_OPTION = 'invite';
  14. const DIAL_OUT_OPTION = 'dialout';
  15. const ADD_TO_CALL_OPTION = 'addtocall';
  16. /**
  17. * The button that provides different invite options.
  18. */
  19. class InviteButton extends Component {
  20. /**
  21. * {@code InviteButton}'s property types.
  22. *
  23. * @static
  24. */
  25. static propTypes = {
  26. /**
  27. * Indicates if the "Add to call" feature is available.
  28. */
  29. _isAddToCallAvailable: PropTypes.bool,
  30. /**
  31. * Indicates if the "Dial out" feature is available.
  32. */
  33. _isDialOutAvailable: PropTypes.bool,
  34. /**
  35. * The function opening the dialog.
  36. */
  37. openDialog: PropTypes.func,
  38. /**
  39. * Invoked to obtain translated strings.
  40. */
  41. t: PropTypes.func
  42. };
  43. /**
  44. * Initializes a new {@code InviteButton} instance.
  45. *
  46. * @param {Object} props - The read-only properties with which the new
  47. * instance is to be initialized.
  48. */
  49. constructor(props) {
  50. super(props);
  51. this._onInviteClick = this._onInviteClick.bind(this);
  52. this._onInviteOptionSelected = this._onInviteOptionSelected.bind(this);
  53. this._updateInviteItems = this._updateInviteItems.bind(this);
  54. this._updateInviteItems(this.props);
  55. }
  56. /**
  57. * Implements React's {@link Component#componentWillReceiveProps()}.
  58. *
  59. * @inheritdoc
  60. * @param {Object} nextProps - The read-only props which this Component will
  61. * receive.
  62. * @returns {void}
  63. */
  64. componentWillReceiveProps(nextProps) {
  65. if (this.props._isDialOutAvailable !== nextProps._isDialOutAvailable
  66. || this.props._isAddToCallAvailable
  67. !== nextProps._isAddToCallAvailable) {
  68. this._updateInviteItems(nextProps);
  69. }
  70. }
  71. /**
  72. * Renders the content of this component.
  73. *
  74. * @returns {ReactElement}
  75. */
  76. render() {
  77. const { t } = this.props;
  78. const { VERTICAL_FILMSTRIP } = interfaceConfig;
  79. return (
  80. <div className = 'filmstrip__invite'>
  81. <div className = 'invite-button-group'>
  82. <Button
  83. onClick = { this._onInviteClick }
  84. shouldFitContainer = { true }>
  85. { t('invite.invitePeople') }
  86. </Button>
  87. { this.props._isDialOutAvailable
  88. || this.props._isAddToCallAvailable
  89. ? <DropdownMenu
  90. items = { this.state.inviteOptions }
  91. onItemActivated = { this._onInviteOptionSelected }
  92. position = { VERTICAL_FILMSTRIP
  93. ? 'bottom right'
  94. : 'top right' }
  95. shouldFlip = { true }
  96. triggerType = 'button' />
  97. : null }
  98. </div>
  99. </div>
  100. );
  101. }
  102. /**
  103. * Handles the click of the invite button.
  104. *
  105. * @private
  106. * @returns {void}
  107. */
  108. _onInviteClick() {
  109. this.props.openDialog(InviteDialog);
  110. }
  111. /**
  112. * Handles selection of the invite options.
  113. *
  114. * @param { Object } option - The invite option that has been selected from
  115. * the dropdown menu.
  116. * @private
  117. * @returns {void}
  118. */
  119. _onInviteOptionSelected(option) {
  120. this.state.inviteOptions[0].items.forEach(item => {
  121. if (item.content === option.item.content) {
  122. item.action();
  123. }
  124. });
  125. }
  126. /**
  127. * Updates the invite items list depending on the availability of the
  128. * features.
  129. *
  130. * @param {Object} props - The read-only properties of the component.
  131. * @private
  132. * @returns {void}
  133. */
  134. _updateInviteItems(props) {
  135. const { t } = this.props;
  136. const inviteItems = [];
  137. inviteItems.splice(
  138. getInviteOptionPosition(SHARE_LINK_OPTION),
  139. 0,
  140. {
  141. content: t('toolbar.invite'),
  142. action: () => this.props.openDialog(InviteDialog)
  143. }
  144. );
  145. if (props._isDialOutAvailable) {
  146. inviteItems.splice(
  147. getInviteOptionPosition(DIAL_OUT_OPTION),
  148. 0,
  149. {
  150. content: t('dialOut.dialOut'),
  151. action: () => this.props.openDialog(DialOutDialog)
  152. }
  153. );
  154. }
  155. if (props._isAddToCallAvailable) {
  156. inviteItems.splice(
  157. getInviteOptionPosition(ADD_TO_CALL_OPTION),
  158. 0,
  159. {
  160. content: interfaceConfig.ADD_PEOPLE_APP_NAME,
  161. action: () => this.props.openDialog(AddPeopleDialog)
  162. }
  163. );
  164. }
  165. const nextState = {
  166. /**
  167. * The list of invite options.
  168. */
  169. inviteOptions: [
  170. {
  171. items: inviteItems
  172. }
  173. ]
  174. };
  175. if (this.state) {
  176. this.setState(nextState);
  177. } else {
  178. // eslint-disable-next-line react/no-direct-mutation-state
  179. this.state = nextState;
  180. }
  181. }
  182. }
  183. /**
  184. * Maps (parts of) the Redux state to the associated {@code InviteButton}'s
  185. * props.
  186. *
  187. * @param {Object} state - The Redux state.
  188. * @private
  189. * @returns {{
  190. * _isAddToCallAvailable: boolean,
  191. * _isDialOutAvailable: boolean
  192. * }}
  193. */
  194. function _mapStateToProps(state) {
  195. const { conference } = state['features/base/conference'];
  196. const { enableUserRolesBasedOnToken } = state['features/base/config'];
  197. const { isGuest } = state['features/base/jwt'];
  198. return {
  199. _isAddToCallAvailable:
  200. !isGuest && isInviteOptionEnabled(ADD_TO_CALL_OPTION),
  201. _isDialOutAvailable:
  202. getLocalParticipant(state).role === PARTICIPANT_ROLE.MODERATOR
  203. && conference && conference.isSIPCallingSupported()
  204. && isInviteOptionEnabled(DIAL_OUT_OPTION)
  205. && (!enableUserRolesBasedOnToken || !isGuest)
  206. };
  207. }
  208. export default translate(connect(_mapStateToProps, { openDialog })(
  209. InviteButton));