From ec454d1da0a799cb64b4348925d766be02d5ee82 Mon Sep 17 00:00:00 2001 From: Lyubo Marinov Date: Wed, 31 May 2017 00:32:13 -0500 Subject: [PATCH] Move ConferenceUrl.inviteURL into React and redux --- lang/main.json | 4 +- modules/URL/ConferenceUrl.js | 21 ++------ react/features/base/conference/actions.js | 5 +- react/features/base/connection/functions.js | 26 +++++++++ react/features/base/connection/index.js | 1 + react/features/base/participants/functions.js | 45 +++++++++------- react/features/invite/actionTypes.js | 3 +- react/features/invite/actions.js | 53 +++++++++---------- .../invite/components/DialInNumbersForm.js | 43 +++++++-------- .../invite/components/InviteDialog.js | 30 +++++------ react/features/invite/reducer.js | 40 +++++++------- .../components/FilmstripOnlyOverlayFrame.js | 12 +---- react/features/share-room/actions.js | 10 ++-- 13 files changed, 147 insertions(+), 146 deletions(-) create mode 100644 react/features/base/connection/functions.js diff --git a/lang/main.json b/lang/main.json index 75e67bcd9..0f1318286 100644 --- a/lang/main.json +++ b/lang/main.json @@ -435,11 +435,11 @@ "invite": { "addPassword": "Add password", "callNumber": "Call __number__", - "enterId": "Enter Meeting ID: __meetingId__ following by # to dial in from a phone", + "enterID": "Enter Meeting ID: __conferenceID__ following by # to dial in from a phone", "howToDialIn": "To dial in, use one of the following numbers and meeting ID", "hidePassword": "Hide password", "inviteTo": "Invite people to __conferenceName__", - "invitedYouTo": "__userName__ has invited you to the __meetingUrl__ conference", + "invitedYouTo": "__userName__ has invited you to the __inviteURL__ conference", "locked": "This call is locked. New callers must have the link and enter the password to join.", "showPassword": "Show password", "unlocked": "This call is unlocked. Any new caller with the link may join the call." diff --git a/modules/URL/ConferenceUrl.js b/modules/URL/ConferenceUrl.js index 78df779cf..45c4b947d 100644 --- a/modules/URL/ConferenceUrl.js +++ b/modules/URL/ConferenceUrl.js @@ -24,24 +24,9 @@ export default class ConferenceUrl { * from the sample URL. */ constructor(location) { - /** - * A simplified version of the conference URL stripped out of - * the parameters which should be used for sending invites. - * Example: - * https://example.com:8888/SomeConference1245 - * @type {string} - */ - this.inviteURL - = location.protocol + "//" + location.host + location.pathname; logger.info("Stored original conference URL: " + location.href); - logger.info("Conference URL for invites: " + this.inviteURL); - } - /** - * Obtains the conference invite URL. - * @return {string} the URL pointing o the conference which is mean to be - * used to invite new participants. - */ - getInviteUrl() { - return this.inviteURL; + logger.info( + "Conference URL for invites: " + location.protocol + "//" + + location.host + location.pathname); } } diff --git a/react/features/base/conference/actions.js b/react/features/base/conference/actions.js index 8040f309d..1e1c29fcb 100644 --- a/react/features/base/conference/actions.js +++ b/react/features/base/conference/actions.js @@ -121,12 +121,11 @@ function _addConferenceListeners(conference, dispatch) { * @returns {void} */ function _setLocalParticipantData(conference, state) { - const localParticipant - = getLocalParticipant(state['features/base/participants']); + const { avatarID } = getLocalParticipant(state); conference.removeCommand(AVATAR_ID_COMMAND); conference.sendCommand(AVATAR_ID_COMMAND, { - value: localParticipant.avatarID + value: avatarID }); } diff --git a/react/features/base/connection/functions.js b/react/features/base/connection/functions.js new file mode 100644 index 000000000..91667ee83 --- /dev/null +++ b/react/features/base/connection/functions.js @@ -0,0 +1,26 @@ +/* @flow */ + +/** + * Retrieves a simplified version of the conference/location URL stripped of URL + * params (i.e. query/search and hash) which should be used for sending invites. + * + * @param {Function|Object} stateOrGetState - The redux state or redux's + * {@code getState} function. + * @returns {string|undefined} + */ +export function getInviteURL(stateOrGetState: Function | Object): ?string { + const state + = typeof stateOrGetState === 'function' + ? stateOrGetState() + : stateOrGetState; + const { locationURL } = state['features/base/connection']; + let inviteURL; + + if (locationURL) { + const { host, pathname, protocol } = locationURL; + + inviteURL = `${protocol}//${host}${pathname}`; + } + + return inviteURL; +} diff --git a/react/features/base/connection/index.js b/react/features/base/connection/index.js index 81e1e72ee..03776f5f0 100644 --- a/react/features/base/connection/index.js +++ b/react/features/base/connection/index.js @@ -1,4 +1,5 @@ export * from './actions'; export * from './actionTypes'; +export * from './functions'; import './reducer'; diff --git a/react/features/base/participants/functions.js b/react/features/base/participants/functions.js index 75dadf59d..15d4495ea 100644 --- a/react/features/base/participants/functions.js +++ b/react/features/base/participants/functions.js @@ -69,13 +69,14 @@ export function getAvatarURL(participant) { /** * Returns local participant from Redux state. * - * @param {(Function|Participant[])} participantsOrGetState - Either the - * features/base/participants Redux state or Redux's getState function to be - * used to retrieve the features/base/participants state. + * @param {(Function|Object|Participant[])} stateOrGetState - The redux state + * features/base/participants, the (whole) redux state, or redux's + * {@code getState} function to be used to retrieve the + * features/base/participants state. * @returns {(Participant|undefined)} */ -export function getLocalParticipant(participantsOrGetState) { - const participants = _getParticipants(participantsOrGetState); +export function getLocalParticipant(stateOrGetState) { + const participants = _getParticipants(stateOrGetState); return participants.find(p => p.local); } @@ -83,15 +84,16 @@ export function getLocalParticipant(participantsOrGetState) { /** * Returns participant by ID from Redux state. * - * @param {(Function|Participant[])} participantsOrGetState - Either the - * features/base/participants Redux state or Redux's getState function to be - * used to retrieve the features/base/participants state. + * @param {(Function|Object|Participant[])} stateOrGetState - The redux state + * features/base/participants, the (whole) redux state, or redux's + * {@code getState} function to be used to retrieve the + * features/base/participants state. * @param {string} id - The ID of the participant to retrieve. * @private * @returns {(Participant|undefined)} */ -export function getParticipantById(participantsOrGetState, id) { - const participants = _getParticipants(participantsOrGetState); +export function getParticipantById(stateOrGetState, id) { + const participants = _getParticipants(stateOrGetState); return participants.find(p => p.id === id); } @@ -99,17 +101,22 @@ export function getParticipantById(participantsOrGetState, id) { /** * Returns array of participants from Redux state. * - * @param {(Function|Participant[])} participantsOrGetState - Either the - * features/base/participants Redux state or Redux's getState function to be - * used to retrieve the features/base/participants state. + * @param {(Function|Object|Participant[])} stateOrGetState - The redux state + * features/base/participants, the (whole) redux state, or redux's + * {@code getState} function to be used to retrieve the + * features/base/participants state. * @private * @returns {Participant[]} */ -function _getParticipants(participantsOrGetState) { - const participants - = typeof participantsOrGetState === 'function' - ? participantsOrGetState()['features/base/participants'] - : participantsOrGetState; +function _getParticipants(stateOrGetState) { + if (Array.isArray(stateOrGetState)) { + return stateOrGetState; + } - return participants || []; + const state + = typeof stateOrGetState === 'function' + ? stateOrGetState() + : stateOrGetState; + + return state['features/base/participants'] || []; } diff --git a/react/features/invite/actionTypes.js b/react/features/invite/actionTypes.js index 303745fad..c57de29bb 100644 --- a/react/features/invite/actionTypes.js +++ b/react/features/invite/actionTypes.js @@ -16,7 +16,8 @@ export const UPDATE_DIAL_IN_NUMBERS_FAILED * * { * type: UPDATE_DIAL_IN_NUMBERS_SUCCESS, - * response: Object + * conferenceID: Object, + * dialInNumbers: Object * } */ export const UPDATE_DIAL_IN_NUMBERS_SUCCESS diff --git a/react/features/invite/actions.js b/react/features/invite/actions.js index f9fb82f0b..65277de33 100644 --- a/react/features/invite/actions.js +++ b/react/features/invite/actions.js @@ -15,23 +15,22 @@ declare var APP: Object; * @returns {Function} */ export function openInviteDialog() { - return openDialog(InviteDialog, { - conferenceUrl: encodeURI(APP.ConferenceUrl.getInviteUrl()) - }); + return openDialog(InviteDialog); } /** - * Sends an ajax requests for dial-in numbers and conference id. + * Sends AJAX requests for dial-in numbers and conference ID. * * @returns {Function} */ export function updateDialInNumbers() { return (dispatch, getState) => { + const state = getState(); const { dialInConfCodeUrl, dialInNumbersUrl, hosts } - = getState()['features/base/config']; - const mucUrl = hosts && hosts.muc; + = state['features/base/config']; + const mucURL = hosts && hosts.muc; - if (!dialInConfCodeUrl || !dialInNumbersUrl || !mucUrl) { + if (!dialInConfCodeUrl || !dialInNumbersUrl || !mucURL) { dispatch({ type: UPDATE_DIAL_IN_NUMBERS_FAILED, error: 'URLs for fetching dial in numbers not properly defined' @@ -40,30 +39,30 @@ export function updateDialInNumbers() { return; } - const { room } = getState()['features/base/conference']; - const conferenceIdUrl - = `${dialInConfCodeUrl}?conference=${room}@${mucUrl}`; + const { room } = state['features/base/conference']; + const conferenceIDURL + = `${dialInConfCodeUrl}?conference=${room}@${mucURL}`; Promise.all([ $.getJSON(dialInNumbersUrl), - $.getJSON(conferenceIdUrl) - ]).then(([ numbersResponse, idResponse ]) => { - if (!idResponse.conference || !idResponse.id) { - return Promise.reject(idResponse.message); - } + $.getJSON(conferenceIDURL) + ]) + .then(([ dialInNumbers, { conference, id, message } ]) => { + if (!conference || !id) { + return Promise.reject(message); + } - dispatch({ - type: UPDATE_DIAL_IN_NUMBERS_SUCCESS, - conferenceId: idResponse, - dialInNumbers: numbersResponse + dispatch({ + type: UPDATE_DIAL_IN_NUMBERS_SUCCESS, + conferenceID: id, + dialInNumbers + }); + }) + .catch(error => { + dispatch({ + type: UPDATE_DIAL_IN_NUMBERS_FAILED, + error + }); }); - }) - .catch(error => { - dispatch({ - type: UPDATE_DIAL_IN_NUMBERS_FAILED, - error - }); - }); - }; } diff --git a/react/features/invite/components/DialInNumbersForm.js b/react/features/invite/components/DialInNumbersForm.js index 986c307a4..258981bc6 100644 --- a/react/features/invite/components/DialInNumbersForm.js +++ b/react/features/invite/components/DialInNumbersForm.js @@ -34,16 +34,17 @@ class DialInNumbersForm extends Component { */ _localUserDisplayName: React.PropTypes.string, - /** - * The url for the JitsiConference. - */ - conferenceUrl: React.PropTypes.string, - /** * Invoked to send an ajax request for dial-in numbers. */ dispatch: React.PropTypes.func, + /** + * The URL of the conference into which this {@code DialInNumbersForm} + * is inviting the local participant. + */ + inviteURL: React.PropTypes.string, + /** * Invoked to obtain translated strings. */ @@ -134,21 +135,21 @@ class DialInNumbersForm extends Component { */ render() { const { _dialIn, t } = this.props; - const { conferenceId, numbers, numbersEnabled } = _dialIn; + const { conferenceID, numbers, numbersEnabled } = _dialIn; const { selectedNumber } = this.state; - if (!conferenceId || !numbers || !numbersEnabled || !selectedNumber) { + if (!conferenceID || !numbers || !numbersEnabled || !selectedNumber) { return null; } - const items = numbers ? this._formatNumbers(numbers) : []; + const items = this._formatNumbers(numbers); return (
@@ -290,18 +291,21 @@ class DialInNumbersForm extends Component { * @returns {string} */ _generateCopyText() { - const welcome = this.props.t('invite.invitedYouTo', { - meetingUrl: this.props.conferenceUrl, + const { t } = this.props; + const welcome = t('invite.invitedYouTo', { + inviteURL: this.props.inviteURL, userName: this.props._localUserDisplayName }); - const callNumber = this.props.t('invite.callNumber', - { number: this.state.selectedNumber.number }); + const callNumber = t('invite.callNumber', { + number: this.state.selectedNumber.number + }); const stepOne = `1) ${callNumber}`; - const enterId = this.props.t('invite.enterId', - { meetingId: this.props._dialIn.conferenceId }); - const stepTwo = `2) ${enterId}`; + const enterID = t('invite.enterID', { + conferenceID: this.props._dialIn.conferenceID + }); + const stepTwo = `2) ${enterID}`; return `${welcome}\n${stepOne}\n${stepTwo}`; } @@ -395,12 +399,9 @@ class DialInNumbersForm extends Component { * }} */ function _mapStateToProps(state) { - const { name } - = getLocalParticipant(state['features/base/participants']); - return { - _localUserDisplayName: name, - _dialIn: state['features/invite/dial-in'] + _localUserDisplayName: getLocalParticipant(state).name, + _dialIn: state['features/invite'] }; } diff --git a/react/features/invite/components/InviteDialog.js b/react/features/invite/components/InviteDialog.js index f04bf227f..3ce30f2e6 100644 --- a/react/features/invite/components/InviteDialog.js +++ b/react/features/invite/components/InviteDialog.js @@ -1,6 +1,7 @@ import React, { Component } from 'react'; import { connect } from 'react-redux'; +import { getInviteURL } from '../../base/connection'; import { Dialog } from '../../base/dialog'; import { translate } from '../../base/i18n'; import JitsiMeetJS from '../../base/lib-jitsi-meet'; @@ -24,20 +25,19 @@ class InviteDialog extends Component { static propTypes = { /** * The redux store representation of the JitsiConference. - * */ _conference: React.PropTypes.object, + /** + * The url for the JitsiConference. + */ + _inviteURL: React.PropTypes.string, + /** * Whether or not the current user is a conference moderator. */ _isModerator: React.PropTypes.bool, - /** - * The url for the JitsiConference. - */ - conferenceUrl: React.PropTypes.string, - /** * Invoked to obtain translated strings. */ @@ -60,11 +60,9 @@ class InviteDialog extends Component { * @returns {ReactElement} */ render() { - const { _conference, conferenceUrl } = this.props; + const { _conference, _inviteURL, t } = this.props; const titleString - = this.props.t( - 'invite.inviteTo', - { conferenceName: _conference.room }); + = t('invite.inviteTo', { conferenceName: _conference.room }); return (
- - + + { - switch (action.type) { - case UPDATE_DIAL_IN_NUMBERS_FAILED: { - return { - ...state, - error: action.error - }; - } +ReducerRegistry.register('features/invite', (state = DEFAULT_STATE, action) => { + switch (action.type) { + case UPDATE_DIAL_IN_NUMBERS_FAILED: + return { + ...state, + error: action.error + }; - case UPDATE_DIAL_IN_NUMBERS_SUCCESS: { - const { numbers, numbersEnabled } = action.dialInNumbers; + case UPDATE_DIAL_IN_NUMBERS_SUCCESS: { + const { numbers, numbersEnabled } = action.dialInNumbers; - return { - conferenceId: action.conferenceId.id, - error: null, - numbers, - numbersEnabled - }; - } - } + return { + conferenceID: action.conferenceID, + numbers, + numbersEnabled + }; + } + } - return state; - }); + return state; +}); diff --git a/react/features/overlay/components/FilmstripOnlyOverlayFrame.js b/react/features/overlay/components/FilmstripOnlyOverlayFrame.js index 160a5a45f..98f06a8ce 100644 --- a/react/features/overlay/components/FilmstripOnlyOverlayFrame.js +++ b/react/features/overlay/components/FilmstripOnlyOverlayFrame.js @@ -115,18 +115,8 @@ class FilmstripOnlyOverlayFrame extends Component { * }} */ function _mapStateToProps(state) { - const participant - = getLocalParticipant( - state['features/base/participants']); - const { avatarId, avatarUrl, email } = participant || {}; - return { - _avatar: getAvatarURL({ - avatarId, - avatarUrl, - email, - participantId: participant.id - }) + _avatar: getAvatarURL(getLocalParticipant(state) || {}) }; } diff --git a/react/features/share-room/actions.js b/react/features/share-room/actions.js index 3bcd4bcd6..09b12e774 100644 --- a/react/features/share-room/actions.js +++ b/react/features/share-room/actions.js @@ -1,5 +1,7 @@ /* @flow */ +import { getInviteURL } from '../base/connection'; + import { BEGIN_SHARE_ROOM, END_SHARE_ROOM } from './actionTypes'; /** @@ -12,12 +14,8 @@ import { BEGIN_SHARE_ROOM, END_SHARE_ROOM } from './actionTypes'; export function beginShareRoom(roomURL: ?string): Function { return (dispatch, getState) => { if (!roomURL) { - const { locationURL } = getState()['features/base/connection']; - - if (locationURL) { - // eslint-disable-next-line no-param-reassign - roomURL = locationURL.toString(); - } + // eslint-disable-next-line no-param-reassign + roomURL = getInviteURL(getState); } roomURL && dispatch({ type: BEGIN_SHARE_ROOM,