fix(branding): Fix dynamic logo display
* Display of the logo has been reworked (simplified). * The logo will not be displayed if the call to `branding` endpoint fails. * Add more docs.
This commit is contained in:
parent
ed6e75b241
commit
d2ec0ea6f3
|
@ -24,35 +24,19 @@ const _RIGHT_WATERMARK_STYLE = {
|
||||||
type Props = {
|
type Props = {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The user selected url used to navigate to on logo click.
|
* The link used to navigate to on logo click.
|
||||||
*/
|
*/
|
||||||
_customLogoLink: string,
|
_logoLink: string,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The url of the user selected logo.
|
* The url for the logo.
|
||||||
*/
|
*/
|
||||||
_customLogoUrl: string,
|
_logoUrl: string,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether or not the current user is logged in through a JWT.
|
* If the Jitsi watermark should be displayed or not.
|
||||||
*/
|
*/
|
||||||
_isGuest: boolean,
|
_showJitsiWatermark: boolean,
|
||||||
|
|
||||||
/**
|
|
||||||
* Whether or not the current meeting is a vpaas one.
|
|
||||||
*/
|
|
||||||
_isVpaas: boolean,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Flag used to signal that the logo can be displayed.
|
|
||||||
* It becomes true after the user customization options are fetched.
|
|
||||||
*/
|
|
||||||
_readyToDisplayJitsiWatermark: boolean,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns true if welcome page is visible at the moment.
|
|
||||||
*/
|
|
||||||
_welcomePageIsVisible: boolean,
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The default value for the Jitsi logo URL.
|
* The default value for the Jitsi logo URL.
|
||||||
|
@ -75,27 +59,11 @@ type State = {
|
||||||
*/
|
*/
|
||||||
brandWatermarkLink: string,
|
brandWatermarkLink: string,
|
||||||
|
|
||||||
/**
|
|
||||||
* The url to open when clicking the Jitsi watermark.
|
|
||||||
*/
|
|
||||||
jitsiWatermarkLink: string,
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether or not the brand watermark should be displayed.
|
* Whether or not the brand watermark should be displayed.
|
||||||
*/
|
*/
|
||||||
showBrandWatermark: boolean,
|
showBrandWatermark: boolean,
|
||||||
|
|
||||||
/**
|
|
||||||
* Whether or not the Jitsi watermark should be displayed.
|
|
||||||
*/
|
|
||||||
showJitsiWatermark: boolean,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Whether or not the Jitsi watermark should be displayed for users not
|
|
||||||
* logged in through a JWT.
|
|
||||||
*/
|
|
||||||
showJitsiWatermarkForGuests: boolean,
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether or not the show the "powered by Jitsi.org" link.
|
* Whether or not the show the "powered by Jitsi.org" link.
|
||||||
*/
|
*/
|
||||||
|
@ -117,29 +85,17 @@ class Watermarks extends Component<Props, State> {
|
||||||
super(props);
|
super(props);
|
||||||
|
|
||||||
let showBrandWatermark;
|
let showBrandWatermark;
|
||||||
let showJitsiWatermark;
|
|
||||||
let showJitsiWatermarkForGuests;
|
|
||||||
|
|
||||||
if (interfaceConfig.filmStripOnly) {
|
if (interfaceConfig.filmStripOnly) {
|
||||||
showBrandWatermark = false;
|
showBrandWatermark = false;
|
||||||
showJitsiWatermark = false;
|
|
||||||
showJitsiWatermarkForGuests = false;
|
|
||||||
} else {
|
} else {
|
||||||
showBrandWatermark = interfaceConfig.SHOW_BRAND_WATERMARK;
|
showBrandWatermark = interfaceConfig.SHOW_BRAND_WATERMARK;
|
||||||
showJitsiWatermark = interfaceConfig.SHOW_JITSI_WATERMARK;
|
|
||||||
showJitsiWatermarkForGuests
|
|
||||||
= interfaceConfig.SHOW_WATERMARK_FOR_GUESTS;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this.state = {
|
this.state = {
|
||||||
brandWatermarkLink:
|
brandWatermarkLink:
|
||||||
showBrandWatermark ? interfaceConfig.BRAND_WATERMARK_LINK : '',
|
showBrandWatermark ? interfaceConfig.BRAND_WATERMARK_LINK : '',
|
||||||
jitsiWatermarkLink:
|
|
||||||
showJitsiWatermark || showJitsiWatermarkForGuests
|
|
||||||
? interfaceConfig.JITSI_WATERMARK_LINK : '',
|
|
||||||
showBrandWatermark,
|
showBrandWatermark,
|
||||||
showJitsiWatermark,
|
|
||||||
showJitsiWatermarkForGuests,
|
|
||||||
showPoweredBy: interfaceConfig.SHOW_POWERED_BY
|
showPoweredBy: interfaceConfig.SHOW_POWERED_BY
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -166,55 +122,6 @@ class Watermarks extends Component<Props, State> {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns true if the watermark is ready to be displayed.
|
|
||||||
*
|
|
||||||
* @private
|
|
||||||
* @returns {boolean}
|
|
||||||
*/
|
|
||||||
_canDisplayJitsiWatermark() {
|
|
||||||
const {
|
|
||||||
showJitsiWatermark,
|
|
||||||
showJitsiWatermarkForGuests
|
|
||||||
} = this.state;
|
|
||||||
const {
|
|
||||||
_isGuest,
|
|
||||||
_readyToDisplayJitsiWatermark,
|
|
||||||
_welcomePageIsVisible
|
|
||||||
} = this.props;
|
|
||||||
|
|
||||||
return (_readyToDisplayJitsiWatermark
|
|
||||||
&& (showJitsiWatermark || (_isGuest && showJitsiWatermarkForGuests)))
|
|
||||||
|| _welcomePageIsVisible;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the background image style.
|
|
||||||
*
|
|
||||||
* @private
|
|
||||||
* @returns {string}
|
|
||||||
*/
|
|
||||||
_getBackgroundImageStyle() {
|
|
||||||
const {
|
|
||||||
_customLogoUrl,
|
|
||||||
_isVpaas,
|
|
||||||
defaultJitsiLogoURL
|
|
||||||
} = this.props;
|
|
||||||
let style = 'none';
|
|
||||||
|
|
||||||
if (_isVpaas) {
|
|
||||||
if (_customLogoUrl) {
|
|
||||||
style = `url(${_customLogoUrl})`;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
style = `url(${_customLogoUrl
|
|
||||||
|| defaultJitsiLogoURL
|
|
||||||
|| interfaceConfig.DEFAULT_LOGO_URL})`;
|
|
||||||
}
|
|
||||||
|
|
||||||
return style;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Renders a brand watermark if it is enabled.
|
* Renders a brand watermark if it is enabled.
|
||||||
*
|
*
|
||||||
|
@ -254,33 +161,28 @@ class Watermarks extends Component<Props, State> {
|
||||||
* @returns {ReactElement|null}
|
* @returns {ReactElement|null}
|
||||||
*/
|
*/
|
||||||
_renderJitsiWatermark() {
|
_renderJitsiWatermark() {
|
||||||
|
const {
|
||||||
|
_logoLink,
|
||||||
|
_logoUrl,
|
||||||
|
_showJitsiWatermark
|
||||||
|
} = this.props;
|
||||||
let reactElement = null;
|
let reactElement = null;
|
||||||
|
|
||||||
if (this._canDisplayJitsiWatermark()) {
|
if (_showJitsiWatermark) {
|
||||||
const backgroundImage = this._getBackgroundImageStyle();
|
|
||||||
const link = this.props._customLogoLink || this.state.jitsiWatermarkLink;
|
|
||||||
const additionalStyles = {};
|
|
||||||
|
|
||||||
if (backgroundImage === 'none') {
|
|
||||||
additionalStyles.height = 0;
|
|
||||||
additionalStyles.width = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
const style = {
|
const style = {
|
||||||
backgroundImage,
|
backgroundImage: `url(${_logoUrl})`,
|
||||||
maxWidth: 140,
|
maxWidth: 140,
|
||||||
maxHeight: 70,
|
maxHeight: 70
|
||||||
...additionalStyles
|
|
||||||
};
|
};
|
||||||
|
|
||||||
reactElement = (<div
|
reactElement = (<div
|
||||||
className = 'watermark leftwatermark'
|
className = 'watermark leftwatermark'
|
||||||
style = { style } />);
|
style = { style } />);
|
||||||
|
|
||||||
if (link) {
|
if (_logoLink) {
|
||||||
reactElement = (
|
reactElement = (
|
||||||
<a
|
<a
|
||||||
href = { link }
|
href = { _logoLink }
|
||||||
target = '_new'>
|
target = '_new'>
|
||||||
{ reactElement }
|
{ reactElement }
|
||||||
</a>
|
</a>
|
||||||
|
@ -319,27 +221,52 @@ class Watermarks extends Component<Props, State> {
|
||||||
* Maps parts of Redux store to component prop types.
|
* Maps parts of Redux store to component prop types.
|
||||||
*
|
*
|
||||||
* @param {Object} state - Snapshot of Redux store.
|
* @param {Object} state - Snapshot of Redux store.
|
||||||
|
* @param {Object} ownProps - Component's own props.
|
||||||
* @returns {Props}
|
* @returns {Props}
|
||||||
*/
|
*/
|
||||||
function _mapStateToProps(state) {
|
function _mapStateToProps(state, ownProps) {
|
||||||
const { isGuest } = state['features/base/jwt'];
|
const { isGuest } = state['features/base/jwt'];
|
||||||
const { customizationReady, logoClickUrl, logoImageUrl } = state['features/dynamic-branding'];
|
const {
|
||||||
const { room } = state['features/base/conference'];
|
customizationReady,
|
||||||
|
customizationFailed,
|
||||||
|
defaultBranding,
|
||||||
|
useDynamicBrandingData,
|
||||||
|
logoClickUrl,
|
||||||
|
logoImageUrl
|
||||||
|
} = state['features/dynamic-branding'];
|
||||||
|
const isValidRoom = state['features/base/conference'].room;
|
||||||
|
const {
|
||||||
|
DEFAULT_LOGO_URL,
|
||||||
|
JITSI_WATERMARK_LINK,
|
||||||
|
SHOW_JITSI_WATERMARK,
|
||||||
|
SHOW_JITSI_WATERMARK_FOR_GUESTS,
|
||||||
|
filmStripOnly
|
||||||
|
} = interfaceConfig;
|
||||||
|
let _showJitsiWatermark = (!filmStripOnly
|
||||||
|
&& (customizationReady && !customizationFailed)
|
||||||
|
&& (SHOW_JITSI_WATERMARK || (isGuest && SHOW_JITSI_WATERMARK_FOR_GUESTS)))
|
||||||
|
|| !isValidRoom;
|
||||||
|
let _logoUrl = logoImageUrl;
|
||||||
|
let _logoLink = logoClickUrl;
|
||||||
|
|
||||||
|
if (useDynamicBrandingData) {
|
||||||
|
if (isVpaasMeeting(state)) {
|
||||||
|
// don't show logo if request fails or no logo set for vpaas meetings
|
||||||
|
_showJitsiWatermark = !customizationFailed && Boolean(logoImageUrl);
|
||||||
|
} else if (defaultBranding) {
|
||||||
|
_logoUrl = DEFAULT_LOGO_URL;
|
||||||
|
_logoLink = JITSI_WATERMARK_LINK;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// When there is no custom branding data use defaults
|
||||||
|
_logoUrl = ownProps.defaultJitsiLogoURL || DEFAULT_LOGO_URL;
|
||||||
|
_logoLink = JITSI_WATERMARK_LINK;
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
/**
|
_logoLink,
|
||||||
* The indicator which determines whether the local participant is a
|
_logoUrl,
|
||||||
* guest in the conference.
|
_showJitsiWatermark
|
||||||
*
|
|
||||||
* @private
|
|
||||||
* @type {boolean}
|
|
||||||
*/
|
|
||||||
_customLogoLink: logoClickUrl,
|
|
||||||
_customLogoUrl: logoImageUrl,
|
|
||||||
_isGuest: isGuest,
|
|
||||||
_isVpaas: isVpaasMeeting(state),
|
|
||||||
_readyToDisplayJitsiWatermark: customizationReady,
|
|
||||||
_welcomePageIsVisible: !room
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,11 @@
|
||||||
*/
|
*/
|
||||||
export const SET_DYNAMIC_BRANDING_DATA = 'SET_DYNAMIC_BRANDING_DATA';
|
export const SET_DYNAMIC_BRANDING_DATA = 'SET_DYNAMIC_BRANDING_DATA';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Action used to signal the customization failed.
|
||||||
|
*/
|
||||||
|
export const SET_DYNAMIC_BRANDING_FAILED = 'SET_DYNAMIC_BRANDING_FAILED';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Action used to signal the branding elements are ready to be displayed
|
* Action used to signal the branding elements are ready to be displayed
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -4,7 +4,11 @@ import { getLogger } from 'jitsi-meet-logger';
|
||||||
|
|
||||||
import { doGetJSON } from '../base/util';
|
import { doGetJSON } from '../base/util';
|
||||||
|
|
||||||
import { SET_DYNAMIC_BRANDING_DATA, SET_DYNAMIC_BRANDING_READY } from './actionTypes';
|
import {
|
||||||
|
SET_DYNAMIC_BRANDING_DATA,
|
||||||
|
SET_DYNAMIC_BRANDING_FAILED,
|
||||||
|
SET_DYNAMIC_BRANDING_READY
|
||||||
|
} from './actionTypes';
|
||||||
import { extractFqnFromPath } from './functions';
|
import { extractFqnFromPath } from './functions';
|
||||||
|
|
||||||
const logger = getLogger(__filename);
|
const logger = getLogger(__filename);
|
||||||
|
@ -32,6 +36,8 @@ export function fetchCustomBrandingData() {
|
||||||
return dispatch(setDynamicBrandingData(res));
|
return dispatch(setDynamicBrandingData(res));
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
logger.error('Error fetching branding data', err);
|
logger.error('Error fetching branding data', err);
|
||||||
|
|
||||||
|
return dispatch(setDynamicBrandingFailed());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -63,3 +69,14 @@ function setDynamicBrandingReady() {
|
||||||
type: SET_DYNAMIC_BRANDING_READY
|
type: SET_DYNAMIC_BRANDING_READY
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Action used to signal the branding request failed.
|
||||||
|
*
|
||||||
|
* @returns {Object}
|
||||||
|
*/
|
||||||
|
function setDynamicBrandingFailed() {
|
||||||
|
return {
|
||||||
|
type: SET_DYNAMIC_BRANDING_FAILED
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
|
@ -2,7 +2,11 @@
|
||||||
|
|
||||||
import { ReducerRegistry } from '../base/redux';
|
import { ReducerRegistry } from '../base/redux';
|
||||||
|
|
||||||
import { SET_DYNAMIC_BRANDING_DATA, SET_DYNAMIC_BRANDING_READY } from './actionTypes';
|
import {
|
||||||
|
SET_DYNAMIC_BRANDING_DATA,
|
||||||
|
SET_DYNAMIC_BRANDING_FAILED,
|
||||||
|
SET_DYNAMIC_BRANDING_READY
|
||||||
|
} from './actionTypes';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The name of the redux store/state property which is the root of the redux
|
* The name of the redux store/state property which is the root of the redux
|
||||||
|
@ -11,12 +15,80 @@ import { SET_DYNAMIC_BRANDING_DATA, SET_DYNAMIC_BRANDING_READY } from './actionT
|
||||||
const STORE_NAME = 'features/dynamic-branding';
|
const STORE_NAME = 'features/dynamic-branding';
|
||||||
|
|
||||||
const DEFAULT_STATE = {
|
const DEFAULT_STATE = {
|
||||||
|
/**
|
||||||
|
* The custom background color for the LargeVideo.
|
||||||
|
*
|
||||||
|
* @public
|
||||||
|
* @type {string}
|
||||||
|
*/
|
||||||
backgroundColor: '',
|
backgroundColor: '',
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The custom background image used on the LargeVideo.
|
||||||
|
*
|
||||||
|
* @public
|
||||||
|
* @type {string}
|
||||||
|
*/
|
||||||
backgroundImageUrl: '',
|
backgroundImageUrl: '',
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Flag indicating that the logo (JitsiWatermark) can be displayed.
|
||||||
|
* This is used in order to avoid image flickering.
|
||||||
|
*
|
||||||
|
* @public
|
||||||
|
* @type {boolean}
|
||||||
|
*/
|
||||||
customizationReady: false,
|
customizationReady: false,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Flag indicating that the dynamic branding data request has failed.
|
||||||
|
* When the request fails there is no logo (JitsiWatermark) displayed.
|
||||||
|
*
|
||||||
|
* @public
|
||||||
|
* @type {boolean}
|
||||||
|
*/
|
||||||
|
customizationFailed: false,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Flag indicating that the dynamic branding has not been modified and should use
|
||||||
|
* the default options.
|
||||||
|
*
|
||||||
|
* @public
|
||||||
|
* @type {boolean}
|
||||||
|
*/
|
||||||
|
defaultBranding: true,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The custom invite domain.
|
||||||
|
*
|
||||||
|
* @public
|
||||||
|
* @type {string}
|
||||||
|
*/
|
||||||
inviteDomain: '',
|
inviteDomain: '',
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The custom url used when the user clicks the logo.
|
||||||
|
*
|
||||||
|
* @public
|
||||||
|
* @type {string}
|
||||||
|
*/
|
||||||
logoClickUrl: '',
|
logoClickUrl: '',
|
||||||
logoImageUrl: ''
|
|
||||||
|
/**
|
||||||
|
* The custom logo (JitisWatermark).
|
||||||
|
*
|
||||||
|
* @public
|
||||||
|
* @type {string}
|
||||||
|
*/
|
||||||
|
logoImageUrl: '',
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Flag used to signal if the app should use a custom logo or not
|
||||||
|
*
|
||||||
|
* @public
|
||||||
|
* @type {boolean}
|
||||||
|
*/
|
||||||
|
useDynamicBrandingData: false
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -25,15 +97,33 @@ const DEFAULT_STATE = {
|
||||||
ReducerRegistry.register(STORE_NAME, (state = DEFAULT_STATE, action) => {
|
ReducerRegistry.register(STORE_NAME, (state = DEFAULT_STATE, action) => {
|
||||||
switch (action.type) {
|
switch (action.type) {
|
||||||
case SET_DYNAMIC_BRANDING_DATA: {
|
case SET_DYNAMIC_BRANDING_DATA: {
|
||||||
const { backgroundColor, backgroundImageUrl, inviteDomain, logoClickUrl, logoImageUrl } = action.value;
|
const {
|
||||||
|
backgroundColor,
|
||||||
|
backgroundImageUrl,
|
||||||
|
defaultBranding,
|
||||||
|
inviteDomain,
|
||||||
|
logoClickUrl,
|
||||||
|
logoImageUrl
|
||||||
|
} = action.value;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
backgroundColor,
|
backgroundColor,
|
||||||
backgroundImageUrl,
|
backgroundImageUrl,
|
||||||
|
defaultBranding,
|
||||||
inviteDomain,
|
inviteDomain,
|
||||||
logoClickUrl,
|
logoClickUrl,
|
||||||
logoImageUrl,
|
logoImageUrl,
|
||||||
customizationReady: true
|
customizationFailed: false,
|
||||||
|
customizationReady: true,
|
||||||
|
useDynamicBrandingData: true
|
||||||
|
};
|
||||||
|
}
|
||||||
|
case SET_DYNAMIC_BRANDING_FAILED: {
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
customizationReady: true,
|
||||||
|
customizationFailed: true,
|
||||||
|
useDynamicBrandingData: true
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
case SET_DYNAMIC_BRANDING_READY:
|
case SET_DYNAMIC_BRANDING_READY:
|
||||||
|
@ -41,7 +131,6 @@ ReducerRegistry.register(STORE_NAME, (state = DEFAULT_STATE, action) => {
|
||||||
...state,
|
...state,
|
||||||
customizationReady: true
|
customizationReady: true
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return state;
|
return state;
|
||||||
|
|
Loading…
Reference in New Issue