Browse Source

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.
j8
Vlad Piersec 4 years ago
parent
commit
d2ec0ea6f3

+ 57
- 130
react/features/base/react/components/web/Watermarks.js View File

@@ -24,35 +24,19 @@ const _RIGHT_WATERMARK_STYLE = {
24 24
 type Props = {
25 25
 
26 26
     /**
27
-     * The user selected url used to navigate to on logo click.
27
+     * The link used to navigate to on logo click.
28 28
      */
29
-    _customLogoLink: string,
29
+    _logoLink: string,
30 30
 
31 31
     /**
32
-     * The url of the user selected logo.
32
+     * The url for the logo.
33 33
      */
34
-    _customLogoUrl: string,
34
+    _logoUrl: string,
35 35
 
36 36
     /**
37
-     * Whether or not the current user is logged in through a JWT.
37
+     * If the Jitsi watermark should be displayed or not.
38 38
      */
39
-    _isGuest: boolean,
40
-
41
-    /**
42
-     * Whether or not the current meeting is a vpaas one.
43
-     */
44
-    _isVpaas: boolean,
45
-
46
-    /**
47
-     * Flag used to signal that the logo can be displayed.
48
-     * It becomes true after the user customization options are fetched.
49
-     */
50
-    _readyToDisplayJitsiWatermark: boolean,
51
-
52
-    /**
53
-     * Returns true if welcome page is visible at the moment.
54
-     */
55
-    _welcomePageIsVisible: boolean,
39
+    _showJitsiWatermark: boolean,
56 40
 
57 41
     /**
58 42
      * The default value for the Jitsi logo URL.
@@ -75,27 +59,11 @@ type State = {
75 59
      */
76 60
     brandWatermarkLink: string,
77 61
 
78
-    /**
79
-     * The url to open when clicking the Jitsi watermark.
80
-     */
81
-    jitsiWatermarkLink: string,
82
-
83 62
     /**
84 63
      * Whether or not the brand watermark should be displayed.
85 64
      */
86 65
     showBrandWatermark: boolean,
87 66
 
88
-    /**
89
-     * Whether or not the Jitsi watermark should be displayed.
90
-     */
91
-    showJitsiWatermark: boolean,
92
-
93
-    /**
94
-     * Whether or not the Jitsi watermark should be displayed for users not
95
-     * logged in through a JWT.
96
-     */
97
-    showJitsiWatermarkForGuests: boolean,
98
-
99 67
     /**
100 68
      * Whether or not the show the "powered by Jitsi.org" link.
101 69
      */
@@ -117,29 +85,17 @@ class Watermarks extends Component<Props, State> {
117 85
         super(props);
118 86
 
119 87
         let showBrandWatermark;
120
-        let showJitsiWatermark;
121
-        let showJitsiWatermarkForGuests;
122 88
 
123 89
         if (interfaceConfig.filmStripOnly) {
124 90
             showBrandWatermark = false;
125
-            showJitsiWatermark = false;
126
-            showJitsiWatermarkForGuests = false;
127 91
         } else {
128 92
             showBrandWatermark = interfaceConfig.SHOW_BRAND_WATERMARK;
129
-            showJitsiWatermark = interfaceConfig.SHOW_JITSI_WATERMARK;
130
-            showJitsiWatermarkForGuests
131
-                = interfaceConfig.SHOW_WATERMARK_FOR_GUESTS;
132 93
         }
133 94
 
134 95
         this.state = {
135 96
             brandWatermarkLink:
136 97
                 showBrandWatermark ? interfaceConfig.BRAND_WATERMARK_LINK : '',
137
-            jitsiWatermarkLink:
138
-                showJitsiWatermark || showJitsiWatermarkForGuests
139
-                    ? interfaceConfig.JITSI_WATERMARK_LINK : '',
140 98
             showBrandWatermark,
141
-            showJitsiWatermark,
142
-            showJitsiWatermarkForGuests,
143 99
             showPoweredBy: interfaceConfig.SHOW_POWERED_BY
144 100
         };
145 101
     }
@@ -166,55 +122,6 @@ class Watermarks extends Component<Props, State> {
166 122
         );
167 123
     }
168 124
 
169
-    /**
170
-     * Returns true if the watermark is ready to be displayed.
171
-     *
172
-     * @private
173
-     * @returns {boolean}
174
-     */
175
-    _canDisplayJitsiWatermark() {
176
-        const {
177
-            showJitsiWatermark,
178
-            showJitsiWatermarkForGuests
179
-        } = this.state;
180
-        const {
181
-            _isGuest,
182
-            _readyToDisplayJitsiWatermark,
183
-            _welcomePageIsVisible
184
-        } = this.props;
185
-
186
-        return (_readyToDisplayJitsiWatermark
187
-            && (showJitsiWatermark || (_isGuest && showJitsiWatermarkForGuests)))
188
-            || _welcomePageIsVisible;
189
-    }
190
-
191
-    /**
192
-     * Returns the background image style.
193
-     *
194
-     * @private
195
-     * @returns {string}
196
-     */
197
-    _getBackgroundImageStyle() {
198
-        const {
199
-            _customLogoUrl,
200
-            _isVpaas,
201
-            defaultJitsiLogoURL
202
-        } = this.props;
203
-        let style = 'none';
204
-
205
-        if (_isVpaas) {
206
-            if (_customLogoUrl) {
207
-                style = `url(${_customLogoUrl})`;
208
-            }
209
-        } else {
210
-            style = `url(${_customLogoUrl
211
-                || defaultJitsiLogoURL
212
-                || interfaceConfig.DEFAULT_LOGO_URL})`;
213
-        }
214
-
215
-        return style;
216
-    }
217
-
218 125
     /**
219 126
      * Renders a brand watermark if it is enabled.
220 127
      *
@@ -254,33 +161,28 @@ class Watermarks extends Component<Props, State> {
254 161
      * @returns {ReactElement|null}
255 162
      */
256 163
     _renderJitsiWatermark() {
164
+        const {
165
+            _logoLink,
166
+            _logoUrl,
167
+            _showJitsiWatermark
168
+        } = this.props;
257 169
         let reactElement = null;
258 170
 
259
-        if (this._canDisplayJitsiWatermark()) {
260
-            const backgroundImage = this._getBackgroundImageStyle();
261
-            const link = this.props._customLogoLink || this.state.jitsiWatermarkLink;
262
-            const additionalStyles = {};
263
-
264
-            if (backgroundImage === 'none') {
265
-                additionalStyles.height = 0;
266
-                additionalStyles.width = 0;
267
-            }
268
-
171
+        if (_showJitsiWatermark) {
269 172
             const style = {
270
-                backgroundImage,
173
+                backgroundImage: `url(${_logoUrl})`,
271 174
                 maxWidth: 140,
272
-                maxHeight: 70,
273
-                ...additionalStyles
175
+                maxHeight: 70
274 176
             };
275 177
 
276 178
             reactElement = (<div
277 179
                 className = 'watermark leftwatermark'
278 180
                 style = { style } />);
279 181
 
280
-            if (link) {
182
+            if (_logoLink) {
281 183
                 reactElement = (
282 184
                     <a
283
-                        href = { link }
185
+                        href = { _logoLink }
284 186
                         target = '_new'>
285 187
                         { reactElement }
286 188
                     </a>
@@ -319,27 +221,52 @@ class Watermarks extends Component<Props, State> {
319 221
  * Maps parts of Redux store to component prop types.
320 222
  *
321 223
  * @param {Object} state - Snapshot of Redux store.
224
+ * @param {Object} ownProps - Component's own props.
322 225
  * @returns {Props}
323 226
  */
324
-function _mapStateToProps(state) {
227
+function _mapStateToProps(state, ownProps) {
325 228
     const { isGuest } = state['features/base/jwt'];
326
-    const { customizationReady, logoClickUrl, logoImageUrl } = state['features/dynamic-branding'];
327
-    const { room } = state['features/base/conference'];
229
+    const {
230
+        customizationReady,
231
+        customizationFailed,
232
+        defaultBranding,
233
+        useDynamicBrandingData,
234
+        logoClickUrl,
235
+        logoImageUrl
236
+    } = state['features/dynamic-branding'];
237
+    const isValidRoom = state['features/base/conference'].room;
238
+    const {
239
+        DEFAULT_LOGO_URL,
240
+        JITSI_WATERMARK_LINK,
241
+        SHOW_JITSI_WATERMARK,
242
+        SHOW_JITSI_WATERMARK_FOR_GUESTS,
243
+        filmStripOnly
244
+    } = interfaceConfig;
245
+    let _showJitsiWatermark = (!filmStripOnly
246
+          && (customizationReady && !customizationFailed)
247
+          && (SHOW_JITSI_WATERMARK || (isGuest && SHOW_JITSI_WATERMARK_FOR_GUESTS)))
248
+    || !isValidRoom;
249
+    let _logoUrl = logoImageUrl;
250
+    let _logoLink = logoClickUrl;
251
+
252
+    if (useDynamicBrandingData) {
253
+        if (isVpaasMeeting(state)) {
254
+            // don't show logo if request fails or no logo set for vpaas meetings
255
+            _showJitsiWatermark = !customizationFailed && Boolean(logoImageUrl);
256
+        } else if (defaultBranding) {
257
+            _logoUrl = DEFAULT_LOGO_URL;
258
+            _logoLink = JITSI_WATERMARK_LINK;
259
+        }
260
+    } else {
261
+        // When there is no custom branding data use defaults
262
+        _logoUrl = ownProps.defaultJitsiLogoURL || DEFAULT_LOGO_URL;
263
+        _logoLink = JITSI_WATERMARK_LINK;
264
+    }
328 265
 
329 266
     return {
330
-        /**
331
-         * The indicator which determines whether the local participant is a
332
-         * guest in the conference.
333
-         *
334
-         * @private
335
-         * @type {boolean}
336
-         */
337
-        _customLogoLink: logoClickUrl,
338
-        _customLogoUrl: logoImageUrl,
339
-        _isGuest: isGuest,
340
-        _isVpaas: isVpaasMeeting(state),
341
-        _readyToDisplayJitsiWatermark: customizationReady,
342
-        _welcomePageIsVisible: !room
267
+        _logoLink,
268
+        _logoUrl,
269
+        _showJitsiWatermark
343 270
     };
344 271
 }
345 272
 

+ 5
- 0
react/features/dynamic-branding/actionTypes.js View File

@@ -3,6 +3,11 @@
3 3
  */
4 4
 export const SET_DYNAMIC_BRANDING_DATA = 'SET_DYNAMIC_BRANDING_DATA';
5 5
 
6
+/**
7
+ * Action used to signal the customization failed.
8
+ */
9
+export const SET_DYNAMIC_BRANDING_FAILED = 'SET_DYNAMIC_BRANDING_FAILED';
10
+
6 11
 /**
7 12
  * Action used to signal the branding elements are ready to be displayed
8 13
  */

+ 18
- 1
react/features/dynamic-branding/actions.js View File

@@ -4,7 +4,11 @@ import { getLogger } from 'jitsi-meet-logger';
4 4
 
5 5
 import { doGetJSON } from '../base/util';
6 6
 
7
-import { SET_DYNAMIC_BRANDING_DATA, SET_DYNAMIC_BRANDING_READY } from './actionTypes';
7
+import {
8
+    SET_DYNAMIC_BRANDING_DATA,
9
+    SET_DYNAMIC_BRANDING_FAILED,
10
+    SET_DYNAMIC_BRANDING_READY
11
+} from './actionTypes';
8 12
 import { extractFqnFromPath } from './functions';
9 13
 
10 14
 const logger = getLogger(__filename);
@@ -32,6 +36,8 @@ export function fetchCustomBrandingData() {
32 36
                     return dispatch(setDynamicBrandingData(res));
33 37
                 } catch (err) {
34 38
                     logger.error('Error fetching branding data', err);
39
+
40
+                    return dispatch(setDynamicBrandingFailed());
35 41
                 }
36 42
             }
37 43
 
@@ -63,3 +69,14 @@ function setDynamicBrandingReady() {
63 69
         type: SET_DYNAMIC_BRANDING_READY
64 70
     };
65 71
 }
72
+
73
+/**
74
+ * Action used to signal the branding request failed.
75
+ *
76
+ * @returns {Object}
77
+ */
78
+function setDynamicBrandingFailed() {
79
+    return {
80
+        type: SET_DYNAMIC_BRANDING_FAILED
81
+    };
82
+}

+ 94
- 5
react/features/dynamic-branding/reducer.js View File

@@ -2,7 +2,11 @@
2 2
 
3 3
 import { ReducerRegistry } from '../base/redux';
4 4
 
5
-import { SET_DYNAMIC_BRANDING_DATA, SET_DYNAMIC_BRANDING_READY } from './actionTypes';
5
+import {
6
+    SET_DYNAMIC_BRANDING_DATA,
7
+    SET_DYNAMIC_BRANDING_FAILED,
8
+    SET_DYNAMIC_BRANDING_READY
9
+} from './actionTypes';
6 10
 
7 11
 /**
8 12
  * 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
11 15
 const STORE_NAME = 'features/dynamic-branding';
12 16
 
13 17
 const DEFAULT_STATE = {
18
+    /**
19
+     * The custom background color for the LargeVideo.
20
+     *
21
+     * @public
22
+     * @type {string}
23
+     */
14 24
     backgroundColor: '',
25
+
26
+    /**
27
+     * The custom background image used on the LargeVideo.
28
+     *
29
+     * @public
30
+     * @type {string}
31
+     */
15 32
     backgroundImageUrl: '',
33
+
34
+    /**
35
+     * Flag indicating that the logo (JitsiWatermark) can be displayed.
36
+     * This is used in order to avoid image flickering.
37
+     *
38
+     * @public
39
+     * @type {boolean}
40
+     */
16 41
     customizationReady: false,
42
+
43
+    /**
44
+     * Flag indicating that the dynamic branding data request has failed.
45
+     * When the request fails there is no logo (JitsiWatermark) displayed.
46
+     *
47
+     * @public
48
+     * @type {boolean}
49
+     */
50
+    customizationFailed: false,
51
+
52
+    /**
53
+     * Flag indicating that the dynamic branding has not been modified and should use
54
+     * the default options.
55
+     *
56
+     * @public
57
+     * @type {boolean}
58
+     */
59
+    defaultBranding: true,
60
+
61
+    /**
62
+     * The custom invite domain.
63
+     *
64
+     * @public
65
+     * @type {string}
66
+     */
17 67
     inviteDomain: '',
68
+
69
+    /**
70
+     * The custom url used when the user clicks the logo.
71
+     *
72
+     * @public
73
+     * @type {string}
74
+     */
18 75
     logoClickUrl: '',
19
-    logoImageUrl: ''
76
+
77
+    /**
78
+     * The custom logo (JitisWatermark).
79
+     *
80
+     * @public
81
+     * @type {string}
82
+     */
83
+    logoImageUrl: '',
84
+
85
+    /**
86
+     * Flag used to signal if the app should use a custom logo or not
87
+     *
88
+     * @public
89
+     * @type {boolean}
90
+     */
91
+    useDynamicBrandingData: false
20 92
 };
21 93
 
22 94
 /**
@@ -25,15 +97,33 @@ const DEFAULT_STATE = {
25 97
 ReducerRegistry.register(STORE_NAME, (state = DEFAULT_STATE, action) => {
26 98
     switch (action.type) {
27 99
     case SET_DYNAMIC_BRANDING_DATA: {
28
-        const { backgroundColor, backgroundImageUrl, inviteDomain, logoClickUrl, logoImageUrl } = action.value;
100
+        const {
101
+            backgroundColor,
102
+            backgroundImageUrl,
103
+            defaultBranding,
104
+            inviteDomain,
105
+            logoClickUrl,
106
+            logoImageUrl
107
+        } = action.value;
29 108
 
30 109
         return {
31 110
             backgroundColor,
32 111
             backgroundImageUrl,
112
+            defaultBranding,
33 113
             inviteDomain,
34 114
             logoClickUrl,
35 115
             logoImageUrl,
36
-            customizationReady: true
116
+            customizationFailed: false,
117
+            customizationReady: true,
118
+            useDynamicBrandingData: true
119
+        };
120
+    }
121
+    case SET_DYNAMIC_BRANDING_FAILED: {
122
+        return {
123
+            ...state,
124
+            customizationReady: true,
125
+            customizationFailed: true,
126
+            useDynamicBrandingData: true
37 127
         };
38 128
     }
39 129
     case SET_DYNAMIC_BRANDING_READY:
@@ -41,7 +131,6 @@ ReducerRegistry.register(STORE_NAME, (state = DEFAULT_STATE, action) => {
41 131
             ...state,
42 132
             customizationReady: true
43 133
         };
44
-
45 134
     }
46 135
 
47 136
     return state;

Loading…
Cancel
Save