@vizbeetv/homesso-sdk-qa 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +319 -0
- package/es5/index.cjs +1821 -0
- package/es5/index.mjs +1811 -0
- package/es6/index.cjs +1722 -0
- package/es6/index.mjs +1712 -0
- package/package.json +36 -0
- package/types/VizbeeHomeSSOManager.d.ts +186 -0
- package/types/VizbeeSignInStatusCallback.d.ts +34 -0
- package/types/index.d.ts +63 -0
- package/types/metrics/IVizbeeAttributesProvider.d.ts +3 -0
- package/types/metrics/VizbeeMetricsConstants.d.ts +27 -0
- package/types/metrics/VizbeeMetricsManager.d.ts +15 -0
- package/types/model/VizbeeSenderSignInInfo.d.ts +20 -0
- package/types/model/VizbeeSignInInfo.d.ts +11 -0
- package/types/model/VizbeeSignInStatus.d.ts +31 -0
- package/types/types.d.ts +77 -0
- package/types/ui/VizbeeHomeSSOUIConfig.d.ts +156 -0
- package/types/ui/VizbeeHomeSSOUIManager.d.ts +105 -0
- package/types/ui/VizbeeSnackBar.d.ts +100 -0
- package/types/utils/Logger.d.ts +208 -0
- package/types/utils/constants.d.ts +27 -0
- package/types/utils/http-client.d.ts +114 -0
package/es6/index.mjs
ADDED
|
@@ -0,0 +1,1712 @@
|
|
|
1
|
+
/******************************************************************************
|
|
2
|
+
Copyright (c) Microsoft Corporation.
|
|
3
|
+
|
|
4
|
+
Permission to use, copy, modify, and/or distribute this software for any
|
|
5
|
+
purpose with or without fee is hereby granted.
|
|
6
|
+
|
|
7
|
+
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
|
8
|
+
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
|
9
|
+
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
|
10
|
+
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
|
11
|
+
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
|
12
|
+
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
|
13
|
+
PERFORMANCE OF THIS SOFTWARE.
|
|
14
|
+
***************************************************************************** */
|
|
15
|
+
|
|
16
|
+
function __awaiter(thisArg, _arguments, P, generator) {
|
|
17
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
18
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
19
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
20
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
21
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
22
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
|
|
27
|
+
var e = new Error(message);
|
|
28
|
+
return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* @const VizbeeConstants
|
|
33
|
+
* @description Metrics Constants used throughout the Vizbee Home SSO implementation
|
|
34
|
+
*/
|
|
35
|
+
const VizbeeMetricsConstants = {
|
|
36
|
+
// Events
|
|
37
|
+
METRICS_EVENT_SCREEN_HOMESSO_SIGNIN_RECEIVED: 'SCREEN_HOMESSO_SIGNIN_RECEIVED',
|
|
38
|
+
METRICS_EVENT_SCREEN_HOMESSO_SIGNIN_STATUS: 'SCREEN_HOMESSO_SIGNIN_STATUS',
|
|
39
|
+
// Attributes
|
|
40
|
+
METRICS_ATTR_SCREEN_HOMESSO_SDK_VERSION: 'SCREEN_HOMESSO_SDK_VERSION',
|
|
41
|
+
METRICS_ATTR_IS_SCREEN_SIGNED_IN: 'IS_SCREEN_SIGNED_IN',
|
|
42
|
+
METRICS_ATTR_IS_REMOTE_SIGNED_IN: 'IS_REMOTE_SIGNED_IN',
|
|
43
|
+
METRICS_ATTR_IS_SCREEN_SIGN_IN_STATUS: 'SCREEN_SIGN_IN_STATUS',
|
|
44
|
+
METRICS_ATTR_SCREEN_HOMESSO_USER_ID: 'SCREEN_HOMESSO_USER_ID',
|
|
45
|
+
METRICS_ATTR_SCREEN_HOMESSO_USER_INFO: 'SCREEN_HOMESSO_USER_INFO',
|
|
46
|
+
METRICS_ATTR_HOMESSO_SIGN_IN_TYPE: 'HOMESSO_SIGN_IN_TYPE',
|
|
47
|
+
METRICS_ATTR_REMOTE_DEVICE_ID: 'REMOTE_DEVICE_ID',
|
|
48
|
+
METRICS_ATTR_REMOTE_DEVICE_TYPE: 'REMOTE_DEVICE_TYPE',
|
|
49
|
+
METRICS_ATTR_REMOTE_FRIENDLY_NAME: 'REMOTE_FRIENDLY_NAME',
|
|
50
|
+
METRICS_ATTR_REMOTE_NETWORK_SESSION_ID: 'REMOTE_NETWORK_SESSION_ID',
|
|
51
|
+
METRICS_ATTR_USER_LOGIN_TYPE: 'user_login_type',
|
|
52
|
+
METRICS_ATTR_USER_IS_SIGNED_IN: 'user_is_signed_in',
|
|
53
|
+
METRICS_ATTR_USER_LOGIN: 'user_login',
|
|
54
|
+
METRICS_ATTR_USER_NAME: 'user_name',
|
|
55
|
+
METRICS_ATTR_USER_SUBSCRIPTION_TYPE: 'user_subscription_type',
|
|
56
|
+
METRICS_ATTR_USER_SUBSCRIPTION_VALUE: 'user_subscription_value',
|
|
57
|
+
METRICS_ATTR_USER_SUBSCRIPTION_RENEWAL_TYPE: 'user_subscription_renewal_type',
|
|
58
|
+
METRICS_ATTR_USER_ADDITIONAL_INFO: 'user_additional_info',
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Logger
|
|
63
|
+
* A flexible logging system for TypeScript SDK with
|
|
64
|
+
* enable/disable capabilities and different log levels.
|
|
65
|
+
*
|
|
66
|
+
* Features:
|
|
67
|
+
* - Multiple severity levels from ERROR to TRACE
|
|
68
|
+
* - Colored console output with timestamps
|
|
69
|
+
* - Local storage persistence with size management
|
|
70
|
+
* - Environment-aware execution (handles environments without localStorage)
|
|
71
|
+
* - Export and clearing capabilities
|
|
72
|
+
*/
|
|
73
|
+
/**
|
|
74
|
+
* Defines logging severity levels in ascending order of verbosity.
|
|
75
|
+
* Lower values indicate higher severity. This hierarchy ensures
|
|
76
|
+
* that when a specific level is set, all logs of that level and
|
|
77
|
+
* higher severity (lower enum value) will be captured.
|
|
78
|
+
*/
|
|
79
|
+
var LogLevel;
|
|
80
|
+
(function (LogLevel) {
|
|
81
|
+
/** Critical application errors that prevent proper functioning */
|
|
82
|
+
LogLevel[LogLevel["ERROR"] = 0] = "ERROR";
|
|
83
|
+
/** Important issues that don't stop execution but require attention */
|
|
84
|
+
LogLevel[LogLevel["WARN"] = 1] = "WARN";
|
|
85
|
+
/** General operational information about system behavior */
|
|
86
|
+
LogLevel[LogLevel["INFO"] = 2] = "INFO";
|
|
87
|
+
/** Detailed diagnostic information for troubleshooting */
|
|
88
|
+
LogLevel[LogLevel["DEBUG"] = 3] = "DEBUG";
|
|
89
|
+
/** Extremely verbose execution flow information */
|
|
90
|
+
LogLevel[LogLevel["TRACE"] = 4] = "TRACE";
|
|
91
|
+
})(LogLevel || (LogLevel = {}));
|
|
92
|
+
/**
|
|
93
|
+
* Default configuration applied when creating a new logger
|
|
94
|
+
* without explicit settings. These values can be overridden
|
|
95
|
+
* through the constructor or setConfig method.
|
|
96
|
+
*/
|
|
97
|
+
const DEFAULT_CONFIG = {
|
|
98
|
+
enabled: false,
|
|
99
|
+
level: LogLevel.ERROR,
|
|
100
|
+
useTimestamp: true,
|
|
101
|
+
useColors: true,
|
|
102
|
+
logToConsole: true,
|
|
103
|
+
logToStorage: false,
|
|
104
|
+
maxStorageLogs: 1000,
|
|
105
|
+
};
|
|
106
|
+
/**
|
|
107
|
+
* Core logger implementation that provides multiple severity levels,
|
|
108
|
+
* configurable outputs, and flexible message formatting.
|
|
109
|
+
*
|
|
110
|
+
* The logger handles both console output and storage persistence,
|
|
111
|
+
* with environment detection to gracefully handle different contexts.
|
|
112
|
+
*/
|
|
113
|
+
class Logger {
|
|
114
|
+
/**
|
|
115
|
+
* Creates a new logger instance with optional custom configuration.
|
|
116
|
+
* The provided configuration is merged with default settings.
|
|
117
|
+
*
|
|
118
|
+
* @param config - Partial configuration to override default values
|
|
119
|
+
*/
|
|
120
|
+
constructor(config = {}) {
|
|
121
|
+
/**
|
|
122
|
+
* Storage key used for persisting logs in localStorage.
|
|
123
|
+
* Prefixed with 'vizbee_homesso_' to avoid collisions.
|
|
124
|
+
*/
|
|
125
|
+
this.storageKey = 'vizbee_homesso_logs';
|
|
126
|
+
this.config = Object.assign(Object.assign({}, DEFAULT_CONFIG), config);
|
|
127
|
+
// Initialize storage if enabled in the configuration
|
|
128
|
+
if (this.config.logToStorage) {
|
|
129
|
+
this.initializeStorage();
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Enables or disables all logging functionality.
|
|
134
|
+
* When disabled, no logs will be output regardless of level.
|
|
135
|
+
*
|
|
136
|
+
* @param enabled - Whether logging should be active (defaults to true)
|
|
137
|
+
*/
|
|
138
|
+
enable(enabled = true) {
|
|
139
|
+
this.config.enabled = enabled;
|
|
140
|
+
this.info(`Logger ${enabled ? 'enabled' : 'disabled'}`);
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* Sets the minimum severity level for capturing logs.
|
|
144
|
+
* Only logs at this level and more severe levels will be processed.
|
|
145
|
+
*
|
|
146
|
+
* @param level - The minimum LogLevel to capture
|
|
147
|
+
*/
|
|
148
|
+
setLevel(level) {
|
|
149
|
+
this.config.level = level;
|
|
150
|
+
this.info(`Log level set to ${LogLevel[level]}`);
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* Returns a copy of the current logger configuration.
|
|
154
|
+
* Returns a new object to prevent accidental modification.
|
|
155
|
+
*
|
|
156
|
+
* @returns The complete current configuration
|
|
157
|
+
*/
|
|
158
|
+
getConfig() {
|
|
159
|
+
return Object.assign({}, this.config);
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* Updates logger configuration with new settings.
|
|
163
|
+
* Merges the provided settings with the existing configuration.
|
|
164
|
+
*
|
|
165
|
+
* @param config - Partial configuration to apply
|
|
166
|
+
*/
|
|
167
|
+
setConfig(config) {
|
|
168
|
+
// Store current storage setting to detect changes
|
|
169
|
+
const wasStorageEnabled = this.config.logToStorage;
|
|
170
|
+
// Update configuration by merging with existing settings
|
|
171
|
+
this.config = Object.assign(Object.assign({}, this.config), config);
|
|
172
|
+
// Initialize storage if it was just enabled
|
|
173
|
+
if (!wasStorageEnabled && this.config.logToStorage) {
|
|
174
|
+
this.initializeStorage();
|
|
175
|
+
}
|
|
176
|
+
this.info('Logger configuration updated');
|
|
177
|
+
}
|
|
178
|
+
/**
|
|
179
|
+
* Logs an error message (highest severity).
|
|
180
|
+
* Use for critical failures that prevent proper operation.
|
|
181
|
+
*
|
|
182
|
+
* @param message - The error message to log
|
|
183
|
+
* @param data - Optional supplementary information
|
|
184
|
+
*/
|
|
185
|
+
error(message, ...data) {
|
|
186
|
+
this.log(LogLevel.ERROR, message, data);
|
|
187
|
+
}
|
|
188
|
+
/**
|
|
189
|
+
* Logs a warning message.
|
|
190
|
+
* Use for potential issues that don't stop execution.
|
|
191
|
+
*
|
|
192
|
+
* @param message - The warning message to log
|
|
193
|
+
* @param data - Optional supplementary information
|
|
194
|
+
*/
|
|
195
|
+
warn(message, ...data) {
|
|
196
|
+
this.log(LogLevel.WARN, message, data);
|
|
197
|
+
}
|
|
198
|
+
/**
|
|
199
|
+
* Logs an informational message.
|
|
200
|
+
* Use for general application state and noteworthy events.
|
|
201
|
+
*
|
|
202
|
+
* @param message - The info message to log
|
|
203
|
+
* @param data - Optional supplementary information
|
|
204
|
+
*/
|
|
205
|
+
info(message, ...data) {
|
|
206
|
+
this.log(LogLevel.INFO, message, data);
|
|
207
|
+
}
|
|
208
|
+
/**
|
|
209
|
+
* Logs a debug message.
|
|
210
|
+
* Use for detailed information helpful during development.
|
|
211
|
+
*
|
|
212
|
+
* @param message - The debug message to log
|
|
213
|
+
* @param data - Optional supplementary information
|
|
214
|
+
*/
|
|
215
|
+
debug(message, ...data) {
|
|
216
|
+
this.log(LogLevel.DEBUG, message, data);
|
|
217
|
+
}
|
|
218
|
+
/**
|
|
219
|
+
* Logs a trace message (lowest severity/highest verbosity).
|
|
220
|
+
* Use for extremely detailed execution path tracking.
|
|
221
|
+
*
|
|
222
|
+
* @param message - The trace message to log
|
|
223
|
+
* @param data - Optional supplementary information
|
|
224
|
+
*/
|
|
225
|
+
trace(message, ...data) {
|
|
226
|
+
this.log(LogLevel.TRACE, message, data);
|
|
227
|
+
}
|
|
228
|
+
/**
|
|
229
|
+
* Core logging method that handles level filtering and message routing.
|
|
230
|
+
* Formats the message and sends it to appropriate outputs based on configuration.
|
|
231
|
+
*
|
|
232
|
+
* @param level - Log severity level
|
|
233
|
+
* @param message - The message to log
|
|
234
|
+
* @param data - Additional data to include with the log
|
|
235
|
+
*/
|
|
236
|
+
log(level, message, data = []) {
|
|
237
|
+
// Early return if logging is disabled or level is too verbose
|
|
238
|
+
if (!this.config.enabled || level > this.config.level) {
|
|
239
|
+
return;
|
|
240
|
+
}
|
|
241
|
+
// Format components based on configuration
|
|
242
|
+
const timestamp = this.config.useTimestamp
|
|
243
|
+
? `[${new Date().toISOString()}]`
|
|
244
|
+
: '';
|
|
245
|
+
const levelName = `[${LogLevel[level]}]`;
|
|
246
|
+
// Create the formatted message with application prefix
|
|
247
|
+
const formattedMessage = `${timestamp}[VizbeeHomeSSO]${levelName}: ${message}`;
|
|
248
|
+
// Send to appropriate outputs based on configuration
|
|
249
|
+
if (this.config.logToConsole) {
|
|
250
|
+
this.logToConsole(level, formattedMessage, data);
|
|
251
|
+
}
|
|
252
|
+
if (this.config.logToStorage) {
|
|
253
|
+
this.logToStorage(formattedMessage, data);
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
/**
|
|
257
|
+
* Handles console output with optional color styling.
|
|
258
|
+
* Applies different colors based on log level for better readability.
|
|
259
|
+
*
|
|
260
|
+
* @param level - Log severity level
|
|
261
|
+
* @param message - Formatted message to output
|
|
262
|
+
* @param data - Additional data to log
|
|
263
|
+
*/
|
|
264
|
+
logToConsole(level, message, data) {
|
|
265
|
+
const hasData = data && data.length > 0;
|
|
266
|
+
// Apply color styling if enabled
|
|
267
|
+
if (this.config.useColors) {
|
|
268
|
+
const styles = this.getConsoleStyles(level);
|
|
269
|
+
if (hasData) {
|
|
270
|
+
console.log(`%c${message}`, styles, ...data);
|
|
271
|
+
}
|
|
272
|
+
else {
|
|
273
|
+
console.log(`%c${message}`, styles);
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
else {
|
|
277
|
+
// Plain output without colors
|
|
278
|
+
if (hasData) {
|
|
279
|
+
console.log(message, ...data);
|
|
280
|
+
}
|
|
281
|
+
else {
|
|
282
|
+
console.log(message);
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
/**
|
|
287
|
+
* Determines CSS styling for console output based on log level.
|
|
288
|
+
* Returns different colors to visually distinguish log levels.
|
|
289
|
+
*
|
|
290
|
+
* @param level - Log severity level
|
|
291
|
+
* @returns CSS style string for console output
|
|
292
|
+
*/
|
|
293
|
+
getConsoleStyles(level) {
|
|
294
|
+
switch (level) {
|
|
295
|
+
case LogLevel.ERROR:
|
|
296
|
+
return 'color: #FF5252; font-weight: bold'; // Bright red, bold
|
|
297
|
+
case LogLevel.WARN:
|
|
298
|
+
return 'color: #FFC107; font-weight: bold'; // Amber, bold
|
|
299
|
+
case LogLevel.INFO:
|
|
300
|
+
return 'color: #2196F3'; // Blue
|
|
301
|
+
case LogLevel.DEBUG:
|
|
302
|
+
return 'color: #4CAF50'; // Green
|
|
303
|
+
case LogLevel.TRACE:
|
|
304
|
+
return 'color: #9E9E9E'; // Gray
|
|
305
|
+
default:
|
|
306
|
+
return '';
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
/**
|
|
310
|
+
* Sets up localStorage for persisting logs if available.
|
|
311
|
+
* Creates the initial empty logs array if not already present.
|
|
312
|
+
* Gracefully handles environments without localStorage access.
|
|
313
|
+
*/
|
|
314
|
+
initializeStorage() {
|
|
315
|
+
try {
|
|
316
|
+
// Verify localStorage is available in this environment
|
|
317
|
+
if (typeof localStorage !== 'undefined') {
|
|
318
|
+
// Create empty logs array if not already initialized
|
|
319
|
+
if (!localStorage.getItem(this.storageKey)) {
|
|
320
|
+
localStorage.setItem(this.storageKey, JSON.stringify([]));
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
catch (error) {
|
|
325
|
+
// Handle environments where localStorage is not available or blocked
|
|
326
|
+
console.warn('localStorage not available for logging', error);
|
|
327
|
+
this.config.logToStorage = false;
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
/**
|
|
331
|
+
* Persists a log entry to localStorage with rotation management.
|
|
332
|
+
* Removes oldest entries when the maximum count is exceeded.
|
|
333
|
+
* Handles storage errors gracefully.
|
|
334
|
+
*
|
|
335
|
+
* @param message - Formatted message to store
|
|
336
|
+
* @param data - Additional data to include
|
|
337
|
+
*/
|
|
338
|
+
logToStorage(message, data) {
|
|
339
|
+
try {
|
|
340
|
+
if (typeof localStorage !== 'undefined') {
|
|
341
|
+
// Retrieve current logs
|
|
342
|
+
const logs = JSON.parse(localStorage.getItem(this.storageKey) || '[]');
|
|
343
|
+
// Add new log entry
|
|
344
|
+
logs.push({
|
|
345
|
+
timestamp: new Date().toISOString(),
|
|
346
|
+
message,
|
|
347
|
+
data: data.length > 0 ? JSON.stringify(data) : undefined,
|
|
348
|
+
});
|
|
349
|
+
// Apply size limit by removing oldest logs if needed
|
|
350
|
+
if (logs.length > (this.config.maxStorageLogs || 1000)) {
|
|
351
|
+
logs.shift(); // Remove oldest log
|
|
352
|
+
}
|
|
353
|
+
// Save updated logs back to storage
|
|
354
|
+
localStorage.setItem(this.storageKey, JSON.stringify(logs));
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
catch (error) {
|
|
358
|
+
console.error('Failed to write logs to storage', error);
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
/**
|
|
362
|
+
* Exports all stored logs as a JSON string.
|
|
363
|
+
* Returns an empty array string if storage is unavailable.
|
|
364
|
+
*
|
|
365
|
+
* @returns JSON string containing all stored logs
|
|
366
|
+
*/
|
|
367
|
+
exportLogs() {
|
|
368
|
+
try {
|
|
369
|
+
if (typeof localStorage !== 'undefined') {
|
|
370
|
+
const logs = localStorage.getItem(this.storageKey) || '[]';
|
|
371
|
+
return logs;
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
catch (error) {
|
|
375
|
+
console.error('Failed to export logs', error);
|
|
376
|
+
}
|
|
377
|
+
return '[]';
|
|
378
|
+
}
|
|
379
|
+
/**
|
|
380
|
+
* Clears all logs from storage.
|
|
381
|
+
* Replaces the current logs with an empty array.
|
|
382
|
+
*/
|
|
383
|
+
clearLogs() {
|
|
384
|
+
try {
|
|
385
|
+
if (typeof localStorage !== 'undefined') {
|
|
386
|
+
localStorage.setItem(this.storageKey, JSON.stringify([]));
|
|
387
|
+
this.info('Logs cleared from storage');
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
catch (error) {
|
|
391
|
+
console.error('Failed to clear logs', error);
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
/**
|
|
396
|
+
* Default singleton logger instance with standard configuration.
|
|
397
|
+
* Available as a ready-to-use logger throughout the application.
|
|
398
|
+
* For custom configurations, create additional Logger instances.
|
|
399
|
+
*/
|
|
400
|
+
const logger = new Logger();
|
|
401
|
+
|
|
402
|
+
const LOG_TAG$1 = 'VizbeeHomeSSOManager';
|
|
403
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
404
|
+
class VizbeeMetricsManager {
|
|
405
|
+
constructor() {
|
|
406
|
+
var _a, _b, _c;
|
|
407
|
+
this.senderInfo = null;
|
|
408
|
+
this.getSignInInfo = () => __awaiter(this, void 0, void 0, function* () { return []; });
|
|
409
|
+
if ((_c = (_b = (_a = window === null || window === void 0 ? void 0 : window.vizbee) === null || _a === void 0 ? void 0 : _a.continuity) === null || _b === void 0 ? void 0 : _b.analytics) === null || _c === void 0 ? void 0 : _c.AnalyticsProvider) {
|
|
410
|
+
this.metricsManager =
|
|
411
|
+
new window.vizbee.continuity.analytics.AnalyticsProvider();
|
|
412
|
+
// Create a wrapper with 'provider' property
|
|
413
|
+
const attributesProvider = {
|
|
414
|
+
getAttributes: () => this.getAttributes(),
|
|
415
|
+
};
|
|
416
|
+
this.metricsManager.addProvider(attributesProvider, '.*');
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
log(event, attributes, bypassAttributeProviders = false) {
|
|
420
|
+
if (!this.metricsManager) {
|
|
421
|
+
return;
|
|
422
|
+
}
|
|
423
|
+
logger.debug(`[${LOG_TAG$1}][log] - Logging metrics event: `, event, attributes, bypassAttributeProviders);
|
|
424
|
+
if (event ===
|
|
425
|
+
VizbeeMetricsConstants.METRICS_EVENT_SCREEN_HOMESSO_SIGNIN_RECEIVED) {
|
|
426
|
+
this.senderInfo = attributes.senderInfo;
|
|
427
|
+
}
|
|
428
|
+
const attributesToBeSent = this.addDefaultAttributes();
|
|
429
|
+
attributesToBeSent[VizbeeMetricsConstants.METRICS_ATTR_IS_SCREEN_SIGNED_IN] = attributes.isScreenSignedIn;
|
|
430
|
+
attributesToBeSent[VizbeeMetricsConstants.METRICS_ATTR_IS_REMOTE_SIGNED_IN] = attributes.isRemoteSignedIn;
|
|
431
|
+
attributesToBeSent[VizbeeMetricsConstants.METRICS_ATTR_HOMESSO_SIGN_IN_TYPE] = attributes.signInType;
|
|
432
|
+
attributesToBeSent[VizbeeMetricsConstants.METRICS_ATTR_IS_SCREEN_SIGN_IN_STATUS] = attributes.signInState;
|
|
433
|
+
if (attributes.userId) {
|
|
434
|
+
attributesToBeSent[VizbeeMetricsConstants.METRICS_ATTR_SCREEN_HOMESSO_USER_ID] = attributes.userId;
|
|
435
|
+
}
|
|
436
|
+
logger.debug(`[${LOG_TAG$1}][log] - Logging metrics event: `, event, attributesToBeSent);
|
|
437
|
+
this.metricsManager.logMetrics(event, attributesToBeSent);
|
|
438
|
+
}
|
|
439
|
+
setCustomAttributes(customAttributes) {
|
|
440
|
+
this.metricsManager.setCustomAttributes(customAttributes);
|
|
441
|
+
}
|
|
442
|
+
getAttributes() {
|
|
443
|
+
return this.createAttributesJson();
|
|
444
|
+
}
|
|
445
|
+
createAttributesJson() {
|
|
446
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
447
|
+
const attributes = {};
|
|
448
|
+
const userInfoArray = [];
|
|
449
|
+
const signInInfoList = yield this.getSignInInfo();
|
|
450
|
+
signInInfoList === null || signInInfoList === void 0 ? void 0 : signInInfoList.forEach((signInInfo) => {
|
|
451
|
+
const userInfoObject = this.createUserInfoObject(signInInfo);
|
|
452
|
+
userInfoArray.push(userInfoObject);
|
|
453
|
+
});
|
|
454
|
+
attributes[VizbeeMetricsConstants.METRICS_ATTR_SCREEN_HOMESSO_USER_INFO] =
|
|
455
|
+
userInfoArray;
|
|
456
|
+
return attributes;
|
|
457
|
+
});
|
|
458
|
+
}
|
|
459
|
+
createUserInfoObject(signInInfo) {
|
|
460
|
+
const UNKNOWN_VALUE = 'UNKNOWN';
|
|
461
|
+
const userInfo = {
|
|
462
|
+
[VizbeeMetricsConstants.METRICS_ATTR_USER_LOGIN_TYPE]: signInInfo.userLoginType,
|
|
463
|
+
[VizbeeMetricsConstants.METRICS_ATTR_USER_IS_SIGNED_IN]: signInInfo.isSignedIn,
|
|
464
|
+
[VizbeeMetricsConstants.METRICS_ATTR_USER_LOGIN]: signInInfo.userLogin || UNKNOWN_VALUE,
|
|
465
|
+
[VizbeeMetricsConstants.METRICS_ATTR_USER_NAME]: signInInfo.userName || UNKNOWN_VALUE,
|
|
466
|
+
[VizbeeMetricsConstants.METRICS_ATTR_USER_SUBSCRIPTION_TYPE]: signInInfo.userSubscriptionType || UNKNOWN_VALUE,
|
|
467
|
+
[VizbeeMetricsConstants.METRICS_ATTR_USER_SUBSCRIPTION_VALUE]: signInInfo.userSubscriptionValue || UNKNOWN_VALUE,
|
|
468
|
+
[VizbeeMetricsConstants.METRICS_ATTR_USER_SUBSCRIPTION_RENEWAL_TYPE]: signInInfo.userSubscriptionRenewalType || UNKNOWN_VALUE,
|
|
469
|
+
};
|
|
470
|
+
if (signInInfo.userAdditionalInfo) {
|
|
471
|
+
userInfo[VizbeeMetricsConstants.METRICS_ATTR_USER_ADDITIONAL_INFO] =
|
|
472
|
+
signInInfo.userAdditionalInfo || {};
|
|
473
|
+
}
|
|
474
|
+
return userInfo;
|
|
475
|
+
}
|
|
476
|
+
addDefaultAttributes() {
|
|
477
|
+
var _a, _b, _c, _d;
|
|
478
|
+
const attributes = {};
|
|
479
|
+
attributes[VizbeeMetricsConstants.METRICS_ATTR_SCREEN_HOMESSO_SDK_VERSION] =
|
|
480
|
+
'1.0.1';
|
|
481
|
+
attributes['REMOTE_FRIENDLY_NAME'] = (_a = this.senderInfo) === null || _a === void 0 ? void 0 : _a.friendlyName;
|
|
482
|
+
attributes['REMOTE_DEVICE_ID'] = (_b = this.senderInfo) === null || _b === void 0 ? void 0 : _b.deviceId;
|
|
483
|
+
attributes['REMOTE_DEVICE_TYPE'] = (_c = this.senderInfo) === null || _c === void 0 ? void 0 : _c.deviceType;
|
|
484
|
+
attributes['REMOTE_NETWORK_SESSION_ID'] = (_d = this.senderInfo) === null || _d === void 0 ? void 0 : _d.networkSessionId;
|
|
485
|
+
return attributes;
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
/**
|
|
490
|
+
* @const VizbeeConstants
|
|
491
|
+
* @description Constants used throughout the Vizbee Home SSO implementation
|
|
492
|
+
*/
|
|
493
|
+
const VizbeeConstants = {
|
|
494
|
+
EVENT_SSO_NAME: 'tv.vizbee.homesso.signin',
|
|
495
|
+
// Sign in event keys
|
|
496
|
+
KEY_SUB_TYPE: 'sub_type',
|
|
497
|
+
KEY_SIGN_IN_STATUS: 'sstatus',
|
|
498
|
+
KEY_STATE: 'sstate',
|
|
499
|
+
KEY_CUSTOM_DATA: 'custom_data',
|
|
500
|
+
KEY_REG_CODE: 'regcode',
|
|
501
|
+
// Custom metadata keys
|
|
502
|
+
KEY_START_SIGN_IN_INFO: 'sinfo',
|
|
503
|
+
KEY_IS_SIGNED_IN: 'is_signed_in',
|
|
504
|
+
KEY_SIGN_IN_TYPE: 'stype',
|
|
505
|
+
KEY_DEVICE_MODEL: 'device_model',
|
|
506
|
+
KEY_DEVICE_OS: 'device_os',
|
|
507
|
+
// Event subtypes
|
|
508
|
+
EVENT_SUBTYPE_START_SIGN_IN: 'start_sign_in',
|
|
509
|
+
EVENT_SUBTYPE_SIGN_IN_STATUS: 'sign_in_status',
|
|
510
|
+
// SDK events types
|
|
511
|
+
VIZBEE_SESSION_READY: 'vizbee-bicast-session-ready',
|
|
512
|
+
};
|
|
513
|
+
// Enum for sign in states
|
|
514
|
+
var VizbeeSignInState;
|
|
515
|
+
(function (VizbeeSignInState) {
|
|
516
|
+
VizbeeSignInState["SIGN_IN_NOT_STARTED"] = "not_started";
|
|
517
|
+
VizbeeSignInState["SIGN_IN_IN_PROGRESS"] = "in_progress";
|
|
518
|
+
VizbeeSignInState["SIGN_IN_COMPLETED"] = "completed";
|
|
519
|
+
VizbeeSignInState["SIGN_IN_FAILED"] = "failed";
|
|
520
|
+
VizbeeSignInState["SIGN_IN_CANCELLED"] = "cancelled";
|
|
521
|
+
})(VizbeeSignInState || (VizbeeSignInState = {}));
|
|
522
|
+
|
|
523
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
524
|
+
// Base abstract class for sign in status
|
|
525
|
+
class VizbeeSignInStatus {
|
|
526
|
+
constructor(signInType, customData) {
|
|
527
|
+
this.signInType = signInType;
|
|
528
|
+
this.customData = customData;
|
|
529
|
+
}
|
|
530
|
+
serialize() {
|
|
531
|
+
return {
|
|
532
|
+
[VizbeeConstants.KEY_SIGN_IN_TYPE]: this.signInType,
|
|
533
|
+
[VizbeeConstants.KEY_STATE]: this.getState(),
|
|
534
|
+
[VizbeeConstants.KEY_CUSTOM_DATA]: this.customData,
|
|
535
|
+
};
|
|
536
|
+
}
|
|
537
|
+
}
|
|
538
|
+
// Progress status class
|
|
539
|
+
class ProgressStatus extends VizbeeSignInStatus {
|
|
540
|
+
constructor(signInType, customData = null) {
|
|
541
|
+
super(signInType, customData);
|
|
542
|
+
this.signInType = signInType;
|
|
543
|
+
this.customData = customData;
|
|
544
|
+
}
|
|
545
|
+
getState() {
|
|
546
|
+
return VizbeeSignInState.SIGN_IN_IN_PROGRESS;
|
|
547
|
+
}
|
|
548
|
+
}
|
|
549
|
+
// Success status class
|
|
550
|
+
class SuccessStatus extends VizbeeSignInStatus {
|
|
551
|
+
constructor(signInType, userId = null, customData = null) {
|
|
552
|
+
super(signInType, customData);
|
|
553
|
+
this.signInType = signInType;
|
|
554
|
+
this.userId = userId;
|
|
555
|
+
this.customData = customData;
|
|
556
|
+
}
|
|
557
|
+
getState() {
|
|
558
|
+
return VizbeeSignInState.SIGN_IN_COMPLETED;
|
|
559
|
+
}
|
|
560
|
+
}
|
|
561
|
+
// Failure status class
|
|
562
|
+
class FailureStatus extends VizbeeSignInStatus {
|
|
563
|
+
constructor(signInType, isCancelled, reason = null, exception = null, customData = null) {
|
|
564
|
+
super(signInType, customData);
|
|
565
|
+
this.signInType = signInType;
|
|
566
|
+
this.isCancelled = isCancelled;
|
|
567
|
+
this.reason = reason;
|
|
568
|
+
this.exception = exception;
|
|
569
|
+
this.customData = customData;
|
|
570
|
+
}
|
|
571
|
+
getState() {
|
|
572
|
+
return this.isCancelled
|
|
573
|
+
? VizbeeSignInState.SIGN_IN_CANCELLED
|
|
574
|
+
: VizbeeSignInState.SIGN_IN_FAILED;
|
|
575
|
+
}
|
|
576
|
+
}
|
|
577
|
+
|
|
578
|
+
/**
|
|
579
|
+
* @fileoverview Configuration and type definitions for Vizbee Home SSO UI components
|
|
580
|
+
* Defines interfaces and default configurations for various modal states and themes
|
|
581
|
+
*/
|
|
582
|
+
/**
|
|
583
|
+
* Enum defining the different types of sign-in modals available in the system
|
|
584
|
+
*/
|
|
585
|
+
var SignInModalType;
|
|
586
|
+
(function (SignInModalType) {
|
|
587
|
+
SignInModalType["INFORMATION"] = "information";
|
|
588
|
+
SignInModalType["PROGRESS"] = "progress";
|
|
589
|
+
SignInModalType["SUCCESS"] = "success";
|
|
590
|
+
})(SignInModalType || (SignInModalType = {}));
|
|
591
|
+
/**
|
|
592
|
+
* Default theme configuration with basic color scheme
|
|
593
|
+
*/
|
|
594
|
+
const defaultTheme = {
|
|
595
|
+
primaryColor: '#000000',
|
|
596
|
+
secondaryColor: '#262626',
|
|
597
|
+
tertiaryColor: '#FFFFFF',
|
|
598
|
+
subTextColor: undefined,
|
|
599
|
+
primaryFont: undefined,
|
|
600
|
+
secondaryFont: undefined,
|
|
601
|
+
direction: 'ltr',
|
|
602
|
+
};
|
|
603
|
+
/**
|
|
604
|
+
* Collection of Base64 encoded icon images used in different modal states
|
|
605
|
+
*/
|
|
606
|
+
const icons = {
|
|
607
|
+
vzb_unconnected: `data:image/png;base64,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`,
|
|
608
|
+
vzb_connection_progress_0: `data:image/png;base64,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`,
|
|
609
|
+
vzb_connection_progress_1: `data:image/png;base64,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`,
|
|
610
|
+
vzb_connection_progress_2: `data:image/png;base64,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`,
|
|
611
|
+
vzb_connected: `data:image/png;base64,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`,
|
|
612
|
+
};
|
|
613
|
+
/**
|
|
614
|
+
* Default configuration for informational sign-in modal
|
|
615
|
+
* Shown when initial sign-in process starts
|
|
616
|
+
*/
|
|
617
|
+
const defaultInformationalModalConfig = {
|
|
618
|
+
enable: true,
|
|
619
|
+
options: {
|
|
620
|
+
width: undefined,
|
|
621
|
+
backgroundColor: undefined,
|
|
622
|
+
marginBottom: undefined,
|
|
623
|
+
marginRight: undefined,
|
|
624
|
+
direction: undefined,
|
|
625
|
+
iconBase64String: icons['vzb_unconnected'],
|
|
626
|
+
iconWidth: undefined,
|
|
627
|
+
iconHeight: undefined,
|
|
628
|
+
iconMarginRight: undefined,
|
|
629
|
+
titleText: 'Mobile Sign In',
|
|
630
|
+
titleTextFontFamily: undefined,
|
|
631
|
+
titleTextFontColor: undefined,
|
|
632
|
+
titleTextFontSize: undefined,
|
|
633
|
+
descriptionText: 'Please use your mobile app to complete the sign in process.',
|
|
634
|
+
descriptionTextFontFamily: undefined,
|
|
635
|
+
descriptionTextFontColor: undefined,
|
|
636
|
+
descriptionTextFontSize: undefined,
|
|
637
|
+
position: 'bottom-right',
|
|
638
|
+
borderColor: undefined,
|
|
639
|
+
borderWidth: undefined,
|
|
640
|
+
boxShadow: undefined,
|
|
641
|
+
height: undefined,
|
|
642
|
+
minHeight: undefined,
|
|
643
|
+
padding: undefined,
|
|
644
|
+
borderRadius: undefined,
|
|
645
|
+
edgeMargin: undefined,
|
|
646
|
+
marginTop: undefined,
|
|
647
|
+
marginLeft: undefined,
|
|
648
|
+
titleTextFontWeight: undefined,
|
|
649
|
+
titleTextLineHeight: undefined,
|
|
650
|
+
titleMarginBottom: undefined,
|
|
651
|
+
descriptionTextFontWeight: undefined,
|
|
652
|
+
descriptionTextLineHeight: undefined,
|
|
653
|
+
},
|
|
654
|
+
};
|
|
655
|
+
/**
|
|
656
|
+
* Default configuration for progress sign-in modal
|
|
657
|
+
* Shown while sign-in is in progress
|
|
658
|
+
*/
|
|
659
|
+
const defaultProgressModalConfig = {
|
|
660
|
+
enable: true,
|
|
661
|
+
options: {
|
|
662
|
+
width: undefined,
|
|
663
|
+
backgroundColor: undefined,
|
|
664
|
+
marginBottom: undefined,
|
|
665
|
+
marginRight: undefined,
|
|
666
|
+
direction: undefined,
|
|
667
|
+
iconBase64String: icons['vzb_connection_progress_0'],
|
|
668
|
+
iconBase64Strings: [
|
|
669
|
+
icons['vzb_connection_progress_0'],
|
|
670
|
+
icons['vzb_connection_progress_1'],
|
|
671
|
+
icons['vzb_connection_progress_2'],
|
|
672
|
+
icons['vzb_connection_progress_1'],
|
|
673
|
+
],
|
|
674
|
+
iconWidth: undefined,
|
|
675
|
+
iconHeight: undefined,
|
|
676
|
+
iconMarginRight: undefined,
|
|
677
|
+
titleText: undefined,
|
|
678
|
+
titleTextFontFamily: undefined,
|
|
679
|
+
titleTextFontColor: undefined,
|
|
680
|
+
titleTextFontSize: undefined,
|
|
681
|
+
descriptionText: 'Signing in using your mobile app ...',
|
|
682
|
+
descriptionTextFontFamily: undefined,
|
|
683
|
+
descriptionTextFontColor: undefined,
|
|
684
|
+
descriptionTextFontSize: undefined,
|
|
685
|
+
position: 'bottom-right',
|
|
686
|
+
borderColor: undefined,
|
|
687
|
+
borderWidth: undefined,
|
|
688
|
+
boxShadow: undefined,
|
|
689
|
+
height: undefined,
|
|
690
|
+
minHeight: undefined,
|
|
691
|
+
padding: undefined,
|
|
692
|
+
borderRadius: undefined,
|
|
693
|
+
edgeMargin: undefined,
|
|
694
|
+
marginTop: undefined,
|
|
695
|
+
marginLeft: undefined,
|
|
696
|
+
titleTextFontWeight: undefined,
|
|
697
|
+
titleTextLineHeight: undefined,
|
|
698
|
+
titleMarginBottom: undefined,
|
|
699
|
+
descriptionTextFontWeight: undefined,
|
|
700
|
+
descriptionTextLineHeight: undefined,
|
|
701
|
+
},
|
|
702
|
+
};
|
|
703
|
+
/**
|
|
704
|
+
* Default configuration for success sign-in modal
|
|
705
|
+
* Shown when sign-in process completes successfully
|
|
706
|
+
*/
|
|
707
|
+
const defaultSuccessModalConfig = {
|
|
708
|
+
enable: true,
|
|
709
|
+
options: {
|
|
710
|
+
width: undefined,
|
|
711
|
+
backgroundColor: undefined,
|
|
712
|
+
marginBottom: undefined,
|
|
713
|
+
marginRight: undefined,
|
|
714
|
+
direction: undefined,
|
|
715
|
+
iconBase64String: icons['vzb_connected'],
|
|
716
|
+
iconWidth: undefined,
|
|
717
|
+
iconHeight: undefined,
|
|
718
|
+
iconMarginRight: undefined,
|
|
719
|
+
titleText: 'Mobile Sign In Successful!',
|
|
720
|
+
titleTextFontFamily: undefined,
|
|
721
|
+
titleTextFontColor: undefined,
|
|
722
|
+
titleTextFontSize: undefined,
|
|
723
|
+
descriptionText: 'Cast or select any content to start watching.',
|
|
724
|
+
descriptionTextFontFamily: undefined,
|
|
725
|
+
descriptionTextFontColor: undefined,
|
|
726
|
+
descriptionTextFontSize: undefined,
|
|
727
|
+
position: 'bottom-right',
|
|
728
|
+
duration: 10000,
|
|
729
|
+
borderColor: undefined,
|
|
730
|
+
borderWidth: undefined,
|
|
731
|
+
boxShadow: undefined,
|
|
732
|
+
height: undefined,
|
|
733
|
+
minHeight: undefined,
|
|
734
|
+
padding: undefined,
|
|
735
|
+
borderRadius: undefined,
|
|
736
|
+
edgeMargin: undefined,
|
|
737
|
+
marginTop: undefined,
|
|
738
|
+
marginLeft: undefined,
|
|
739
|
+
titleTextFontWeight: undefined,
|
|
740
|
+
titleTextLineHeight: undefined,
|
|
741
|
+
titleMarginBottom: undefined,
|
|
742
|
+
descriptionTextFontWeight: undefined,
|
|
743
|
+
descriptionTextLineHeight: undefined,
|
|
744
|
+
},
|
|
745
|
+
};
|
|
746
|
+
|
|
747
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
748
|
+
/**
|
|
749
|
+
* Singleton class responsible for managing UI configurations for Home SSO experience
|
|
750
|
+
* Handles theme customization and specific modal configurations for different sign-in states
|
|
751
|
+
*/
|
|
752
|
+
class VizbeeHomeSSOUIManager {
|
|
753
|
+
/**
|
|
754
|
+
* Private constructor to enforce singleton pattern
|
|
755
|
+
* Initializes configurations with default values using deep merge
|
|
756
|
+
*/
|
|
757
|
+
constructor() {
|
|
758
|
+
this.themeConfig = this.deepMerge({}, defaultTheme);
|
|
759
|
+
this.commonModalConfig = this.deepMerge({});
|
|
760
|
+
this.informationalModalConfig =
|
|
761
|
+
this.deepMerge(defaultInformationalModalConfig.options);
|
|
762
|
+
this.progressModalConfig = this.deepMerge(defaultProgressModalConfig.options);
|
|
763
|
+
this.successModalConfig = this.deepMerge(defaultSuccessModalConfig.options);
|
|
764
|
+
}
|
|
765
|
+
/**
|
|
766
|
+
* Gets the singleton instance of VizbeeHomeSSOUIManager
|
|
767
|
+
* Creates a new instance if one doesn't exist
|
|
768
|
+
* @returns The singleton instance of VizbeeHomeSSOUIManager
|
|
769
|
+
*/
|
|
770
|
+
static getInstance() {
|
|
771
|
+
if (!VizbeeHomeSSOUIManager.instance) {
|
|
772
|
+
VizbeeHomeSSOUIManager.instance = new VizbeeHomeSSOUIManager();
|
|
773
|
+
}
|
|
774
|
+
return VizbeeHomeSSOUIManager.instance;
|
|
775
|
+
}
|
|
776
|
+
/**
|
|
777
|
+
* Creates a deep clone of an object or array
|
|
778
|
+
* @param obj - Object to clone
|
|
779
|
+
* @returns Deep cloned copy of the input
|
|
780
|
+
*/
|
|
781
|
+
deepClone(obj) {
|
|
782
|
+
// Handle primitives and null
|
|
783
|
+
if (obj === null || typeof obj !== 'object') {
|
|
784
|
+
return obj;
|
|
785
|
+
}
|
|
786
|
+
try {
|
|
787
|
+
// Attempt JSON serialization - this will throw on circular references
|
|
788
|
+
return JSON.parse(JSON.stringify(obj));
|
|
789
|
+
}
|
|
790
|
+
catch (error) {
|
|
791
|
+
// Fall back to manual deep cloning when JSON serialization fails
|
|
792
|
+
return this.fallbackDeepClone(obj);
|
|
793
|
+
}
|
|
794
|
+
}
|
|
795
|
+
// Fallback manual deep clone that handles circular references
|
|
796
|
+
fallbackDeepClone(obj, visited = new Map()) {
|
|
797
|
+
if (obj === null || typeof obj !== 'object') {
|
|
798
|
+
return obj;
|
|
799
|
+
}
|
|
800
|
+
// Handle circular references
|
|
801
|
+
if (visited.has(obj)) {
|
|
802
|
+
return visited.get(obj);
|
|
803
|
+
}
|
|
804
|
+
// Handle arrays
|
|
805
|
+
if (Array.isArray(obj)) {
|
|
806
|
+
const clone = [];
|
|
807
|
+
visited.set(obj, clone);
|
|
808
|
+
for (let i = 0; i < obj.length; i++) {
|
|
809
|
+
clone[i] = this.fallbackDeepClone(obj[i], visited);
|
|
810
|
+
}
|
|
811
|
+
return clone;
|
|
812
|
+
}
|
|
813
|
+
// Handle objects
|
|
814
|
+
const clone = {};
|
|
815
|
+
visited.set(obj, clone);
|
|
816
|
+
Object.keys(obj).forEach(key => {
|
|
817
|
+
clone[key] = this.fallbackDeepClone(obj[key], visited);
|
|
818
|
+
});
|
|
819
|
+
return clone;
|
|
820
|
+
}
|
|
821
|
+
/**
|
|
822
|
+
* Performs a deep merge of multiple objects
|
|
823
|
+
* @param target - Base object to merge into
|
|
824
|
+
* @param sources - Array of objects to merge from
|
|
825
|
+
* @returns Merged object combining all sources into target
|
|
826
|
+
*/
|
|
827
|
+
deepMerge(target, ...sources) {
|
|
828
|
+
const result = JSON.parse(JSON.stringify(target));
|
|
829
|
+
if (sources.length === 0)
|
|
830
|
+
return result;
|
|
831
|
+
for (const source of sources) {
|
|
832
|
+
if (!source)
|
|
833
|
+
continue;
|
|
834
|
+
for (const key of Object.keys(source)) {
|
|
835
|
+
const sourceValue = source[key];
|
|
836
|
+
if (sourceValue === undefined)
|
|
837
|
+
continue;
|
|
838
|
+
if (sourceValue === null) {
|
|
839
|
+
result[key] = null;
|
|
840
|
+
continue;
|
|
841
|
+
}
|
|
842
|
+
if (typeof sourceValue === 'object' && !Array.isArray(sourceValue)) {
|
|
843
|
+
if (!result[key] || typeof result[key] !== 'object') {
|
|
844
|
+
result[key] = {};
|
|
845
|
+
}
|
|
846
|
+
result[key] = this.deepMerge(result[key], sourceValue);
|
|
847
|
+
}
|
|
848
|
+
else {
|
|
849
|
+
result[key] = JSON.parse(JSON.stringify(sourceValue));
|
|
850
|
+
}
|
|
851
|
+
}
|
|
852
|
+
}
|
|
853
|
+
return result;
|
|
854
|
+
}
|
|
855
|
+
/**
|
|
856
|
+
* Maps theme configuration to modal configuration properties
|
|
857
|
+
* @param theme - Current theme configuration
|
|
858
|
+
* @returns Partial modal configuration based on theme
|
|
859
|
+
*/
|
|
860
|
+
mapThemeToModalConfig(theme) {
|
|
861
|
+
return {
|
|
862
|
+
borderColor: theme.primaryColor,
|
|
863
|
+
backgroundColor: theme.secondaryColor,
|
|
864
|
+
titleTextFontColor: theme.tertiaryColor,
|
|
865
|
+
descriptionTextFontColor: theme.subTextColor,
|
|
866
|
+
titleTextFontFamily: theme.primaryFont,
|
|
867
|
+
descriptionTextFontFamily: theme.secondaryFont,
|
|
868
|
+
direction: theme.direction,
|
|
869
|
+
};
|
|
870
|
+
}
|
|
871
|
+
/**
|
|
872
|
+
* Returns default configurations for all modal types
|
|
873
|
+
* @returns Object containing default configs for informational, progress, and success modals
|
|
874
|
+
*/
|
|
875
|
+
getDefaultConfig() {
|
|
876
|
+
const themeBasedConfig = this.mapThemeToModalConfig(this.themeConfig);
|
|
877
|
+
const informational = this.deepMerge(defaultInformationalModalConfig.options, themeBasedConfig);
|
|
878
|
+
const progress = this.deepMerge(defaultProgressModalConfig.options, themeBasedConfig);
|
|
879
|
+
const successBase = this.deepMerge(defaultSuccessModalConfig.options, themeBasedConfig);
|
|
880
|
+
return {
|
|
881
|
+
informational,
|
|
882
|
+
progress,
|
|
883
|
+
success: Object.assign(Object.assign({}, successBase), { duration: defaultSuccessModalConfig.options.duration }),
|
|
884
|
+
};
|
|
885
|
+
}
|
|
886
|
+
/**
|
|
887
|
+
* Updates the current theme configuration
|
|
888
|
+
* @param theme - Partial theme configuration to merge with current theme
|
|
889
|
+
*/
|
|
890
|
+
setTheme(theme) {
|
|
891
|
+
this.themeConfig = this.deepMerge(defaultTheme, theme);
|
|
892
|
+
}
|
|
893
|
+
/**
|
|
894
|
+
* Retrieves current theme configuration
|
|
895
|
+
* @returns Deep clone of current theme configuration
|
|
896
|
+
*/
|
|
897
|
+
getTheme() {
|
|
898
|
+
return this.deepClone(this.themeConfig);
|
|
899
|
+
}
|
|
900
|
+
/**
|
|
901
|
+
* Updates common modal configuration applied to all modal types
|
|
902
|
+
* @param config - Partial configuration to merge with current common config
|
|
903
|
+
*/
|
|
904
|
+
setCommonModalConfig(config) {
|
|
905
|
+
this.commonModalConfig = this.deepMerge(this.commonModalConfig, config);
|
|
906
|
+
}
|
|
907
|
+
/**
|
|
908
|
+
* Updates informational sign-in modal configuration
|
|
909
|
+
* @param config - Partial configuration to merge with current informational config
|
|
910
|
+
*/
|
|
911
|
+
setInformationalSignInModalConfig(config) {
|
|
912
|
+
this.informationalModalConfig = this.deepMerge(this.informationalModalConfig, config);
|
|
913
|
+
}
|
|
914
|
+
/**
|
|
915
|
+
* Updates progress sign-in modal configuration
|
|
916
|
+
* @param config - Partial configuration to merge with current progress config
|
|
917
|
+
*/
|
|
918
|
+
setProgressSignInModalConfig(config) {
|
|
919
|
+
this.progressModalConfig = this.deepMerge(this.progressModalConfig, config);
|
|
920
|
+
}
|
|
921
|
+
/**
|
|
922
|
+
* Updates success sign-in modal configuration
|
|
923
|
+
* @param config - Partial configuration to merge with current success config
|
|
924
|
+
*/
|
|
925
|
+
setSuccessSignInModalConfig(config) {
|
|
926
|
+
this.successModalConfig = this.deepMerge(this.successModalConfig, config);
|
|
927
|
+
}
|
|
928
|
+
/**
|
|
929
|
+
* Retrieves complete configuration for informational sign-in modal
|
|
930
|
+
* Combines default, theme-based, common, and specific configurations
|
|
931
|
+
* @returns Complete informational modal configuration
|
|
932
|
+
*/
|
|
933
|
+
getInformationalSignInModalConfig() {
|
|
934
|
+
const themeBasedConfig = this.mapThemeToModalConfig(this.themeConfig);
|
|
935
|
+
return this.deepMerge(defaultInformationalModalConfig.options, themeBasedConfig, this.commonModalConfig, this.informationalModalConfig);
|
|
936
|
+
}
|
|
937
|
+
/**
|
|
938
|
+
* Retrieves complete configuration for progress sign-in modal
|
|
939
|
+
* Combines default, theme-based, common, and specific configurations
|
|
940
|
+
* @returns Complete progress modal configuration
|
|
941
|
+
*/
|
|
942
|
+
getProgressSignInModalConfig() {
|
|
943
|
+
const themeBasedConfig = this.mapThemeToModalConfig(this.themeConfig);
|
|
944
|
+
return this.deepMerge(defaultProgressModalConfig.options, themeBasedConfig, this.commonModalConfig, this.progressModalConfig);
|
|
945
|
+
}
|
|
946
|
+
/**
|
|
947
|
+
* Retrieves complete configuration for success sign-in modal
|
|
948
|
+
* Combines default, theme-based, common, and specific configurations
|
|
949
|
+
* @returns Complete success modal configuration
|
|
950
|
+
*/
|
|
951
|
+
getSuccessSignInModalConfig() {
|
|
952
|
+
const themeBasedConfig = this.mapThemeToModalConfig(this.themeConfig);
|
|
953
|
+
const baseConfig = this.deepMerge(defaultSuccessModalConfig.options, themeBasedConfig, this.commonModalConfig, this.successModalConfig);
|
|
954
|
+
return Object.assign(Object.assign({}, baseConfig), { duration: this.successModalConfig.duration });
|
|
955
|
+
}
|
|
956
|
+
}
|
|
957
|
+
|
|
958
|
+
/**
|
|
959
|
+
* A class that manages the display of snackbar notifications with customizable styling and animations
|
|
960
|
+
*/
|
|
961
|
+
class VizbeeSnackbar {
|
|
962
|
+
/**
|
|
963
|
+
* Creates a new instance of VizbeeSnackbar
|
|
964
|
+
*/
|
|
965
|
+
constructor() {
|
|
966
|
+
this.BASE_DIMENSIONS = {
|
|
967
|
+
REFERENCE_WIDTH: 1920,
|
|
968
|
+
REFERENCE_HEIGHT: 1080,
|
|
969
|
+
WIDTH: 720,
|
|
970
|
+
PADDING: 20,
|
|
971
|
+
BORDER_RADIUS: 20,
|
|
972
|
+
BORDER_WIDTH: 2,
|
|
973
|
+
MARGIN: 32,
|
|
974
|
+
ICON_SIZE: 40,
|
|
975
|
+
ICON_MARGIN: 12,
|
|
976
|
+
TITLE_FONT_SIZE: 32,
|
|
977
|
+
MESSAGE_FONT_SIZE: 28,
|
|
978
|
+
};
|
|
979
|
+
this.uiManager = VizbeeHomeSSOUIManager.getInstance();
|
|
980
|
+
this.setupContainer();
|
|
981
|
+
}
|
|
982
|
+
/**
|
|
983
|
+
* Shows the snackbar with the specified options
|
|
984
|
+
*/
|
|
985
|
+
show(options) {
|
|
986
|
+
this.hide();
|
|
987
|
+
clearTimeout(this.showSnackbarTimerId);
|
|
988
|
+
this.showSnackbarTimerId = window.setTimeout(() => {
|
|
989
|
+
this.createSnackbar(options);
|
|
990
|
+
if (this.currentSnackbar) {
|
|
991
|
+
this.currentSnackbar.style.transform =
|
|
992
|
+
this.getSlideTransform('top-right');
|
|
993
|
+
}
|
|
994
|
+
if (options === null || options === void 0 ? void 0 : options.shouldAnimateIcon) {
|
|
995
|
+
this.startIconAnimation(options.iconBase64Strings);
|
|
996
|
+
}
|
|
997
|
+
if ((options === null || options === void 0 ? void 0 : options.duration) && options.duration > 0) {
|
|
998
|
+
this.timeoutId = window.setTimeout(() => this.hide(), options.duration);
|
|
999
|
+
}
|
|
1000
|
+
}, 1000);
|
|
1001
|
+
}
|
|
1002
|
+
/**
|
|
1003
|
+
* Hides the currently displayed snackbar
|
|
1004
|
+
*/
|
|
1005
|
+
hide() {
|
|
1006
|
+
this.stopIconAnimation();
|
|
1007
|
+
if (this.timeoutId) {
|
|
1008
|
+
clearTimeout(this.timeoutId);
|
|
1009
|
+
this.timeoutId = undefined;
|
|
1010
|
+
}
|
|
1011
|
+
if (this.currentSnackbar) {
|
|
1012
|
+
this.currentSnackbar.style.transform = this.getSlideTransform('bottom-right', true);
|
|
1013
|
+
this.currentSnackbar.style.opacity = '0';
|
|
1014
|
+
setTimeout(() => {
|
|
1015
|
+
var _a;
|
|
1016
|
+
if (((_a = this.currentSnackbar) === null || _a === void 0 ? void 0 : _a.parentNode) === this.container) {
|
|
1017
|
+
this.container.removeChild(this.currentSnackbar);
|
|
1018
|
+
}
|
|
1019
|
+
this.currentSnackbar = undefined;
|
|
1020
|
+
}, 300);
|
|
1021
|
+
}
|
|
1022
|
+
}
|
|
1023
|
+
getScreenScale() {
|
|
1024
|
+
const width = window.innerWidth;
|
|
1025
|
+
return width / this.BASE_DIMENSIONS.REFERENCE_WIDTH;
|
|
1026
|
+
}
|
|
1027
|
+
scaleValue(value) {
|
|
1028
|
+
return Math.round(value * this.getScreenScale());
|
|
1029
|
+
}
|
|
1030
|
+
setupContainer() {
|
|
1031
|
+
this.container = document.createElement('div');
|
|
1032
|
+
this.container.style.cssText = `
|
|
1033
|
+
position: fixed;
|
|
1034
|
+
z-index: 9999;
|
|
1035
|
+
pointer-events: none;
|
|
1036
|
+
width: 100%;
|
|
1037
|
+
height: 100%;
|
|
1038
|
+
top: 0;
|
|
1039
|
+
left: 0;
|
|
1040
|
+
`;
|
|
1041
|
+
document.body.appendChild(this.container);
|
|
1042
|
+
}
|
|
1043
|
+
getSlideTransform(position, hide = false) {
|
|
1044
|
+
const transformValue = '150%';
|
|
1045
|
+
const isTop = position.includes('top');
|
|
1046
|
+
return `translateY(${(hide === isTop ? '-' : '') + transformValue})`;
|
|
1047
|
+
}
|
|
1048
|
+
getPositionStyles(position, edgeMargin) {
|
|
1049
|
+
const margin = edgeMargin || this.scaleValue(this.BASE_DIMENSIONS.MARGIN) + 'px';
|
|
1050
|
+
const positions = {
|
|
1051
|
+
'top-right': `top: ${margin}; right: ${margin};`,
|
|
1052
|
+
'top-left': `top: ${margin}; left: ${margin};`,
|
|
1053
|
+
'bottom-right': `bottom: ${margin}; right: ${margin};`,
|
|
1054
|
+
'bottom-left': `bottom: ${margin}; left: ${margin};`,
|
|
1055
|
+
};
|
|
1056
|
+
return positions[position];
|
|
1057
|
+
}
|
|
1058
|
+
startIconAnimation(iconBase64Strings) {
|
|
1059
|
+
if (this.animationInterval) {
|
|
1060
|
+
clearInterval(this.animationInterval);
|
|
1061
|
+
}
|
|
1062
|
+
if (!iconBase64Strings || iconBase64Strings.length === 0) {
|
|
1063
|
+
return;
|
|
1064
|
+
}
|
|
1065
|
+
let currentIndex = 0;
|
|
1066
|
+
this.animationInterval = window.setInterval(() => {
|
|
1067
|
+
if (this.currentIconElement) {
|
|
1068
|
+
currentIndex = (currentIndex + 1) % iconBase64Strings.length;
|
|
1069
|
+
this.currentIconElement.src = iconBase64Strings[currentIndex];
|
|
1070
|
+
}
|
|
1071
|
+
}, 500);
|
|
1072
|
+
}
|
|
1073
|
+
stopIconAnimation() {
|
|
1074
|
+
if (this.animationInterval) {
|
|
1075
|
+
clearInterval(this.animationInterval);
|
|
1076
|
+
this.animationInterval = undefined;
|
|
1077
|
+
}
|
|
1078
|
+
}
|
|
1079
|
+
/**
|
|
1080
|
+
* Whether the snackbar should render right-to-left.
|
|
1081
|
+
* Defaults to LTR when no direction is provided.
|
|
1082
|
+
*/
|
|
1083
|
+
isRtl(options) {
|
|
1084
|
+
return ((options === null || options === void 0 ? void 0 : options.direction) || 'ltr') === 'rtl';
|
|
1085
|
+
}
|
|
1086
|
+
createSnackbar(options) {
|
|
1087
|
+
const snackbar = document.createElement('div');
|
|
1088
|
+
snackbar.style.cssText = this.getSnackbarStyles(options);
|
|
1089
|
+
const isRtl = this.isRtl(options);
|
|
1090
|
+
const contentWrapper = this.createContentWrapper(isRtl);
|
|
1091
|
+
const iconBase64 = options === null || options === void 0 ? void 0 : options.iconBase64String;
|
|
1092
|
+
if (iconBase64) {
|
|
1093
|
+
const iconWrapper = this.createIconWrapper(iconBase64, options.iconWidth, options.iconHeight, options.iconMarginRight, isRtl);
|
|
1094
|
+
contentWrapper.appendChild(iconWrapper);
|
|
1095
|
+
}
|
|
1096
|
+
const textWrapper = this.createTextWrapper(options);
|
|
1097
|
+
contentWrapper.appendChild(textWrapper);
|
|
1098
|
+
snackbar.appendChild(contentWrapper);
|
|
1099
|
+
this.container.appendChild(snackbar);
|
|
1100
|
+
this.currentSnackbar = snackbar;
|
|
1101
|
+
requestAnimationFrame(() => {
|
|
1102
|
+
snackbar.style.opacity = '1';
|
|
1103
|
+
snackbar.style.transform = 'translateY(0)';
|
|
1104
|
+
});
|
|
1105
|
+
}
|
|
1106
|
+
getSnackbarStyles(options) {
|
|
1107
|
+
var _a;
|
|
1108
|
+
const theme = this.uiManager.getTheme();
|
|
1109
|
+
const borderColor = (options === null || options === void 0 ? void 0 : options.borderColor) || theme.primaryColor;
|
|
1110
|
+
const borderWidth = (options === null || options === void 0 ? void 0 : options.borderWidth) ||
|
|
1111
|
+
this.scaleValue(this.BASE_DIMENSIONS.BORDER_WIDTH) + 'px';
|
|
1112
|
+
const boxShadow = (options === null || options === void 0 ? void 0 : options.boxShadow) ||
|
|
1113
|
+
`0 ${this.scaleValue(2)}px ${this.scaleValue(8)}px rgba(0, 0, 0, 0.4)`;
|
|
1114
|
+
const padding = (options === null || options === void 0 ? void 0 : options.padding) || this.scaleValue(this.BASE_DIMENSIONS.PADDING) + 'px';
|
|
1115
|
+
const borderRadius = (options === null || options === void 0 ? void 0 : options.borderRadius) ||
|
|
1116
|
+
this.scaleValue(this.BASE_DIMENSIONS.BORDER_RADIUS) + 'px';
|
|
1117
|
+
return `
|
|
1118
|
+
position: absolute;
|
|
1119
|
+
display: flex;
|
|
1120
|
+
background: ${(options === null || options === void 0 ? void 0 : options.backgroundColor) || 'rgba(0, 0, 0, 0.75)'};
|
|
1121
|
+
color: white;
|
|
1122
|
+
width: ${(options === null || options === void 0 ? void 0 : options.width) || this.scaleValue(this.BASE_DIMENSIONS.WIDTH) + 'px'};
|
|
1123
|
+
${(options === null || options === void 0 ? void 0 : options.height) ? `height: ${options.height};` : ''}
|
|
1124
|
+
${(options === null || options === void 0 ? void 0 : options.minHeight) ? `min-height: ${options.minHeight};` : ''}
|
|
1125
|
+
padding: ${padding};
|
|
1126
|
+
border-radius: ${borderRadius};
|
|
1127
|
+
border: ${borderWidth} solid ${borderColor};
|
|
1128
|
+
box-shadow: ${boxShadow};
|
|
1129
|
+
font-family: ${theme.primaryFont || '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif'};
|
|
1130
|
+
pointer-events: auto;
|
|
1131
|
+
transition: all 0.3s ease;
|
|
1132
|
+
opacity: 0;
|
|
1133
|
+
margin-top: ${(options === null || options === void 0 ? void 0 : options.marginTop) || '0'};
|
|
1134
|
+
margin-right: ${(options === null || options === void 0 ? void 0 : options.marginRight) || '0'};
|
|
1135
|
+
margin-bottom: ${(options === null || options === void 0 ? void 0 : options.marginBottom) || '0'};
|
|
1136
|
+
margin-left: ${(options === null || options === void 0 ? void 0 : options.marginLeft) || '0'};
|
|
1137
|
+
${this.getPositionStyles((options === null || options === void 0 ? void 0 : options.position) || 'bottom-right', options === null || options === void 0 ? void 0 : options.edgeMargin)}
|
|
1138
|
+
transform: translateY(${((_a = options === null || options === void 0 ? void 0 : options.position) === null || _a === void 0 ? void 0 : _a.includes('top')) ? '-150%' : '150%'});
|
|
1139
|
+
`;
|
|
1140
|
+
}
|
|
1141
|
+
createContentWrapper(isRtl = false) {
|
|
1142
|
+
const wrapper = document.createElement('div');
|
|
1143
|
+
// `row-reverse` places the icon on the trailing (right) side for RTL.
|
|
1144
|
+
// Using an explicit flex-direction keeps ordering deterministic across TV
|
|
1145
|
+
// browsers rather than relying on `direction`-driven flex reordering.
|
|
1146
|
+
wrapper.style.cssText = `
|
|
1147
|
+
display: flex;
|
|
1148
|
+
flex-direction: ${isRtl ? 'row-reverse' : 'row'};
|
|
1149
|
+
align-items: flex-start;
|
|
1150
|
+
height: 100%;
|
|
1151
|
+
width: 100%;
|
|
1152
|
+
`;
|
|
1153
|
+
return wrapper;
|
|
1154
|
+
}
|
|
1155
|
+
createIconWrapper(iconBase64, width, height, marginRight, isRtl = false) {
|
|
1156
|
+
const wrapper = document.createElement('div');
|
|
1157
|
+
const iconSize = this.scaleValue(this.BASE_DIMENSIONS.ICON_SIZE);
|
|
1158
|
+
const iconGap = marginRight || this.scaleValue(this.BASE_DIMENSIONS.ICON_MARGIN) + 'px';
|
|
1159
|
+
// The gap always sits between the icon and the text. In RTL the icon is on
|
|
1160
|
+
// the right (row-reverse), so the gap belongs on its left instead.
|
|
1161
|
+
const iconGapSide = isRtl ? 'margin-left' : 'margin-right';
|
|
1162
|
+
wrapper.style.cssText = `
|
|
1163
|
+
${iconGapSide}: ${iconGap};
|
|
1164
|
+
display: flex;
|
|
1165
|
+
align-items: flex-start;
|
|
1166
|
+
justify-content: center;
|
|
1167
|
+
min-width: ${width || iconSize + 'px'};
|
|
1168
|
+
width: ${width || iconSize + 'px'};
|
|
1169
|
+
height: ${height || iconSize + 'px'};
|
|
1170
|
+
color: white;
|
|
1171
|
+
margin-top: 0;
|
|
1172
|
+
`;
|
|
1173
|
+
const iconElement = document.createElement('img');
|
|
1174
|
+
iconElement.src = iconBase64;
|
|
1175
|
+
iconElement.style.cssText = `
|
|
1176
|
+
width: 100%;
|
|
1177
|
+
height: 100%;
|
|
1178
|
+
object-fit: contain;
|
|
1179
|
+
vertical-align: middle;
|
|
1180
|
+
`;
|
|
1181
|
+
this.currentIconElement = iconElement;
|
|
1182
|
+
wrapper.appendChild(iconElement);
|
|
1183
|
+
return wrapper;
|
|
1184
|
+
}
|
|
1185
|
+
createTextWrapper(options) {
|
|
1186
|
+
const isRtl = this.isRtl(options);
|
|
1187
|
+
const wrapper = document.createElement('div');
|
|
1188
|
+
// `direction` drives bidi text shaping; `text-align` aligns the title and
|
|
1189
|
+
// description to the leading edge. Both inherit to the child text elements.
|
|
1190
|
+
wrapper.style.cssText = `
|
|
1191
|
+
flex: 1;
|
|
1192
|
+
display: flex;
|
|
1193
|
+
flex-direction: column;
|
|
1194
|
+
justify-content: flex-start;
|
|
1195
|
+
direction: ${isRtl ? 'rtl' : 'ltr'};
|
|
1196
|
+
text-align: ${isRtl ? 'right' : 'left'};
|
|
1197
|
+
`;
|
|
1198
|
+
if (options === null || options === void 0 ? void 0 : options.titleText) {
|
|
1199
|
+
const titleElement = document.createElement('div');
|
|
1200
|
+
titleElement.style.cssText = `
|
|
1201
|
+
font-size: ${(options === null || options === void 0 ? void 0 : options.titleTextFontSize) || this.scaleValue(this.BASE_DIMENSIONS.TITLE_FONT_SIZE) + 'px'};
|
|
1202
|
+
font-family: ${(options === null || options === void 0 ? void 0 : options.titleTextFontFamily) || '-apple-system'};
|
|
1203
|
+
color: ${(options === null || options === void 0 ? void 0 : options.titleTextFontColor) || 'white'};
|
|
1204
|
+
font-weight: ${(options === null || options === void 0 ? void 0 : options.titleTextFontWeight) || '500'};
|
|
1205
|
+
margin-bottom: ${(options === null || options === void 0 ? void 0 : options.titleMarginBottom) || this.scaleValue(4) + 'px'};
|
|
1206
|
+
line-height: ${(options === null || options === void 0 ? void 0 : options.titleTextLineHeight) || '1.2'};
|
|
1207
|
+
`;
|
|
1208
|
+
titleElement.textContent = options.titleText;
|
|
1209
|
+
wrapper.appendChild(titleElement);
|
|
1210
|
+
}
|
|
1211
|
+
const messageElement = document.createElement('div');
|
|
1212
|
+
messageElement.style.cssText = `
|
|
1213
|
+
font-size: ${(options === null || options === void 0 ? void 0 : options.descriptionTextFontSize) ||
|
|
1214
|
+
this.scaleValue((options === null || options === void 0 ? void 0 : options.titleText)
|
|
1215
|
+
? this.BASE_DIMENSIONS.MESSAGE_FONT_SIZE
|
|
1216
|
+
: this.BASE_DIMENSIONS.TITLE_FONT_SIZE) + 'px'};
|
|
1217
|
+
font-family: ${(options === null || options === void 0 ? void 0 : options.descriptionTextFontFamily) || '-apple-system'};
|
|
1218
|
+
color: ${(options === null || options === void 0 ? void 0 : options.descriptionTextFontColor) || 'rgba(255, 255, 255, 0.9)'};
|
|
1219
|
+
font-weight: ${(options === null || options === void 0 ? void 0 : options.descriptionTextFontWeight) || 'normal'};
|
|
1220
|
+
line-height: ${(options === null || options === void 0 ? void 0 : options.descriptionTextLineHeight) || '1.3'};
|
|
1221
|
+
`;
|
|
1222
|
+
messageElement.textContent = options.descriptionText;
|
|
1223
|
+
wrapper.appendChild(messageElement);
|
|
1224
|
+
return wrapper;
|
|
1225
|
+
}
|
|
1226
|
+
}
|
|
1227
|
+
|
|
1228
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
1229
|
+
const LOG_TAG = 'VizbeeHomeSSOManager';
|
|
1230
|
+
/**
|
|
1231
|
+
* Manages Single Sign-On (SSO) functionality between mobile and TV devices in the Vizbee ecosystem.
|
|
1232
|
+
* Implements singleton pattern for global state management.
|
|
1233
|
+
*
|
|
1234
|
+
* @remarks
|
|
1235
|
+
* This class serves as the central manager for SSO operations, handling:
|
|
1236
|
+
* - Communication between mobile and TV devices
|
|
1237
|
+
* - Sign-in status management and updates
|
|
1238
|
+
* - UI state management
|
|
1239
|
+
* - Analytics and metrics tracking
|
|
1240
|
+
*
|
|
1241
|
+
* @class VizbeeHomeSSOManager
|
|
1242
|
+
* @public
|
|
1243
|
+
*/
|
|
1244
|
+
class VizbeeHomeSSOManager {
|
|
1245
|
+
/**
|
|
1246
|
+
* Private constructor to enforce singleton pattern
|
|
1247
|
+
* Initializes necessary components and sets up default handlers
|
|
1248
|
+
*
|
|
1249
|
+
* @internal
|
|
1250
|
+
*/
|
|
1251
|
+
constructor() {
|
|
1252
|
+
/** @internal List of sign-in information for different services */
|
|
1253
|
+
this.signInInfoList = [];
|
|
1254
|
+
/** @internal Tracks if remote device is signed in */
|
|
1255
|
+
this.isRemoteSignedIn = false;
|
|
1256
|
+
/** @internal Tracks if screen device is signed in */
|
|
1257
|
+
this.isScreenSignedIn = false;
|
|
1258
|
+
/** @internal Tracks if sign-in process is currently active */
|
|
1259
|
+
this.isSignInInProgress = false;
|
|
1260
|
+
/** @internal Information about the sender device */
|
|
1261
|
+
this.senderInfo = null;
|
|
1262
|
+
/**
|
|
1263
|
+
* Modal display preferences for the SSO UI
|
|
1264
|
+
* @public
|
|
1265
|
+
*/
|
|
1266
|
+
this.modalPreferences = {};
|
|
1267
|
+
this.vizbeeHomeSSOUIManager = VizbeeHomeSSOUIManager.getInstance();
|
|
1268
|
+
this.snackbar = new VizbeeSnackbar();
|
|
1269
|
+
this.vizbeeMetricsManager = new VizbeeMetricsManager();
|
|
1270
|
+
}
|
|
1271
|
+
/**
|
|
1272
|
+
* Gets the singleton instance of VizbeeHomeSSOManager
|
|
1273
|
+
* Creates a new instance if one doesn't exist
|
|
1274
|
+
*
|
|
1275
|
+
* @returns The singleton instance of the SSO manager
|
|
1276
|
+
* @public
|
|
1277
|
+
*/
|
|
1278
|
+
static getInstance() {
|
|
1279
|
+
if (!VizbeeHomeSSOManager.instance) {
|
|
1280
|
+
VizbeeHomeSSOManager.instance = new VizbeeHomeSSOManager();
|
|
1281
|
+
}
|
|
1282
|
+
return VizbeeHomeSSOManager.instance;
|
|
1283
|
+
}
|
|
1284
|
+
init() {
|
|
1285
|
+
this.initializeVizbeeSession();
|
|
1286
|
+
}
|
|
1287
|
+
/**
|
|
1288
|
+
* Sets up a handler for processing sign-in events from mobile devices
|
|
1289
|
+
*
|
|
1290
|
+
* @param handler - Callback function to process sign-in information and provide status updates
|
|
1291
|
+
* @public
|
|
1292
|
+
*/
|
|
1293
|
+
setSignInHandler(handler) {
|
|
1294
|
+
logger.debug(`[${LOG_TAG}][setSignInHandler] - setSignInHandler called`);
|
|
1295
|
+
if (!handler) {
|
|
1296
|
+
logger.error(`[${LOG_TAG}][setSignInHandler] - Error: Sign-in handler is missing`);
|
|
1297
|
+
return;
|
|
1298
|
+
}
|
|
1299
|
+
if (typeof handler !== 'function') {
|
|
1300
|
+
logger.error(`[${LOG_TAG}][setSignInHandler] - Error: Sign-in handler is not a function`);
|
|
1301
|
+
return;
|
|
1302
|
+
}
|
|
1303
|
+
logger.info(`[${LOG_TAG}][setSignInHandler] - Setting sign-in handler`);
|
|
1304
|
+
this.signInHandler = handler;
|
|
1305
|
+
}
|
|
1306
|
+
/**
|
|
1307
|
+
* Sets the callback for retrieving sign-in information
|
|
1308
|
+
*
|
|
1309
|
+
* @param getSignInInfo - Async callback that provides the list of sign-in information
|
|
1310
|
+
* @public
|
|
1311
|
+
*/
|
|
1312
|
+
setSignInInfoGetter(getSignInInfo) {
|
|
1313
|
+
if (!getSignInInfo) {
|
|
1314
|
+
logger.error(`[${LOG_TAG}][setSignInInfoGetter] - Error: GetSignInInfo callback is missing`);
|
|
1315
|
+
return;
|
|
1316
|
+
}
|
|
1317
|
+
if (typeof getSignInInfo !== 'function') {
|
|
1318
|
+
logger.error(`[${LOG_TAG}][setSignInInfoGetter] - Error: GetSignInInfo is not a function`);
|
|
1319
|
+
return;
|
|
1320
|
+
}
|
|
1321
|
+
if (!this.vizbeeMetricsManager) {
|
|
1322
|
+
logger.error(`[${LOG_TAG}][setSignInInfoGetter] - Error: Metrics manager is missing`);
|
|
1323
|
+
return;
|
|
1324
|
+
}
|
|
1325
|
+
if (!this.vizbeeMetricsManager.getSignInInfo) {
|
|
1326
|
+
logger.error(`[${LOG_TAG}][setSignInInfoGetter] - Error: GetAttributes callback is missing`);
|
|
1327
|
+
return;
|
|
1328
|
+
}
|
|
1329
|
+
this.vizbeeMetricsManager.getSignInInfo = getSignInInfo;
|
|
1330
|
+
}
|
|
1331
|
+
/**
|
|
1332
|
+
* Handles sign-in progress updates
|
|
1333
|
+
* Updates UI, sends status to mobile device, and logs metrics
|
|
1334
|
+
*
|
|
1335
|
+
* @param progressStatus - Current progress status of the sign-in process
|
|
1336
|
+
* @public
|
|
1337
|
+
*/
|
|
1338
|
+
onProgress(progressStatus) {
|
|
1339
|
+
logger.info(`[${LOG_TAG}][onProgress] - OnProgress is invoked`);
|
|
1340
|
+
this.isSignInInProgress = true;
|
|
1341
|
+
this.sendStatusToSender(progressStatus);
|
|
1342
|
+
this.updateProgressUI();
|
|
1343
|
+
this.vizbeeMetricsManager.log(VizbeeMetricsConstants.METRICS_EVENT_SCREEN_HOMESSO_SIGNIN_STATUS, {
|
|
1344
|
+
isScreenSignedIn: false,
|
|
1345
|
+
isRemoteSignedIn: this.isRemoteSignedIn,
|
|
1346
|
+
signInState: progressStatus.getState(),
|
|
1347
|
+
userId: null,
|
|
1348
|
+
signInType: progressStatus.signInType,
|
|
1349
|
+
});
|
|
1350
|
+
}
|
|
1351
|
+
/**
|
|
1352
|
+
* Handles successful sign-in completion
|
|
1353
|
+
* Updates UI, sends success status to mobile device, and logs metrics
|
|
1354
|
+
*
|
|
1355
|
+
* @param successStatus - Success status details
|
|
1356
|
+
* @public
|
|
1357
|
+
*/
|
|
1358
|
+
onSuccess(successStatus) {
|
|
1359
|
+
logger.info(`[${LOG_TAG}][onSuccess] - OnSuccess is invoked`);
|
|
1360
|
+
this.isSignInInProgress = false;
|
|
1361
|
+
this.isRemoteSignedIn = true;
|
|
1362
|
+
this.sendStatusToSender(successStatus);
|
|
1363
|
+
this.updateSuccessUI();
|
|
1364
|
+
this.vizbeeMetricsManager.log(VizbeeMetricsConstants.METRICS_EVENT_SCREEN_HOMESSO_SIGNIN_STATUS, {
|
|
1365
|
+
isScreenSignedIn: true,
|
|
1366
|
+
isRemoteSignedIn: this.isRemoteSignedIn,
|
|
1367
|
+
signInState: successStatus.getState(),
|
|
1368
|
+
userId: successStatus.userId,
|
|
1369
|
+
signInType: successStatus.signInType,
|
|
1370
|
+
});
|
|
1371
|
+
}
|
|
1372
|
+
/**
|
|
1373
|
+
* Handles sign-in failures
|
|
1374
|
+
* Updates UI and sends failure status to mobile device
|
|
1375
|
+
*
|
|
1376
|
+
* @param failureStatus - Failure status details
|
|
1377
|
+
* @public
|
|
1378
|
+
*/
|
|
1379
|
+
onFailure(failureStatus) {
|
|
1380
|
+
logger.info(`[${LOG_TAG}][onFailure] - OnFailure is invoked`);
|
|
1381
|
+
this.isSignInInProgress = false;
|
|
1382
|
+
this.sendStatusToSender(failureStatus);
|
|
1383
|
+
this.updateFailureUI();
|
|
1384
|
+
this.vizbeeMetricsManager.log(VizbeeMetricsConstants.METRICS_EVENT_SCREEN_HOMESSO_SIGNIN_STATUS, {
|
|
1385
|
+
isScreenSignedIn: false,
|
|
1386
|
+
isRemoteSignedIn: this.isRemoteSignedIn,
|
|
1387
|
+
signInState: failureStatus.getState(),
|
|
1388
|
+
userId: null,
|
|
1389
|
+
signInType: failureStatus.signInType,
|
|
1390
|
+
});
|
|
1391
|
+
}
|
|
1392
|
+
/**
|
|
1393
|
+
* Adds custom attributes for metrics tracking
|
|
1394
|
+
*
|
|
1395
|
+
* @param customEventAttributes - Dictionary of custom attributes to track
|
|
1396
|
+
* @public
|
|
1397
|
+
*/
|
|
1398
|
+
addCustomEventAttributes(customEventAttributes) {
|
|
1399
|
+
var _a;
|
|
1400
|
+
if (customEventAttributes) {
|
|
1401
|
+
(_a = this.vizbeeMetricsManager) === null || _a === void 0 ? void 0 : _a.setCustomAttributes(customEventAttributes);
|
|
1402
|
+
}
|
|
1403
|
+
}
|
|
1404
|
+
/**
|
|
1405
|
+
* Initializes Vizbee session and messaging client
|
|
1406
|
+
*
|
|
1407
|
+
* @throws Error if initialization fails
|
|
1408
|
+
* @internal
|
|
1409
|
+
*/
|
|
1410
|
+
initializeVizbeeSession() {
|
|
1411
|
+
var _a, _b;
|
|
1412
|
+
try {
|
|
1413
|
+
logger.info(`[${LOG_TAG}][initializeVizbeeSession] - Initializing Vizbee session`);
|
|
1414
|
+
// Check if vizbee and continuity exist before accessing xmessages
|
|
1415
|
+
if (!((_b = (_a = window.vizbee) === null || _a === void 0 ? void 0 : _a.continuity) === null || _b === void 0 ? void 0 : _b.xmessages)) {
|
|
1416
|
+
throw new Error('Vizbee continuity or xmessages not initialized');
|
|
1417
|
+
}
|
|
1418
|
+
// Access VizbeeBicastSessionManager directly from the existing object
|
|
1419
|
+
const sessionManager = new window.vizbee.continuity.xmessages.VizbeeBicastSessionManager();
|
|
1420
|
+
if (!sessionManager) {
|
|
1421
|
+
throw new Error('Session manager initialization failed');
|
|
1422
|
+
}
|
|
1423
|
+
// add sessionStateListener
|
|
1424
|
+
logger.debug(`[${LOG_TAG}]initializeVizbeeSession - Adding session state listener`);
|
|
1425
|
+
sessionManager.addSessionStateListener({
|
|
1426
|
+
onSessionStateChanged: (state) => {
|
|
1427
|
+
logger.info(`[${LOG_TAG}][onSessionStateChanged] - Session state changed:`, state);
|
|
1428
|
+
if (state === 3) {
|
|
1429
|
+
this.vizbeeSession = sessionManager.getSession();
|
|
1430
|
+
this.vizbeeMessagingClient =
|
|
1431
|
+
this.vizbeeSession.getMessagingClient();
|
|
1432
|
+
if (this.signInHandler) {
|
|
1433
|
+
logger.info(`[${LOG_TAG}][onSessionStateChanged] - Adding sign-in request receiver`);
|
|
1434
|
+
this.vizbeeMessagingClient.addReceiver(VizbeeConstants.EVENT_SSO_NAME, (payload, namespace, device) => __awaiter(this, void 0, void 0, function* () {
|
|
1435
|
+
logger.debug(`[${LOG_TAG}][onSessionStateChanged] - Received sign-in request on namespace:`, namespace);
|
|
1436
|
+
this.senderInfo = device;
|
|
1437
|
+
yield this.handleSignInRequest(payload, this.signInHandler);
|
|
1438
|
+
}));
|
|
1439
|
+
}
|
|
1440
|
+
else {
|
|
1441
|
+
logger.warn(`[${LOG_TAG}][onSessionStateChanged] - Error: Sign-in handler is missing`);
|
|
1442
|
+
}
|
|
1443
|
+
}
|
|
1444
|
+
},
|
|
1445
|
+
});
|
|
1446
|
+
}
|
|
1447
|
+
catch (error) {
|
|
1448
|
+
logger.warn(`[${LOG_TAG}][onSessionStateChanged] - Error initializing Vizbee session:`, error);
|
|
1449
|
+
throw error;
|
|
1450
|
+
}
|
|
1451
|
+
}
|
|
1452
|
+
/**
|
|
1453
|
+
* Processes incoming sign-in requests
|
|
1454
|
+
* Validates request and triggers appropriate handler
|
|
1455
|
+
*
|
|
1456
|
+
* @param payload - Sign-in request payload
|
|
1457
|
+
* @param handler - Callback to handle the sign-in request
|
|
1458
|
+
* @internal
|
|
1459
|
+
*/
|
|
1460
|
+
handleSignInRequest(payload, handler) {
|
|
1461
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
1462
|
+
var _a, _b;
|
|
1463
|
+
const senderSignInInfo = payload[VizbeeConstants.KEY_START_SIGN_IN_INFO];
|
|
1464
|
+
if (!senderSignInInfo) {
|
|
1465
|
+
logger.warn(`[${LOG_TAG}][handleSignInRequest] - Error: Sender info is missing`);
|
|
1466
|
+
return;
|
|
1467
|
+
}
|
|
1468
|
+
const signInType = senderSignInInfo[VizbeeConstants.KEY_SIGN_IN_TYPE];
|
|
1469
|
+
this.isScreenSignedIn = yield this.isUserAlreadySignedIn(signInType);
|
|
1470
|
+
this.isRemoteSignedIn = payload[VizbeeConstants.KEY_START_SIGN_IN_INFO][VizbeeConstants.KEY_IS_SIGNED_IN];
|
|
1471
|
+
this.vizbeeMetricsManager.log(VizbeeMetricsConstants.METRICS_EVENT_SCREEN_HOMESSO_SIGNIN_RECEIVED, {
|
|
1472
|
+
isScreenSignedIn: this.isScreenSignedIn,
|
|
1473
|
+
isRemoteSignedIn: this.isRemoteSignedIn,
|
|
1474
|
+
signInType: signInType,
|
|
1475
|
+
senderInfo: this.senderInfo,
|
|
1476
|
+
});
|
|
1477
|
+
if (yield this.shouldIgnoreSignInRequest()) {
|
|
1478
|
+
return;
|
|
1479
|
+
}
|
|
1480
|
+
const signInInfo = {
|
|
1481
|
+
isSignedIn: this.isRemoteSignedIn,
|
|
1482
|
+
signInType: signInType,
|
|
1483
|
+
deviceId: (_a = this.senderInfo) === null || _a === void 0 ? void 0 : _a.deviceId,
|
|
1484
|
+
deviceType: (_b = this.senderInfo) === null || _b === void 0 ? void 0 : _b.deviceType,
|
|
1485
|
+
customData: {},
|
|
1486
|
+
};
|
|
1487
|
+
handler(signInInfo, this.handleSignInStatus.bind(this));
|
|
1488
|
+
});
|
|
1489
|
+
}
|
|
1490
|
+
/**
|
|
1491
|
+
* Determines if a sign-in request should be ignored
|
|
1492
|
+
* Checks various conditions like existing sign-in state
|
|
1493
|
+
*
|
|
1494
|
+
* @returns Promise<boolean> indicating if request should be ignored
|
|
1495
|
+
* @internal
|
|
1496
|
+
*/
|
|
1497
|
+
shouldIgnoreSignInRequest() {
|
|
1498
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
1499
|
+
if (this.isScreenSignedIn) {
|
|
1500
|
+
logger.info(`[${LOG_TAG}][shouldIgnoreSignInRequest] - User is already signed in`);
|
|
1501
|
+
return true;
|
|
1502
|
+
}
|
|
1503
|
+
return false;
|
|
1504
|
+
});
|
|
1505
|
+
}
|
|
1506
|
+
/**
|
|
1507
|
+
* Checks if user is already signed in for a specific sign-in type
|
|
1508
|
+
*
|
|
1509
|
+
* @param signInType - Type of sign-in to check
|
|
1510
|
+
* @returns Promise<boolean> indicating if user is signed in
|
|
1511
|
+
* @internal
|
|
1512
|
+
*/
|
|
1513
|
+
isUserAlreadySignedIn(signInType) {
|
|
1514
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
1515
|
+
var _a, _b;
|
|
1516
|
+
try {
|
|
1517
|
+
const attributes = yield ((_b = (_a = this.vizbeeMetricsManager) === null || _a === void 0 ? void 0 : _a.getAttributes) === null || _b === void 0 ? void 0 : _b.call(_a));
|
|
1518
|
+
const signInInfoList = attributes === null || attributes === void 0 ? void 0 : attributes['SCREEN_HOMESSO_USER_INFO'];
|
|
1519
|
+
logger.info(`[${LOG_TAG}][isUserAlreadySignedIn] - signInInfoList`, signInInfoList);
|
|
1520
|
+
const tvSignInInfo = signInInfoList.find((info) => info.user_login_type === signInType);
|
|
1521
|
+
logger.debug(`[${LOG_TAG}][isUserAlreadySignedIn] - TV sign in status fetched:`, tvSignInInfo);
|
|
1522
|
+
return tvSignInInfo === null || tvSignInInfo === void 0 ? void 0 : tvSignInInfo.user_is_signed_in;
|
|
1523
|
+
}
|
|
1524
|
+
catch (error) {
|
|
1525
|
+
logger.warn(`[${LOG_TAG}][isUserAlreadySignedIn] - Error checking sign-in status:`, error);
|
|
1526
|
+
return false;
|
|
1527
|
+
}
|
|
1528
|
+
});
|
|
1529
|
+
}
|
|
1530
|
+
/**
|
|
1531
|
+
* Handles sign-in status updates
|
|
1532
|
+
* Routes status updates to appropriate handlers
|
|
1533
|
+
*
|
|
1534
|
+
* @param status - Current status of the sign-in process
|
|
1535
|
+
* @internal
|
|
1536
|
+
*/
|
|
1537
|
+
handleSignInStatus(status) {
|
|
1538
|
+
var _a, _b;
|
|
1539
|
+
if (status instanceof ProgressStatus) {
|
|
1540
|
+
const regcode = (_a = status.customData) === null || _a === void 0 ? void 0 : _a.regcode;
|
|
1541
|
+
if (regcode) {
|
|
1542
|
+
this.onProgress(status);
|
|
1543
|
+
}
|
|
1544
|
+
}
|
|
1545
|
+
else if (status instanceof SuccessStatus) {
|
|
1546
|
+
const userEmail = (_b = status.customData) === null || _b === void 0 ? void 0 : _b.email;
|
|
1547
|
+
if (userEmail) {
|
|
1548
|
+
this.onSuccess(status);
|
|
1549
|
+
}
|
|
1550
|
+
}
|
|
1551
|
+
else if (status instanceof FailureStatus) {
|
|
1552
|
+
this.onFailure(status);
|
|
1553
|
+
}
|
|
1554
|
+
}
|
|
1555
|
+
/**
|
|
1556
|
+
* Sends status updates to mobile device
|
|
1557
|
+
*
|
|
1558
|
+
* @param status - Status to send to mobile device
|
|
1559
|
+
* @internal
|
|
1560
|
+
*/
|
|
1561
|
+
sendStatusToSender(status) {
|
|
1562
|
+
const signInStatus = this.serializeStatus(status);
|
|
1563
|
+
const data = {
|
|
1564
|
+
[VizbeeConstants.KEY_SUB_TYPE]: VizbeeConstants.EVENT_SUBTYPE_SIGN_IN_STATUS,
|
|
1565
|
+
[VizbeeConstants.KEY_SIGN_IN_STATUS]: signInStatus,
|
|
1566
|
+
};
|
|
1567
|
+
this.vizbeeMessagingClient.send(data, VizbeeConstants.EVENT_SSO_NAME);
|
|
1568
|
+
}
|
|
1569
|
+
/**
|
|
1570
|
+
* Serializes status objects for transmission to mobile device
|
|
1571
|
+
*
|
|
1572
|
+
* @param status - Status object to serialize
|
|
1573
|
+
* @returns Serialized status object or null if invalid status type
|
|
1574
|
+
* @internal
|
|
1575
|
+
*/
|
|
1576
|
+
serializeStatus(status) {
|
|
1577
|
+
if (status instanceof ProgressStatus) {
|
|
1578
|
+
return status.serialize();
|
|
1579
|
+
}
|
|
1580
|
+
else if (status instanceof SuccessStatus) {
|
|
1581
|
+
return status.serialize();
|
|
1582
|
+
}
|
|
1583
|
+
else if (status instanceof FailureStatus) {
|
|
1584
|
+
return status.serialize();
|
|
1585
|
+
}
|
|
1586
|
+
return null;
|
|
1587
|
+
}
|
|
1588
|
+
/**
|
|
1589
|
+
* Updates UI for sign-in progress state
|
|
1590
|
+
* Shows appropriate modal based on remote sign-in status
|
|
1591
|
+
*
|
|
1592
|
+
* @internal
|
|
1593
|
+
*/
|
|
1594
|
+
updateProgressUI() {
|
|
1595
|
+
if (!this.isRemoteSignedIn) {
|
|
1596
|
+
const modalOptions = this.vizbeeHomeSSOUIManager.getInformationalSignInModalConfig();
|
|
1597
|
+
this.snackbar.show(modalOptions);
|
|
1598
|
+
}
|
|
1599
|
+
else {
|
|
1600
|
+
const modalOptions = this.vizbeeHomeSSOUIManager.getProgressSignInModalConfig();
|
|
1601
|
+
this.snackbar.show(Object.assign(Object.assign({}, modalOptions), { shouldAnimateIcon: true }));
|
|
1602
|
+
}
|
|
1603
|
+
}
|
|
1604
|
+
/**
|
|
1605
|
+
* Updates UI for successful sign-in
|
|
1606
|
+
* Shows success modal with appropriate message
|
|
1607
|
+
*
|
|
1608
|
+
* @internal
|
|
1609
|
+
*/
|
|
1610
|
+
updateSuccessUI() {
|
|
1611
|
+
// Enforce only the success duration; leave title/description to the
|
|
1612
|
+
// integrator's config (or the defaults) so the success toast can be
|
|
1613
|
+
// themed/localized like the informational and progress modals.
|
|
1614
|
+
this.vizbeeHomeSSOUIManager.setSuccessSignInModalConfig({ duration: 10000 });
|
|
1615
|
+
const modalOptions = this.vizbeeHomeSSOUIManager.getSuccessSignInModalConfig();
|
|
1616
|
+
this.snackbar.show(modalOptions);
|
|
1617
|
+
}
|
|
1618
|
+
/**
|
|
1619
|
+
* Updates UI for failed sign-in
|
|
1620
|
+
* Hides any active modals
|
|
1621
|
+
*
|
|
1622
|
+
* @internal
|
|
1623
|
+
*/
|
|
1624
|
+
updateFailureUI() {
|
|
1625
|
+
this.snackbar.hide();
|
|
1626
|
+
}
|
|
1627
|
+
}
|
|
1628
|
+
/** @internal Singleton instance of the manager */
|
|
1629
|
+
VizbeeHomeSSOManager.instance = null;
|
|
1630
|
+
|
|
1631
|
+
const UNKNOWN_VALUE = 'UNKNOWN';
|
|
1632
|
+
|
|
1633
|
+
/**
|
|
1634
|
+
* @class HomeSSOContext
|
|
1635
|
+
* @description Context provider for Vizbee Home SSO functionality
|
|
1636
|
+
*/
|
|
1637
|
+
class HomeSSOContext {
|
|
1638
|
+
constructor() {
|
|
1639
|
+
this.homeSSOUIManager = null;
|
|
1640
|
+
}
|
|
1641
|
+
/**
|
|
1642
|
+
* Gets the singleton instance of HomeSSOContext
|
|
1643
|
+
* @returns The singleton instance of HomeSSOContext
|
|
1644
|
+
*/
|
|
1645
|
+
static getInstance() {
|
|
1646
|
+
if (!HomeSSOContext.instance) {
|
|
1647
|
+
HomeSSOContext.instance = new HomeSSOContext();
|
|
1648
|
+
}
|
|
1649
|
+
return HomeSSOContext.instance;
|
|
1650
|
+
}
|
|
1651
|
+
/**
|
|
1652
|
+
* Gets the HomeSSOManager instance
|
|
1653
|
+
* @returns The singleton instance of VizbeeHomeSSOManager
|
|
1654
|
+
*/
|
|
1655
|
+
getHomeSSOManager() {
|
|
1656
|
+
return VizbeeHomeSSOManager.getInstance();
|
|
1657
|
+
}
|
|
1658
|
+
/**
|
|
1659
|
+
* Gets the HomeSSOUIManager instance
|
|
1660
|
+
* @param config Optional UI configuration including theme settings
|
|
1661
|
+
* @returns The singleton instance of VizbeeHomeSSOUIManager
|
|
1662
|
+
*/
|
|
1663
|
+
getHomeSSOUIManager() {
|
|
1664
|
+
return VizbeeHomeSSOUIManager.getInstance();
|
|
1665
|
+
}
|
|
1666
|
+
enableLogger(enable) {
|
|
1667
|
+
logger.setConfig({
|
|
1668
|
+
enabled: enable,
|
|
1669
|
+
});
|
|
1670
|
+
}
|
|
1671
|
+
setLoggerLevel(level) {
|
|
1672
|
+
logger.setConfig({
|
|
1673
|
+
enabled: true,
|
|
1674
|
+
level: level,
|
|
1675
|
+
});
|
|
1676
|
+
}
|
|
1677
|
+
}
|
|
1678
|
+
HomeSSOContext.instance = null;
|
|
1679
|
+
const init = () => {
|
|
1680
|
+
// Initialize the global namespace
|
|
1681
|
+
if (typeof window !== 'undefined') {
|
|
1682
|
+
if (!window.vizbee) {
|
|
1683
|
+
window.addEventListener('VIZBEE_SDK_READY', () => {
|
|
1684
|
+
if (window.vizbee) {
|
|
1685
|
+
setupHomeSSO();
|
|
1686
|
+
}
|
|
1687
|
+
});
|
|
1688
|
+
}
|
|
1689
|
+
else {
|
|
1690
|
+
setupHomeSSO();
|
|
1691
|
+
}
|
|
1692
|
+
}
|
|
1693
|
+
};
|
|
1694
|
+
const setupHomeSSO = () => {
|
|
1695
|
+
window.vizbee.homesso = {
|
|
1696
|
+
HomeSSOContext: HomeSSOContext,
|
|
1697
|
+
messages: {
|
|
1698
|
+
ProgressStatus,
|
|
1699
|
+
SuccessStatus,
|
|
1700
|
+
FailureStatus,
|
|
1701
|
+
},
|
|
1702
|
+
LoggerLevel: LogLevel,
|
|
1703
|
+
// Replaced at build time with package.json's version by
|
|
1704
|
+
// @rollup/plugin-replace (same token the metrics manager uses), so
|
|
1705
|
+
// integrators can read the loaded SDK version off the namespace.
|
|
1706
|
+
VERSION: '1.0.1',
|
|
1707
|
+
};
|
|
1708
|
+
window.dispatchEvent(new Event('VIZBEE_HOMESSO_READY'));
|
|
1709
|
+
};
|
|
1710
|
+
init();
|
|
1711
|
+
|
|
1712
|
+
export { FailureStatus, HomeSSOContext, LogLevel, ProgressStatus, SuccessStatus, UNKNOWN_VALUE, VizbeeHomeSSOManager, VizbeeHomeSSOUIManager };
|