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.

middleware.js 6.6KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233
  1. /* @flow */
  2. import i18next from 'i18next';
  3. import { NativeModules, NativeEventEmitter } from 'react-native';
  4. import { MiddlewareRegistry } from '../../base/redux';
  5. import { APP_WILL_MOUNT, APP_WILL_UNMOUNT } from '../../app';
  6. import { getInviteURL } from '../../base/connection';
  7. import {
  8. getInviteResultsForQuery,
  9. isAddPeopleEnabled,
  10. isDialOutEnabled,
  11. sendInvitesForItems
  12. } from '../../invite';
  13. import { inviteVideoRooms } from '../../videosipgw';
  14. import { sendInviteSuccess, sendInviteFailure } from './actions';
  15. import {
  16. _SET_INVITE_SEARCH_SUBSCRIPTIONS,
  17. LAUNCH_NATIVE_INVITE,
  18. SEND_INVITE_SUCCESS,
  19. SEND_INVITE_FAILURE
  20. } from './actionTypes';
  21. /**
  22. * Middleware that captures Redux actions and uses the InviteSearch module to
  23. * turn them into native events so the application knows about them.
  24. *
  25. * @param {Store} store - Redux store.
  26. * @returns {Function}
  27. */
  28. MiddlewareRegistry.register(store => next => action => {
  29. const result = next(action);
  30. switch (action.type) {
  31. case APP_WILL_MOUNT:
  32. return _appWillMount(store, next, action);
  33. case APP_WILL_UNMOUNT:
  34. store.dispatch({
  35. type: _SET_INVITE_SEARCH_SUBSCRIPTIONS,
  36. subscriptions: undefined
  37. });
  38. break;
  39. case LAUNCH_NATIVE_INVITE:
  40. launchNativeInvite(store);
  41. break;
  42. case SEND_INVITE_SUCCESS:
  43. onSendInviteSuccess(action);
  44. break;
  45. case SEND_INVITE_FAILURE:
  46. onSendInviteFailure(action);
  47. break;
  48. }
  49. return result;
  50. });
  51. /**
  52. * Notifies the feature jwt that the action {@link APP_WILL_MOUNT} is being
  53. * dispatched within a specific redux {@code store}.
  54. *
  55. * @param {Store} store - The redux store in which the specified {@code action}
  56. * is being dispatched.
  57. * @param {Dispatch} next - The redux dispatch function to dispatch the
  58. * specified {@code action} to the specified {@code store}.
  59. * @param {Action} action - The redux action {@code APP_WILL_MOUNT} which is
  60. * being dispatched in the specified {@code store}.
  61. * @private
  62. * @returns {*}
  63. */
  64. function _appWillMount({ dispatch, getState }, next, action) {
  65. const result = next(action);
  66. const emitter = new NativeEventEmitter(NativeModules.InviteSearch);
  67. const context = {
  68. dispatch,
  69. getState
  70. };
  71. const subscriptions = [
  72. emitter.addListener(
  73. 'performQueryAction',
  74. _onPerformQueryAction,
  75. context),
  76. emitter.addListener(
  77. 'performSubmitInviteAction',
  78. _onPerformSubmitInviteAction,
  79. context)
  80. ];
  81. dispatch({
  82. type: _SET_INVITE_SEARCH_SUBSCRIPTIONS,
  83. subscriptions
  84. });
  85. return result;
  86. }
  87. /**
  88. * Sends a request to the native counterpart of InviteSearch to launch a native.
  89. * invite search.
  90. *
  91. * @param {Object} store - The redux store.
  92. * @private
  93. * @returns {void}
  94. */
  95. function launchNativeInvite(store: { getState: Function }) {
  96. // The JavaScript App needs to provide uniquely identifying information
  97. // to the native module so that the latter may match the former
  98. // to the native JitsiMeetView which hosts it.
  99. const { app } = store.getState()['features/app'];
  100. if (app) {
  101. const { externalAPIScope } = app.props;
  102. if (externalAPIScope) {
  103. NativeModules.InviteSearch.launchNativeInvite(externalAPIScope);
  104. }
  105. }
  106. }
  107. /**
  108. * Sends a notification to the native counterpart of InviteSearch that all
  109. * invites were sent successfully.
  110. *
  111. * @param {Object} action - The redux action {@code SEND_INVITE_SUCCESS} which
  112. * is being dispatched.
  113. * @returns {void}
  114. */
  115. function onSendInviteSuccess({ inviteScope }) {
  116. NativeModules.InviteSearch.inviteSucceeded(inviteScope);
  117. }
  118. /**
  119. * Sends a notification to the native counterpart of InviteSearch that some
  120. * invite items failed to send successfully.
  121. *
  122. * @param {Object} action - The redux action {@code SEND_INVITE_FAILURE} which
  123. * is being dispatched.
  124. * @returns {void}
  125. */
  126. function onSendInviteFailure({ items, inviteScope }) {
  127. NativeModules.InviteSearch.inviteFailedForItems(items, inviteScope);
  128. }
  129. /**
  130. * Handles InviteSearch's event {@code performQueryAction}.
  131. *
  132. * @param {Object} event - The details of the InviteSearch event
  133. * {@code performQueryAction}.
  134. * @returns {void}
  135. */
  136. function _onPerformQueryAction({ query, inviteScope }) {
  137. const { getState } = this; // eslint-disable-line no-invalid-this
  138. const state = getState();
  139. const {
  140. dialOutAuthUrl,
  141. peopleSearchQueryTypes,
  142. peopleSearchUrl
  143. } = state['features/base/config'];
  144. const options = {
  145. dialOutAuthUrl,
  146. enableAddPeople: isAddPeopleEnabled(state),
  147. enableDialOut: isDialOutEnabled(state),
  148. jwt: state['features/base/jwt'].jwt,
  149. peopleSearchQueryTypes,
  150. peopleSearchUrl
  151. };
  152. getInviteResultsForQuery(query, options)
  153. .catch(() => [])
  154. .then(results => {
  155. const translatedResults = results.map(result => {
  156. if (result.type === 'phone') {
  157. result.title = i18next.t('addPeople.telephone', {
  158. number: result.number
  159. });
  160. if (result.showCountryCodeReminder) {
  161. result.subtitle = i18next.t(
  162. 'addPeople.countryReminder'
  163. );
  164. }
  165. }
  166. return result;
  167. }).filter(result => result.type !== 'phone' || result.allowed);
  168. NativeModules.InviteSearch.receivedResults(
  169. translatedResults,
  170. query,
  171. inviteScope);
  172. });
  173. }
  174. /**
  175. * Handles InviteSearch's event {@code performSubmitInviteAction}.
  176. *
  177. * @param {Object} event - The details of the InviteSearch event.
  178. * @returns {void}
  179. */
  180. function _onPerformSubmitInviteAction({ selectedItems, inviteScope }) {
  181. const { dispatch, getState } = this; // eslint-disable-line no-invalid-this
  182. const state = getState();
  183. const { conference } = state['features/base/conference'];
  184. const {
  185. inviteServiceUrl
  186. } = state['features/base/config'];
  187. const options = {
  188. conference,
  189. inviteServiceUrl,
  190. inviteUrl: getInviteURL(state),
  191. inviteVideoRooms,
  192. jwt: state['features/base/jwt'].jwt
  193. };
  194. sendInvitesForItems(selectedItems, options)
  195. .then(invitesLeftToSend => {
  196. if (invitesLeftToSend.length) {
  197. dispatch(sendInviteFailure(invitesLeftToSend, inviteScope));
  198. } else {
  199. dispatch(sendInviteSuccess(inviteScope));
  200. }
  201. });
  202. }