diff --git a/bigbluebutton-html5/client/main.jsx b/bigbluebutton-html5/client/main.jsx index 8a0d1df182..893beb2ef4 100755 --- a/bigbluebutton-html5/client/main.jsx +++ b/bigbluebutton-html5/client/main.jsx @@ -7,7 +7,6 @@ import Base from '/imports/startup/client/base'; import JoinHandler from '/imports/ui/components/join-handler/component'; import AuthenticatedHandler from '/imports/ui/components/authenticated-handler/component'; import Subscriptions from '/imports/ui/components/subscriptions/component'; -import JoinLoading from '/imports/ui/components/join-loading/component'; Meteor.startup(() => { // Logs all uncaught exceptions to the client logger @@ -34,15 +33,13 @@ Meteor.startup(() => { // TODO make this a Promise render( - - - - - - - - - , + + + + + + + , document.getElementById('app'), ); }); diff --git a/bigbluebutton-html5/imports/startup/client/base.jsx b/bigbluebutton-html5/imports/startup/client/base.jsx index 7b4dbe945e..eae2a5cbc0 100755 --- a/bigbluebutton-html5/imports/startup/client/base.jsx +++ b/bigbluebutton-html5/imports/startup/client/base.jsx @@ -3,7 +3,9 @@ import { withTracker } from 'meteor/react-meteor-data'; import PropTypes from 'prop-types'; import Auth from '/imports/ui/services/auth'; import AppContainer from '/imports/ui/components/app/container'; +import ErrorScreen from '/imports/ui/components/error-screen/component'; import MeetingEnded from '/imports/ui/components/meeting-ended/component'; +import LoadingScreen from '/imports/ui/components/loading-screen/component'; import Settings from '/imports/ui/services/settings'; import AudioManager from '/imports/ui/services/audio-manager'; import logger from '/imports/startup/client/logger'; @@ -16,7 +18,6 @@ import Breakouts from '/imports/api/breakouts'; import AudioService from '/imports/ui/components/audio/service'; import { FormattedMessage } from 'react-intl'; import { notify } from '/imports/ui/services/notification'; -import { withJoinLoadingConsumer } from '/imports/ui/components/join-loading/context/context'; const HTML = document.getElementsByTagName('html')[0]; @@ -86,29 +87,12 @@ class Base extends Component { ejected, isMeteorConnected, subscriptionsReady, - codeError, - meetingHasEnded, - dispatch, } = this.props; const { loading, meetingExisted, } = this.state; - if (codeError && !meetingHasEnded) { - // 680 is set for the codeError when the user requests a logout - if (codeError !== '680') { - logger.error({ logCode: 'startup_client_usercouldnotlogin_error' }, `User could not log in HTML5, hit ${codeError}`); - } - Session.set('codeError', codeError); - return dispatch('hasError'); - } - - if (!(loading || !subscriptionsReady) - && !meetingHasEnded && meetingExist) { - dispatch('hideLoading'); - } - if (!prevProps.subscriptionsReady && subscriptionsReady) { logger.info({ logCode: 'startup_client_subscriptions_ready' }, 'Subscriptions are ready'); } @@ -168,14 +152,21 @@ class Base extends Component { renderByState() { const { updateLoadingState } = this; const stateControls = { updateLoadingState }; + const { loading } = this.state; const codeError = Session.get('codeError'); const { ejected, + meetingExist, meetingHasEnded, meetingIsBreakout, + subscriptionsReady, User, } = this.props; + if ((loading || !subscriptionsReady) && !meetingHasEnded && meetingExist) { + return ({loading}); + } + if (ejected && ejected.ejectedReason) { const { ejectedReason } = ejected; AudioManager.exitAudio(); @@ -188,6 +179,14 @@ class Base extends Component { AudioManager.exitAudio(); return (); } + + if (codeError && !meetingHasEnded) { + // 680 is set for the codeError when the user requests a logout + if (codeError !== '680') { + logger.error({ logCode: 'startup_client_usercouldnotlogin_error' }, `User could not log in HTML5, hit ${codeError}`); + } + return (); + } // this.props.annotationsHandler.stop(); return (); } @@ -197,11 +196,15 @@ class Base extends Component { const { locale, meetingExist } = this.props; const stateControls = { updateLoadingState }; const { meetingExisted } = this.state; - if ((!meetingExisted && !meetingExist && Auth.loggedIn)) return null; + return ( - - {this.renderByState()} - + (!meetingExisted && !meetingExist && Auth.loggedIn) + ? + : ( + + {this.renderByState()} + + ) ); } } @@ -313,4 +316,4 @@ const BaseContainer = withTracker(() => { }; })(Base); -export default withJoinLoadingConsumer(BaseContainer); +export default BaseContainer; diff --git a/bigbluebutton-html5/imports/startup/client/intl.jsx b/bigbluebutton-html5/imports/startup/client/intl.jsx index 8f541853ec..c93805c743 100644 --- a/bigbluebutton-html5/imports/startup/client/intl.jsx +++ b/bigbluebutton-html5/imports/startup/client/intl.jsx @@ -2,7 +2,7 @@ import React, { Component } from 'react'; import PropTypes from 'prop-types'; import { IntlProvider, addLocaleData } from 'react-intl'; import Settings from '/imports/ui/services/settings'; -import { withJoinLoadingConsumer } from '/imports/ui/components/join-loading/context/context'; +import LoadingScreen from '/imports/ui/components/loading-screen/component'; // currently supported locales. import ar from 'react-intl/locale-data/ar'; @@ -106,7 +106,7 @@ class IntlStartup extends Component { fetchLocalizedMessages(locale) { const url = `/html5client/locale?locale=${locale}`; - const { dispatch } = this.props; + this.setState({ fetching: true }, () => { fetch(url) .then((response) => { @@ -120,7 +120,6 @@ class IntlStartup extends Component { const dasherizedLocale = normalizedLocale.replace('_', '-'); this.setState({ messages, fetching: false, normalizedLocale: dasherizedLocale }, () => { this.saveLocale(dasherizedLocale); - dispatch('hideLoading'); }); }) .catch(() => { @@ -147,7 +146,7 @@ class IntlStartup extends Component { const { fetching, normalizedLocale, messages } = this.state; const { children } = this.props; - return !fetching && ( + return fetching ? : ( {children} @@ -155,7 +154,7 @@ class IntlStartup extends Component { } } -export default withJoinLoadingConsumer(IntlStartup); +export default IntlStartup; IntlStartup.propTypes = propTypes; IntlStartup.defaultProps = defaultProps; diff --git a/bigbluebutton-html5/imports/ui/components/authenticated-handler/component.jsx b/bigbluebutton-html5/imports/ui/components/authenticated-handler/component.jsx index f13b2bd894..209052abd1 100644 --- a/bigbluebutton-html5/imports/ui/components/authenticated-handler/component.jsx +++ b/bigbluebutton-html5/imports/ui/components/authenticated-handler/component.jsx @@ -2,13 +2,18 @@ import React, { Component } from 'react'; import { Session } from 'meteor/session'; import logger from '/imports/startup/client/logger'; import Auth from '/imports/ui/services/auth'; -import { withJoinLoadingConsumer } from '/imports/ui/components/join-loading/context/context'; +import LoadingScreen from '/imports/ui/components/loading-screen/component'; const STATUS_CONNECTING = 'connecting'; const CHAT_CONFIG = Meteor.settings.public.chat; const PUBLIC_CHAT_ID = CHAT_CONFIG.public_id; class AuthenticatedHandler extends Component { + static setError(codeError) { + Session.set('hasError', true); + if (codeError) Session.set('codeError', codeError); + } + static shouldAuthenticate(status, lastStatus) { return lastStatus != null && lastStatus === STATUS_CONNECTING && status.connected; } @@ -30,32 +35,7 @@ class AuthenticatedHandler extends Component { }); } - constructor(props) { - super(props); - this.setError = this.setError.bind(this); - this.authenticatedRouteHandler = this.authenticatedRouteHandler.bind(this); - this.state = { - authenticated: false, - }; - } - - componentDidMount() { - if (Session.get('codeError')) { - return this.setError(Session.get('codeError')); - } - return this.authenticatedRouteHandler((value, error) => { - if (error) return this.setError(error); - return this.setState({ authenticated: true }); - }); - } - - setError(codeError) { - const { dispatch } = this.props; - dispatch('hasError'); - if (codeError) Session.set('codeError', codeError); - } - - async authenticatedRouteHandler(callback) { + static async authenticatedRouteHandler(callback) { if (Auth.loggedIn) { callback(); } @@ -63,7 +43,6 @@ class AuthenticatedHandler extends Component { AuthenticatedHandler.addReconnectObservable(); const setReason = (reason) => { - this.setError(reason.error); logger.error({ logCode: 'authenticatedhandlercomponent_setreason', extraInfo: { reason }, @@ -81,6 +60,21 @@ class AuthenticatedHandler extends Component { } } + constructor(props) { + super(props); + this.state = { + authenticated: false, + }; + } + + componentDidMount() { + if (Session.get('codeError')) return this.changeState(true); + AuthenticatedHandler.authenticatedRouteHandler((value, error) => { + if (error) AuthenticatedHandler.setError(error); + this.setState({ authenticated: true }); + }); + } + render() { const { children, @@ -95,9 +89,11 @@ class AuthenticatedHandler extends Component { Session.set('isPollOpen', false); Session.set('breakoutRoomIsOpen', false); - return authenticated && children; + return authenticated + ? children + : (); } } -export default withJoinLoadingConsumer(AuthenticatedHandler); +export default AuthenticatedHandler; diff --git a/bigbluebutton-html5/imports/ui/components/error-screen/component.jsx b/bigbluebutton-html5/imports/ui/components/error-screen/component.jsx index 609b7f6dee..bfcf865a4e 100644 --- a/bigbluebutton-html5/imports/ui/components/error-screen/component.jsx +++ b/bigbluebutton-html5/imports/ui/components/error-screen/component.jsx @@ -57,16 +57,16 @@ class ErrorScreen extends React.PureComponent { children, } = this.props; - const codeError = Session.get('codeError') || code; let formatedMessage = intl.formatMessage(intlMessages[defaultProps.code]); - if (codeError in intlMessages) { - formatedMessage = intl.formatMessage(intlMessages[codeError]); + if (code in intlMessages) { + formatedMessage = intl.formatMessage(intlMessages[code]); } + return (

- {codeError} + {code}

{formatedMessage} diff --git a/bigbluebutton-html5/imports/ui/components/join-handler/component.jsx b/bigbluebutton-html5/imports/ui/components/join-handler/component.jsx index 57d1b3c7b8..d5e2d13c4b 100644 --- a/bigbluebutton-html5/imports/ui/components/join-handler/component.jsx +++ b/bigbluebutton-html5/imports/ui/components/join-handler/component.jsx @@ -6,7 +6,7 @@ import { setCustomLogoUrl } from '/imports/ui/components/user-list/service'; import { makeCall } from '/imports/ui/services/api'; import deviceInfo from '/imports/utils/deviceInfo'; import logger from '/imports/startup/client/logger'; -import { withJoinLoadingConsumer } from '/imports/ui/components/join-loading/context/context'; +import LoadingScreen from '/imports/ui/components/loading-screen/component'; const propTypes = { children: PropTypes.element.isRequired, @@ -17,10 +17,14 @@ const { showParticipantsOnLogin } = APP_CONFIG; const CHAT_ENABLED = Meteor.settings.public.chat.enabled; class JoinHandler extends Component { + static setError(codeError) { + Session.set('hasError', true); + if (codeError) Session.set('codeError', codeError); + } + constructor(props) { super(props); this.fetchToken = this.fetchToken.bind(this); - this.setError = this.setError.bind(this); this.numFetchTokenRetries = 0; this.state = { @@ -37,12 +41,6 @@ class JoinHandler extends Component { this._isMounted = false; } - setError(codeError) { - const { dispatch } = this.props; - if (codeError) Session.set('codeError', codeError); - dispatch('hasError'); - } - async fetchToken() { if (!this._isMounted) return; @@ -65,7 +63,7 @@ class JoinHandler extends Component { const sessionToken = urlParams.get('sessionToken'); if (!sessionToken) { - this.setError('400'); + JoinHandler.setError('400'); Session.set('errorMessageDescription', 'Session token was not provided'); } @@ -143,6 +141,7 @@ class JoinHandler extends Component { const { response } = parseToJson; setLogoutURL(response); + if (response.returncode !== 'FAILED') { await setAuth(response); @@ -168,11 +167,9 @@ class JoinHandler extends Component { response, }, }, 'User successfully went through main.joinRouteHandler'); - this.setState({ joined: true }); } else { const e = new Error(response.message); if (!Session.get('codeError')) Session.set('errorMessageDescription', response.message); - this.setError(401); logger.error({ logCode: 'joinhandler_component_joinroutehandler_error', extraInfo: { @@ -181,15 +178,18 @@ class JoinHandler extends Component { }, }, 'User faced an error on main.joinRouteHandler.'); } + this.setState({ joined: true }); } render() { const { children } = this.props; const { joined } = this.state; - return joined && children; + return joined + ? children + : (); } } -export default withJoinLoadingConsumer(JoinHandler); +export default JoinHandler; JoinHandler.propTypes = propTypes; diff --git a/bigbluebutton-html5/imports/ui/components/join-loading/component.jsx b/bigbluebutton-html5/imports/ui/components/join-loading/component.jsx deleted file mode 100644 index c52f5c81b1..0000000000 --- a/bigbluebutton-html5/imports/ui/components/join-loading/component.jsx +++ /dev/null @@ -1,23 +0,0 @@ -import React, { Fragment } from 'react'; -import LoadingScreen from '/imports/ui/components/loading-screen/component'; -import ErrorScreen from '/imports/ui/components/error-screen/component'; -import { withJoinLoadingContext } from './context/context'; -import IntlProvider from '/imports/startup/client/intl'; -import Settings from '/imports/ui/services/settings'; - -const JoinLoadComponent = (props) => { - const { children, showLoading, hasError } = props; - const { locale } = Settings.application; - return ( - - {(showLoading && !hasError) && ()} - {hasError ? ( - - - - ) : children} - - ); -}; - -export default withJoinLoadingContext(JoinLoadComponent); diff --git a/bigbluebutton-html5/imports/ui/components/join-loading/context/context.jsx b/bigbluebutton-html5/imports/ui/components/join-loading/context/context.jsx deleted file mode 100644 index 3c40b6c545..0000000000 --- a/bigbluebutton-html5/imports/ui/components/join-loading/context/context.jsx +++ /dev/null @@ -1,64 +0,0 @@ -import React, { useReducer, createContext } from 'react'; - -function reducer(state, action) { - switch (action) { - case 'showLoading': - return { - ...state, - showLoading: true, - }; - case 'hideLoading': - return { - ...state, - showLoading: false, - }; - case 'hasError': - return { - ...state, - hasError: true, - }; - default: - throw new Error(); - } -} - -const JoinLoadingContext = createContext({}); -const initialState = { - showLoading: true, - hasError: false, -}; -const JoinLoading = Component => (props) => { - const [state, dispatch] = useReducer(reducer, initialState); - const contextValue = { - ...props, - ...state, - dispatch, - }; - - return ( - - - - ); -}; - -const joinLoadingContextConsumer = Component => props => ( - - { contexts => } - -); - - -const withJoinLoadingConsumer = Component => joinLoadingContextConsumer(Component); - -const withJoinLoadingContext = Component => JoinLoading(withJoinLoadingConsumer(Component)); - -export { - withJoinLoadingContext, - withJoinLoadingConsumer, - joinLoadingContextConsumer, - JoinLoading, - reducer, - initialState, - JoinLoadingContext, -}; diff --git a/bigbluebutton-html5/imports/ui/components/loading-screen/styles.scss b/bigbluebutton-html5/imports/ui/components/loading-screen/styles.scss index 0cfaa82333..eeaf0ceade 100644 --- a/bigbluebutton-html5/imports/ui/components/loading-screen/styles.scss +++ b/bigbluebutton-html5/imports/ui/components/loading-screen/styles.scss @@ -11,18 +11,13 @@ } .background { + position: fixed; display: flex; flex-flow: column; justify-content: center; - position: fixed; width: 100%; height: 100%; - top: 0; - left: 0; - right: 0; - bottom: 0; background-color: var(--loader-bg); - z-index: 99999; } .message { diff --git a/bigbluebutton-html5/imports/ui/components/subscriptions/component.jsx b/bigbluebutton-html5/imports/ui/components/subscriptions/component.jsx index 33e4d51a79..55ccf33c9b 100755 --- a/bigbluebutton-html5/imports/ui/components/subscriptions/component.jsx +++ b/bigbluebutton-html5/imports/ui/components/subscriptions/component.jsx @@ -8,7 +8,6 @@ import Annotations from '/imports/api/annotations'; import AnnotationsTextService from '/imports/ui/components/whiteboard/annotations/text/service'; import AnnotationsLocal from '/imports/ui/components/whiteboard/service'; import mapUser from '/imports/ui/services/user/mapUser'; -import { withJoinLoadingConsumer } from '/imports/ui/components/join-loading/context/context'; const CHAT_CONFIG = Meteor.settings.public.chat; const CHAT_ENABLED = CHAT_CONFIG.enabled; @@ -35,7 +34,7 @@ class Subscriptions extends Component { } } -export default withJoinLoadingConsumer(withTracker(({ dispatch }) => { +export default withTracker(() => { const { credentials } = Auth; const { meetingId, requesterUserId } = credentials; if (Session.get('codeError')) { @@ -51,7 +50,6 @@ export default withJoinLoadingConsumer(withTracker(({ dispatch }) => { extraInfo: { error }, }, 'Error while subscribing to collections'); Session.set('codeError', error.error); - dispatch('hasError'); }, }; @@ -117,4 +115,4 @@ export default withJoinLoadingConsumer(withTracker(({ dispatch }) => { subscriptionsReady: ready, subscriptionsHandlers, }; -})(Subscriptions)); +})(Subscriptions);