2018-05-01 04:43:47 +00:00
|
|
|
// @flow
|
|
|
|
|
|
|
|
import i18next from 'i18next';
|
|
|
|
import { NativeEventEmitter, NativeModules } from 'react-native';
|
|
|
|
|
|
|
|
import { MiddlewareRegistry } from '../base/redux';
|
2018-05-10 04:45:24 +00:00
|
|
|
import { APP_WILL_MOUNT, APP_WILL_UNMOUNT, getAppProp } from '../app';
|
2018-05-01 04:43:47 +00:00
|
|
|
|
2018-05-03 01:20:31 +00:00
|
|
|
import { invite } from './actions';
|
2018-05-01 04:43:47 +00:00
|
|
|
import {
|
|
|
|
BEGIN_ADD_PEOPLE,
|
|
|
|
_SET_EMITTER_SUBSCRIPTIONS
|
|
|
|
} from './actionTypes';
|
|
|
|
import {
|
|
|
|
getInviteResultsForQuery,
|
|
|
|
isAddPeopleEnabled,
|
2018-04-25 11:06:46 +00:00
|
|
|
isDialOutEnabled
|
2018-05-01 04:43:47 +00:00
|
|
|
} from './functions';
|
|
|
|
import './middleware.any';
|
|
|
|
|
|
|
|
/**
|
|
|
|
* The react-native module of the feature invite.
|
|
|
|
*/
|
|
|
|
const { Invite } = NativeModules;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* The middleware of the feature invite specific to mobile/react-native.
|
|
|
|
*
|
|
|
|
* @param {Store} store - The redux store.
|
|
|
|
* @returns {Function}
|
|
|
|
*/
|
|
|
|
Invite && MiddlewareRegistry.register(store => next => action => {
|
|
|
|
switch (action.type) {
|
2018-05-02 11:37:20 +00:00
|
|
|
case _SET_EMITTER_SUBSCRIPTIONS:
|
|
|
|
return _setEmitterSubscriptions(store, next, action);
|
|
|
|
|
2018-05-01 04:43:47 +00:00
|
|
|
case APP_WILL_MOUNT:
|
|
|
|
return _appWillMount(store, next, action);
|
|
|
|
|
|
|
|
case APP_WILL_UNMOUNT: {
|
|
|
|
const result = next(action);
|
|
|
|
|
|
|
|
store.dispatch({
|
|
|
|
type: _SET_EMITTER_SUBSCRIPTIONS,
|
|
|
|
emitterSubscriptions: undefined
|
|
|
|
});
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
case BEGIN_ADD_PEOPLE:
|
|
|
|
return _beginAddPeople(store, next, action);
|
|
|
|
}
|
|
|
|
|
|
|
|
return next(action);
|
|
|
|
});
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Notifies the feature jwt that the action {@link APP_WILL_MOUNT} is being
|
|
|
|
* dispatched within a specific redux {@code store}.
|
|
|
|
*
|
|
|
|
* @param {Store} store - The redux store in which the specified {@code action}
|
|
|
|
* is being dispatched.
|
|
|
|
* @param {Dispatch} next - The redux dispatch function to dispatch the
|
|
|
|
* specified {@code action} to the specified {@code store}.
|
|
|
|
* @param {Action} action - The redux action {@code APP_WILL_MOUNT} which is
|
|
|
|
* being dispatched in the specified {@code store}.
|
|
|
|
* @private
|
|
|
|
* @returns {*} The value returned by {@code next(action)}.
|
|
|
|
*/
|
|
|
|
function _appWillMount({ dispatch, getState }, next, action) {
|
|
|
|
const result = next(action);
|
|
|
|
|
|
|
|
const emitter = new NativeEventEmitter(Invite);
|
|
|
|
const context = {
|
|
|
|
dispatch,
|
|
|
|
getState
|
|
|
|
};
|
|
|
|
|
|
|
|
dispatch({
|
|
|
|
type: _SET_EMITTER_SUBSCRIPTIONS,
|
|
|
|
emitterSubscriptions: [
|
|
|
|
emitter.addListener(
|
|
|
|
'org.jitsi.meet:features/invite#invite',
|
|
|
|
_onInvite,
|
2018-05-02 11:20:20 +00:00
|
|
|
context),
|
|
|
|
emitter.addListener(
|
|
|
|
'org.jitsi.meet:features/invite#performQuery',
|
|
|
|
_onPerformQuery,
|
2018-05-01 04:43:47 +00:00
|
|
|
context)
|
|
|
|
]
|
|
|
|
});
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Notifies the feature invite that the action {@link BEGIN_ADD_PEOPLE} is being
|
|
|
|
* dispatched within a specific redux {@code store}.
|
|
|
|
*
|
|
|
|
* @param {Store} store - The redux store in which the specified {@code action}
|
|
|
|
* is being dispatched.
|
|
|
|
* @param {Dispatch} next - The redux {@code dispatch} function to dispatch the
|
|
|
|
* specified {@code action} to the specified {@code store}.
|
|
|
|
* @param {Action} action - The redux action {@code BEGIN_ADD_PEOPLE} which is
|
|
|
|
* being dispatched in the specified {@code store}.
|
|
|
|
* @private
|
|
|
|
* @returns {*} The value returned by {@code next(action)}.
|
|
|
|
*/
|
2018-05-10 04:45:24 +00:00
|
|
|
function _beginAddPeople(store, next, action) {
|
2018-05-01 04:43:47 +00:00
|
|
|
const result = next(action);
|
|
|
|
|
|
|
|
// The JavaScript App needs to provide uniquely identifying information to
|
|
|
|
// the native Invite module so that the latter may match the former to the
|
|
|
|
// native JitsiMeetView which hosts it.
|
2018-05-10 04:45:24 +00:00
|
|
|
const externalAPIScope = getAppProp(store, 'externalAPIScope');
|
2018-05-01 04:43:47 +00:00
|
|
|
|
2018-05-10 04:45:24 +00:00
|
|
|
externalAPIScope && Invite.beginAddPeople(externalAPIScope);
|
2018-05-01 04:43:47 +00:00
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Handles the {@code invite} event of the feature invite i.e. invites specific
|
|
|
|
* invitees to the current, ongoing conference.
|
|
|
|
*
|
|
|
|
* @param {Object} event - The details of the event.
|
|
|
|
* @returns {void}
|
|
|
|
*/
|
2018-05-03 01:20:31 +00:00
|
|
|
function _onInvite({ addPeopleControllerScope, externalAPIScope, invitees }) {
|
2018-04-25 11:06:46 +00:00
|
|
|
const { dispatch, getState } = this; // eslint-disable-line no-invalid-this
|
2018-05-02 11:43:42 +00:00
|
|
|
|
|
|
|
// If there are multiple JitsiMeetView instances alive, they will all get
|
|
|
|
// the event, since there is a single bridge, so make sure we don't act if
|
|
|
|
// the event is not for us.
|
2018-05-10 04:45:24 +00:00
|
|
|
if (getAppProp(getState, 'externalAPIScope') !== externalAPIScope) {
|
2018-05-02 11:43:42 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2018-05-03 01:20:31 +00:00
|
|
|
dispatch(invite(invitees))
|
2018-05-01 04:43:47 +00:00
|
|
|
.then(failedInvitees =>
|
|
|
|
Invite.inviteSettled(
|
|
|
|
externalAPIScope,
|
|
|
|
addPeopleControllerScope,
|
|
|
|
failedInvitees));
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Handles the {@code performQuery} event of the feature invite i.e. queries for
|
|
|
|
* invitees who may subsequently be invited to the current, ongoing conference.
|
|
|
|
*
|
|
|
|
* @param {Object} event - The details of the event.
|
|
|
|
* @returns {void}
|
|
|
|
*/
|
|
|
|
function _onPerformQuery(
|
|
|
|
{ addPeopleControllerScope, externalAPIScope, query }) {
|
|
|
|
const { getState } = this; // eslint-disable-line no-invalid-this
|
|
|
|
const state = getState();
|
2018-05-02 11:43:42 +00:00
|
|
|
|
|
|
|
// If there are multiple JitsiMeetView instances alive, they will all get
|
|
|
|
// the event, since there is a single bridge, so make sure we don't act if
|
|
|
|
// the event is not for us.
|
2018-05-10 04:45:24 +00:00
|
|
|
if (getAppProp(state, 'externalAPIScope') !== externalAPIScope) {
|
2018-05-02 11:43:42 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2018-05-01 04:43:47 +00:00
|
|
|
const {
|
|
|
|
dialOutAuthUrl,
|
|
|
|
peopleSearchQueryTypes,
|
|
|
|
peopleSearchUrl
|
|
|
|
} = state['features/base/config'];
|
|
|
|
const options = {
|
|
|
|
dialOutAuthUrl,
|
|
|
|
addPeopleEnabled: isAddPeopleEnabled(state),
|
|
|
|
dialOutEnabled: isDialOutEnabled(state),
|
|
|
|
jwt: state['features/base/jwt'].jwt,
|
|
|
|
peopleSearchQueryTypes,
|
|
|
|
peopleSearchUrl
|
|
|
|
};
|
|
|
|
|
|
|
|
getInviteResultsForQuery(query, options)
|
|
|
|
.catch(() => [])
|
|
|
|
.then(results => {
|
|
|
|
const translatedResults = results.map(result => {
|
|
|
|
if (result.type === 'phone') {
|
|
|
|
result.title = i18next.t('addPeople.telephone', {
|
|
|
|
number: result.number
|
|
|
|
});
|
|
|
|
|
|
|
|
if (result.showCountryCodeReminder) {
|
|
|
|
result.subtitle = i18next.t(
|
|
|
|
'addPeople.countryReminder'
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}).filter(result => result.type !== 'phone' || result.allowed);
|
|
|
|
|
|
|
|
Invite.receivedResults(
|
|
|
|
externalAPIScope,
|
|
|
|
addPeopleControllerScope,
|
|
|
|
query,
|
|
|
|
translatedResults);
|
|
|
|
});
|
|
|
|
}
|
2018-05-02 11:37:20 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Notifies the feature invite that the action
|
|
|
|
* {@link _SET_EMITTER_SUBSCRIPTIONS} is being dispatched within a specific
|
|
|
|
* redux {@code store}.
|
|
|
|
*
|
|
|
|
* @param {Store} store - The redux store in which the specified {@code action}
|
|
|
|
* is being dispatched.
|
|
|
|
* @param {Dispatch} next - The redux dispatch function to dispatch the
|
|
|
|
* specified {@code action} to the specified {@code store}.
|
|
|
|
* @param {Action} action - The redux action {@code _SET_EMITTER_SUBSCRIPTIONS}
|
|
|
|
* which is being dispatched in the specified {@code store}.
|
|
|
|
* @private
|
|
|
|
* @returns {*}
|
|
|
|
*/
|
|
|
|
function _setEmitterSubscriptions({ getState }, next, action) {
|
|
|
|
const { emitterSubscriptions } = getState()['features/invite'];
|
|
|
|
|
|
|
|
if (emitterSubscriptions) {
|
|
|
|
for (const subscription of emitterSubscriptions) {
|
|
|
|
subscription.remove();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return next(action);
|
|
|
|
}
|