diff --git a/app.js b/app.js index 84d4a93d57..708726d448 100644 --- a/app.js +++ b/app.js @@ -31,12 +31,6 @@ if (window.Olm) { window.APP = { API, conference, - - // Used for automated performance tests. - connectionTimes: { - 'index.loaded': window.indexLoadedTime - }, - translation, UI }; diff --git a/react/features/analytics/functions.ts b/react/features/analytics/functions.ts index fae5778736..299cdf1864 100644 --- a/react/features/analytics/functions.ts +++ b/react/features/analytics/functions.ts @@ -16,6 +16,7 @@ import { getJitsiMeetGlobalNS } from '../base/util/helpers'; import { inIframe } from '../base/util/iframeUtils'; import { loadScript } from '../base/util/loadScript'; import { parseURIString } from '../base/util/uri'; +import { isPrejoinPageVisible } from '../prejoin/functions'; import AmplitudeHandler from './handlers/AmplitudeHandler'; import MatomoHandler from './handlers/MatomoHandler'; @@ -180,8 +181,12 @@ export function initAnalytics(store: IStore, handlers: Array) { externalApi?: boolean; group?: string; inIframe?: boolean; + isPromotedFromVisitor?: boolean; + isVisitor?: boolean; server?: string; tenant?: string; + wasLobbyVisible?: boolean; + wasPrejoinDisplayed?: boolean; websocket?: boolean; } & typeof deploymentInfo = {}; @@ -207,6 +212,15 @@ export function initAnalytics(store: IStore, handlers: Array) { // Report the tenant from the URL. permanentProperties.tenant = tenant || '/'; + permanentProperties.wasPrejoinDisplayed = isPrejoinPageVisible(state); + + // Currently we don't know if there will be lobby. We will update it to true if we go through lobby. + permanentProperties.wasLobbyVisible = false; + + // Setting visitor properties to false by default. We will update them later if it turns out we are visitor. + permanentProperties.isVisitor = false; + permanentProperties.isPromotedFromVisitor = false; + // Optionally, include local deployment information based on the // contents of window.config.deploymentInfo. if (deploymentInfo) { diff --git a/react/features/analytics/middleware.ts b/react/features/analytics/middleware.ts index 76e6797493..bd62ff81d5 100644 --- a/react/features/analytics/middleware.ts +++ b/react/features/analytics/middleware.ts @@ -5,6 +5,7 @@ import { SET_ROOM } from '../base/conference/actionTypes'; import { SET_CONFIG } from '../base/config/actionTypes'; +import { analytics } from '../base/lib-jitsi-meet'; import { SET_NETWORK_INFO } from '../base/net-info/actionTypes'; import MiddlewareRegistry from '../base/redux/MiddlewareRegistry'; import { @@ -16,6 +17,10 @@ import { getLocalAudioTrack, getLocalVideoTrack } from '../base/tracks/functions'; +import { SET_LOBBY_VISIBILITY } from '../lobby/actionTypes'; +import { getIsLobbyVisible } from '../lobby/functions'; +import { I_AM_VISITOR_MODE } from '../visitors/actionTypes'; +import { iAmVisitor } from '../visitors/functions'; import { createLocalTracksDurationEvent, createNetworkInfoEvent } from './AnalyticsEvents'; import { UPDATE_LOCAL_TRACKS_DURATION } from './actionTypes'; @@ -81,6 +86,18 @@ function calculateLocalTrackDuration(state: IReduxState) { */ MiddlewareRegistry.register(store => next => action => { switch (action.type) { + case I_AM_VISITOR_MODE: { + const oldIAmVisitor = iAmVisitor(store.getState()); + const result = next(action); + const newIAmVisitor = iAmVisitor(store.getState()); + + analytics.addPermanentProperties({ + isVisitor: newIAmVisitor, + isPromotedFromVisitor: oldIAmVisitor && !newIAmVisitor + }); + + return result; + } case SET_CONFIG: if (navigator.product === 'ReactNative') { // Resetting the analytics is currently not needed for web because @@ -144,6 +161,14 @@ MiddlewareRegistry.register(store => next => action => { }); break; } + case SET_LOBBY_VISIBILITY: + if (getIsLobbyVisible(store.getState())) { + analytics.addPermanentProperties({ + wasLobbyVisible: true + }); + } + + break; case SET_NETWORK_INFO: sendAnalytics( createNetworkInfoEvent({ diff --git a/react/features/base/conference/actions.ts b/react/features/base/conference/actions.ts index ce7b2a706d..f932d3c4a9 100644 --- a/react/features/base/conference/actions.ts +++ b/react/features/base/conference/actions.ts @@ -510,15 +510,18 @@ export function conferenceWillJoin(conference?: IJitsiConference) { * * @param {JitsiConference} conference - The JitsiConference instance which will * be left by the local participant. + * @param {boolean} isRedirect - Indicates if the action has been dispatched as part of visitor promotion. * @returns {{ * type: CONFERENCE_LEFT, - * conference: JitsiConference + * conference: JitsiConference, + * isRedirect: boolean * }} */ -export function conferenceWillLeave(conference?: IJitsiConference) { +export function conferenceWillLeave(conference?: IJitsiConference, isRedirect?: boolean) { return { type: CONFERENCE_WILL_LEAVE, - conference + conference, + isRedirect }; } @@ -1008,7 +1011,7 @@ export function redirect(vnode: string, focusJid: string, username: string) { } dispatch(overwriteConfig(newConfig)) // @ts-ignore - .then(() => dispatch(conferenceWillLeave(conference || joining))) + .then(() => dispatch(conferenceWillLeave(conference || joining, true))) .then(() => dispatch(disconnect())) .then(() => dispatch(setIAmVisitor(Boolean(vnode)))) diff --git a/react/features/visitors/reducer.ts b/react/features/visitors/reducer.ts index 4a88e7c4c2..7a353d70e7 100644 --- a/react/features/visitors/reducer.ts +++ b/react/features/visitors/reducer.ts @@ -18,7 +18,12 @@ ReducerRegistry.register('features/visitors', (state = DEFAULT_S case CONFERENCE_WILL_LEAVE: { return { ...state, - ...DEFAULT_STATE + ...DEFAULT_STATE, + + // If the action was called because a visitor was promoted don't clear the iAmVisitor field. It will be set + // to false with the I_AM_VISITOR_MODE action and we will be able to distinguish leaving the conference use + // case and promoting a visitor use case. + iAmVisitor: action.isRedirect ? state.iAmVisitor : DEFAULT_STATE.iAmVisitor }; } case UPDATE_VISITORS_COUNT: { diff --git a/react/index.web.js b/react/index.web.js index 283bc57b30..1b3f8328a3 100644 --- a/react/index.web.js +++ b/react/index.web.js @@ -1,5 +1,3 @@ -/* global APP */ - import React from 'react'; import ReactDOM from 'react-dom'; @@ -13,16 +11,6 @@ import PrejoinApp from './features/prejoin/components/web/PrejoinApp'; const logger = getLogger('index.web'); const OS = Platform.OS; -/** - * Renders the app when the DOM tree has been loaded. - */ -document.addEventListener('DOMContentLoaded', () => { - const now = window.performance.now(); - - APP.connectionTimes['document.ready'] = now; - logger.log('(TIME) document ready:\t', now); -}); - // Workaround for the issue when returning to a page with the back button and // the page is loaded from the 'back-forward' cache on iOS which causes nothing // to be rendered. @@ -42,6 +30,18 @@ if (OS === 'ios') { const globalNS = getJitsiMeetGlobalNS(); +// Used for automated performance tests. +globalNS.connectionTimes = { + 'index.loaded': window.indexLoadedTime +}; + +document.addEventListener('DOMContentLoaded', () => { + const now = window.performance.now(); + + globalNS.connectionTimes['document.ready'] = now; + logger.log('(TIME) document ready:\t', now); +}); + globalNS.entryPoints = { APP: App, PREJOIN: PrejoinApp,