@product7/feedback-sdk 1.2.8 → 1.3.0
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/dist/feedback-sdk.js +1530 -1861
- package/dist/feedback-sdk.js.map +1 -1
- package/dist/feedback-sdk.min.js +1 -1
- package/dist/feedback-sdk.min.js.map +1 -1
- package/package.json +1 -1
- package/src/api/mock-data/index.js +202 -0
- package/src/api/services/ChangelogService.js +28 -0
- package/src/api/services/FeedbackService.js +44 -0
- package/src/api/services/HelpService.js +50 -0
- package/src/api/services/MessengerService.js +197 -0
- package/src/api/services/SurveyService.js +99 -0
- package/src/api/utils/helpers.js +30 -0
- package/src/core/APIService.js +40 -1142
- package/src/core/BaseAPIService.js +245 -0
- package/src/core/FeedbackSDK.js +0 -68
- package/src/styles/base.js +75 -0
- package/src/styles/changelog.js +698 -0
- package/src/styles/feedback.js +574 -0
- package/src/styles/styles.js +5 -1379
- package/src/widgets/MessengerWidget.js +1 -2
- package/src/widgets/messenger/components/MessengerLauncher.js +7 -7
- package/src/widgets/messenger/components/NavigationTabs.js +16 -4
- package/src/widgets/messenger/views/ChangelogView.js +9 -9
- package/src/widgets/messenger/views/ChatView.js +9 -20
- package/src/widgets/messenger/views/ConversationsView.js +9 -13
- package/src/widgets/messenger/views/HelpView.js +15 -14
- package/src/widgets/messenger/views/HomeView.js +6 -15
package/dist/feedback-sdk.js
CHANGED
|
@@ -4,91 +4,6 @@
|
|
|
4
4
|
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.FeedbackSDK = {}));
|
|
5
5
|
})(this, (function (exports) { 'use strict';
|
|
6
6
|
|
|
7
|
-
class SDKError extends Error {
|
|
8
|
-
constructor(message, cause) {
|
|
9
|
-
super(message);
|
|
10
|
-
this.name = 'SDKError';
|
|
11
|
-
this.cause = cause;
|
|
12
|
-
|
|
13
|
-
if (Error.captureStackTrace) {
|
|
14
|
-
Error.captureStackTrace(this, SDKError);
|
|
15
|
-
}
|
|
16
|
-
}
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
class APIError extends Error {
|
|
20
|
-
constructor(status, message, response) {
|
|
21
|
-
super(message);
|
|
22
|
-
this.name = 'APIError';
|
|
23
|
-
this.status = status;
|
|
24
|
-
this.response = response;
|
|
25
|
-
|
|
26
|
-
if (Error.captureStackTrace) {
|
|
27
|
-
Error.captureStackTrace(this, APIError);
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
isNetworkError() {
|
|
32
|
-
return this.status === 0;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
isClientError() {
|
|
36
|
-
return this.status >= 400 && this.status < 500;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
isServerError() {
|
|
40
|
-
return this.status >= 500 && this.status < 600;
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
class WidgetError extends Error {
|
|
45
|
-
constructor(message, widgetType, widgetId) {
|
|
46
|
-
super(message);
|
|
47
|
-
this.name = 'WidgetError';
|
|
48
|
-
this.widgetType = widgetType;
|
|
49
|
-
this.widgetId = widgetId;
|
|
50
|
-
|
|
51
|
-
if (Error.captureStackTrace) {
|
|
52
|
-
Error.captureStackTrace(this, WidgetError);
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
class ConfigError extends Error {
|
|
58
|
-
constructor(message, configKey) {
|
|
59
|
-
super(message);
|
|
60
|
-
this.name = 'ConfigError';
|
|
61
|
-
this.configKey = configKey;
|
|
62
|
-
|
|
63
|
-
if (Error.captureStackTrace) {
|
|
64
|
-
Error.captureStackTrace(this, ConfigError);
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
class ValidationError extends Error {
|
|
70
|
-
constructor(message, field, value) {
|
|
71
|
-
super(message);
|
|
72
|
-
this.name = 'ValidationError';
|
|
73
|
-
this.field = field;
|
|
74
|
-
this.value = value;
|
|
75
|
-
|
|
76
|
-
if (Error.captureStackTrace) {
|
|
77
|
-
Error.captureStackTrace(this, ValidationError);
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
const MOCK_CONFIG = {
|
|
83
|
-
primaryColor: '#21244A',
|
|
84
|
-
backgroundColor: '#ffffff',
|
|
85
|
-
textColor: '#1F2937',
|
|
86
|
-
boardId: 'feature-requests',
|
|
87
|
-
size: 'medium',
|
|
88
|
-
displayMode: 'modal',
|
|
89
|
-
};
|
|
90
|
-
|
|
91
|
-
// Mock changelogs for development
|
|
92
7
|
const MOCK_CHANGELOGS = [
|
|
93
8
|
{
|
|
94
9
|
id: 'changelog_1',
|
|
@@ -139,7 +54,6 @@
|
|
|
139
54
|
},
|
|
140
55
|
];
|
|
141
56
|
|
|
142
|
-
// Mock conversations for development
|
|
143
57
|
const MOCK_CONVERSATIONS = [
|
|
144
58
|
{
|
|
145
59
|
id: 'conv_1',
|
|
@@ -171,7 +85,6 @@
|
|
|
171
85
|
},
|
|
172
86
|
];
|
|
173
87
|
|
|
174
|
-
// Mock messages for development
|
|
175
88
|
const MOCK_MESSAGES = {
|
|
176
89
|
conv_1: [
|
|
177
90
|
{
|
|
@@ -218,7 +131,6 @@
|
|
|
218
131
|
],
|
|
219
132
|
};
|
|
220
133
|
|
|
221
|
-
// Mock help collections for development
|
|
222
134
|
const MOCK_HELP_COLLECTIONS = [
|
|
223
135
|
{
|
|
224
136
|
id: 'collection_1',
|
|
@@ -264,7 +176,6 @@
|
|
|
264
176
|
},
|
|
265
177
|
];
|
|
266
178
|
|
|
267
|
-
// Mock surveys for development
|
|
268
179
|
const MOCK_SURVEYS = [
|
|
269
180
|
{
|
|
270
181
|
id: 'mock_nps_survey',
|
|
@@ -296,110 +207,73 @@
|
|
|
296
207
|
},
|
|
297
208
|
];
|
|
298
209
|
|
|
299
|
-
|
|
300
|
-
const ENV_URLS = {
|
|
301
|
-
production: {
|
|
302
|
-
base: 'https://api.product7.io/api/v1',
|
|
303
|
-
withWorkspace: (workspace) => `https://${workspace}.api.product7.io/api/v1`,
|
|
304
|
-
},
|
|
305
|
-
staging: {
|
|
306
|
-
base: 'https://staging.api.product7.io/api/v1',
|
|
307
|
-
withWorkspace: (workspace) =>
|
|
308
|
-
`https://${workspace}.staging.api.product7.io/api/v1`,
|
|
309
|
-
},
|
|
310
|
-
};
|
|
210
|
+
const delay$1 = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
311
211
|
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
this.sessionExpiry = null;
|
|
317
|
-
this.userContext = config.userContext || null;
|
|
318
|
-
this.mock = config.mock || false;
|
|
319
|
-
this.env = config.env || 'production';
|
|
212
|
+
function getDeviceInfo() {
|
|
213
|
+
if (typeof navigator === 'undefined') {
|
|
214
|
+
return { device: null, browser: null, os: null };
|
|
215
|
+
}
|
|
320
216
|
|
|
321
|
-
|
|
322
|
-
this.baseURL = config.apiUrl;
|
|
323
|
-
} else {
|
|
324
|
-
const envConfig = ENV_URLS[this.env] || ENV_URLS.production;
|
|
325
|
-
this.baseURL = this.workspace
|
|
326
|
-
? envConfig.withWorkspace(this.workspace)
|
|
327
|
-
: envConfig.base;
|
|
328
|
-
}
|
|
217
|
+
const ua = navigator.userAgent;
|
|
329
218
|
|
|
330
|
-
|
|
219
|
+
let device = 'desktop';
|
|
220
|
+
if (/Mobi|Android/i.test(ua)) {
|
|
221
|
+
device = /Tablet|iPad/i.test(ua) ? 'tablet' : 'mobile';
|
|
331
222
|
}
|
|
332
223
|
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
return { sessionToken: this.sessionToken };
|
|
340
|
-
}
|
|
224
|
+
let browser = 'unknown';
|
|
225
|
+
if (ua.includes('Firefox')) browser = 'firefox';
|
|
226
|
+
else if (ua.includes('Edg')) browser = 'edge';
|
|
227
|
+
else if (ua.includes('Chrome')) browser = 'chrome';
|
|
228
|
+
else if (ua.includes('Safari')) browser = 'safari';
|
|
229
|
+
else if (ua.includes('Opera') || ua.includes('OPR')) browser = 'opera';
|
|
341
230
|
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
231
|
+
let os = 'unknown';
|
|
232
|
+
if (ua.includes('Windows')) os = 'windows';
|
|
233
|
+
else if (ua.includes('Mac')) os = 'macos';
|
|
234
|
+
else if (ua.includes('Linux')) os = 'linux';
|
|
235
|
+
else if (ua.includes('Android')) os = 'android';
|
|
236
|
+
else if (ua.includes('iPhone') || ua.includes('iPad')) os = 'ios';
|
|
346
237
|
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
this.sessionToken = 'mock_session_' + Date.now();
|
|
350
|
-
this.sessionExpiry = new Date(Date.now() + 3600 * 1000);
|
|
351
|
-
this._storeSession();
|
|
352
|
-
return {
|
|
353
|
-
sessionToken: this.sessionToken,
|
|
354
|
-
config: MOCK_CONFIG,
|
|
355
|
-
expiresIn: 3600,
|
|
356
|
-
};
|
|
357
|
-
}
|
|
238
|
+
return { device, browser, os };
|
|
239
|
+
}
|
|
358
240
|
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
241
|
+
class ChangelogService {
|
|
242
|
+
constructor(baseAPI) {
|
|
243
|
+
this.api = baseAPI;
|
|
244
|
+
}
|
|
363
245
|
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
method: 'POST',
|
|
367
|
-
body: JSON.stringify(payload),
|
|
368
|
-
headers: {
|
|
369
|
-
'Content-Type': 'application/json',
|
|
370
|
-
},
|
|
371
|
-
});
|
|
246
|
+
async getChangelogs(options = {}) {
|
|
247
|
+
await this.api._ensureSession();
|
|
372
248
|
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
249
|
+
if (this.api.mock) {
|
|
250
|
+
await delay$1(300);
|
|
251
|
+
return { success: true, data: MOCK_CHANGELOGS };
|
|
252
|
+
}
|
|
376
253
|
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
};
|
|
382
|
-
} catch (error) {
|
|
383
|
-
throw new APIError(
|
|
384
|
-
error.status || 500,
|
|
385
|
-
`Failed to initialize widget: ${error.message}`,
|
|
386
|
-
error.response
|
|
254
|
+
return this.api._handleAuthRetry(async () => {
|
|
255
|
+
const endpoint = this.api._getEndpointWithParams(
|
|
256
|
+
'/widget/changelogs',
|
|
257
|
+
options
|
|
387
258
|
);
|
|
388
|
-
|
|
259
|
+
return await this.api._makeRequest(endpoint, {
|
|
260
|
+
method: 'GET',
|
|
261
|
+
headers: { Authorization: `Bearer ${this.api.sessionToken}` },
|
|
262
|
+
});
|
|
263
|
+
});
|
|
389
264
|
}
|
|
265
|
+
}
|
|
390
266
|
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
267
|
+
class FeedbackService {
|
|
268
|
+
constructor(baseAPI) {
|
|
269
|
+
this.api = baseAPI;
|
|
270
|
+
}
|
|
395
271
|
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
}
|
|
272
|
+
async submitFeedback(feedbackData) {
|
|
273
|
+
await this.api._ensureSession();
|
|
399
274
|
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
await new Promise((resolve) => setTimeout(resolve, 500));
|
|
275
|
+
if (this.api.mock) {
|
|
276
|
+
await delay$1(500);
|
|
403
277
|
return {
|
|
404
278
|
success: true,
|
|
405
279
|
data: {
|
|
@@ -419,313 +293,98 @@
|
|
|
419
293
|
attachments: feedbackData.attachments || [],
|
|
420
294
|
};
|
|
421
295
|
|
|
422
|
-
|
|
423
|
-
const response = await this._makeRequest('/widget/feedback', {
|
|
296
|
+
return this.api._handleAuthRetry(async () => {
|
|
297
|
+
const response = await this.api._makeRequest('/widget/feedback', {
|
|
424
298
|
method: 'POST',
|
|
425
299
|
body: JSON.stringify(payload),
|
|
426
300
|
headers: {
|
|
427
301
|
'Content-Type': 'application/json',
|
|
428
|
-
Authorization: `Bearer ${this.sessionToken}`,
|
|
302
|
+
Authorization: `Bearer ${this.api.sessionToken}`,
|
|
429
303
|
},
|
|
430
304
|
});
|
|
431
|
-
|
|
432
305
|
return response;
|
|
433
|
-
}
|
|
434
|
-
if (error.status === 401) {
|
|
435
|
-
this.sessionToken = null;
|
|
436
|
-
this.sessionExpiry = null;
|
|
437
|
-
await this.init();
|
|
438
|
-
return this.submitFeedback(feedbackData);
|
|
439
|
-
}
|
|
440
|
-
|
|
441
|
-
throw new APIError(
|
|
442
|
-
error.status || 500,
|
|
443
|
-
`Failed to submit feedback: ${error.message}`,
|
|
444
|
-
error.response
|
|
445
|
-
);
|
|
446
|
-
}
|
|
306
|
+
});
|
|
447
307
|
}
|
|
308
|
+
}
|
|
448
309
|
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
* @param {Object} context.userProperties - Additional user properties
|
|
454
|
-
* @returns {Promise<Array>} Array of active surveys matching targeting rules
|
|
455
|
-
*/
|
|
456
|
-
async getActiveSurveys(context = {}) {
|
|
457
|
-
if (!this.isSessionValid()) {
|
|
458
|
-
await this.init();
|
|
459
|
-
}
|
|
310
|
+
class HelpService {
|
|
311
|
+
constructor(baseAPI) {
|
|
312
|
+
this.api = baseAPI;
|
|
313
|
+
}
|
|
460
314
|
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
}
|
|
315
|
+
async getHelpCollections(options = {}) {
|
|
316
|
+
await this.api._ensureSession();
|
|
464
317
|
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
return {
|
|
469
|
-
success: true,
|
|
470
|
-
data: MOCK_SURVEYS,
|
|
471
|
-
};
|
|
318
|
+
if (this.api.mock) {
|
|
319
|
+
await delay$1(200);
|
|
320
|
+
return { status: true, data: MOCK_HELP_COLLECTIONS };
|
|
472
321
|
}
|
|
473
322
|
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
queryParams.append('url', currentUrl);
|
|
483
|
-
}
|
|
484
|
-
|
|
485
|
-
// Auto-detect device info
|
|
486
|
-
const deviceInfo = this._getDeviceInfo();
|
|
487
|
-
if (deviceInfo.device) queryParams.append('device', deviceInfo.device);
|
|
488
|
-
if (deviceInfo.browser) queryParams.append('browser', deviceInfo.browser);
|
|
489
|
-
if (deviceInfo.os) queryParams.append('os', deviceInfo.os);
|
|
490
|
-
|
|
491
|
-
// Add user properties if provided
|
|
492
|
-
if (context.userProperties) {
|
|
493
|
-
queryParams.append(
|
|
494
|
-
'user_properties',
|
|
495
|
-
JSON.stringify(context.userProperties)
|
|
496
|
-
);
|
|
497
|
-
}
|
|
498
|
-
|
|
499
|
-
const endpoint = `/widget/surveys/active${queryParams.toString() ? '?' + queryParams.toString() : ''}`;
|
|
500
|
-
|
|
501
|
-
const response = await this._makeRequest(endpoint, {
|
|
502
|
-
method: 'GET',
|
|
503
|
-
headers: {
|
|
504
|
-
Authorization: `Bearer ${this.sessionToken}`,
|
|
505
|
-
},
|
|
506
|
-
});
|
|
507
|
-
|
|
508
|
-
return response;
|
|
509
|
-
} catch (error) {
|
|
510
|
-
if (error.status === 401) {
|
|
511
|
-
this.sessionToken = null;
|
|
512
|
-
this.sessionExpiry = null;
|
|
513
|
-
await this.init();
|
|
514
|
-
return this.getActiveSurveys(context);
|
|
515
|
-
}
|
|
516
|
-
|
|
517
|
-
throw new APIError(
|
|
518
|
-
error.status || 500,
|
|
519
|
-
`Failed to get active surveys: ${error.message}`,
|
|
520
|
-
error.response
|
|
521
|
-
);
|
|
522
|
-
}
|
|
323
|
+
const endpoint = this.api._getEndpointWithParams(
|
|
324
|
+
'/widget/help/collections',
|
|
325
|
+
options
|
|
326
|
+
);
|
|
327
|
+
return this.api._makeRequest(endpoint, {
|
|
328
|
+
method: 'GET',
|
|
329
|
+
headers: { Authorization: `Bearer ${this.api.sessionToken}` },
|
|
330
|
+
});
|
|
523
331
|
}
|
|
524
332
|
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
* @returns {Object} Device info object
|
|
528
|
-
*/
|
|
529
|
-
_getDeviceInfo() {
|
|
530
|
-
if (typeof navigator === 'undefined') {
|
|
531
|
-
return { device: null, browser: null, os: null };
|
|
532
|
-
}
|
|
533
|
-
|
|
534
|
-
const ua = navigator.userAgent;
|
|
333
|
+
async searchHelpArticles(query, options = {}) {
|
|
334
|
+
await this.api._ensureSession();
|
|
535
335
|
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
336
|
+
if (this.api.mock) {
|
|
337
|
+
await delay$1(200);
|
|
338
|
+
const filtered = MOCK_HELP_COLLECTIONS.filter(
|
|
339
|
+
(c) =>
|
|
340
|
+
c.title.toLowerCase().includes(query.toLowerCase()) ||
|
|
341
|
+
c.description.toLowerCase().includes(query.toLowerCase())
|
|
342
|
+
);
|
|
343
|
+
return { status: true, data: filtered };
|
|
540
344
|
}
|
|
541
345
|
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
let os = 'unknown';
|
|
552
|
-
if (ua.includes('Windows')) os = 'windows';
|
|
553
|
-
else if (ua.includes('Mac')) os = 'macos';
|
|
554
|
-
else if (ua.includes('Linux')) os = 'linux';
|
|
555
|
-
else if (ua.includes('Android')) os = 'android';
|
|
556
|
-
else if (ua.includes('iPhone') || ua.includes('iPad')) os = 'ios';
|
|
557
|
-
|
|
558
|
-
return { device, browser, os };
|
|
346
|
+
const params = { q: query, ...options };
|
|
347
|
+
const endpoint = this.api._getEndpointWithParams(
|
|
348
|
+
'/widget/help/search',
|
|
349
|
+
params
|
|
350
|
+
);
|
|
351
|
+
return this.api._makeRequest(endpoint, {
|
|
352
|
+
method: 'GET',
|
|
353
|
+
headers: { Authorization: `Bearer ${this.api.sessionToken}` },
|
|
354
|
+
});
|
|
559
355
|
}
|
|
356
|
+
}
|
|
560
357
|
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
* @param {number|string} responseData.rating - The rating/score value
|
|
566
|
-
* @param {string} responseData.feedback - Optional text feedback
|
|
567
|
-
* @param {Object} responseData.answers - For custom surveys, key-value pairs
|
|
568
|
-
* @returns {Promise<Object>} Submission result
|
|
569
|
-
*/
|
|
570
|
-
async submitSurveyResponse(surveyId, responseData) {
|
|
571
|
-
if (!this.isSessionValid()) {
|
|
572
|
-
await this.init();
|
|
573
|
-
}
|
|
574
|
-
|
|
575
|
-
if (!this.sessionToken) {
|
|
576
|
-
throw new APIError(401, 'No valid session token available');
|
|
577
|
-
}
|
|
358
|
+
class MessengerService {
|
|
359
|
+
constructor(baseAPI) {
|
|
360
|
+
this.api = baseAPI;
|
|
361
|
+
}
|
|
578
362
|
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
}
|
|
363
|
+
async getMessengerSettings() {
|
|
364
|
+
await this.api._ensureSession();
|
|
582
365
|
|
|
583
|
-
|
|
584
|
-
if (this.mock) {
|
|
585
|
-
await new Promise((resolve) => setTimeout(resolve, 300));
|
|
366
|
+
if (this.api.mock) {
|
|
586
367
|
return {
|
|
587
|
-
|
|
368
|
+
status: true,
|
|
588
369
|
data: {
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
370
|
+
enabled: true,
|
|
371
|
+
greeting_message: 'Hi there! How can we help you today?',
|
|
372
|
+
team_name: 'Support Team',
|
|
373
|
+
response_time: 'Usually replies within a few minutes',
|
|
592
374
|
},
|
|
593
|
-
message: 'Survey response submitted successfully!',
|
|
594
375
|
};
|
|
595
376
|
}
|
|
596
377
|
|
|
597
|
-
|
|
598
|
-
rating: responseData.rating,
|
|
599
|
-
feedback: responseData.feedback || '',
|
|
600
|
-
answers: responseData.answers || {},
|
|
601
|
-
};
|
|
602
|
-
|
|
603
|
-
try {
|
|
604
|
-
const response = await this._makeRequest(
|
|
605
|
-
`/widget/surveys/${surveyId}/responses`,
|
|
606
|
-
{
|
|
607
|
-
method: 'POST',
|
|
608
|
-
body: JSON.stringify(payload),
|
|
609
|
-
headers: {
|
|
610
|
-
'Content-Type': 'application/json',
|
|
611
|
-
Authorization: `Bearer ${this.sessionToken}`,
|
|
612
|
-
},
|
|
613
|
-
}
|
|
614
|
-
);
|
|
615
|
-
|
|
616
|
-
return response;
|
|
617
|
-
} catch (error) {
|
|
618
|
-
if (error.status === 401) {
|
|
619
|
-
this.sessionToken = null;
|
|
620
|
-
this.sessionExpiry = null;
|
|
621
|
-
await this.init();
|
|
622
|
-
return this.submitSurveyResponse(surveyId, responseData);
|
|
623
|
-
}
|
|
624
|
-
|
|
625
|
-
throw new APIError(
|
|
626
|
-
error.status || 500,
|
|
627
|
-
`Failed to submit survey response: ${error.message}`,
|
|
628
|
-
error.response
|
|
629
|
-
);
|
|
630
|
-
}
|
|
631
|
-
}
|
|
632
|
-
|
|
633
|
-
/**
|
|
634
|
-
* Dismiss a survey (mark as seen but not completed)
|
|
635
|
-
* @param {string} surveyId - The survey ID to dismiss
|
|
636
|
-
* @returns {Promise<Object>} Dismissal result
|
|
637
|
-
*/
|
|
638
|
-
async dismissSurvey(surveyId) {
|
|
639
|
-
if (!this.isSessionValid()) {
|
|
640
|
-
await this.init();
|
|
641
|
-
}
|
|
642
|
-
|
|
643
|
-
if (!this.sessionToken) {
|
|
644
|
-
throw new APIError(401, 'No valid session token available');
|
|
645
|
-
}
|
|
646
|
-
|
|
647
|
-
if (!surveyId) {
|
|
648
|
-
throw new APIError(400, 'Survey ID is required');
|
|
649
|
-
}
|
|
650
|
-
|
|
651
|
-
// Mock mode - simulate success
|
|
652
|
-
if (this.mock) {
|
|
653
|
-
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
654
|
-
return {
|
|
655
|
-
success: true,
|
|
656
|
-
message: 'Survey dismissed successfully',
|
|
657
|
-
};
|
|
658
|
-
}
|
|
659
|
-
|
|
660
|
-
try {
|
|
661
|
-
const response = await this._makeRequest(
|
|
662
|
-
`/widget/surveys/${surveyId}/dismiss`,
|
|
663
|
-
{
|
|
664
|
-
method: 'POST',
|
|
665
|
-
headers: {
|
|
666
|
-
Authorization: `Bearer ${this.sessionToken}`,
|
|
667
|
-
},
|
|
668
|
-
}
|
|
669
|
-
);
|
|
670
|
-
|
|
671
|
-
return response;
|
|
672
|
-
} catch (error) {
|
|
673
|
-
if (error.status === 401) {
|
|
674
|
-
this.sessionToken = null;
|
|
675
|
-
this.sessionExpiry = null;
|
|
676
|
-
await this.init();
|
|
677
|
-
return this.dismissSurvey(surveyId);
|
|
678
|
-
}
|
|
679
|
-
|
|
680
|
-
throw new APIError(
|
|
681
|
-
error.status || 500,
|
|
682
|
-
`Failed to dismiss survey: ${error.message}`,
|
|
683
|
-
error.response
|
|
684
|
-
);
|
|
685
|
-
}
|
|
686
|
-
}
|
|
687
|
-
|
|
688
|
-
// ==========================================
|
|
689
|
-
// MESSENGER / CHAT ENDPOINTS
|
|
690
|
-
// ==========================================
|
|
691
|
-
|
|
692
|
-
/**
|
|
693
|
-
* Get messenger settings
|
|
694
|
-
* @returns {Promise<Object>} Messenger settings
|
|
695
|
-
*/
|
|
696
|
-
async getMessengerSettings() {
|
|
697
|
-
if (!this.isSessionValid()) {
|
|
698
|
-
await this.init();
|
|
699
|
-
}
|
|
700
|
-
|
|
701
|
-
if (this.mock) {
|
|
702
|
-
return {
|
|
703
|
-
status: true,
|
|
704
|
-
data: {
|
|
705
|
-
enabled: true,
|
|
706
|
-
greeting_message: 'Hi there! How can we help you today?',
|
|
707
|
-
team_name: 'Support Team',
|
|
708
|
-
response_time: 'Usually replies within a few minutes',
|
|
709
|
-
},
|
|
710
|
-
};
|
|
711
|
-
}
|
|
712
|
-
|
|
713
|
-
return this._makeRequest('/widget/messenger/settings', {
|
|
378
|
+
return this.api._makeRequest('/widget/messenger/settings', {
|
|
714
379
|
method: 'GET',
|
|
715
|
-
headers: { Authorization: `Bearer ${this.sessionToken}` },
|
|
380
|
+
headers: { Authorization: `Bearer ${this.api.sessionToken}` },
|
|
716
381
|
});
|
|
717
382
|
}
|
|
718
383
|
|
|
719
|
-
/**
|
|
720
|
-
* Check if agents are online
|
|
721
|
-
* @returns {Promise<Object>} Agent availability status
|
|
722
|
-
*/
|
|
723
384
|
async checkAgentsOnline() {
|
|
724
|
-
|
|
725
|
-
await this.init();
|
|
726
|
-
}
|
|
385
|
+
await this.api._ensureSession();
|
|
727
386
|
|
|
728
|
-
if (this.mock) {
|
|
387
|
+
if (this.api.mock) {
|
|
729
388
|
return {
|
|
730
389
|
status: true,
|
|
731
390
|
data: {
|
|
@@ -736,26 +395,17 @@
|
|
|
736
395
|
};
|
|
737
396
|
}
|
|
738
397
|
|
|
739
|
-
return this._makeRequest('/widget/messenger/agents/online', {
|
|
398
|
+
return this.api._makeRequest('/widget/messenger/agents/online', {
|
|
740
399
|
method: 'GET',
|
|
741
|
-
headers: { Authorization: `Bearer ${this.sessionToken}` },
|
|
400
|
+
headers: { Authorization: `Bearer ${this.api.sessionToken}` },
|
|
742
401
|
});
|
|
743
402
|
}
|
|
744
403
|
|
|
745
|
-
/**
|
|
746
|
-
* Get all conversations for the current contact
|
|
747
|
-
* @param {Object} options - Query options
|
|
748
|
-
* @param {number} options.page - Page number
|
|
749
|
-
* @param {number} options.limit - Items per page
|
|
750
|
-
* @returns {Promise<Object>} Conversations list
|
|
751
|
-
*/
|
|
752
404
|
async getConversations(options = {}) {
|
|
753
|
-
|
|
754
|
-
await this.init();
|
|
755
|
-
}
|
|
405
|
+
await this.api._ensureSession();
|
|
756
406
|
|
|
757
|
-
if (this.mock) {
|
|
758
|
-
await
|
|
407
|
+
if (this.api.mock) {
|
|
408
|
+
await delay$1(300);
|
|
759
409
|
return {
|
|
760
410
|
status: true,
|
|
761
411
|
data: MOCK_CONVERSATIONS,
|
|
@@ -763,92 +413,42 @@
|
|
|
763
413
|
};
|
|
764
414
|
}
|
|
765
415
|
|
|
766
|
-
const
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
return this._makeRequest(endpoint, {
|
|
416
|
+
const endpoint = this.api._getEndpointWithParams(
|
|
417
|
+
'/widget/messenger/conversations',
|
|
418
|
+
options
|
|
419
|
+
);
|
|
420
|
+
return this.api._makeRequest(endpoint, {
|
|
772
421
|
method: 'GET',
|
|
773
|
-
headers: { Authorization: `Bearer ${this.sessionToken}` },
|
|
422
|
+
headers: { Authorization: `Bearer ${this.api.sessionToken}` },
|
|
774
423
|
});
|
|
775
424
|
}
|
|
776
425
|
|
|
777
|
-
/**
|
|
778
|
-
* Get a single conversation with messages
|
|
779
|
-
* @param {string} conversationId - Conversation ID
|
|
780
|
-
* @returns {Promise<Object>} Conversation with messages
|
|
781
|
-
*/
|
|
782
426
|
async getConversation(conversationId) {
|
|
783
|
-
|
|
784
|
-
await this.init();
|
|
785
|
-
}
|
|
427
|
+
await this.api._ensureSession();
|
|
786
428
|
|
|
787
|
-
if (this.mock) {
|
|
788
|
-
await
|
|
429
|
+
if (this.api.mock) {
|
|
430
|
+
await delay$1(200);
|
|
789
431
|
const conv = MOCK_CONVERSATIONS.find((c) => c.id === conversationId);
|
|
790
432
|
return {
|
|
791
433
|
status: true,
|
|
792
|
-
data: {
|
|
793
|
-
...conv,
|
|
794
|
-
messages: MOCK_MESSAGES[conversationId] || [],
|
|
795
|
-
},
|
|
434
|
+
data: { ...conv, messages: MOCK_MESSAGES[conversationId] || [] },
|
|
796
435
|
};
|
|
797
436
|
}
|
|
798
437
|
|
|
799
|
-
return this._makeRequest(
|
|
438
|
+
return this.api._makeRequest(
|
|
800
439
|
`/widget/messenger/conversations/${conversationId}`,
|
|
801
440
|
{
|
|
802
441
|
method: 'GET',
|
|
803
|
-
headers: { Authorization: `Bearer ${this.sessionToken}` },
|
|
442
|
+
headers: { Authorization: `Bearer ${this.api.sessionToken}` },
|
|
804
443
|
}
|
|
805
444
|
);
|
|
806
445
|
}
|
|
807
446
|
|
|
808
|
-
/**
|
|
809
|
-
* Get messages for a conversation
|
|
810
|
-
* @param {string} conversationId - Conversation ID
|
|
811
|
-
* @param {Object} options - Query options
|
|
812
|
-
* @returns {Promise<Object>} Messages list
|
|
813
|
-
*/
|
|
814
|
-
async getMessages(conversationId, options = {}) {
|
|
815
|
-
if (!this.isSessionValid()) {
|
|
816
|
-
await this.init();
|
|
817
|
-
}
|
|
818
|
-
|
|
819
|
-
if (this.mock) {
|
|
820
|
-
await new Promise((resolve) => setTimeout(resolve, 200));
|
|
821
|
-
return {
|
|
822
|
-
status: true,
|
|
823
|
-
data: MOCK_MESSAGES[conversationId] || [],
|
|
824
|
-
};
|
|
825
|
-
}
|
|
826
|
-
|
|
827
|
-
const params = new URLSearchParams();
|
|
828
|
-
if (options.page) params.append('page', options.page);
|
|
829
|
-
if (options.limit) params.append('limit', options.limit);
|
|
830
|
-
|
|
831
|
-
const endpoint = `/widget/messenger/conversations/${conversationId}/messages${params.toString() ? '?' + params.toString() : ''}`;
|
|
832
|
-
return this._makeRequest(endpoint, {
|
|
833
|
-
method: 'GET',
|
|
834
|
-
headers: { Authorization: `Bearer ${this.sessionToken}` },
|
|
835
|
-
});
|
|
836
|
-
}
|
|
837
|
-
|
|
838
|
-
/**
|
|
839
|
-
* Start a new conversation
|
|
840
|
-
* @param {Object} data - Conversation data
|
|
841
|
-
* @param {string} data.message - Initial message content
|
|
842
|
-
* @param {string} data.subject - Optional subject
|
|
843
|
-
* @returns {Promise<Object>} Created conversation
|
|
844
|
-
*/
|
|
845
447
|
async startConversation(data) {
|
|
846
|
-
|
|
847
|
-
await this.init();
|
|
848
|
-
}
|
|
448
|
+
await this.api._ensureSession();
|
|
849
449
|
|
|
850
|
-
if (this.mock) {
|
|
851
|
-
await
|
|
450
|
+
if (this.api.mock) {
|
|
451
|
+
await delay$1(300);
|
|
852
452
|
const newConv = {
|
|
853
453
|
id: 'conv_' + Date.now(),
|
|
854
454
|
subject: data.subject || 'New conversation',
|
|
@@ -869,11 +469,11 @@
|
|
|
869
469
|
return { status: true, data: newConv };
|
|
870
470
|
}
|
|
871
471
|
|
|
872
|
-
return this._makeRequest('/widget/messenger/conversations', {
|
|
472
|
+
return this.api._makeRequest('/widget/messenger/conversations', {
|
|
873
473
|
method: 'POST',
|
|
874
474
|
headers: {
|
|
875
475
|
'Content-Type': 'application/json',
|
|
876
|
-
Authorization: `Bearer ${this.sessionToken}`,
|
|
476
|
+
Authorization: `Bearer ${this.api.sessionToken}`,
|
|
877
477
|
},
|
|
878
478
|
body: JSON.stringify({
|
|
879
479
|
message: data.message,
|
|
@@ -882,20 +482,11 @@
|
|
|
882
482
|
});
|
|
883
483
|
}
|
|
884
484
|
|
|
885
|
-
/**
|
|
886
|
-
* Send a message in a conversation
|
|
887
|
-
* @param {string} conversationId - Conversation ID
|
|
888
|
-
* @param {Object} data - Message data
|
|
889
|
-
* @param {string} data.content - Message content
|
|
890
|
-
* @returns {Promise<Object>} Sent message
|
|
891
|
-
*/
|
|
892
485
|
async sendMessage(conversationId, data) {
|
|
893
|
-
|
|
894
|
-
await this.init();
|
|
895
|
-
}
|
|
486
|
+
await this.api._ensureSession();
|
|
896
487
|
|
|
897
|
-
if (this.mock) {
|
|
898
|
-
await
|
|
488
|
+
if (this.api.mock) {
|
|
489
|
+
await delay$1(200);
|
|
899
490
|
const newMessage = {
|
|
900
491
|
id: 'msg_' + Date.now(),
|
|
901
492
|
content: data.content,
|
|
@@ -909,80 +500,23 @@
|
|
|
909
500
|
return { status: true, data: newMessage };
|
|
910
501
|
}
|
|
911
502
|
|
|
912
|
-
return this._makeRequest(
|
|
503
|
+
return this.api._makeRequest(
|
|
913
504
|
`/widget/messenger/conversations/${conversationId}/messages`,
|
|
914
505
|
{
|
|
915
506
|
method: 'POST',
|
|
916
507
|
headers: {
|
|
917
508
|
'Content-Type': 'application/json',
|
|
918
|
-
Authorization: `Bearer ${this.sessionToken}`,
|
|
509
|
+
Authorization: `Bearer ${this.api.sessionToken}`,
|
|
919
510
|
},
|
|
920
511
|
body: JSON.stringify({ content: data.content }),
|
|
921
512
|
}
|
|
922
513
|
);
|
|
923
514
|
}
|
|
924
515
|
|
|
925
|
-
/**
|
|
926
|
-
* Send typing indicator
|
|
927
|
-
* @param {string} conversationId - Conversation ID
|
|
928
|
-
* @param {boolean} isTyping - Whether user is typing
|
|
929
|
-
* @returns {Promise<Object>} Response
|
|
930
|
-
*/
|
|
931
|
-
async sendTypingIndicator(conversationId, isTyping) {
|
|
932
|
-
if (!this.isSessionValid()) {
|
|
933
|
-
await this.init();
|
|
934
|
-
}
|
|
935
|
-
|
|
936
|
-
if (this.mock) {
|
|
937
|
-
return { status: true };
|
|
938
|
-
}
|
|
939
|
-
|
|
940
|
-
return this._makeRequest(
|
|
941
|
-
`/widget/messenger/conversations/${conversationId}/typing`,
|
|
942
|
-
{
|
|
943
|
-
method: 'POST',
|
|
944
|
-
headers: {
|
|
945
|
-
'Content-Type': 'application/json',
|
|
946
|
-
Authorization: `Bearer ${this.sessionToken}`,
|
|
947
|
-
},
|
|
948
|
-
body: JSON.stringify({ is_typing: isTyping }),
|
|
949
|
-
}
|
|
950
|
-
);
|
|
951
|
-
}
|
|
952
|
-
|
|
953
|
-
/**
|
|
954
|
-
* Mark conversation as read
|
|
955
|
-
* @param {string} conversationId - Conversation ID
|
|
956
|
-
* @returns {Promise<Object>} Response
|
|
957
|
-
*/
|
|
958
|
-
async markConversationAsRead(conversationId) {
|
|
959
|
-
if (!this.isSessionValid()) {
|
|
960
|
-
await this.init();
|
|
961
|
-
}
|
|
962
|
-
|
|
963
|
-
if (this.mock) {
|
|
964
|
-
return { status: true };
|
|
965
|
-
}
|
|
966
|
-
|
|
967
|
-
return this._makeRequest(
|
|
968
|
-
`/widget/messenger/conversations/${conversationId}/read`,
|
|
969
|
-
{
|
|
970
|
-
method: 'POST',
|
|
971
|
-
headers: { Authorization: `Bearer ${this.sessionToken}` },
|
|
972
|
-
}
|
|
973
|
-
);
|
|
974
|
-
}
|
|
975
|
-
|
|
976
|
-
/**
|
|
977
|
-
* Get unread count
|
|
978
|
-
* @returns {Promise<Object>} Unread count data
|
|
979
|
-
*/
|
|
980
516
|
async getUnreadCount() {
|
|
981
|
-
|
|
982
|
-
await this.init();
|
|
983
|
-
}
|
|
517
|
+
await this.api._ensureSession();
|
|
984
518
|
|
|
985
|
-
if (this.mock) {
|
|
519
|
+
if (this.api.mock) {
|
|
986
520
|
const count = MOCK_CONVERSATIONS.reduce(
|
|
987
521
|
(sum, c) => sum + (c.unread || 0),
|
|
988
522
|
0
|
|
@@ -993,187 +527,325 @@
|
|
|
993
527
|
};
|
|
994
528
|
}
|
|
995
529
|
|
|
996
|
-
return this._makeRequest('/widget/messenger/unread', {
|
|
530
|
+
return this.api._makeRequest('/widget/messenger/unread', {
|
|
997
531
|
method: 'GET',
|
|
998
|
-
headers: { Authorization: `Bearer ${this.sessionToken}` },
|
|
532
|
+
headers: { Authorization: `Bearer ${this.api.sessionToken}` },
|
|
999
533
|
});
|
|
1000
534
|
}
|
|
1001
535
|
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
* @param {string} conversationId - Conversation ID
|
|
1005
|
-
* @param {Object} data - Rating data
|
|
1006
|
-
* @param {number} data.rating - Rating (1-5 or thumbs up/down)
|
|
1007
|
-
* @param {string} data.comment - Optional comment
|
|
1008
|
-
* @returns {Promise<Object>} Response
|
|
1009
|
-
*/
|
|
1010
|
-
async submitRating(conversationId, data) {
|
|
1011
|
-
if (!this.isSessionValid()) {
|
|
1012
|
-
await this.init();
|
|
1013
|
-
}
|
|
536
|
+
async markConversationAsRead(conversationId) {
|
|
537
|
+
await this.api._ensureSession();
|
|
1014
538
|
|
|
1015
|
-
if (this.mock) {
|
|
1016
|
-
return { status: true
|
|
539
|
+
if (this.api.mock) {
|
|
540
|
+
return { status: true };
|
|
1017
541
|
}
|
|
1018
542
|
|
|
1019
|
-
return this._makeRequest(
|
|
1020
|
-
`/widget/messenger/conversations/${conversationId}/
|
|
543
|
+
return this.api._makeRequest(
|
|
544
|
+
`/widget/messenger/conversations/${conversationId}/read`,
|
|
1021
545
|
{
|
|
1022
546
|
method: 'POST',
|
|
1023
|
-
headers: {
|
|
1024
|
-
'Content-Type': 'application/json',
|
|
1025
|
-
Authorization: `Bearer ${this.sessionToken}`,
|
|
1026
|
-
},
|
|
1027
|
-
body: JSON.stringify({
|
|
1028
|
-
rating: data.rating,
|
|
1029
|
-
comment: data.comment || '',
|
|
1030
|
-
}),
|
|
547
|
+
headers: { Authorization: `Bearer ${this.api.sessionToken}` },
|
|
1031
548
|
}
|
|
1032
549
|
);
|
|
1033
550
|
}
|
|
551
|
+
}
|
|
1034
552
|
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
* @returns {Promise<Object>} Response
|
|
1041
|
-
*/
|
|
1042
|
-
async identifyContact(data) {
|
|
1043
|
-
if (!this.isSessionValid()) {
|
|
1044
|
-
await this.init();
|
|
1045
|
-
}
|
|
553
|
+
class SDKError extends Error {
|
|
554
|
+
constructor(message, cause) {
|
|
555
|
+
super(message);
|
|
556
|
+
this.name = 'SDKError';
|
|
557
|
+
this.cause = cause;
|
|
1046
558
|
|
|
1047
|
-
if (
|
|
1048
|
-
|
|
559
|
+
if (Error.captureStackTrace) {
|
|
560
|
+
Error.captureStackTrace(this, SDKError);
|
|
1049
561
|
}
|
|
1050
|
-
|
|
1051
|
-
return this._makeRequest('/widget/messenger/identify', {
|
|
1052
|
-
method: 'POST',
|
|
1053
|
-
headers: {
|
|
1054
|
-
'Content-Type': 'application/json',
|
|
1055
|
-
Authorization: `Bearer ${this.sessionToken}`,
|
|
1056
|
-
},
|
|
1057
|
-
body: JSON.stringify(data),
|
|
1058
|
-
});
|
|
1059
562
|
}
|
|
563
|
+
}
|
|
1060
564
|
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
565
|
+
class APIError extends Error {
|
|
566
|
+
constructor(status, message, response) {
|
|
567
|
+
super(message);
|
|
568
|
+
this.name = 'APIError';
|
|
569
|
+
this.status = status;
|
|
570
|
+
this.response = response;
|
|
1064
571
|
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
* @param {Object} options - Query options
|
|
1068
|
-
* @returns {Promise<Object>} Collections list
|
|
1069
|
-
*/
|
|
1070
|
-
async getHelpCollections(options = {}) {
|
|
1071
|
-
if (!this.isSessionValid()) {
|
|
1072
|
-
await this.init();
|
|
572
|
+
if (Error.captureStackTrace) {
|
|
573
|
+
Error.captureStackTrace(this, APIError);
|
|
1073
574
|
}
|
|
575
|
+
}
|
|
1074
576
|
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
}
|
|
577
|
+
isNetworkError() {
|
|
578
|
+
return this.status === 0;
|
|
579
|
+
}
|
|
1079
580
|
|
|
1080
|
-
|
|
1081
|
-
|
|
581
|
+
isClientError() {
|
|
582
|
+
return this.status >= 400 && this.status < 500;
|
|
583
|
+
}
|
|
1082
584
|
|
|
1083
|
-
|
|
1084
|
-
return this.
|
|
1085
|
-
method: 'GET',
|
|
1086
|
-
headers: { Authorization: `Bearer ${this.sessionToken}` },
|
|
1087
|
-
});
|
|
585
|
+
isServerError() {
|
|
586
|
+
return this.status >= 500 && this.status < 600;
|
|
1088
587
|
}
|
|
588
|
+
}
|
|
1089
589
|
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
if (
|
|
1098
|
-
|
|
590
|
+
class WidgetError extends Error {
|
|
591
|
+
constructor(message, widgetType, widgetId) {
|
|
592
|
+
super(message);
|
|
593
|
+
this.name = 'WidgetError';
|
|
594
|
+
this.widgetType = widgetType;
|
|
595
|
+
this.widgetId = widgetId;
|
|
596
|
+
|
|
597
|
+
if (Error.captureStackTrace) {
|
|
598
|
+
Error.captureStackTrace(this, WidgetError);
|
|
1099
599
|
}
|
|
600
|
+
}
|
|
601
|
+
}
|
|
1100
602
|
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
603
|
+
class ConfigError extends Error {
|
|
604
|
+
constructor(message, configKey) {
|
|
605
|
+
super(message);
|
|
606
|
+
this.name = 'ConfigError';
|
|
607
|
+
this.configKey = configKey;
|
|
608
|
+
|
|
609
|
+
if (Error.captureStackTrace) {
|
|
610
|
+
Error.captureStackTrace(this, ConfigError);
|
|
611
|
+
}
|
|
612
|
+
}
|
|
613
|
+
}
|
|
614
|
+
|
|
615
|
+
class ValidationError extends Error {
|
|
616
|
+
constructor(message, field, value) {
|
|
617
|
+
super(message);
|
|
618
|
+
this.name = 'ValidationError';
|
|
619
|
+
this.field = field;
|
|
620
|
+
this.value = value;
|
|
621
|
+
|
|
622
|
+
if (Error.captureStackTrace) {
|
|
623
|
+
Error.captureStackTrace(this, ValidationError);
|
|
624
|
+
}
|
|
625
|
+
}
|
|
626
|
+
}
|
|
627
|
+
|
|
628
|
+
class SurveyService {
|
|
629
|
+
constructor(baseAPI) {
|
|
630
|
+
this.api = baseAPI;
|
|
631
|
+
}
|
|
632
|
+
|
|
633
|
+
async getActiveSurveys(context = {}) {
|
|
634
|
+
await this.api._ensureSession();
|
|
635
|
+
|
|
636
|
+
if (this.api.mock) {
|
|
637
|
+
await delay$1(200);
|
|
638
|
+
return { success: true, data: MOCK_SURVEYS };
|
|
639
|
+
}
|
|
640
|
+
|
|
641
|
+
const params = {
|
|
642
|
+
url:
|
|
643
|
+
context.url ||
|
|
644
|
+
(typeof window !== 'undefined' ? window.location.href : ''),
|
|
645
|
+
...getDeviceInfo(),
|
|
646
|
+
...(context.userProperties && {
|
|
647
|
+
user_properties: context.userProperties,
|
|
648
|
+
}),
|
|
649
|
+
};
|
|
650
|
+
|
|
651
|
+
return this.api._handleAuthRetry(async () => {
|
|
652
|
+
const endpoint = this.api._getEndpointWithParams(
|
|
653
|
+
'/widget/surveys/active',
|
|
654
|
+
params
|
|
1107
655
|
);
|
|
1108
|
-
return
|
|
656
|
+
return await this.api._makeRequest(endpoint, {
|
|
657
|
+
method: 'GET',
|
|
658
|
+
headers: { Authorization: `Bearer ${this.api.sessionToken}` },
|
|
659
|
+
});
|
|
660
|
+
});
|
|
661
|
+
}
|
|
662
|
+
|
|
663
|
+
async submitSurveyResponse(surveyId, responseData) {
|
|
664
|
+
if (!surveyId) throw new APIError(400, 'Survey ID is required');
|
|
665
|
+
|
|
666
|
+
await this.api._ensureSession();
|
|
667
|
+
|
|
668
|
+
if (this.api.mock) {
|
|
669
|
+
await delay$1(300);
|
|
670
|
+
return {
|
|
671
|
+
success: true,
|
|
672
|
+
data: {
|
|
673
|
+
id: 'mock_response_' + Date.now(),
|
|
674
|
+
survey_id: surveyId,
|
|
675
|
+
...responseData,
|
|
676
|
+
},
|
|
677
|
+
message: 'Survey response submitted successfully!',
|
|
678
|
+
};
|
|
1109
679
|
}
|
|
1110
680
|
|
|
1111
|
-
const
|
|
1112
|
-
|
|
681
|
+
const payload = {
|
|
682
|
+
rating: responseData.rating,
|
|
683
|
+
feedback: responseData.feedback || '',
|
|
684
|
+
answers: responseData.answers || {},
|
|
685
|
+
};
|
|
1113
686
|
|
|
1114
|
-
return this.
|
|
1115
|
-
|
|
1116
|
-
|
|
687
|
+
return this.api._handleAuthRetry(async () => {
|
|
688
|
+
return await this.api._makeRequest(
|
|
689
|
+
`/widget/surveys/${surveyId}/responses`,
|
|
690
|
+
{
|
|
691
|
+
method: 'POST',
|
|
692
|
+
body: JSON.stringify(payload),
|
|
693
|
+
headers: {
|
|
694
|
+
'Content-Type': 'application/json',
|
|
695
|
+
Authorization: `Bearer ${this.api.sessionToken}`,
|
|
696
|
+
},
|
|
697
|
+
}
|
|
698
|
+
);
|
|
1117
699
|
});
|
|
1118
700
|
}
|
|
1119
701
|
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
// ==========================================
|
|
702
|
+
async dismissSurvey(surveyId) {
|
|
703
|
+
if (!surveyId) throw new APIError(400, 'Survey ID is required');
|
|
1123
704
|
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
* @returns {Promise<Object>} Changelogs response
|
|
1130
|
-
*/
|
|
1131
|
-
async getChangelogs(options = {}) {
|
|
1132
|
-
if (!this.isSessionValid()) {
|
|
1133
|
-
await this.init();
|
|
705
|
+
await this.api._ensureSession();
|
|
706
|
+
|
|
707
|
+
if (this.api.mock) {
|
|
708
|
+
await delay$1(100);
|
|
709
|
+
return { success: true, message: 'Survey dismissed successfully' };
|
|
1134
710
|
}
|
|
1135
711
|
|
|
1136
|
-
|
|
1137
|
-
|
|
712
|
+
return this.api._handleAuthRetry(async () => {
|
|
713
|
+
return await this.api._makeRequest(
|
|
714
|
+
`/widget/surveys/${surveyId}/dismiss`,
|
|
715
|
+
{
|
|
716
|
+
method: 'POST',
|
|
717
|
+
headers: { Authorization: `Bearer ${this.api.sessionToken}` },
|
|
718
|
+
}
|
|
719
|
+
);
|
|
720
|
+
});
|
|
721
|
+
}
|
|
722
|
+
}
|
|
723
|
+
|
|
724
|
+
class BaseAPIService {
|
|
725
|
+
constructor(config = {}) {
|
|
726
|
+
this.workspace = config.workspace;
|
|
727
|
+
this.sessionToken = null;
|
|
728
|
+
this.sessionExpiry = null;
|
|
729
|
+
this.userContext = config.userContext || null;
|
|
730
|
+
this.mock = config.mock || false;
|
|
731
|
+
this.env = config.env || 'production';
|
|
732
|
+
this.baseURL = this._getBaseURL(config);
|
|
733
|
+
|
|
734
|
+
this._loadStoredSession();
|
|
735
|
+
}
|
|
736
|
+
|
|
737
|
+
_getBaseURL(config) {
|
|
738
|
+
if (config.apiUrl) return config.apiUrl;
|
|
739
|
+
|
|
740
|
+
const ENV_URLS = {
|
|
741
|
+
production: {
|
|
742
|
+
base: 'https://api.product7.io/api/v1',
|
|
743
|
+
withWorkspace: (ws) => `https://${ws}.api.product7.io/api/v1`,
|
|
744
|
+
},
|
|
745
|
+
staging: {
|
|
746
|
+
base: 'https://staging.api.product7.io/api/v1',
|
|
747
|
+
withWorkspace: (ws) => `https://${ws}.staging.api.product7.io/api/v1`,
|
|
748
|
+
},
|
|
749
|
+
};
|
|
750
|
+
|
|
751
|
+
const envConfig = ENV_URLS[this.env] || ENV_URLS.production;
|
|
752
|
+
return this.workspace
|
|
753
|
+
? envConfig.withWorkspace(this.workspace)
|
|
754
|
+
: envConfig.base;
|
|
755
|
+
}
|
|
756
|
+
|
|
757
|
+
async init(userContext = null) {
|
|
758
|
+
if (userContext) {
|
|
759
|
+
this.userContext = userContext;
|
|
760
|
+
}
|
|
761
|
+
|
|
762
|
+
if (this.isSessionValid()) {
|
|
763
|
+
return { sessionToken: this.sessionToken };
|
|
764
|
+
}
|
|
765
|
+
|
|
766
|
+
if (!this.workspace || !this.userContext) {
|
|
767
|
+
throw new APIError(
|
|
768
|
+
400,
|
|
769
|
+
`Missing ${!this.workspace ? 'workspace' : 'user context'} for initialization`
|
|
770
|
+
);
|
|
1138
771
|
}
|
|
1139
772
|
|
|
1140
|
-
// Mock mode - return mock changelogs
|
|
1141
773
|
if (this.mock) {
|
|
1142
|
-
|
|
1143
|
-
return {
|
|
1144
|
-
success: true,
|
|
1145
|
-
data: MOCK_CHANGELOGS,
|
|
1146
|
-
};
|
|
774
|
+
return this._initMockSession();
|
|
1147
775
|
}
|
|
1148
776
|
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
777
|
+
return this._initRealSession();
|
|
778
|
+
}
|
|
779
|
+
|
|
780
|
+
async _initMockSession() {
|
|
781
|
+
this.sessionToken = 'mock_session_' + Date.now();
|
|
782
|
+
this.sessionExpiry = new Date(Date.now() + 3600 * 1000);
|
|
783
|
+
this._storeSession();
|
|
784
|
+
return {
|
|
785
|
+
sessionToken: this.sessionToken,
|
|
786
|
+
config: {
|
|
787
|
+
primaryColor: '#21244A',
|
|
788
|
+
backgroundColor: '#ffffff',
|
|
789
|
+
textColor: '#1F2937',
|
|
790
|
+
boardId: 'feature-requests',
|
|
791
|
+
size: 'medium',
|
|
792
|
+
displayMode: 'modal',
|
|
793
|
+
},
|
|
794
|
+
expiresIn: 3600,
|
|
795
|
+
};
|
|
796
|
+
}
|
|
1153
797
|
|
|
1154
|
-
|
|
798
|
+
async _initRealSession() {
|
|
799
|
+
const payload = {
|
|
800
|
+
workspace: this.workspace,
|
|
801
|
+
user: this.userContext,
|
|
802
|
+
};
|
|
1155
803
|
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
},
|
|
804
|
+
try {
|
|
805
|
+
const response = await this._makeRequest('/widget/init', {
|
|
806
|
+
method: 'POST',
|
|
807
|
+
body: JSON.stringify(payload),
|
|
808
|
+
headers: { 'Content-Type': 'application/json' },
|
|
1161
809
|
});
|
|
1162
810
|
|
|
1163
|
-
|
|
811
|
+
this.sessionToken = response.session_token;
|
|
812
|
+
this.sessionExpiry = new Date(Date.now() + response.expires_in * 1000);
|
|
813
|
+
this._storeSession();
|
|
814
|
+
|
|
815
|
+
return {
|
|
816
|
+
sessionToken: this.sessionToken,
|
|
817
|
+
config: response.config || {},
|
|
818
|
+
expiresIn: response.expires_in,
|
|
819
|
+
};
|
|
820
|
+
} catch (error) {
|
|
821
|
+
throw new APIError(
|
|
822
|
+
error.status || 500,
|
|
823
|
+
`Failed to initialize widget: ${error.message}`,
|
|
824
|
+
error.response
|
|
825
|
+
);
|
|
826
|
+
}
|
|
827
|
+
}
|
|
828
|
+
|
|
829
|
+
async _ensureSession() {
|
|
830
|
+
if (!this.isSessionValid()) {
|
|
831
|
+
await this.init();
|
|
832
|
+
}
|
|
833
|
+
if (!this.sessionToken) {
|
|
834
|
+
throw new APIError(401, 'No valid session token available');
|
|
835
|
+
}
|
|
836
|
+
}
|
|
837
|
+
|
|
838
|
+
async _handleAuthRetry(method, ...args) {
|
|
839
|
+
try {
|
|
840
|
+
return await method.apply(this, args);
|
|
1164
841
|
} catch (error) {
|
|
1165
842
|
if (error.status === 401) {
|
|
1166
843
|
this.sessionToken = null;
|
|
1167
844
|
this.sessionExpiry = null;
|
|
1168
845
|
await this.init();
|
|
1169
|
-
return
|
|
846
|
+
return await method.apply(this, args);
|
|
1170
847
|
}
|
|
1171
|
-
|
|
1172
|
-
throw new APIError(
|
|
1173
|
-
error.status || 500,
|
|
1174
|
-
`Failed to get changelogs: ${error.message}`,
|
|
1175
|
-
error.response
|
|
1176
|
-
);
|
|
848
|
+
throw error;
|
|
1177
849
|
}
|
|
1178
850
|
}
|
|
1179
851
|
|
|
@@ -1185,12 +857,7 @@
|
|
|
1185
857
|
|
|
1186
858
|
setUserContext(userContext) {
|
|
1187
859
|
this.userContext = userContext;
|
|
1188
|
-
|
|
1189
|
-
localStorage.setItem(
|
|
1190
|
-
'feedbackSDK_userContext',
|
|
1191
|
-
JSON.stringify(userContext)
|
|
1192
|
-
);
|
|
1193
|
-
}
|
|
860
|
+
this._storeData('feedbackSDK_userContext', userContext);
|
|
1194
861
|
}
|
|
1195
862
|
|
|
1196
863
|
getUserContext() {
|
|
@@ -1200,30 +867,26 @@
|
|
|
1200
867
|
clearSession() {
|
|
1201
868
|
this.sessionToken = null;
|
|
1202
869
|
this.sessionExpiry = null;
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
localStorage.removeItem('feedbackSDK_userContext');
|
|
1206
|
-
}
|
|
870
|
+
this._removeData('feedbackSDK_session');
|
|
871
|
+
this._removeData('feedbackSDK_userContext');
|
|
1207
872
|
}
|
|
1208
873
|
|
|
1209
874
|
_storeSession() {
|
|
1210
875
|
if (typeof localStorage === 'undefined') return;
|
|
1211
|
-
|
|
1212
876
|
try {
|
|
1213
877
|
const sessionData = {
|
|
1214
878
|
token: this.sessionToken,
|
|
1215
879
|
expiry: this.sessionExpiry.toISOString(),
|
|
1216
880
|
workspace: this.workspace,
|
|
1217
881
|
};
|
|
1218
|
-
|
|
882
|
+
this._storeData('feedbackSDK_session', sessionData);
|
|
1219
883
|
} catch (error) {
|
|
1220
|
-
//
|
|
884
|
+
// Silent fail
|
|
1221
885
|
}
|
|
1222
886
|
}
|
|
1223
887
|
|
|
1224
888
|
_loadStoredSession() {
|
|
1225
889
|
if (typeof localStorage === 'undefined') return false;
|
|
1226
|
-
|
|
1227
890
|
try {
|
|
1228
891
|
const stored = localStorage.getItem('feedbackSDK_session');
|
|
1229
892
|
if (!stored) return false;
|
|
@@ -1238,6 +901,18 @@
|
|
|
1238
901
|
}
|
|
1239
902
|
}
|
|
1240
903
|
|
|
904
|
+
_storeData(key, value) {
|
|
905
|
+
if (typeof localStorage !== 'undefined') {
|
|
906
|
+
localStorage.setItem(key, JSON.stringify(value));
|
|
907
|
+
}
|
|
908
|
+
}
|
|
909
|
+
|
|
910
|
+
_removeData(key) {
|
|
911
|
+
if (typeof localStorage !== 'undefined') {
|
|
912
|
+
localStorage.removeItem(key);
|
|
913
|
+
}
|
|
914
|
+
}
|
|
915
|
+
|
|
1241
916
|
async _makeRequest(endpoint, options = {}) {
|
|
1242
917
|
const url = `${this.baseURL}${endpoint}`;
|
|
1243
918
|
|
|
@@ -1266,68 +941,172 @@
|
|
|
1266
941
|
|
|
1267
942
|
return await response.text();
|
|
1268
943
|
} catch (error) {
|
|
1269
|
-
if (error instanceof APIError)
|
|
1270
|
-
throw error;
|
|
1271
|
-
}
|
|
944
|
+
if (error instanceof APIError) throw error;
|
|
1272
945
|
throw new APIError(0, error.message, null);
|
|
1273
946
|
}
|
|
1274
947
|
}
|
|
1275
|
-
}
|
|
1276
948
|
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
949
|
+
_buildQueryParams(params) {
|
|
950
|
+
const queryParams = new URLSearchParams();
|
|
951
|
+
Object.entries(params).forEach(([key, value]) => {
|
|
952
|
+
if (value !== undefined && value !== null) {
|
|
953
|
+
queryParams.append(
|
|
954
|
+
key,
|
|
955
|
+
typeof value === 'object' ? JSON.stringify(value) : value
|
|
956
|
+
);
|
|
957
|
+
}
|
|
958
|
+
});
|
|
959
|
+
return queryParams.toString();
|
|
1280
960
|
}
|
|
1281
961
|
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
}
|
|
1286
|
-
this.events.get(event).push(callback);
|
|
1287
|
-
|
|
1288
|
-
return () => this.off(event, callback);
|
|
962
|
+
_getEndpointWithParams(endpoint, params) {
|
|
963
|
+
const queryString = this._buildQueryParams(params);
|
|
964
|
+
return `${endpoint}${queryString ? '?' + queryString : ''}`;
|
|
1289
965
|
}
|
|
966
|
+
}
|
|
1290
967
|
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
968
|
+
class APIService extends BaseAPIService {
|
|
969
|
+
constructor(config = {}) {
|
|
970
|
+
super(config);
|
|
971
|
+
|
|
972
|
+
this.feedback = new FeedbackService(this);
|
|
973
|
+
this.survey = new SurveyService(this);
|
|
974
|
+
this.messenger = new MessengerService(this);
|
|
975
|
+
this.help = new HelpService(this);
|
|
976
|
+
this.changelog = new ChangelogService(this);
|
|
1299
977
|
}
|
|
1300
978
|
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
if (callbacks) {
|
|
1304
|
-
callbacks.forEach((callback) => {
|
|
1305
|
-
try {
|
|
1306
|
-
callback(data);
|
|
1307
|
-
} catch (error) {
|
|
1308
|
-
console.error('[FeedbackSDK] Event callback error:', error);
|
|
1309
|
-
}
|
|
1310
|
-
});
|
|
1311
|
-
}
|
|
979
|
+
async submitFeedback(data) {
|
|
980
|
+
return this.feedback.submitFeedback(data);
|
|
1312
981
|
}
|
|
1313
982
|
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
callback(data);
|
|
1317
|
-
unsubscribe();
|
|
1318
|
-
});
|
|
1319
|
-
return unsubscribe;
|
|
983
|
+
async getActiveSurveys(context) {
|
|
984
|
+
return this.survey.getActiveSurveys(context);
|
|
1320
985
|
}
|
|
1321
986
|
|
|
1322
|
-
|
|
1323
|
-
this.
|
|
987
|
+
async submitSurveyResponse(surveyId, responseData) {
|
|
988
|
+
return this.survey.submitSurveyResponse(surveyId, responseData);
|
|
1324
989
|
}
|
|
1325
990
|
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
return callbacks ? callbacks.length : 0;
|
|
991
|
+
async dismissSurvey(surveyId) {
|
|
992
|
+
return this.survey.dismissSurvey(surveyId);
|
|
1329
993
|
}
|
|
1330
|
-
|
|
994
|
+
|
|
995
|
+
async getMessengerSettings() {
|
|
996
|
+
return this.messenger.getMessengerSettings();
|
|
997
|
+
}
|
|
998
|
+
|
|
999
|
+
async checkAgentsOnline() {
|
|
1000
|
+
return this.messenger.checkAgentsOnline();
|
|
1001
|
+
}
|
|
1002
|
+
|
|
1003
|
+
async getConversations(options) {
|
|
1004
|
+
return this.messenger.getConversations(options);
|
|
1005
|
+
}
|
|
1006
|
+
|
|
1007
|
+
async getConversation(conversationId) {
|
|
1008
|
+
return this.messenger.getConversation(conversationId);
|
|
1009
|
+
}
|
|
1010
|
+
|
|
1011
|
+
async getMessages(conversationId, options) {
|
|
1012
|
+
return this.messenger.getMessages(conversationId, options);
|
|
1013
|
+
}
|
|
1014
|
+
|
|
1015
|
+
async startConversation(data) {
|
|
1016
|
+
return this.messenger.startConversation(data);
|
|
1017
|
+
}
|
|
1018
|
+
|
|
1019
|
+
async sendMessage(conversationId, data) {
|
|
1020
|
+
return this.messenger.sendMessage(conversationId, data);
|
|
1021
|
+
}
|
|
1022
|
+
|
|
1023
|
+
async sendTypingIndicator(conversationId, isTyping) {
|
|
1024
|
+
return this.messenger.sendTypingIndicator(conversationId, isTyping);
|
|
1025
|
+
}
|
|
1026
|
+
|
|
1027
|
+
async markConversationAsRead(conversationId) {
|
|
1028
|
+
return this.messenger.markConversationAsRead(conversationId);
|
|
1029
|
+
}
|
|
1030
|
+
|
|
1031
|
+
async getUnreadCount() {
|
|
1032
|
+
return this.messenger.getUnreadCount();
|
|
1033
|
+
}
|
|
1034
|
+
|
|
1035
|
+
async submitRating(conversationId, data) {
|
|
1036
|
+
return this.messenger.submitRating(conversationId, data);
|
|
1037
|
+
}
|
|
1038
|
+
|
|
1039
|
+
async identifyContact(data) {
|
|
1040
|
+
return this.messenger.identifyContact(data);
|
|
1041
|
+
}
|
|
1042
|
+
|
|
1043
|
+
async getHelpCollections(options) {
|
|
1044
|
+
return this.help.getHelpCollections(options);
|
|
1045
|
+
}
|
|
1046
|
+
|
|
1047
|
+
async searchHelpArticles(query, options) {
|
|
1048
|
+
return this.help.searchHelpArticles(query, options);
|
|
1049
|
+
}
|
|
1050
|
+
|
|
1051
|
+
async getChangelogs(options) {
|
|
1052
|
+
return this.changelog.getChangelogs(options);
|
|
1053
|
+
}
|
|
1054
|
+
}
|
|
1055
|
+
|
|
1056
|
+
class EventBus {
|
|
1057
|
+
constructor() {
|
|
1058
|
+
this.events = new Map();
|
|
1059
|
+
}
|
|
1060
|
+
|
|
1061
|
+
on(event, callback) {
|
|
1062
|
+
if (!this.events.has(event)) {
|
|
1063
|
+
this.events.set(event, []);
|
|
1064
|
+
}
|
|
1065
|
+
this.events.get(event).push(callback);
|
|
1066
|
+
|
|
1067
|
+
return () => this.off(event, callback);
|
|
1068
|
+
}
|
|
1069
|
+
|
|
1070
|
+
off(event, callback) {
|
|
1071
|
+
const callbacks = this.events.get(event);
|
|
1072
|
+
if (callbacks) {
|
|
1073
|
+
const index = callbacks.indexOf(callback);
|
|
1074
|
+
if (index > -1) {
|
|
1075
|
+
callbacks.splice(index, 1);
|
|
1076
|
+
}
|
|
1077
|
+
}
|
|
1078
|
+
}
|
|
1079
|
+
|
|
1080
|
+
emit(event, data) {
|
|
1081
|
+
const callbacks = this.events.get(event);
|
|
1082
|
+
if (callbacks) {
|
|
1083
|
+
callbacks.forEach((callback) => {
|
|
1084
|
+
try {
|
|
1085
|
+
callback(data);
|
|
1086
|
+
} catch (error) {
|
|
1087
|
+
console.error('[FeedbackSDK] Event callback error:', error);
|
|
1088
|
+
}
|
|
1089
|
+
});
|
|
1090
|
+
}
|
|
1091
|
+
}
|
|
1092
|
+
|
|
1093
|
+
once(event, callback) {
|
|
1094
|
+
const unsubscribe = this.on(event, (data) => {
|
|
1095
|
+
callback(data);
|
|
1096
|
+
unsubscribe();
|
|
1097
|
+
});
|
|
1098
|
+
return unsubscribe;
|
|
1099
|
+
}
|
|
1100
|
+
|
|
1101
|
+
clear() {
|
|
1102
|
+
this.events.clear();
|
|
1103
|
+
}
|
|
1104
|
+
|
|
1105
|
+
getListenerCount(event) {
|
|
1106
|
+
const callbacks = this.events.get(event);
|
|
1107
|
+
return callbacks ? callbacks.length : 0;
|
|
1108
|
+
}
|
|
1109
|
+
}
|
|
1331
1110
|
|
|
1332
1111
|
function generateId(prefix = 'feedback') {
|
|
1333
1112
|
const timestamp = Date.now();
|
|
@@ -3503,15 +3282,12 @@
|
|
|
3503
3282
|
}
|
|
3504
3283
|
}
|
|
3505
3284
|
|
|
3506
|
-
/**
|
|
3507
|
-
* MessengerLauncher - Floating trigger button for messenger
|
|
3508
|
-
*/
|
|
3509
3285
|
class MessengerLauncher {
|
|
3510
3286
|
constructor(state, options = {}) {
|
|
3511
3287
|
this.state = state;
|
|
3512
3288
|
this.options = {
|
|
3513
3289
|
position: options.position || 'bottom-right',
|
|
3514
|
-
primaryColor: options.primaryColor || '#
|
|
3290
|
+
primaryColor: options.primaryColor || '#155eff',
|
|
3515
3291
|
...options,
|
|
3516
3292
|
};
|
|
3517
3293
|
this.element = null;
|
|
@@ -3525,7 +3301,6 @@
|
|
|
3525
3301
|
this._updateContent();
|
|
3526
3302
|
this._attachEvents();
|
|
3527
3303
|
|
|
3528
|
-
// Subscribe to state changes
|
|
3529
3304
|
this._unsubscribe = this.state.subscribe((type, data) => {
|
|
3530
3305
|
if (type === 'openChange') {
|
|
3531
3306
|
this._updateIcon();
|
|
@@ -3547,10 +3322,14 @@
|
|
|
3547
3322
|
this.element.innerHTML = `
|
|
3548
3323
|
<button class="messenger-launcher-btn" aria-label="Open messenger" style="background: ${this.options.primaryColor};">
|
|
3549
3324
|
<span class="messenger-launcher-icon messenger-launcher-icon-chat">
|
|
3550
|
-
<
|
|
3325
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="#ffffff" viewBox="0 0 256 256">
|
|
3326
|
+
<path d="M144,140a12,12,0,1,1-12-12A12,12,0,0,1,144,140Zm44-12a12,12,0,1,0,12,12A12,12,0,0,0,188,128Zm51.34,83.47a16,16,0,0,1-19.87,19.87l-24.71-7.27A80,80,0,0,1,86.43,183.42a79,79,0,0,1-25.19-7.35l-24.71,7.27a16,16,0,0,1-19.87-19.87l7.27-24.71A80,80,0,1,1,169.58,72.59a80,80,0,0,1,62.49,114.17ZM81.3,166.3a79.94,79.94,0,0,1,70.38-93.87A64,64,0,0,0,39.55,134.19a8,8,0,0,1,.63,6L32,168l27.76-8.17a8,8,0,0,1,6,.63A63.45,63.45,0,0,0,81.3,166.3Zm135.15,15.89a64,64,0,1,0-26.26,26.26,8,8,0,0,1,6-.63L224,216l-8.17-27.76A8,8,0,0,1,216.45,182.19Z"></path>
|
|
3327
|
+
</svg>
|
|
3551
3328
|
</span>
|
|
3552
3329
|
<span class="messenger-launcher-icon messenger-launcher-icon-close" style="display: none;">
|
|
3553
|
-
<
|
|
3330
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="#ffffff" viewBox="0 0 256 256">
|
|
3331
|
+
<path d="M205.66,194.34a8,8,0,0,1-11.32,11.32L128,139.31,61.66,205.66a8,8,0,0,1-11.32-11.32L116.69,128,50.34,61.66A8,8,0,0,1,61.66,50.34L128,116.69l66.34-66.35a8,8,0,0,1,11.32,11.32L139.31,128Z"></path>
|
|
3332
|
+
</svg>
|
|
3554
3333
|
</span>
|
|
3555
3334
|
${badgeHtml}
|
|
3556
3335
|
</button>
|
|
@@ -3733,19 +3512,31 @@
|
|
|
3733
3512
|
}
|
|
3734
3513
|
|
|
3735
3514
|
_getHomeIcon() {
|
|
3736
|
-
return `<
|
|
3515
|
+
return `<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="#000000" viewBox="0 0 256 256">
|
|
3516
|
+
<path d="M216,115.54V208a8,8,0,0,1-8,8H160a8,8,0,0,1-8-8V160a8,8,0,0,0-8-8H112a8,8,0,0,0-8,8v48a8,8,0,0,1-8,8H48a8,8,0,0,1-8-8V115.54a8,8,0,0,1,2.62-5.92l80-75.54a8,8,0,0,1,10.77,0l80,75.54A8,8,0,0,1,216,115.54Z" opacity="0.2"></path>
|
|
3517
|
+
<path d="M218.83,103.77l-80-75.48a1.14,1.14,0,0,1-.11-.11,16,16,0,0,0-21.53,0l-.11.11L37.17,103.77A16,16,0,0,0,32,115.55V208a16,16,0,0,0,16,16H96a16,16,0,0,0,16-16V160h32v48a16,16,0,0,0,16,16h48a16,16,0,0,0,16-16V115.55A16,16,0,0,0,218.83,103.77ZM208,208H160V160a16,16,0,0,0-16-16H112a16,16,0,0,0-16,16v48H48V115.55l.11-.1L128,40l79.9,75.43.11.1Z"></path>
|
|
3518
|
+
</svg>`;
|
|
3737
3519
|
}
|
|
3738
3520
|
|
|
3739
3521
|
_getMessagesIcon() {
|
|
3740
|
-
return `<
|
|
3522
|
+
return `<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="#000000" viewBox="0 0 256 256">
|
|
3523
|
+
<path d="M224,64V192a8,8,0,0,1-8,8H82.5a8,8,0,0,0-5.15,1.88l-32.2,28.23A8,8,0,0,1,32,224V64a8,8,0,0,1,8-8H216A8,8,0,0,1,224,64Z" opacity="0.2"></path>
|
|
3524
|
+
<path d="M216,48H40A16,16,0,0,0,24,64V224a15.85,15.85,0,0,0,9.24,14.5A16.13,16.13,0,0,0,40,240a15.89,15.89,0,0,0,10.25-3.78.69.69,0,0,0,.13-.11L82.5,208H216a16,16,0,0,0,16-16V64A16,16,0,0,0,216,48ZM40,224h0ZM216,192H82.5a16,16,0,0,0-10.3,3.75l-.12.11L40,224V64H216Z"></path>
|
|
3525
|
+
</svg>`;
|
|
3741
3526
|
}
|
|
3742
3527
|
|
|
3743
3528
|
_getHelpIcon() {
|
|
3744
|
-
return `<
|
|
3529
|
+
return `<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="#000000" viewBox="0 0 256 256">
|
|
3530
|
+
<path d="M224,128a96,96,0,1,1-96-96A96,96,0,0,1,224,128Z" opacity="0.2"></path>
|
|
3531
|
+
<path d="M128,24A104,104,0,1,0,232,128,104.11,104.11,0,0,0,128,24Zm0,192a88,88,0,1,1,88-88A88.1,88.1,0,0,1,128,216Zm16-40a8,8,0,0,1-8,8,16,16,0,0,1-16-16V128a8,8,0,0,1,0-16,16,16,0,0,1,16,16v40A8,8,0,0,1,144,176ZM112,84a12,12,0,1,1,12,12A12,12,0,0,1,112,84Z"></path>
|
|
3532
|
+
</svg>`;
|
|
3745
3533
|
}
|
|
3746
3534
|
|
|
3747
3535
|
_getChangelogIcon() {
|
|
3748
|
-
return `<
|
|
3536
|
+
return `<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="#000000" viewBox="0 0 256 256">
|
|
3537
|
+
<path d="M200,144a32,32,0,0,1-63.5,4.5L85.83,121.25a32.07,32.07,0,0,1-41.54-34l-24.15-21a8,8,0,0,1,10.25-12.29L54.55,75a32,32,0,0,1,59.16,2.5l50.63,27.25a31.88,31.88,0,0,1,35.66,7l26.46-23A8,8,0,1,1,236.71,101l-26.46,23A32,32,0,0,1,200,144Z" opacity="0.2"></path>
|
|
3538
|
+
<path d="M228.54,86.66l-26.46,23.07A40,40,0,0,0,168,72.13L120.89,46.5a40,40,0,0,0-75.44-4l-22-19.2a8,8,0,0,0-10.5,12L35.44,54.77a40,40,0,0,0,50,61.07l47.1,25.64a40,40,0,0,0,75.41,4.07l26.46-23.07a8,8,0,0,0-10.5-12ZM56,96A24,24,0,1,1,77.25,82.75,24,24,0,0,1,56,96Zm144,64a24,24,0,1,1,24-24A24,24,0,0,1,200,160Z"></path>
|
|
3539
|
+
</svg>`;
|
|
3749
3540
|
}
|
|
3750
3541
|
|
|
3751
3542
|
destroy() {
|
|
@@ -3888,9 +3679,6 @@
|
|
|
3888
3679
|
}
|
|
3889
3680
|
}
|
|
3890
3681
|
|
|
3891
|
-
/**
|
|
3892
|
-
* ChangelogView - Changelog and announcements
|
|
3893
|
-
*/
|
|
3894
3682
|
class ChangelogView {
|
|
3895
3683
|
constructor(state, options = {}) {
|
|
3896
3684
|
this.state = state;
|
|
@@ -3905,7 +3693,6 @@
|
|
|
3905
3693
|
|
|
3906
3694
|
this._updateContent();
|
|
3907
3695
|
|
|
3908
|
-
// Subscribe to state changes
|
|
3909
3696
|
this._unsubscribe = this.state.subscribe((type) => {
|
|
3910
3697
|
if (type === 'changelogUpdate') {
|
|
3911
3698
|
this._updateChangelogList();
|
|
@@ -3922,7 +3709,9 @@
|
|
|
3922
3709
|
<div class="messenger-changelog-header">
|
|
3923
3710
|
<h2>Changelog</h2>
|
|
3924
3711
|
<button class="messenger-close-btn" aria-label="Close">
|
|
3925
|
-
<
|
|
3712
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" fill="#000000" viewBox="0 0 256 256">
|
|
3713
|
+
<path d="M205.66,194.34a8,8,0,0,1-11.32,11.32L128,139.31,61.66,205.66a8,8,0,0,1-11.32-11.32L116.69,128,50.34,61.66A8,8,0,0,1,61.66,50.34L128,116.69l66.34-66.35a8,8,0,0,1,11.32,11.32L139.31,128Z"></path>
|
|
3714
|
+
</svg>
|
|
3926
3715
|
</button>
|
|
3927
3716
|
</div>
|
|
3928
3717
|
|
|
@@ -3958,7 +3747,6 @@
|
|
|
3958
3747
|
.map((item) => this._renderChangelogCard(item))
|
|
3959
3748
|
.join('');
|
|
3960
3749
|
|
|
3961
|
-
// Attach click events
|
|
3962
3750
|
this._attachChangelogEvents();
|
|
3963
3751
|
}
|
|
3964
3752
|
|
|
@@ -3989,7 +3777,9 @@
|
|
|
3989
3777
|
${item.description ? `<p class="messenger-changelog-description">${this._truncateText(item.description, 100)}</p>` : ''}
|
|
3990
3778
|
<div class="messenger-changelog-meta">
|
|
3991
3779
|
<span class="messenger-changelog-date">${dateStr}</span>
|
|
3992
|
-
<
|
|
3780
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="#000000" viewBox="0 0 256 256" class="messenger-changelog-arrow">
|
|
3781
|
+
<path d="M181.66,133.66l-80,80a8,8,0,0,1-11.32-11.32L164.69,128,90.34,53.66a8,8,0,0,1,11.32-11.32l80,80A8,8,0,0,1,181.66,133.66Z"></path>
|
|
3782
|
+
</svg>
|
|
3993
3783
|
</div>
|
|
3994
3784
|
</div>
|
|
3995
3785
|
</div>
|
|
@@ -4024,7 +3814,9 @@
|
|
|
4024
3814
|
return `
|
|
4025
3815
|
<div class="messenger-changelog-empty">
|
|
4026
3816
|
<div class="messenger-changelog-empty-icon">
|
|
4027
|
-
<
|
|
3817
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" fill="#000000" viewBox="0 0 256 256">
|
|
3818
|
+
<path d="M228.54,86.66l-26.46,23.07A40,40,0,0,0,168,72.13L120.89,46.5a40,40,0,0,0-75.44-4l-22-19.2a8,8,0,0,0-10.5,12L35.44,54.77a40,40,0,0,0,50,61.07l47.1,25.64a40,40,0,0,0,75.41,4.07l26.46-23.07a8,8,0,0,0-10.5-12ZM56,96A24,24,0,1,1,77.25,82.75,24,24,0,0,1,56,96Zm144,64a24,24,0,1,1,24-24A24,24,0,0,1,200,160Z"></path>
|
|
3819
|
+
</svg>
|
|
4028
3820
|
</div>
|
|
4029
3821
|
<h3>No changelog yet</h3>
|
|
4030
3822
|
<p>Check back later for updates</p>
|
|
@@ -4049,7 +3841,6 @@
|
|
|
4049
3841
|
}
|
|
4050
3842
|
|
|
4051
3843
|
_attachEvents() {
|
|
4052
|
-
// Close button
|
|
4053
3844
|
this.element
|
|
4054
3845
|
.querySelector('.messenger-close-btn')
|
|
4055
3846
|
.addEventListener('click', () => {
|
|
@@ -4087,9 +3878,6 @@
|
|
|
4087
3878
|
}
|
|
4088
3879
|
}
|
|
4089
3880
|
|
|
4090
|
-
/**
|
|
4091
|
-
* ChatView - Individual conversation chat
|
|
4092
|
-
*/
|
|
4093
3881
|
class ChatView {
|
|
4094
3882
|
constructor(state, options = {}) {
|
|
4095
3883
|
this.state = state;
|
|
@@ -4107,7 +3895,6 @@
|
|
|
4107
3895
|
|
|
4108
3896
|
this._updateContent();
|
|
4109
3897
|
|
|
4110
|
-
// Subscribe to state changes
|
|
4111
3898
|
this._unsubscribe = this.state.subscribe((type, data) => {
|
|
4112
3899
|
if (
|
|
4113
3900
|
type === 'messageAdded' &&
|
|
@@ -4158,14 +3945,18 @@
|
|
|
4158
3945
|
this.element.innerHTML = `
|
|
4159
3946
|
<div class="messenger-chat-header">
|
|
4160
3947
|
<button class="messenger-back-btn" aria-label="Back">
|
|
4161
|
-
<
|
|
3948
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" fill="#000000" viewBox="0 0 256 256">
|
|
3949
|
+
<path d="M165.66,202.34a8,8,0,0,1-11.32,11.32l-80-80a8,8,0,0,1,0-11.32l80-80a8,8,0,0,1,11.32,11.32L91.31,128Z"></path>
|
|
3950
|
+
</svg>
|
|
4162
3951
|
</button>
|
|
4163
3952
|
<div class="messenger-chat-header-info">
|
|
4164
3953
|
${avatarHtml}
|
|
4165
3954
|
<span class="messenger-chat-title">${title}</span>
|
|
4166
3955
|
</div>
|
|
4167
3956
|
<button class="messenger-close-btn" aria-label="Close">
|
|
4168
|
-
<
|
|
3957
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" fill="#000000" viewBox="0 0 256 256">
|
|
3958
|
+
<path d="M205.66,194.34a8,8,0,0,1-11.32,11.32L128,139.31,61.66,205.66a8,8,0,0,1-11.32-11.32L116.69,128,50.34,61.66A8,8,0,0,1,61.66,50.34L128,116.69l66.34-66.35a8,8,0,0,1,11.32,11.32L139.31,128Z"></path>
|
|
3959
|
+
</svg>
|
|
4169
3960
|
</button>
|
|
4170
3961
|
</div>
|
|
4171
3962
|
|
|
@@ -4184,7 +3975,9 @@
|
|
|
4184
3975
|
<textarea class="messenger-compose-input" placeholder="${placeholder}" rows="1"></textarea>
|
|
4185
3976
|
</div>
|
|
4186
3977
|
<button class="messenger-compose-send" aria-label="Send" disabled>
|
|
4187
|
-
<
|
|
3978
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" fill="#000000" viewBox="0 0 256 256">
|
|
3979
|
+
<path d="M227.32,28.68a16,16,0,0,0-15.66-4.08l-.15,0L19.57,82.84a16,16,0,0,0-2.49,29.8L102,154l41.3,84.87A15.86,15.86,0,0,0,157.74,248q.69,0,1.38-.06a15.88,15.88,0,0,0,14-11.51l58.2-191.94c0-.05,0-.1,0-.15A16,16,0,0,0,227.32,28.68ZM157.83,231.85l-.05.14L118.42,148.9l47.24-47.25a8,8,0,0,0-11.31-11.31L107.1,137.58,24,98.22l.14,0L216,40Z"></path>
|
|
3980
|
+
</svg>
|
|
4188
3981
|
</button>
|
|
4189
3982
|
</div>
|
|
4190
3983
|
`;
|
|
@@ -4304,7 +4097,6 @@
|
|
|
4304
4097
|
|
|
4305
4098
|
_formatMessageContent(content) {
|
|
4306
4099
|
if (!content) return '';
|
|
4307
|
-
// Basic HTML escaping and line breaks
|
|
4308
4100
|
return content
|
|
4309
4101
|
.replace(/&/g, '&')
|
|
4310
4102
|
.replace(/</g, '<')
|
|
@@ -4339,33 +4131,27 @@
|
|
|
4339
4131
|
}
|
|
4340
4132
|
|
|
4341
4133
|
_attachEvents() {
|
|
4342
|
-
// Back button
|
|
4343
4134
|
this.element
|
|
4344
4135
|
.querySelector('.messenger-back-btn')
|
|
4345
4136
|
.addEventListener('click', () => {
|
|
4346
4137
|
this.state.setView('messages');
|
|
4347
4138
|
});
|
|
4348
4139
|
|
|
4349
|
-
// Close button
|
|
4350
4140
|
this.element
|
|
4351
4141
|
.querySelector('.messenger-close-btn')
|
|
4352
4142
|
.addEventListener('click', () => {
|
|
4353
4143
|
this.state.setOpen(false);
|
|
4354
4144
|
});
|
|
4355
4145
|
|
|
4356
|
-
// Compose input
|
|
4357
4146
|
const input = this.element.querySelector('.messenger-compose-input');
|
|
4358
4147
|
const sendBtn = this.element.querySelector('.messenger-compose-send');
|
|
4359
4148
|
|
|
4360
4149
|
input.addEventListener('input', () => {
|
|
4361
|
-
// Auto-resize textarea
|
|
4362
4150
|
input.style.height = 'auto';
|
|
4363
4151
|
input.style.height = Math.min(input.scrollHeight, 120) + 'px';
|
|
4364
4152
|
|
|
4365
|
-
// Enable/disable send button
|
|
4366
4153
|
sendBtn.disabled = !input.value.trim();
|
|
4367
4154
|
|
|
4368
|
-
// Send typing indicator
|
|
4369
4155
|
if (input.value.trim()) {
|
|
4370
4156
|
this._startTyping();
|
|
4371
4157
|
}
|
|
@@ -4389,18 +4175,15 @@
|
|
|
4389
4175
|
|
|
4390
4176
|
if (!content) return;
|
|
4391
4177
|
|
|
4392
|
-
// Stop typing indicator
|
|
4393
4178
|
this._stopTyping();
|
|
4394
4179
|
|
|
4395
4180
|
const isNewConversation = !this.state.activeConversationId;
|
|
4396
4181
|
|
|
4397
4182
|
if (isNewConversation) {
|
|
4398
|
-
// Start a new conversation
|
|
4399
4183
|
if (this.options.onStartConversation) {
|
|
4400
4184
|
this.options.onStartConversation(content);
|
|
4401
4185
|
}
|
|
4402
4186
|
} else {
|
|
4403
|
-
// Add message to existing conversation
|
|
4404
4187
|
const message = {
|
|
4405
4188
|
id: 'msg_' + Date.now(),
|
|
4406
4189
|
content: content,
|
|
@@ -4410,13 +4193,11 @@
|
|
|
4410
4193
|
|
|
4411
4194
|
this.state.addMessage(this.state.activeConversationId, message);
|
|
4412
4195
|
|
|
4413
|
-
// Emit event for API integration
|
|
4414
4196
|
if (this.options.onSendMessage) {
|
|
4415
4197
|
this.options.onSendMessage(this.state.activeConversationId, message);
|
|
4416
4198
|
}
|
|
4417
4199
|
}
|
|
4418
4200
|
|
|
4419
|
-
// Clear input
|
|
4420
4201
|
input.value = '';
|
|
4421
4202
|
input.style.height = 'auto';
|
|
4422
4203
|
this.element.querySelector('.messenger-compose-send').disabled = true;
|
|
@@ -4430,7 +4211,6 @@
|
|
|
4430
4211
|
}
|
|
4431
4212
|
}
|
|
4432
4213
|
|
|
4433
|
-
// Reset typing timeout
|
|
4434
4214
|
if (this._typingTimeout) {
|
|
4435
4215
|
clearTimeout(this._typingTimeout);
|
|
4436
4216
|
}
|
|
@@ -4485,9 +4265,6 @@
|
|
|
4485
4265
|
}
|
|
4486
4266
|
}
|
|
4487
4267
|
|
|
4488
|
-
/**
|
|
4489
|
-
* ConversationsView - Message thread list
|
|
4490
|
-
*/
|
|
4491
4268
|
class ConversationsView {
|
|
4492
4269
|
constructor(state, options = {}) {
|
|
4493
4270
|
this.state = state;
|
|
@@ -4503,7 +4280,6 @@
|
|
|
4503
4280
|
this._updateContent();
|
|
4504
4281
|
this._attachEvents();
|
|
4505
4282
|
|
|
4506
|
-
// Subscribe to state changes
|
|
4507
4283
|
this._unsubscribe = this.state.subscribe((type) => {
|
|
4508
4284
|
if (
|
|
4509
4285
|
type === 'conversationsUpdate' ||
|
|
@@ -4526,7 +4302,9 @@
|
|
|
4526
4302
|
conversationsHtml = `
|
|
4527
4303
|
<div class="messenger-conversations-empty">
|
|
4528
4304
|
<div class="messenger-conversations-empty-icon">
|
|
4529
|
-
<
|
|
4305
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" fill="#000000" viewBox="0 0 256 256">
|
|
4306
|
+
<path d="M216,48H40A16,16,0,0,0,24,64V224a15.85,15.85,0,0,0,9.24,14.5A16.13,16.13,0,0,0,40,240a15.89,15.89,0,0,0,10.25-3.78.69.69,0,0,0,.13-.11L82.5,208H216a16,16,0,0,0,16-16V64A16,16,0,0,0,216,48ZM40,224h0ZM216,192H82.5a16,16,0,0,0-10.3,3.75l-.12.11L40,224V64H216Z"></path>
|
|
4307
|
+
</svg>
|
|
4530
4308
|
</div>
|
|
4531
4309
|
<h3>No conversations yet</h3>
|
|
4532
4310
|
<p>Start a new conversation with our team</p>
|
|
@@ -4544,7 +4322,9 @@
|
|
|
4544
4322
|
<div class="messenger-conversations-header">
|
|
4545
4323
|
<h2>Messages</h2>
|
|
4546
4324
|
<button class="messenger-close-btn" aria-label="Close">
|
|
4547
|
-
<
|
|
4325
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" fill="#000000" viewBox="0 0 256 256">
|
|
4326
|
+
<path d="M205.66,194.34a8,8,0,0,1-11.32,11.32L128,139.31,61.66,205.66a8,8,0,0,1-11.32-11.32L116.69,128,50.34,61.66A8,8,0,0,1,61.66,50.34L128,116.69l66.34-66.35a8,8,0,0,1,11.32,11.32L139.31,128Z"></path>
|
|
4327
|
+
</svg>
|
|
4548
4328
|
</button>
|
|
4549
4329
|
</div>
|
|
4550
4330
|
|
|
@@ -4556,7 +4336,9 @@
|
|
|
4556
4336
|
<button class="messenger-new-message-btn">
|
|
4557
4337
|
<div class="messenger-new-message-avatars">${avatarsHtml}</div>
|
|
4558
4338
|
<span>Send us a message</span>
|
|
4559
|
-
<
|
|
4339
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="#000000" viewBox="0 0 256 256">
|
|
4340
|
+
<path d="M221.66,133.66l-72,72a8,8,0,0,1-11.32-11.32L196.69,136H40a8,8,0,0,1,0-16H196.69L138.34,61.66a8,8,0,0,1,11.32-11.32l72,72A8,8,0,0,1,221.66,133.66Z"></path>
|
|
4341
|
+
</svg>
|
|
4560
4342
|
</button>
|
|
4561
4343
|
</div>
|
|
4562
4344
|
`;
|
|
@@ -4655,7 +4437,6 @@
|
|
|
4655
4437
|
}
|
|
4656
4438
|
|
|
4657
4439
|
_attachEvents() {
|
|
4658
|
-
// Close button
|
|
4659
4440
|
const closeBtn = this.element.querySelector('.messenger-close-btn');
|
|
4660
4441
|
if (closeBtn) {
|
|
4661
4442
|
closeBtn.addEventListener('click', () => {
|
|
@@ -4663,7 +4444,6 @@
|
|
|
4663
4444
|
});
|
|
4664
4445
|
}
|
|
4665
4446
|
|
|
4666
|
-
// Conversation items
|
|
4667
4447
|
this.element
|
|
4668
4448
|
.querySelectorAll('.messenger-conversation-item')
|
|
4669
4449
|
.forEach((item) => {
|
|
@@ -4673,14 +4453,12 @@
|
|
|
4673
4453
|
this.state.markAsRead(convId);
|
|
4674
4454
|
this.state.setView('chat');
|
|
4675
4455
|
|
|
4676
|
-
// Notify widget to fetch messages
|
|
4677
4456
|
if (this.options.onSelectConversation) {
|
|
4678
4457
|
this.options.onSelectConversation(convId);
|
|
4679
4458
|
}
|
|
4680
4459
|
});
|
|
4681
4460
|
});
|
|
4682
4461
|
|
|
4683
|
-
// New message button
|
|
4684
4462
|
const newMsgBtn = this.element.querySelector('.messenger-new-message-btn');
|
|
4685
4463
|
if (newMsgBtn) {
|
|
4686
4464
|
newMsgBtn.addEventListener('click', () => {
|
|
@@ -4690,11 +4468,9 @@
|
|
|
4690
4468
|
}
|
|
4691
4469
|
|
|
4692
4470
|
_startNewConversation() {
|
|
4693
|
-
// Set view to chat with no active conversation (new conversation mode)
|
|
4694
4471
|
this.state.setActiveConversation(null);
|
|
4695
4472
|
this.state.setView('chat');
|
|
4696
4473
|
|
|
4697
|
-
// Notify widget to handle new conversation flow
|
|
4698
4474
|
if (this.options.onStartNewConversation) {
|
|
4699
4475
|
this.options.onStartNewConversation();
|
|
4700
4476
|
}
|
|
@@ -4710,9 +4486,6 @@
|
|
|
4710
4486
|
}
|
|
4711
4487
|
}
|
|
4712
4488
|
|
|
4713
|
-
/**
|
|
4714
|
-
* HelpView - Help collections browse with Intercom-style design
|
|
4715
|
-
*/
|
|
4716
4489
|
class HelpView {
|
|
4717
4490
|
constructor(state, options = {}) {
|
|
4718
4491
|
this.state = state;
|
|
@@ -4727,7 +4500,6 @@
|
|
|
4727
4500
|
|
|
4728
4501
|
this._updateContent();
|
|
4729
4502
|
|
|
4730
|
-
// Subscribe to state changes
|
|
4731
4503
|
this._unsubscribe = this.state.subscribe((type) => {
|
|
4732
4504
|
if (type === 'helpArticlesUpdate' || type === 'helpSearchChange') {
|
|
4733
4505
|
this._updateCollectionsList();
|
|
@@ -4746,7 +4518,9 @@
|
|
|
4746
4518
|
<div class="messenger-help-header">
|
|
4747
4519
|
<h2>Help</h2>
|
|
4748
4520
|
<button class="messenger-close-btn" aria-label="Close">
|
|
4749
|
-
<
|
|
4521
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" fill="#000000" viewBox="0 0 256 256">
|
|
4522
|
+
<path d="M205.66,194.34a8,8,0,0,1-11.32,11.32L128,139.31,61.66,205.66a8,8,0,0,1-11.32-11.32L116.69,128,50.34,61.66A8,8,0,0,1,61.66,50.34L128,116.69l66.34-66.35a8,8,0,0,1,11.32,11.32L139.31,128Z"></path>
|
|
4523
|
+
</svg>
|
|
4750
4524
|
</button>
|
|
4751
4525
|
</div>
|
|
4752
4526
|
|
|
@@ -4758,7 +4532,9 @@
|
|
|
4758
4532
|
placeholder="Search for help"
|
|
4759
4533
|
value="${searchQuery}"
|
|
4760
4534
|
/>
|
|
4761
|
-
<
|
|
4535
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" fill="#000000" viewBox="0 0 256 256" class="messenger-help-search-icon">
|
|
4536
|
+
<path d="M229.66,218.34l-50.07-50.06a88.11,88.11,0,1,0-11.31,11.31l50.06,50.07a8,8,0,0,0,11.32-11.32ZM40,112a72,72,0,1,1,72,72A72.08,72.08,0,0,1,40,112Z"></path>
|
|
4537
|
+
</svg>
|
|
4762
4538
|
</div>
|
|
4763
4539
|
</div>
|
|
4764
4540
|
|
|
@@ -4781,7 +4557,6 @@
|
|
|
4781
4557
|
const collections = this.state.helpArticles || [];
|
|
4782
4558
|
const searchQuery = (this.state.helpSearchQuery || '').toLowerCase();
|
|
4783
4559
|
|
|
4784
|
-
// Filter collections by search
|
|
4785
4560
|
const filteredCollections = searchQuery
|
|
4786
4561
|
? collections.filter(
|
|
4787
4562
|
(c) =>
|
|
@@ -4790,7 +4565,6 @@
|
|
|
4790
4565
|
)
|
|
4791
4566
|
: collections;
|
|
4792
4567
|
|
|
4793
|
-
// Update collection count
|
|
4794
4568
|
const headerEl = this.element.querySelector(
|
|
4795
4569
|
'.messenger-help-collections-header'
|
|
4796
4570
|
);
|
|
@@ -4807,7 +4581,6 @@
|
|
|
4807
4581
|
.map((collection) => this._renderCollectionItem(collection))
|
|
4808
4582
|
.join('');
|
|
4809
4583
|
|
|
4810
|
-
// Attach click events
|
|
4811
4584
|
this._attachCollectionEvents();
|
|
4812
4585
|
}
|
|
4813
4586
|
|
|
@@ -4820,7 +4593,9 @@
|
|
|
4820
4593
|
<p class="messenger-help-collection-desc">${collection.description || ''}</p>
|
|
4821
4594
|
<span class="messenger-help-collection-count">${articleCount} articles</span>
|
|
4822
4595
|
</div>
|
|
4823
|
-
<
|
|
4596
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" fill="#000000" viewBox="0 0 256 256" class="messenger-help-collection-arrow">
|
|
4597
|
+
<path d="M181.66,133.66l-80,80a8,8,0,0,1-11.32-11.32L164.69,128,90.34,53.66a8,8,0,0,1,11.32-11.32l80,80A8,8,0,0,1,181.66,133.66Z"></path>
|
|
4598
|
+
</svg>
|
|
4824
4599
|
</div>
|
|
4825
4600
|
`;
|
|
4826
4601
|
}
|
|
@@ -4832,7 +4607,9 @@
|
|
|
4832
4607
|
return `
|
|
4833
4608
|
<div class="messenger-help-empty">
|
|
4834
4609
|
<div class="messenger-help-empty-icon">
|
|
4835
|
-
<
|
|
4610
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" fill="#000000" viewBox="0 0 256 256">
|
|
4611
|
+
<path d="M229.66,218.34l-50.07-50.06a88.11,88.11,0,1,0-11.31,11.31l50.06,50.07a8,8,0,0,0,11.32-11.32ZM40,112a72,72,0,1,1,72,72A72.08,72.08,0,0,1,40,112Z"></path>
|
|
4612
|
+
</svg>
|
|
4836
4613
|
</div>
|
|
4837
4614
|
<h3>No results found</h3>
|
|
4838
4615
|
<p>Try a different search term</p>
|
|
@@ -4843,7 +4620,9 @@
|
|
|
4843
4620
|
return `
|
|
4844
4621
|
<div class="messenger-help-empty">
|
|
4845
4622
|
<div class="messenger-help-empty-icon">
|
|
4846
|
-
<
|
|
4623
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" fill="#000000" viewBox="0 0 256 256">
|
|
4624
|
+
<path d="M128,24A104,104,0,1,0,232,128,104.11,104.11,0,0,0,128,24Zm0,192a88,88,0,1,1,88-88A88.1,88.1,0,0,1,128,216Zm16-40a8,8,0,0,1-8,8,16,16,0,0,1-16-16V128a8,8,0,0,1,0-16,16,16,0,0,1,16,16v40A8,8,0,0,1,144,176ZM112,84a12,12,0,1,1,12,12A12,12,0,0,1,112,84Z"></path>
|
|
4625
|
+
</svg>
|
|
4847
4626
|
</div>
|
|
4848
4627
|
<h3>Help collections</h3>
|
|
4849
4628
|
<p>No collections available yet</p>
|
|
@@ -4852,14 +4631,12 @@
|
|
|
4852
4631
|
}
|
|
4853
4632
|
|
|
4854
4633
|
_attachEvents() {
|
|
4855
|
-
// Close button
|
|
4856
4634
|
this.element
|
|
4857
4635
|
.querySelector('.messenger-close-btn')
|
|
4858
4636
|
.addEventListener('click', () => {
|
|
4859
4637
|
this.state.setOpen(false);
|
|
4860
4638
|
});
|
|
4861
4639
|
|
|
4862
|
-
// Search input
|
|
4863
4640
|
const searchInput = this.element.querySelector(
|
|
4864
4641
|
'.messenger-help-search-input'
|
|
4865
4642
|
);
|
|
@@ -4902,9 +4679,6 @@
|
|
|
4902
4679
|
}
|
|
4903
4680
|
}
|
|
4904
4681
|
|
|
4905
|
-
/**
|
|
4906
|
-
* HomeView - Welcome screen with team info and quick actions
|
|
4907
|
-
*/
|
|
4908
4682
|
class HomeView {
|
|
4909
4683
|
constructor(state, options = {}) {
|
|
4910
4684
|
this.state = state;
|
|
@@ -4919,7 +4693,6 @@
|
|
|
4919
4693
|
|
|
4920
4694
|
this._updateContent();
|
|
4921
4695
|
|
|
4922
|
-
// Subscribe to state changes to re-render when data loads
|
|
4923
4696
|
this._unsubscribe = this.state.subscribe((type) => {
|
|
4924
4697
|
if (
|
|
4925
4698
|
type === 'homeChangelogUpdate' ||
|
|
@@ -4945,7 +4718,9 @@
|
|
|
4945
4718
|
</div>
|
|
4946
4719
|
<div class="messenger-home-avatars">${avatarsHtml}</div>
|
|
4947
4720
|
<button class="messenger-close-btn" aria-label="Close">
|
|
4948
|
-
<
|
|
4721
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" fill="#000000" viewBox="0 0 256 256">
|
|
4722
|
+
<path d="M205.66,194.34a8,8,0,0,1-11.32,11.32L128,139.31,61.66,205.66a8,8,0,0,1-11.32-11.32L116.69,128,50.34,61.66A8,8,0,0,1,61.66,50.34L128,116.69l66.34-66.35a8,8,0,0,1,11.32,11.32L139.31,128Z"></path>
|
|
4723
|
+
</svg>
|
|
4949
4724
|
</button>
|
|
4950
4725
|
</div>
|
|
4951
4726
|
<div class="messenger-home-welcome">
|
|
@@ -4958,7 +4733,9 @@
|
|
|
4958
4733
|
<div class="messenger-home-body">
|
|
4959
4734
|
<button class="messenger-home-message-btn">
|
|
4960
4735
|
<span>Send us a message</span>
|
|
4961
|
-
<
|
|
4736
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="#000000" viewBox="0 0 256 256">
|
|
4737
|
+
<path d="M221.66,133.66l-72,72a8,8,0,0,1-11.32-11.32L196.69,136H40a8,8,0,0,1,0-16H196.69L138.34,61.66a8,8,0,0,1,11.32-11.32l72,72A8,8,0,0,1,221.66,133.66Z"></path>
|
|
4738
|
+
</svg>
|
|
4962
4739
|
</button>
|
|
4963
4740
|
|
|
4964
4741
|
${this._renderFeaturedCard()}
|
|
@@ -4973,7 +4750,6 @@
|
|
|
4973
4750
|
_renderAvatarStack() {
|
|
4974
4751
|
const avatars = this.state.teamAvatars;
|
|
4975
4752
|
if (!avatars || avatars.length === 0) {
|
|
4976
|
-
// Default avatars with initials
|
|
4977
4753
|
return `
|
|
4978
4754
|
<div class="messenger-avatar-stack">
|
|
4979
4755
|
<div class="messenger-avatar" style="background: #5856d6;">S</div>
|
|
@@ -5023,7 +4799,6 @@
|
|
|
5023
4799
|
}
|
|
5024
4800
|
|
|
5025
4801
|
_renderFeaturedCard() {
|
|
5026
|
-
// Only show if there's featured content configured
|
|
5027
4802
|
if (!this.options.featuredContent) {
|
|
5028
4803
|
return '';
|
|
5029
4804
|
}
|
|
@@ -5044,7 +4819,6 @@
|
|
|
5044
4819
|
}
|
|
5045
4820
|
|
|
5046
4821
|
_renderRecentChangelog() {
|
|
5047
|
-
// Show recent changelog preview as cards with images
|
|
5048
4822
|
const changelogItems = this.state.homeChangelogItems;
|
|
5049
4823
|
if (changelogItems.length === 0) {
|
|
5050
4824
|
return '';
|
|
@@ -5093,31 +4867,26 @@
|
|
|
5093
4867
|
}
|
|
5094
4868
|
|
|
5095
4869
|
_attachEvents() {
|
|
5096
|
-
// Close button
|
|
5097
4870
|
this.element
|
|
5098
4871
|
.querySelector('.messenger-close-btn')
|
|
5099
4872
|
.addEventListener('click', () => {
|
|
5100
4873
|
this.state.setOpen(false);
|
|
5101
4874
|
});
|
|
5102
4875
|
|
|
5103
|
-
// Send message button
|
|
5104
4876
|
this.element
|
|
5105
4877
|
.querySelector('.messenger-home-message-btn')
|
|
5106
4878
|
.addEventListener('click', () => {
|
|
5107
4879
|
this.state.setView('messages');
|
|
5108
4880
|
});
|
|
5109
4881
|
|
|
5110
|
-
// Changelog items
|
|
5111
4882
|
this.element
|
|
5112
4883
|
.querySelectorAll('.messenger-home-changelog-item')
|
|
5113
4884
|
.forEach((item) => {
|
|
5114
4885
|
item.addEventListener('click', () => {
|
|
5115
|
-
// Navigate to changelog view with specific item selected
|
|
5116
4886
|
this.state.setView('changelog');
|
|
5117
4887
|
});
|
|
5118
4888
|
});
|
|
5119
4889
|
|
|
5120
|
-
// See all changelog
|
|
5121
4890
|
const seeAllBtn = this.element.querySelector(
|
|
5122
4891
|
'.messenger-home-changelog-all'
|
|
5123
4892
|
);
|
|
@@ -5127,7 +4896,6 @@
|
|
|
5127
4896
|
});
|
|
5128
4897
|
}
|
|
5129
4898
|
|
|
5130
|
-
// Featured card action
|
|
5131
4899
|
const featuredBtn = this.element.querySelector(
|
|
5132
4900
|
'.messenger-home-featured-btn'
|
|
5133
4901
|
);
|
|
@@ -5170,7 +4938,7 @@
|
|
|
5170
4938
|
welcomeMessage: options.welcomeMessage || 'How can we help?',
|
|
5171
4939
|
enableHelp: options.enableHelp !== false,
|
|
5172
4940
|
enableChangelog: options.enableChangelog !== false,
|
|
5173
|
-
logoUrl: options.logoUrl || 'https://
|
|
4941
|
+
logoUrl: options.logoUrl || 'https://product7.io/p7logo.svg',
|
|
5174
4942
|
featuredContent: options.featuredContent || null,
|
|
5175
4943
|
primaryColor: options.primaryColor || '#1c1c1e',
|
|
5176
4944
|
// Callbacks
|
|
@@ -5735,7 +5503,6 @@
|
|
|
5735
5503
|
}
|
|
5736
5504
|
|
|
5737
5505
|
async _fetchChangelog() {
|
|
5738
|
-
// Mock data for now - simulating changelog API response
|
|
5739
5506
|
if (this.apiService?.mock) {
|
|
5740
5507
|
return {
|
|
5741
5508
|
homeItems: [
|
|
@@ -6653,7 +6420,6 @@
|
|
|
6653
6420
|
try {
|
|
6654
6421
|
const initData = await this.apiService.init(this.config.userContext);
|
|
6655
6422
|
|
|
6656
|
-
// Merge backend config as base, local config overrides
|
|
6657
6423
|
if (initData.config) {
|
|
6658
6424
|
this.config = deepMerge(initData.config, this.config);
|
|
6659
6425
|
}
|
|
@@ -6706,13 +6472,6 @@
|
|
|
6706
6472
|
return this.widgets.get(id);
|
|
6707
6473
|
}
|
|
6708
6474
|
|
|
6709
|
-
/**
|
|
6710
|
-
* Fetch active surveys from the backend
|
|
6711
|
-
* @param {Object} context - Optional context for targeting
|
|
6712
|
-
* @param {string} context.page - Current page/route
|
|
6713
|
-
* @param {string} context.event - Event trigger name
|
|
6714
|
-
* @returns {Promise<Array>} Array of active survey configurations
|
|
6715
|
-
*/
|
|
6716
6475
|
async getActiveSurveys(context = {}) {
|
|
6717
6476
|
if (!this.initialized) {
|
|
6718
6477
|
throw new SDKError(
|
|
@@ -6732,17 +6491,6 @@
|
|
|
6732
6491
|
}
|
|
6733
6492
|
}
|
|
6734
6493
|
|
|
6735
|
-
/**
|
|
6736
|
-
* Show a survey by its backend ID
|
|
6737
|
-
* Fetches survey configuration from the backend and displays it
|
|
6738
|
-
* @param {string} surveyId - The backend survey ID
|
|
6739
|
-
* @param {Object} options - Additional display options
|
|
6740
|
-
* @param {string} options.position - Position override
|
|
6741
|
-
* @param {string} options.theme - Theme override
|
|
6742
|
-
* @param {Function} options.onSubmit - Callback when survey is submitted
|
|
6743
|
-
* @param {Function} options.onDismiss - Callback when survey is dismissed
|
|
6744
|
-
* @returns {Promise<SurveyWidget>} The survey widget instance
|
|
6745
|
-
*/
|
|
6746
6494
|
async showSurveyById(surveyId, options = {}) {
|
|
6747
6495
|
if (!this.initialized) {
|
|
6748
6496
|
throw new SDKError(
|
|
@@ -6750,7 +6498,6 @@
|
|
|
6750
6498
|
);
|
|
6751
6499
|
}
|
|
6752
6500
|
|
|
6753
|
-
// Fetch active surveys to find the one with matching ID
|
|
6754
6501
|
const surveys = await this.getActiveSurveys();
|
|
6755
6502
|
const surveyConfig = surveys.find((s) => s.id === surveyId);
|
|
6756
6503
|
|
|
@@ -6772,22 +6519,6 @@
|
|
|
6772
6519
|
});
|
|
6773
6520
|
}
|
|
6774
6521
|
|
|
6775
|
-
/**
|
|
6776
|
-
* Show a survey widget (local/manual mode)
|
|
6777
|
-
* For backend-driven surveys, use showSurveyById() instead
|
|
6778
|
-
* @param {Object} options - Survey options
|
|
6779
|
-
* @param {string} options.surveyId - Backend survey ID (for API tracking)
|
|
6780
|
-
* @param {string} options.surveyType - Type of survey: 'nps', 'csat', 'ces', 'custom'
|
|
6781
|
-
* @param {string} options.position - Position: 'bottom-right', 'bottom-left', 'center', 'bottom'
|
|
6782
|
-
* @param {string} options.theme - Theme: 'light', 'dark'
|
|
6783
|
-
* @param {string} options.title - Custom title
|
|
6784
|
-
* @param {string} options.description - Custom description
|
|
6785
|
-
* @param {string} options.lowLabel - Low end label
|
|
6786
|
-
* @param {string} options.highLabel - High end label
|
|
6787
|
-
* @param {Function} options.onSubmit - Callback when survey is submitted
|
|
6788
|
-
* @param {Function} options.onDismiss - Callback when survey is dismissed
|
|
6789
|
-
* @returns {SurveyWidget} The survey widget instance
|
|
6790
|
-
*/
|
|
6791
6522
|
showSurvey(options = {}) {
|
|
6792
6523
|
if (!this.initialized) {
|
|
6793
6524
|
throw new SDKError(
|
|
@@ -6815,20 +6546,6 @@
|
|
|
6815
6546
|
return surveyWidget;
|
|
6816
6547
|
}
|
|
6817
6548
|
|
|
6818
|
-
/**
|
|
6819
|
-
* Show a changelog widget with sidebar
|
|
6820
|
-
* @param {Object} options - Changelog widget options
|
|
6821
|
-
* @param {string} options.position - Position: 'bottom-right', 'bottom-left', 'top-right', 'top-left'
|
|
6822
|
-
* @param {string} options.theme - Theme: 'light', 'dark'
|
|
6823
|
-
* @param {string} options.title - Sidebar title
|
|
6824
|
-
* @param {string} options.triggerText - Text on the trigger button
|
|
6825
|
-
* @param {boolean} options.showBadge - Show notification badge
|
|
6826
|
-
* @param {string} options.viewButtonText - Text for the view update button
|
|
6827
|
-
* @param {string} options.changelogBaseUrl - Base URL for changelog links
|
|
6828
|
-
* @param {boolean} options.openInNewTab - Open changelog links in new tab (default: true)
|
|
6829
|
-
* @param {Function} options.onViewUpdate - Callback when user clicks view update
|
|
6830
|
-
* @returns {ChangelogWidget} The changelog widget instance
|
|
6831
|
-
*/
|
|
6832
6549
|
showChangelog(options = {}) {
|
|
6833
6550
|
if (!this.initialized) {
|
|
6834
6551
|
throw new SDKError(
|
|
@@ -6854,13 +6571,6 @@
|
|
|
6854
6571
|
return changelogWidget;
|
|
6855
6572
|
}
|
|
6856
6573
|
|
|
6857
|
-
/**
|
|
6858
|
-
* Get changelogs from the backend
|
|
6859
|
-
* @param {Object} options - Optional query parameters
|
|
6860
|
-
* @param {number} options.limit - Number of changelogs to fetch
|
|
6861
|
-
* @param {number} options.offset - Offset for pagination
|
|
6862
|
-
* @returns {Promise<Array>} Array of changelog entries
|
|
6863
|
-
*/
|
|
6864
6574
|
async getChangelogs(options = {}) {
|
|
6865
6575
|
if (!this.initialized) {
|
|
6866
6576
|
throw new SDKError(
|
|
@@ -6968,17 +6678,10 @@
|
|
|
6968
6678
|
this.eventBus.emit('sdk:destroyed');
|
|
6969
6679
|
}
|
|
6970
6680
|
|
|
6971
|
-
/**
|
|
6972
|
-
* Check if feedback was recently submitted for this workspace
|
|
6973
|
-
* Uses backend tracking (preferred) with localStorage as fallback
|
|
6974
|
-
* @param {number} cooldownDays - Days to consider as "recently" (default: 30)
|
|
6975
|
-
* @returns {boolean} true if feedback was submitted within the cooldown period
|
|
6976
|
-
*/
|
|
6977
6681
|
hasFeedbackBeenSubmitted(cooldownDays = 30) {
|
|
6978
6682
|
const cooldownMs = cooldownDays * 24 * 60 * 60 * 1000;
|
|
6979
6683
|
const now = Date.now();
|
|
6980
6684
|
|
|
6981
|
-
// Check backend tracking first (from init response)
|
|
6982
6685
|
if (this.config.last_feedback_at) {
|
|
6983
6686
|
try {
|
|
6984
6687
|
const backendTimestamp = new Date(
|
|
@@ -6992,7 +6695,6 @@
|
|
|
6992
6695
|
}
|
|
6993
6696
|
}
|
|
6994
6697
|
|
|
6995
|
-
// Fallback to localStorage
|
|
6996
6698
|
try {
|
|
6997
6699
|
const storageKey = `feedback_submitted_${this.config.workspace}`;
|
|
6998
6700
|
const stored = localStorage.getItem(storageKey);
|
|
@@ -7005,9 +6707,6 @@
|
|
|
7005
6707
|
}
|
|
7006
6708
|
}
|
|
7007
6709
|
|
|
7008
|
-
/**
|
|
7009
|
-
* Clear the feedback submission tracking (allow showing widgets again)
|
|
7010
|
-
*/
|
|
7011
6710
|
clearFeedbackSubmissionTracking() {
|
|
7012
6711
|
try {
|
|
7013
6712
|
const storageKey = `feedback_submitted_${this.config.workspace}`;
|
|
@@ -8893,7 +8592,7 @@
|
|
|
8893
8592
|
}
|
|
8894
8593
|
`;
|
|
8895
8594
|
|
|
8896
|
-
const
|
|
8595
|
+
const baseStyles = `
|
|
8897
8596
|
.feedback-widget {
|
|
8898
8597
|
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', Oxygen, Ubuntu, Cantarell, sans-serif;
|
|
8899
8598
|
font-size: 14px;
|
|
@@ -8908,32 +8607,94 @@
|
|
|
8908
8607
|
box-sizing: border-box;
|
|
8909
8608
|
}
|
|
8910
8609
|
|
|
8911
|
-
|
|
8610
|
+
/* Animations */
|
|
8611
|
+
@keyframes fadeIn {
|
|
8612
|
+
from { opacity: 0; }
|
|
8613
|
+
to { opacity: 1; }
|
|
8614
|
+
}
|
|
8615
|
+
|
|
8616
|
+
@keyframes slideInRight {
|
|
8617
|
+
from {
|
|
8618
|
+
transform: translateX(400px);
|
|
8619
|
+
opacity: 0;
|
|
8620
|
+
}
|
|
8621
|
+
to {
|
|
8622
|
+
transform: translateX(0);
|
|
8623
|
+
opacity: 1;
|
|
8624
|
+
}
|
|
8625
|
+
}
|
|
8626
|
+
|
|
8627
|
+
@keyframes confettiFall {
|
|
8628
|
+
0% {
|
|
8629
|
+
opacity: 1;
|
|
8630
|
+
transform: translateY(0) rotate(0deg) scale(1);
|
|
8631
|
+
}
|
|
8632
|
+
10% {
|
|
8633
|
+
opacity: 1;
|
|
8634
|
+
}
|
|
8635
|
+
100% {
|
|
8636
|
+
opacity: 0;
|
|
8637
|
+
transform: translateY(100vh) rotate(720deg) scale(0.5);
|
|
8638
|
+
}
|
|
8639
|
+
}
|
|
8640
|
+
|
|
8641
|
+
@keyframes changelogSpin {
|
|
8642
|
+
to {
|
|
8643
|
+
transform: rotate(360deg);
|
|
8644
|
+
}
|
|
8645
|
+
}
|
|
8646
|
+
|
|
8647
|
+
/* Accessibility */
|
|
8648
|
+
@media (prefers-reduced-motion: reduce) {
|
|
8649
|
+
* {
|
|
8650
|
+
transition: none !important;
|
|
8651
|
+
animation: none !important;
|
|
8652
|
+
}
|
|
8653
|
+
}
|
|
8654
|
+
|
|
8655
|
+
/* Print */
|
|
8656
|
+
@media print {
|
|
8657
|
+
.feedback-widget,
|
|
8658
|
+
.feedback-panel,
|
|
8659
|
+
.feedback-panel-backdrop,
|
|
8660
|
+
.feedback-success-notification,
|
|
8661
|
+
.changelog-widget,
|
|
8662
|
+
.changelog-modal,
|
|
8663
|
+
.changelog-modal-backdrop,
|
|
8664
|
+
.changelog-list-modal,
|
|
8665
|
+
.changelog-list-modal-backdrop {
|
|
8666
|
+
display: none !important;
|
|
8667
|
+
}
|
|
8668
|
+
}
|
|
8669
|
+
`;
|
|
8670
|
+
|
|
8671
|
+
const changelogStyles = `
|
|
8672
|
+
.changelog-widget {
|
|
8912
8673
|
position: fixed;
|
|
8913
8674
|
z-index: 999999;
|
|
8914
8675
|
}
|
|
8915
8676
|
|
|
8916
|
-
.
|
|
8677
|
+
.changelog-widget.position-bottom-right {
|
|
8917
8678
|
bottom: 20px;
|
|
8918
8679
|
right: 20px;
|
|
8919
8680
|
}
|
|
8920
8681
|
|
|
8921
|
-
.
|
|
8682
|
+
.changelog-widget.position-bottom-left {
|
|
8922
8683
|
bottom: 20px;
|
|
8923
8684
|
left: 20px;
|
|
8924
8685
|
}
|
|
8925
8686
|
|
|
8926
|
-
.
|
|
8687
|
+
.changelog-widget.position-top-right {
|
|
8927
8688
|
top: 20px;
|
|
8928
8689
|
right: 20px;
|
|
8929
8690
|
}
|
|
8930
8691
|
|
|
8931
|
-
.
|
|
8692
|
+
.changelog-widget.position-top-left {
|
|
8932
8693
|
top: 20px;
|
|
8933
8694
|
left: 20px;
|
|
8934
8695
|
}
|
|
8935
8696
|
|
|
8936
|
-
.
|
|
8697
|
+
.changelog-trigger-btn {
|
|
8937
8698
|
position: relative;
|
|
8938
8699
|
display: flex;
|
|
8939
8700
|
align-items: center;
|
|
@@ -8955,1326 +8716,1234 @@
|
|
|
8955
8716
|
width: fit-content;
|
|
8956
8717
|
}
|
|
8957
8718
|
|
|
8958
|
-
.
|
|
8719
|
+
.changelog-trigger-btn:hover {
|
|
8959
8720
|
transform: translateY(-2px);
|
|
8960
8721
|
box-shadow: 0 6px 12px rgba(0, 0, 0, 0.15);
|
|
8961
8722
|
}
|
|
8962
8723
|
|
|
8963
|
-
.
|
|
8964
|
-
opacity: 0.7;
|
|
8965
|
-
cursor: not-allowed;
|
|
8966
|
-
}
|
|
8967
|
-
|
|
8968
|
-
.feedback-trigger-btn:focus-visible {
|
|
8724
|
+
.changelog-trigger-btn:focus-visible {
|
|
8969
8725
|
outline: 2px solid #155EEF;
|
|
8970
8726
|
outline-offset: 2px;
|
|
8971
8727
|
}
|
|
8972
8728
|
|
|
8973
|
-
.
|
|
8729
|
+
.changelog-icon {
|
|
8974
8730
|
flex-shrink: 0;
|
|
8975
8731
|
}
|
|
8976
8732
|
|
|
8977
|
-
.
|
|
8978
|
-
|
|
8979
|
-
|
|
8980
|
-
top: -6px;
|
|
8981
|
-
right: -6px;
|
|
8982
|
-
width: 24px;
|
|
8983
|
-
height: 24px;
|
|
8984
|
-
padding: 4px;
|
|
8985
|
-
display: flex;
|
|
8986
|
-
align-items: center;
|
|
8987
|
-
justify-content: center;
|
|
8988
|
-
background: white;
|
|
8989
|
-
border-radius: 50%;
|
|
8990
|
-
opacity: 0;
|
|
8991
|
-
transition: opacity 0.2s ease;
|
|
8992
|
-
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
|
8993
|
-
cursor: pointer;
|
|
8994
|
-
display: flex;
|
|
8995
|
-
align-items: center;
|
|
8996
|
-
justify-content: center;
|
|
8733
|
+
.changelog-confetti-emoji {
|
|
8734
|
+
font-size: 14px;
|
|
8735
|
+
margin-left: 2px;
|
|
8997
8736
|
}
|
|
8998
8737
|
|
|
8999
|
-
.
|
|
9000
|
-
|
|
9001
|
-
|
|
9002
|
-
|
|
9003
|
-
|
|
9004
|
-
|
|
9005
|
-
|
|
9006
|
-
|
|
9007
|
-
|
|
9008
|
-
.feedback-widget-button:not(.minimized) .feedback-trigger-btn:hover .feedback-minimize-icon {
|
|
9009
|
-
opacity: 1;
|
|
9010
|
-
}
|
|
9011
|
-
|
|
9012
|
-
/* Minimized state - just icon */
|
|
9013
|
-
.feedback-widget-button.minimized .feedback-trigger-btn {
|
|
9014
|
-
padding: 12px;
|
|
9015
|
-
width: 48px;
|
|
9016
|
-
height: 48px;
|
|
9017
|
-
justify-content: center;
|
|
9018
|
-
}
|
|
9019
|
-
|
|
9020
|
-
.feedback-widget-button.minimized .feedback-text {
|
|
9021
|
-
display: none;
|
|
9022
|
-
}
|
|
9023
|
-
|
|
9024
|
-
.feedback-widget-button.minimized .feedback-minimize-icon {
|
|
9025
|
-
display: none;
|
|
9026
|
-
}
|
|
9027
|
-
|
|
9028
|
-
/* Show expand icon on hover when minimized */
|
|
9029
|
-
.feedback-widget-button.minimized .feedback-trigger-btn:hover .feedback-expand-icon {
|
|
9030
|
-
opacity: 1;
|
|
8738
|
+
.changelog-badge {
|
|
8739
|
+
position: absolute;
|
|
8740
|
+
top: -4px;
|
|
8741
|
+
right: -4px;
|
|
8742
|
+
width: 12px;
|
|
8743
|
+
height: 12px;
|
|
8744
|
+
background: #EF4444;
|
|
8745
|
+
border-radius: 50%;
|
|
8746
|
+
border: 2px solid white;
|
|
9031
8747
|
}
|
|
9032
8748
|
|
|
9033
|
-
|
|
9034
|
-
.feedback-panel {
|
|
8749
|
+
.changelog-confetti-container {
|
|
9035
8750
|
position: fixed;
|
|
9036
|
-
|
|
9037
|
-
|
|
9038
|
-
width:
|
|
9039
|
-
|
|
9040
|
-
|
|
9041
|
-
|
|
9042
|
-
|
|
9043
|
-
font-family: inherit;
|
|
8751
|
+
top: 0;
|
|
8752
|
+
left: 0;
|
|
8753
|
+
width: 100%;
|
|
8754
|
+
height: 100%;
|
|
8755
|
+
pointer-events: none;
|
|
8756
|
+
z-index: 1000001;
|
|
8757
|
+
overflow: hidden;
|
|
9044
8758
|
}
|
|
9045
8759
|
|
|
9046
|
-
.
|
|
9047
|
-
|
|
8760
|
+
.changelog-confetti {
|
|
8761
|
+
position: absolute;
|
|
8762
|
+
top: -20px;
|
|
8763
|
+
opacity: 0;
|
|
8764
|
+
animation: confettiFall 2s ease-out forwards;
|
|
9048
8765
|
}
|
|
9049
8766
|
|
|
9050
|
-
.
|
|
8767
|
+
.changelog-modal-backdrop {
|
|
9051
8768
|
position: fixed;
|
|
9052
8769
|
top: 0;
|
|
9053
8770
|
left: 0;
|
|
9054
8771
|
right: 0;
|
|
9055
8772
|
bottom: 0;
|
|
9056
|
-
background: rgba(0, 0, 0, 0.
|
|
8773
|
+
background: rgba(0, 0, 0, 0.5);
|
|
9057
8774
|
opacity: 0;
|
|
9058
8775
|
transition: opacity 0.3s ease;
|
|
9059
8776
|
pointer-events: none;
|
|
9060
|
-
z-index:
|
|
8777
|
+
z-index: 999998;
|
|
8778
|
+
display: flex;
|
|
8779
|
+
align-items: center;
|
|
8780
|
+
justify-content: center;
|
|
9061
8781
|
}
|
|
9062
8782
|
|
|
9063
|
-
.
|
|
8783
|
+
.changelog-modal-backdrop.show {
|
|
9064
8784
|
opacity: 1;
|
|
9065
8785
|
pointer-events: auto;
|
|
9066
8786
|
}
|
|
9067
8787
|
|
|
9068
|
-
.
|
|
9069
|
-
|
|
9070
|
-
|
|
8788
|
+
.changelog-modal {
|
|
8789
|
+
position: fixed;
|
|
8790
|
+
top: 0;
|
|
8791
|
+
left: 0;
|
|
8792
|
+
right: 0;
|
|
8793
|
+
bottom: 0;
|
|
8794
|
+
z-index: 999999;
|
|
9071
8795
|
display: flex;
|
|
9072
|
-
|
|
9073
|
-
|
|
9074
|
-
|
|
9075
|
-
|
|
9076
|
-
|
|
9077
|
-
}
|
|
9078
|
-
|
|
9079
|
-
.feedback-panel.theme-dark .feedback-panel-content {
|
|
9080
|
-
background: #1F2937;
|
|
9081
|
-
color: white;
|
|
8796
|
+
align-items: center;
|
|
8797
|
+
justify-content: center;
|
|
8798
|
+
padding: 20px;
|
|
8799
|
+
pointer-events: none;
|
|
8800
|
+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', Oxygen, Ubuntu, Cantarell, sans-serif;
|
|
9082
8801
|
}
|
|
9083
8802
|
|
|
9084
|
-
.
|
|
9085
|
-
|
|
9086
|
-
align-items: center;
|
|
9087
|
-
justify-content: space-between;
|
|
9088
|
-
padding: 24px;
|
|
9089
|
-
border-bottom: 1px solid #E5E7EB;
|
|
9090
|
-
flex-shrink: 0;
|
|
8803
|
+
.changelog-modal.open {
|
|
8804
|
+
pointer-events: auto;
|
|
9091
8805
|
}
|
|
9092
8806
|
|
|
9093
|
-
.
|
|
9094
|
-
|
|
8807
|
+
.changelog-modal-container {
|
|
8808
|
+
position: relative;
|
|
8809
|
+
width: 100%;
|
|
8810
|
+
max-width: 580px;
|
|
8811
|
+
max-height: 90vh;
|
|
8812
|
+
background: #DBEAFE;
|
|
8813
|
+
border-radius: 24px;
|
|
8814
|
+
overflow: hidden;
|
|
8815
|
+
box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.25);
|
|
8816
|
+
transform: scale(0.9) translateY(20px);
|
|
8817
|
+
opacity: 0;
|
|
8818
|
+
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
|
9095
8819
|
}
|
|
9096
8820
|
|
|
9097
|
-
.
|
|
9098
|
-
|
|
9099
|
-
|
|
9100
|
-
font-weight: 600;
|
|
9101
|
-
color: #111827;
|
|
8821
|
+
.changelog-modal.open .changelog-modal-container {
|
|
8822
|
+
transform: scale(1) translateY(0);
|
|
8823
|
+
opacity: 1;
|
|
9102
8824
|
}
|
|
9103
8825
|
|
|
9104
|
-
.
|
|
9105
|
-
|
|
8826
|
+
.changelog-modal.theme-dark .changelog-modal-container {
|
|
8827
|
+
background: #1E3A5F;
|
|
9106
8828
|
}
|
|
9107
8829
|
|
|
9108
|
-
.
|
|
9109
|
-
|
|
8830
|
+
.changelog-modal-close {
|
|
8831
|
+
position: absolute;
|
|
8832
|
+
top: 16px;
|
|
8833
|
+
right: 16px;
|
|
8834
|
+
background: rgba(255, 255, 255, 0.9);
|
|
9110
8835
|
border: none;
|
|
9111
8836
|
font-size: 24px;
|
|
9112
8837
|
cursor: pointer;
|
|
9113
8838
|
color: #6B7280;
|
|
9114
|
-
padding:
|
|
9115
|
-
width:
|
|
9116
|
-
height:
|
|
8839
|
+
padding: 0;
|
|
8840
|
+
width: 36px;
|
|
8841
|
+
height: 36px;
|
|
9117
8842
|
display: flex;
|
|
9118
8843
|
align-items: center;
|
|
9119
8844
|
justify-content: center;
|
|
9120
|
-
border-radius:
|
|
8845
|
+
border-radius: 50%;
|
|
9121
8846
|
transition: all 0.2s ease;
|
|
8847
|
+
line-height: 1;
|
|
8848
|
+
z-index: 10;
|
|
8849
|
+
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
|
9122
8850
|
}
|
|
9123
8851
|
|
|
9124
|
-
.
|
|
9125
|
-
background:
|
|
8852
|
+
.changelog-modal-close:hover {
|
|
8853
|
+
background: white;
|
|
9126
8854
|
color: #111827;
|
|
8855
|
+
transform: scale(1.05);
|
|
9127
8856
|
}
|
|
9128
8857
|
|
|
9129
|
-
.
|
|
9130
|
-
|
|
9131
|
-
|
|
9132
|
-
}
|
|
9133
|
-
|
|
9134
|
-
.feedback-panel.theme-dark .feedback-panel-close {
|
|
9135
|
-
color: #9CA3AF;
|
|
8858
|
+
.changelog-modal.theme-dark .changelog-modal-close {
|
|
8859
|
+
background: rgba(55, 65, 81, 0.9);
|
|
8860
|
+
color: #D1D5DB;
|
|
9136
8861
|
}
|
|
9137
8862
|
|
|
9138
|
-
.
|
|
8863
|
+
.changelog-modal.theme-dark .changelog-modal-close:hover {
|
|
9139
8864
|
background: #374151;
|
|
9140
8865
|
color: white;
|
|
9141
8866
|
}
|
|
9142
8867
|
|
|
9143
|
-
.
|
|
9144
|
-
flex: 1;
|
|
8868
|
+
.changelog-modal-content {
|
|
9145
8869
|
overflow-y: auto;
|
|
9146
|
-
|
|
8870
|
+
max-height: 90vh;
|
|
9147
8871
|
}
|
|
9148
8872
|
|
|
9149
|
-
.
|
|
8873
|
+
.changelog-loading {
|
|
9150
8874
|
display: flex;
|
|
9151
|
-
|
|
9152
|
-
|
|
8875
|
+
align-items: center;
|
|
8876
|
+
justify-content: center;
|
|
8877
|
+
padding: 80px 20px;
|
|
9153
8878
|
}
|
|
9154
8879
|
|
|
9155
|
-
.
|
|
8880
|
+
.changelog-loading-spinner {
|
|
8881
|
+
width: 32px;
|
|
8882
|
+
height: 32px;
|
|
8883
|
+
border: 3px solid #E5E7EB;
|
|
8884
|
+
border-top-color: #155EEF;
|
|
8885
|
+
border-radius: 50%;
|
|
8886
|
+
animation: changelogSpin 0.8s linear infinite;
|
|
8887
|
+
}
|
|
8888
|
+
|
|
8889
|
+
.changelog-empty {
|
|
9156
8890
|
display: flex;
|
|
9157
8891
|
flex-direction: column;
|
|
9158
|
-
|
|
9159
|
-
|
|
8892
|
+
align-items: center;
|
|
8893
|
+
justify-content: center;
|
|
8894
|
+
padding: 80px 20px;
|
|
8895
|
+
text-align: center;
|
|
8896
|
+
color: #9CA3AF;
|
|
9160
8897
|
}
|
|
9161
8898
|
|
|
9162
|
-
.
|
|
9163
|
-
margin-bottom:
|
|
8899
|
+
.changelog-empty svg {
|
|
8900
|
+
margin-bottom: 16px;
|
|
8901
|
+
stroke: #D1D5DB;
|
|
9164
8902
|
}
|
|
9165
8903
|
|
|
9166
|
-
.
|
|
9167
|
-
|
|
9168
|
-
font-
|
|
9169
|
-
line-height: 1.25;
|
|
9170
|
-
color: #374151;
|
|
8904
|
+
.changelog-empty p {
|
|
8905
|
+
margin: 0;
|
|
8906
|
+
font-size: 15px;
|
|
9171
8907
|
}
|
|
9172
8908
|
|
|
9173
|
-
.
|
|
9174
|
-
|
|
8909
|
+
.changelog-popup-item {
|
|
8910
|
+
display: flex;
|
|
8911
|
+
flex-direction: column;
|
|
9175
8912
|
}
|
|
9176
8913
|
|
|
9177
|
-
.
|
|
9178
|
-
height: 44px;
|
|
8914
|
+
.changelog-popup-image {
|
|
9179
8915
|
width: 100%;
|
|
9180
|
-
|
|
9181
|
-
border: 1px solid #D1D5DB;
|
|
9182
|
-
padding: 10px 14px;
|
|
9183
|
-
font-size: 15px;
|
|
9184
|
-
font-weight: 400;
|
|
9185
|
-
line-height: 1.5;
|
|
9186
|
-
color: #1F2937;
|
|
9187
|
-
font-family: inherit;
|
|
9188
|
-
outline: none;
|
|
9189
|
-
transition: all 0.2s ease;
|
|
8916
|
+
padding: 24px 24px 0;
|
|
9190
8917
|
}
|
|
9191
8918
|
|
|
9192
|
-
.
|
|
9193
|
-
|
|
9194
|
-
|
|
8919
|
+
.changelog-popup-image img {
|
|
8920
|
+
width: 100%;
|
|
8921
|
+
height: auto;
|
|
8922
|
+
display: block;
|
|
8923
|
+
object-fit: cover;
|
|
8924
|
+
border-radius: 12px;
|
|
8925
|
+
border: 2px solid #155EEF;
|
|
8926
|
+
box-shadow: 0 4px 20px rgba(21, 94, 239, 0.2);
|
|
9195
8927
|
}
|
|
9196
8928
|
|
|
9197
|
-
.
|
|
9198
|
-
|
|
9199
|
-
|
|
8929
|
+
.changelog-popup-body {
|
|
8930
|
+
padding: 24px 32px 32px;
|
|
8931
|
+
text-align: center;
|
|
9200
8932
|
}
|
|
9201
8933
|
|
|
9202
|
-
.
|
|
9203
|
-
|
|
8934
|
+
.changelog-popup-title {
|
|
8935
|
+
margin: 0 0 16px;
|
|
8936
|
+
font-size: 18px;
|
|
8937
|
+
font-weight: 600;
|
|
8938
|
+
line-height: 1.3;
|
|
8939
|
+
color: #111827;
|
|
9204
8940
|
}
|
|
9205
8941
|
|
|
9206
|
-
.
|
|
9207
|
-
|
|
9208
|
-
width: 100%;
|
|
9209
|
-
resize: vertical;
|
|
9210
|
-
border-radius: 8px;
|
|
9211
|
-
border: 1px solid #D1D5DB;
|
|
9212
|
-
padding: 10px 14px;
|
|
9213
|
-
font-size: 15px;
|
|
9214
|
-
font-weight: 400;
|
|
9215
|
-
line-height: 1.5;
|
|
9216
|
-
color: #1F2937;
|
|
9217
|
-
font-family: inherit;
|
|
9218
|
-
outline: none;
|
|
9219
|
-
transition: all 0.2s ease;
|
|
9220
|
-
}
|
|
9221
|
-
|
|
9222
|
-
.feedback-form-group textarea::placeholder {
|
|
9223
|
-
font-size: 15px;
|
|
9224
|
-
color: #9CA3AF;
|
|
9225
|
-
}
|
|
9226
|
-
|
|
9227
|
-
.feedback-form-group textarea:focus {
|
|
9228
|
-
border-color: #155EEF;
|
|
9229
|
-
box-shadow: 0 0 0 3px rgba(79, 70, 229, 0.1);
|
|
9230
|
-
}
|
|
9231
|
-
|
|
9232
|
-
.feedback-form-group textarea:focus-visible {
|
|
9233
|
-
outline: none;
|
|
8942
|
+
.changelog-modal.theme-dark .changelog-popup-title {
|
|
8943
|
+
color: white;
|
|
9234
8944
|
}
|
|
9235
8945
|
|
|
9236
|
-
.
|
|
9237
|
-
|
|
9238
|
-
|
|
9239
|
-
|
|
9240
|
-
color:
|
|
8946
|
+
.changelog-popup-description {
|
|
8947
|
+
margin: 0 0 24px;
|
|
8948
|
+
font-size: 17px;
|
|
8949
|
+
line-height: 1.6;
|
|
8950
|
+
color: #4B5563;
|
|
9241
8951
|
}
|
|
9242
8952
|
|
|
9243
|
-
.
|
|
9244
|
-
|
|
9245
|
-
color: #6B7280;
|
|
8953
|
+
.changelog-modal.theme-dark .changelog-popup-description {
|
|
8954
|
+
color: #D1D5DB;
|
|
9246
8955
|
}
|
|
9247
8956
|
|
|
9248
|
-
.
|
|
9249
|
-
position: relative;
|
|
8957
|
+
.changelog-popup-btn {
|
|
9250
8958
|
display: inline-flex;
|
|
9251
8959
|
align-items: center;
|
|
9252
8960
|
justify-content: center;
|
|
9253
|
-
|
|
9254
|
-
|
|
8961
|
+
padding: 14px 32px;
|
|
8962
|
+
font-size: 16px;
|
|
8963
|
+
font-weight: 600;
|
|
8964
|
+
color: white;
|
|
8965
|
+
background: #155EEF;
|
|
9255
8966
|
border: none;
|
|
9256
|
-
|
|
9257
|
-
padding: 10px 18px;
|
|
9258
|
-
font-size: 15px;
|
|
9259
|
-
font-weight: 500;
|
|
9260
|
-
font-family: inherit;
|
|
8967
|
+
border-radius: 10px;
|
|
9261
8968
|
cursor: pointer;
|
|
9262
8969
|
transition: all 0.2s ease;
|
|
9263
8970
|
}
|
|
9264
8971
|
|
|
9265
|
-
.
|
|
9266
|
-
|
|
9267
|
-
|
|
8972
|
+
.changelog-popup-btn:hover {
|
|
8973
|
+
background: #1249CA;
|
|
8974
|
+
transform: translateY(-2px);
|
|
8975
|
+
box-shadow: 0 4px 12px rgba(21, 94, 239, 0.3);
|
|
9268
8976
|
}
|
|
9269
8977
|
|
|
9270
|
-
.
|
|
8978
|
+
.changelog-popup-btn:focus-visible {
|
|
9271
8979
|
outline: 2px solid #155EEF;
|
|
9272
8980
|
outline-offset: 2px;
|
|
9273
8981
|
}
|
|
9274
8982
|
|
|
9275
|
-
.
|
|
9276
|
-
|
|
9277
|
-
|
|
9278
|
-
|
|
8983
|
+
.changelog-popup-footer {
|
|
8984
|
+
padding: 0 32px 24px;
|
|
8985
|
+
display: flex;
|
|
8986
|
+
flex-direction: column;
|
|
8987
|
+
align-items: center;
|
|
8988
|
+
gap: 16px;
|
|
9279
8989
|
}
|
|
9280
8990
|
|
|
9281
|
-
.
|
|
9282
|
-
|
|
8991
|
+
.changelog-popup-dots {
|
|
8992
|
+
display: flex;
|
|
8993
|
+
gap: 8px;
|
|
9283
8994
|
}
|
|
9284
8995
|
|
|
9285
|
-
.
|
|
9286
|
-
|
|
8996
|
+
.changelog-dot {
|
|
8997
|
+
width: 10px;
|
|
8998
|
+
height: 10px;
|
|
8999
|
+
border-radius: 50%;
|
|
9000
|
+
background: rgba(21, 94, 239, 0.3);
|
|
9001
|
+
cursor: pointer;
|
|
9002
|
+
transition: all 0.2s ease;
|
|
9287
9003
|
}
|
|
9288
9004
|
|
|
9289
|
-
.
|
|
9290
|
-
background:
|
|
9291
|
-
color: #6B7280;
|
|
9292
|
-
border: 1px solid #D1D5DB;
|
|
9005
|
+
.changelog-dot:hover {
|
|
9006
|
+
background: rgba(21, 94, 239, 0.5);
|
|
9293
9007
|
}
|
|
9294
9008
|
|
|
9295
|
-
.
|
|
9296
|
-
background: #
|
|
9297
|
-
|
|
9298
|
-
color: #374151;
|
|
9009
|
+
.changelog-dot.active {
|
|
9010
|
+
background: #155EEF;
|
|
9011
|
+
transform: scale(1.2);
|
|
9299
9012
|
}
|
|
9300
9013
|
|
|
9301
|
-
.
|
|
9302
|
-
|
|
9303
|
-
|
|
9014
|
+
.changelog-view-all-btn {
|
|
9015
|
+
display: inline-flex;
|
|
9016
|
+
align-items: center;
|
|
9017
|
+
gap: 6px;
|
|
9018
|
+
background: none;
|
|
9019
|
+
border: none;
|
|
9020
|
+
color: #155EEF;
|
|
9021
|
+
font-size: 14px;
|
|
9022
|
+
font-weight: 500;
|
|
9023
|
+
cursor: pointer;
|
|
9024
|
+
padding: 8px 12px;
|
|
9025
|
+
border-radius: 6px;
|
|
9026
|
+
transition: all 0.2s ease;
|
|
9304
9027
|
}
|
|
9305
9028
|
|
|
9306
|
-
.
|
|
9307
|
-
background:
|
|
9029
|
+
.changelog-view-all-btn:hover {
|
|
9030
|
+
background: rgba(21, 94, 239, 0.1);
|
|
9308
9031
|
}
|
|
9309
9032
|
|
|
9310
|
-
.
|
|
9311
|
-
|
|
9312
|
-
flex-direction: column;
|
|
9313
|
-
gap: 12px;
|
|
9314
|
-
margin-top: auto;
|
|
9315
|
-
padding-top: 24px;
|
|
9033
|
+
.changelog-view-all-btn svg {
|
|
9034
|
+
transition: transform 0.2s ease;
|
|
9316
9035
|
}
|
|
9317
9036
|
|
|
9318
|
-
.
|
|
9319
|
-
|
|
9320
|
-
font-size: 14px;
|
|
9321
|
-
font-weight: 400;
|
|
9322
|
-
margin-top: 8px;
|
|
9323
|
-
padding: 12px;
|
|
9324
|
-
background: #FEE2E2;
|
|
9325
|
-
border: 1px solid #FECACA;
|
|
9326
|
-
border-radius: 8px;
|
|
9327
|
-
display: none;
|
|
9037
|
+
.changelog-view-all-btn:hover svg {
|
|
9038
|
+
transform: translateX(3px);
|
|
9328
9039
|
}
|
|
9329
9040
|
|
|
9330
|
-
.
|
|
9331
|
-
|
|
9041
|
+
.changelog-modal.theme-dark .changelog-view-all-btn {
|
|
9042
|
+
color: #60A5FA;
|
|
9332
9043
|
}
|
|
9333
9044
|
|
|
9334
|
-
.
|
|
9335
|
-
background:
|
|
9336
|
-
border-color: #991B1B;
|
|
9337
|
-
color: #FCA5A5;
|
|
9045
|
+
.changelog-modal.theme-dark .changelog-view-all-btn:hover {
|
|
9046
|
+
background: rgba(96, 165, 250, 0.1);
|
|
9338
9047
|
}
|
|
9339
9048
|
|
|
9340
|
-
.
|
|
9049
|
+
.changelog-list-modal-backdrop {
|
|
9341
9050
|
position: fixed;
|
|
9342
|
-
top:
|
|
9343
|
-
|
|
9344
|
-
|
|
9345
|
-
|
|
9346
|
-
|
|
9347
|
-
|
|
9348
|
-
|
|
9349
|
-
|
|
9350
|
-
|
|
9051
|
+
top: 0;
|
|
9052
|
+
left: 0;
|
|
9053
|
+
right: 0;
|
|
9054
|
+
bottom: 0;
|
|
9055
|
+
background: rgba(0, 0, 0, 0.5);
|
|
9056
|
+
opacity: 0;
|
|
9057
|
+
transition: opacity 0.3s ease;
|
|
9058
|
+
pointer-events: none;
|
|
9059
|
+
z-index: 999998;
|
|
9351
9060
|
}
|
|
9352
9061
|
|
|
9353
|
-
.
|
|
9354
|
-
|
|
9355
|
-
|
|
9356
|
-
padding: 16px 20px;
|
|
9357
|
-
gap: 12px;
|
|
9062
|
+
.changelog-list-modal-backdrop.show {
|
|
9063
|
+
opacity: 1;
|
|
9064
|
+
pointer-events: auto;
|
|
9358
9065
|
}
|
|
9359
9066
|
|
|
9360
|
-
.
|
|
9361
|
-
|
|
9362
|
-
|
|
9363
|
-
|
|
9364
|
-
|
|
9365
|
-
|
|
9067
|
+
.changelog-list-modal {
|
|
9068
|
+
position: fixed;
|
|
9069
|
+
top: 0;
|
|
9070
|
+
left: 0;
|
|
9071
|
+
right: 0;
|
|
9072
|
+
bottom: 0;
|
|
9073
|
+
z-index: 999999;
|
|
9366
9074
|
display: flex;
|
|
9367
9075
|
align-items: center;
|
|
9368
9076
|
justify-content: center;
|
|
9369
|
-
|
|
9370
|
-
|
|
9371
|
-
|
|
9077
|
+
padding: 20px;
|
|
9078
|
+
pointer-events: none;
|
|
9079
|
+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', Oxygen, Ubuntu, Cantarell, sans-serif;
|
|
9372
9080
|
}
|
|
9373
9081
|
|
|
9374
|
-
.
|
|
9375
|
-
|
|
9376
|
-
font-weight: 500;
|
|
9377
|
-
font-size: 14px;
|
|
9378
|
-
flex: 1;
|
|
9082
|
+
.changelog-list-modal.open {
|
|
9083
|
+
pointer-events: auto;
|
|
9379
9084
|
}
|
|
9380
9085
|
|
|
9381
|
-
.
|
|
9382
|
-
|
|
9383
|
-
|
|
9384
|
-
|
|
9385
|
-
|
|
9386
|
-
|
|
9387
|
-
|
|
9388
|
-
|
|
9389
|
-
|
|
9086
|
+
.changelog-list-modal-container {
|
|
9087
|
+
position: relative;
|
|
9088
|
+
width: 100%;
|
|
9089
|
+
max-width: 460px;
|
|
9090
|
+
max-height: 85vh;
|
|
9091
|
+
background: white;
|
|
9092
|
+
border-radius: 20px;
|
|
9093
|
+
overflow: hidden;
|
|
9094
|
+
box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.25);
|
|
9095
|
+
transform: scale(0.9) translateY(20px);
|
|
9096
|
+
opacity: 0;
|
|
9097
|
+
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
|
9390
9098
|
display: flex;
|
|
9391
|
-
|
|
9392
|
-
justify-content: center;
|
|
9393
|
-
transition: all 0.2s ease;
|
|
9394
|
-
border-radius: 4px;
|
|
9395
|
-
flex-shrink: 0;
|
|
9099
|
+
flex-direction: column;
|
|
9396
9100
|
}
|
|
9397
9101
|
|
|
9398
|
-
.
|
|
9399
|
-
|
|
9400
|
-
|
|
9102
|
+
.changelog-list-modal.open .changelog-list-modal-container {
|
|
9103
|
+
transform: scale(1) translateY(0);
|
|
9104
|
+
opacity: 1;
|
|
9401
9105
|
}
|
|
9402
9106
|
|
|
9403
|
-
.
|
|
9404
|
-
|
|
9405
|
-
|
|
9107
|
+
.changelog-list-modal.theme-dark .changelog-list-modal-container {
|
|
9108
|
+
background: #1F2937;
|
|
9109
|
+
color: white;
|
|
9406
9110
|
}
|
|
9407
9111
|
|
|
9408
|
-
|
|
9409
|
-
|
|
9410
|
-
|
|
9411
|
-
|
|
9412
|
-
|
|
9413
|
-
|
|
9414
|
-
|
|
9415
|
-
|
|
9416
|
-
}
|
|
9417
|
-
}
|
|
9418
|
-
|
|
9419
|
-
@keyframes fadeIn {
|
|
9420
|
-
from { opacity: 0; }
|
|
9421
|
-
to { opacity: 1; }
|
|
9112
|
+
.changelog-list-modal-header {
|
|
9113
|
+
display: flex;
|
|
9114
|
+
align-items: center;
|
|
9115
|
+
justify-content: space-between;
|
|
9116
|
+
padding: 14px 20px;
|
|
9117
|
+
border-bottom: 1px solid #E5E7EB;
|
|
9118
|
+
flex-shrink: 0;
|
|
9119
|
+
background: white;
|
|
9422
9120
|
}
|
|
9423
9121
|
|
|
9424
|
-
.
|
|
9425
|
-
|
|
9122
|
+
.changelog-list-modal.theme-dark .changelog-list-modal-header {
|
|
9123
|
+
border-bottom-color: #374151;
|
|
9124
|
+
background: #1F2937;
|
|
9426
9125
|
}
|
|
9427
9126
|
|
|
9428
|
-
|
|
9429
|
-
|
|
9430
|
-
|
|
9431
|
-
|
|
9432
|
-
|
|
9433
|
-
right: 0;
|
|
9434
|
-
left: 0;
|
|
9435
|
-
height: 85vh;
|
|
9436
|
-
max-height: 85vh;
|
|
9437
|
-
transform: translateY(100%);
|
|
9438
|
-
border-radius: 20px 20px 0 0;
|
|
9439
|
-
}
|
|
9440
|
-
|
|
9441
|
-
.feedback-panel.open {
|
|
9442
|
-
transform: translateY(0);
|
|
9443
|
-
}
|
|
9444
|
-
|
|
9445
|
-
.feedback-panel-content {
|
|
9446
|
-
border-radius: 20px 20px 0 0;
|
|
9447
|
-
}
|
|
9448
|
-
|
|
9449
|
-
.feedback-panel-header {
|
|
9450
|
-
padding: 20px;
|
|
9451
|
-
position: relative;
|
|
9452
|
-
}
|
|
9453
|
-
|
|
9454
|
-
.feedback-panel-header::before {
|
|
9455
|
-
content: '';
|
|
9456
|
-
position: absolute;
|
|
9457
|
-
top: 8px;
|
|
9458
|
-
left: 50%;
|
|
9459
|
-
transform: translateX(-50%);
|
|
9460
|
-
width: 40px;
|
|
9461
|
-
height: 4px;
|
|
9462
|
-
background: #D1D5DB;
|
|
9463
|
-
border-radius: 2px;
|
|
9464
|
-
}
|
|
9465
|
-
|
|
9466
|
-
.feedback-panel.theme-dark .feedback-panel-header::before {
|
|
9467
|
-
background: #4B5563;
|
|
9468
|
-
}
|
|
9469
|
-
|
|
9470
|
-
.feedback-panel-body {
|
|
9471
|
-
padding: 20px;
|
|
9472
|
-
}
|
|
9473
|
-
|
|
9474
|
-
.feedback-form-group textarea {
|
|
9475
|
-
min-height: 150px;
|
|
9476
|
-
}
|
|
9477
|
-
|
|
9478
|
-
.feedback-widget-button {
|
|
9479
|
-
bottom: 16px;
|
|
9480
|
-
right: 16px;
|
|
9481
|
-
}
|
|
9482
|
-
|
|
9483
|
-
.feedback-widget-button.position-bottom-left {
|
|
9484
|
-
left: 16px;
|
|
9485
|
-
}
|
|
9486
|
-
|
|
9487
|
-
.feedback-success-notification {
|
|
9488
|
-
top: 16px;
|
|
9489
|
-
right: 16px;
|
|
9490
|
-
left: 16px;
|
|
9491
|
-
min-width: auto;
|
|
9492
|
-
}
|
|
9493
|
-
|
|
9494
|
-
.feedback-minimize-icon,
|
|
9495
|
-
.feedback-expand-icon {
|
|
9496
|
-
top: -4px;
|
|
9497
|
-
right: -4px;
|
|
9498
|
-
width: 20px;
|
|
9499
|
-
height: 20px;
|
|
9500
|
-
}
|
|
9501
|
-
|
|
9502
|
-
.feedback-minimize-icon svg,
|
|
9503
|
-
.feedback-expand-icon svg {
|
|
9504
|
-
width: 14px;
|
|
9505
|
-
height: 14px;
|
|
9506
|
-
}
|
|
9127
|
+
.changelog-list-modal-header h2 {
|
|
9128
|
+
margin: 0;
|
|
9129
|
+
font-size: 16px;
|
|
9130
|
+
font-weight: 600;
|
|
9131
|
+
color: #111827;
|
|
9507
9132
|
}
|
|
9508
9133
|
|
|
9509
|
-
|
|
9510
|
-
|
|
9511
|
-
.feedback-btn,
|
|
9512
|
-
.feedback-panel,
|
|
9513
|
-
.feedback-panel-backdrop,
|
|
9514
|
-
.feedback-success-notification,
|
|
9515
|
-
.feedback-minimize-icon,
|
|
9516
|
-
.feedback-expand-icon {
|
|
9517
|
-
transition: none;
|
|
9518
|
-
animation: none;
|
|
9519
|
-
}
|
|
9134
|
+
.changelog-list-modal.theme-dark .changelog-list-modal-header h2 {
|
|
9135
|
+
color: white;
|
|
9520
9136
|
}
|
|
9521
9137
|
|
|
9522
|
-
|
|
9523
|
-
|
|
9524
|
-
|
|
9525
|
-
|
|
9526
|
-
|
|
9527
|
-
|
|
9528
|
-
|
|
9138
|
+
.changelog-list-modal-close {
|
|
9139
|
+
background: none;
|
|
9140
|
+
border: none;
|
|
9141
|
+
font-size: 22px;
|
|
9142
|
+
cursor: pointer;
|
|
9143
|
+
color: #6B7280;
|
|
9144
|
+
padding: 4px;
|
|
9145
|
+
width: 28px;
|
|
9146
|
+
height: 28px;
|
|
9147
|
+
display: flex;
|
|
9148
|
+
align-items: center;
|
|
9149
|
+
justify-content: center;
|
|
9150
|
+
border-radius: 6px;
|
|
9151
|
+
transition: all 0.2s ease;
|
|
9152
|
+
line-height: 1;
|
|
9529
9153
|
}
|
|
9530
9154
|
|
|
9531
|
-
|
|
9532
|
-
|
|
9533
|
-
|
|
9534
|
-
z-index: 999999;
|
|
9155
|
+
.changelog-list-modal-close:hover {
|
|
9156
|
+
background: #F3F4F6;
|
|
9157
|
+
color: #111827;
|
|
9535
9158
|
}
|
|
9536
9159
|
|
|
9537
|
-
.changelog-
|
|
9538
|
-
|
|
9539
|
-
right: 20px;
|
|
9160
|
+
.changelog-list-modal.theme-dark .changelog-list-modal-close {
|
|
9161
|
+
color: #9CA3AF;
|
|
9540
9162
|
}
|
|
9541
9163
|
|
|
9542
|
-
.changelog-
|
|
9543
|
-
|
|
9544
|
-
|
|
9164
|
+
.changelog-list-modal.theme-dark .changelog-list-modal-close:hover {
|
|
9165
|
+
background: #374151;
|
|
9166
|
+
color: white;
|
|
9545
9167
|
}
|
|
9546
9168
|
|
|
9547
|
-
.changelog-
|
|
9548
|
-
|
|
9549
|
-
|
|
9169
|
+
.changelog-list-modal-body {
|
|
9170
|
+
flex: 1;
|
|
9171
|
+
overflow-y: auto;
|
|
9550
9172
|
}
|
|
9551
9173
|
|
|
9552
|
-
.changelog-
|
|
9553
|
-
|
|
9554
|
-
|
|
9174
|
+
.changelog-list {
|
|
9175
|
+
display: flex;
|
|
9176
|
+
flex-direction: column;
|
|
9555
9177
|
}
|
|
9556
9178
|
|
|
9557
|
-
.changelog-
|
|
9558
|
-
position: relative;
|
|
9179
|
+
.changelog-list-item {
|
|
9559
9180
|
display: flex;
|
|
9181
|
+
flex-direction: row;
|
|
9560
9182
|
align-items: center;
|
|
9561
|
-
|
|
9562
|
-
|
|
9563
|
-
height: 48px;
|
|
9564
|
-
overflow: visible;
|
|
9565
|
-
border-radius: 9999px;
|
|
9566
|
-
border: none;
|
|
9567
|
-
padding: 12px 20px;
|
|
9568
|
-
font-size: 14px;
|
|
9569
|
-
font-weight: 500;
|
|
9570
|
-
font-family: inherit;
|
|
9183
|
+
padding: 12px 16px;
|
|
9184
|
+
border-bottom: 1px solid #E5E7EB;
|
|
9571
9185
|
cursor: pointer;
|
|
9572
|
-
transition:
|
|
9573
|
-
|
|
9574
|
-
background: #155EEF;
|
|
9575
|
-
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
|
|
9576
|
-
width: fit-content;
|
|
9577
|
-
}
|
|
9578
|
-
|
|
9579
|
-
.changelog-trigger-btn:hover {
|
|
9580
|
-
transform: translateY(-2px);
|
|
9581
|
-
box-shadow: 0 6px 12px rgba(0, 0, 0, 0.15);
|
|
9186
|
+
transition: background-color 0.2s ease;
|
|
9187
|
+
position: relative;
|
|
9582
9188
|
}
|
|
9583
9189
|
|
|
9584
|
-
.changelog-
|
|
9585
|
-
|
|
9586
|
-
outline-offset: 2px;
|
|
9190
|
+
.changelog-list-item:hover {
|
|
9191
|
+
background: #F9FAFB;
|
|
9587
9192
|
}
|
|
9588
9193
|
|
|
9589
|
-
.changelog-
|
|
9590
|
-
|
|
9194
|
+
.changelog-list-item:last-child {
|
|
9195
|
+
border-bottom: none;
|
|
9591
9196
|
}
|
|
9592
9197
|
|
|
9593
|
-
.changelog-
|
|
9594
|
-
|
|
9595
|
-
margin-left: 2px;
|
|
9198
|
+
.changelog-list-modal.theme-dark .changelog-list-item {
|
|
9199
|
+
border-bottom-color: #374151;
|
|
9596
9200
|
}
|
|
9597
9201
|
|
|
9598
|
-
.changelog-
|
|
9599
|
-
|
|
9600
|
-
top: -4px;
|
|
9601
|
-
right: -4px;
|
|
9602
|
-
width: 12px;
|
|
9603
|
-
height: 12px;
|
|
9604
|
-
background: #EF4444;
|
|
9605
|
-
border-radius: 50%;
|
|
9606
|
-
border: 2px solid white;
|
|
9202
|
+
.changelog-list-modal.theme-dark .changelog-list-item:hover {
|
|
9203
|
+
background: #374151;
|
|
9607
9204
|
}
|
|
9608
9205
|
|
|
9609
|
-
|
|
9610
|
-
.changelog-confetti-container {
|
|
9611
|
-
position: fixed;
|
|
9612
|
-
top: 0;
|
|
9613
|
-
left: 0;
|
|
9206
|
+
.changelog-list-item-image {
|
|
9614
9207
|
width: 100%;
|
|
9615
|
-
|
|
9616
|
-
|
|
9617
|
-
z-index: 1000001;
|
|
9208
|
+
margin-bottom: 8px;
|
|
9209
|
+
border-radius: 6px;
|
|
9618
9210
|
overflow: hidden;
|
|
9211
|
+
border: 1px solid #E5E7EB;
|
|
9619
9212
|
}
|
|
9620
9213
|
|
|
9621
|
-
.changelog-
|
|
9622
|
-
|
|
9623
|
-
|
|
9624
|
-
|
|
9625
|
-
|
|
9626
|
-
}
|
|
9627
|
-
|
|
9628
|
-
@keyframes confettiFall {
|
|
9629
|
-
0% {
|
|
9630
|
-
opacity: 1;
|
|
9631
|
-
transform: translateY(0) rotate(0deg) scale(1);
|
|
9632
|
-
}
|
|
9633
|
-
10% {
|
|
9634
|
-
opacity: 1;
|
|
9635
|
-
}
|
|
9636
|
-
100% {
|
|
9637
|
-
opacity: 0;
|
|
9638
|
-
transform: translateY(100vh) rotate(720deg) scale(0.5);
|
|
9639
|
-
}
|
|
9640
|
-
}
|
|
9641
|
-
|
|
9642
|
-
/* Changelog Modal */
|
|
9643
|
-
.changelog-modal-backdrop {
|
|
9644
|
-
position: fixed;
|
|
9645
|
-
top: 0;
|
|
9646
|
-
left: 0;
|
|
9647
|
-
right: 0;
|
|
9648
|
-
bottom: 0;
|
|
9649
|
-
background: rgba(0, 0, 0, 0.5);
|
|
9650
|
-
opacity: 0;
|
|
9651
|
-
transition: opacity 0.3s ease;
|
|
9652
|
-
pointer-events: none;
|
|
9653
|
-
z-index: 999998;
|
|
9654
|
-
display: flex;
|
|
9655
|
-
align-items: center;
|
|
9656
|
-
justify-content: center;
|
|
9214
|
+
.changelog-list-item-image img {
|
|
9215
|
+
width: 100%;
|
|
9216
|
+
height: 100px;
|
|
9217
|
+
display: block;
|
|
9218
|
+
object-fit: cover;
|
|
9657
9219
|
}
|
|
9658
9220
|
|
|
9659
|
-
.changelog-
|
|
9660
|
-
|
|
9661
|
-
|
|
9221
|
+
.changelog-list-item-main {
|
|
9222
|
+
flex: 1;
|
|
9223
|
+
min-width: 0;
|
|
9662
9224
|
}
|
|
9663
9225
|
|
|
9664
|
-
.changelog-
|
|
9665
|
-
position: fixed;
|
|
9666
|
-
top: 0;
|
|
9667
|
-
left: 0;
|
|
9668
|
-
right: 0;
|
|
9669
|
-
bottom: 0;
|
|
9670
|
-
z-index: 999999;
|
|
9226
|
+
.changelog-list-item-content {
|
|
9671
9227
|
display: flex;
|
|
9672
|
-
|
|
9673
|
-
|
|
9674
|
-
padding: 20px;
|
|
9675
|
-
pointer-events: none;
|
|
9676
|
-
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', Oxygen, Ubuntu, Cantarell, sans-serif;
|
|
9677
|
-
}
|
|
9678
|
-
|
|
9679
|
-
.changelog-modal.open {
|
|
9680
|
-
pointer-events: auto;
|
|
9681
|
-
}
|
|
9682
|
-
|
|
9683
|
-
.changelog-modal-container {
|
|
9684
|
-
position: relative;
|
|
9685
|
-
width: 100%;
|
|
9686
|
-
max-width: 580px;
|
|
9687
|
-
max-height: 90vh;
|
|
9688
|
-
background: #DBEAFE;
|
|
9689
|
-
border-radius: 24px;
|
|
9690
|
-
overflow: hidden;
|
|
9691
|
-
box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.25);
|
|
9692
|
-
transform: scale(0.9) translateY(20px);
|
|
9693
|
-
opacity: 0;
|
|
9694
|
-
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
|
9228
|
+
flex-direction: column;
|
|
9229
|
+
gap: 3px;
|
|
9695
9230
|
}
|
|
9696
9231
|
|
|
9697
|
-
.changelog-
|
|
9698
|
-
|
|
9699
|
-
|
|
9232
|
+
.changelog-list-item-date {
|
|
9233
|
+
font-size: 11px;
|
|
9234
|
+
color: #6B7280;
|
|
9235
|
+
font-weight: 500;
|
|
9700
9236
|
}
|
|
9701
9237
|
|
|
9702
|
-
.changelog-modal.theme-dark .changelog-
|
|
9703
|
-
|
|
9238
|
+
.changelog-list-modal.theme-dark .changelog-list-item-date {
|
|
9239
|
+
color: #9CA3AF;
|
|
9704
9240
|
}
|
|
9705
9241
|
|
|
9706
|
-
.changelog-
|
|
9707
|
-
position: absolute;
|
|
9708
|
-
top: 16px;
|
|
9709
|
-
right: 16px;
|
|
9710
|
-
background: rgba(255, 255, 255, 0.9);
|
|
9711
|
-
border: none;
|
|
9712
|
-
font-size: 24px;
|
|
9713
|
-
cursor: pointer;
|
|
9714
|
-
color: #6B7280;
|
|
9715
|
-
padding: 0;
|
|
9716
|
-
width: 36px;
|
|
9717
|
-
height: 36px;
|
|
9242
|
+
.changelog-list-item-labels {
|
|
9718
9243
|
display: flex;
|
|
9719
|
-
|
|
9720
|
-
|
|
9721
|
-
|
|
9722
|
-
transition: all 0.2s ease;
|
|
9723
|
-
line-height: 1;
|
|
9724
|
-
z-index: 10;
|
|
9725
|
-
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
|
9244
|
+
flex-wrap: wrap;
|
|
9245
|
+
gap: 4px;
|
|
9246
|
+
margin-bottom: 1px;
|
|
9726
9247
|
}
|
|
9727
9248
|
|
|
9728
|
-
.changelog-
|
|
9729
|
-
|
|
9249
|
+
.changelog-list-item-title {
|
|
9250
|
+
margin: 0;
|
|
9251
|
+
font-size: 14px;
|
|
9252
|
+
font-weight: 600;
|
|
9253
|
+
line-height: 1.3;
|
|
9730
9254
|
color: #111827;
|
|
9731
|
-
transform: scale(1.05);
|
|
9732
9255
|
}
|
|
9733
9256
|
|
|
9734
|
-
.changelog-modal.theme-dark .changelog-
|
|
9735
|
-
background: rgba(55, 65, 81, 0.9);
|
|
9736
|
-
color: #D1D5DB;
|
|
9737
|
-
}
|
|
9738
|
-
|
|
9739
|
-
.changelog-modal.theme-dark .changelog-modal-close:hover {
|
|
9740
|
-
background: #374151;
|
|
9257
|
+
.changelog-list-modal.theme-dark .changelog-list-item-title {
|
|
9741
9258
|
color: white;
|
|
9742
9259
|
}
|
|
9743
9260
|
|
|
9744
|
-
.changelog-
|
|
9745
|
-
|
|
9746
|
-
|
|
9747
|
-
|
|
9748
|
-
|
|
9749
|
-
|
|
9750
|
-
|
|
9751
|
-
|
|
9752
|
-
|
|
9753
|
-
justify-content: center;
|
|
9754
|
-
padding: 80px 20px;
|
|
9755
|
-
}
|
|
9756
|
-
|
|
9757
|
-
.changelog-loading-spinner {
|
|
9758
|
-
width: 32px;
|
|
9759
|
-
height: 32px;
|
|
9760
|
-
border: 3px solid #E5E7EB;
|
|
9761
|
-
border-top-color: #155EEF;
|
|
9762
|
-
border-radius: 50%;
|
|
9763
|
-
animation: changelogSpin 0.8s linear infinite;
|
|
9764
|
-
}
|
|
9765
|
-
|
|
9766
|
-
@keyframes changelogSpin {
|
|
9767
|
-
to {
|
|
9768
|
-
transform: rotate(360deg);
|
|
9769
|
-
}
|
|
9261
|
+
.changelog-list-item-description {
|
|
9262
|
+
margin: 0;
|
|
9263
|
+
font-size: 12px;
|
|
9264
|
+
line-height: 1.4;
|
|
9265
|
+
color: #6B7280;
|
|
9266
|
+
display: -webkit-box;
|
|
9267
|
+
-webkit-line-clamp: 2;
|
|
9268
|
+
-webkit-box-orient: vertical;
|
|
9269
|
+
overflow: hidden;
|
|
9770
9270
|
}
|
|
9771
9271
|
|
|
9772
|
-
|
|
9773
|
-
.changelog-empty {
|
|
9774
|
-
display: flex;
|
|
9775
|
-
flex-direction: column;
|
|
9776
|
-
align-items: center;
|
|
9777
|
-
justify-content: center;
|
|
9778
|
-
padding: 80px 20px;
|
|
9779
|
-
text-align: center;
|
|
9272
|
+
.changelog-list-modal.theme-dark .changelog-list-item-description {
|
|
9780
9273
|
color: #9CA3AF;
|
|
9781
9274
|
}
|
|
9782
9275
|
|
|
9783
|
-
.changelog-
|
|
9784
|
-
|
|
9785
|
-
|
|
9276
|
+
.changelog-list-item-arrow {
|
|
9277
|
+
flex-shrink: 0;
|
|
9278
|
+
margin-left: 12px;
|
|
9279
|
+
color: #9CA3AF;
|
|
9280
|
+
transition: all 0.2s ease;
|
|
9786
9281
|
}
|
|
9787
9282
|
|
|
9788
|
-
.changelog-
|
|
9789
|
-
|
|
9790
|
-
|
|
9283
|
+
.changelog-list-item:hover .changelog-list-item-arrow {
|
|
9284
|
+
color: #155EEF;
|
|
9285
|
+
transform: translateX(3px);
|
|
9791
9286
|
}
|
|
9792
9287
|
|
|
9793
|
-
|
|
9794
|
-
|
|
9795
|
-
display: flex;
|
|
9796
|
-
flex-direction: column;
|
|
9288
|
+
.changelog-list-modal.theme-dark .changelog-list-item-arrow {
|
|
9289
|
+
color: #6B7280;
|
|
9797
9290
|
}
|
|
9798
9291
|
|
|
9799
|
-
.changelog-
|
|
9800
|
-
|
|
9801
|
-
padding: 24px 24px 0;
|
|
9292
|
+
.changelog-list-modal.theme-dark .changelog-list-item:hover .changelog-list-item-arrow {
|
|
9293
|
+
color: #60A5FA;
|
|
9802
9294
|
}
|
|
9803
9295
|
|
|
9804
|
-
|
|
9805
|
-
|
|
9806
|
-
|
|
9807
|
-
|
|
9808
|
-
|
|
9809
|
-
|
|
9810
|
-
|
|
9811
|
-
|
|
9296
|
+
/* ==================== MOBILE RESPONSIVE ==================== */
|
|
9297
|
+
@media (max-width: 768px) {
|
|
9298
|
+
.changelog-widget {
|
|
9299
|
+
bottom: 16px;
|
|
9300
|
+
right: 16px;
|
|
9301
|
+
}
|
|
9302
|
+
|
|
9303
|
+
.changelog-widget.position-bottom-left {
|
|
9304
|
+
left: 16px;
|
|
9305
|
+
}
|
|
9306
|
+
|
|
9307
|
+
.changelog-modal {
|
|
9308
|
+
padding: 16px;
|
|
9309
|
+
}
|
|
9310
|
+
|
|
9311
|
+
.changelog-modal-container {
|
|
9312
|
+
max-width: 100%;
|
|
9313
|
+
border-radius: 20px;
|
|
9314
|
+
}
|
|
9315
|
+
|
|
9316
|
+
.changelog-popup-image {
|
|
9317
|
+
padding: 20px 20px 0;
|
|
9318
|
+
}
|
|
9319
|
+
|
|
9320
|
+
.changelog-popup-body {
|
|
9321
|
+
padding: 20px 24px 24px;
|
|
9322
|
+
}
|
|
9323
|
+
|
|
9324
|
+
.changelog-popup-title {
|
|
9325
|
+
font-size: 22px;
|
|
9326
|
+
}
|
|
9327
|
+
|
|
9328
|
+
.changelog-popup-description {
|
|
9329
|
+
font-size: 15px;
|
|
9330
|
+
}
|
|
9331
|
+
|
|
9332
|
+
.changelog-popup-btn {
|
|
9333
|
+
padding: 12px 28px;
|
|
9334
|
+
font-size: 15px;
|
|
9335
|
+
width: 100%;
|
|
9336
|
+
}
|
|
9337
|
+
|
|
9338
|
+
.changelog-popup-footer {
|
|
9339
|
+
padding: 0 24px 20px;
|
|
9340
|
+
}
|
|
9341
|
+
|
|
9342
|
+
.changelog-list-modal {
|
|
9343
|
+
padding: 16px;
|
|
9344
|
+
}
|
|
9345
|
+
|
|
9346
|
+
.changelog-list-modal-container {
|
|
9347
|
+
max-width: 100%;
|
|
9348
|
+
max-height: 90vh;
|
|
9349
|
+
border-radius: 16px;
|
|
9350
|
+
}
|
|
9351
|
+
|
|
9352
|
+
.changelog-list-item {
|
|
9353
|
+
padding: 10px 14px;
|
|
9354
|
+
}
|
|
9355
|
+
|
|
9356
|
+
.changelog-list-item-image img {
|
|
9357
|
+
height: 80px;
|
|
9358
|
+
}
|
|
9359
|
+
|
|
9360
|
+
.changelog-list-item-title {
|
|
9361
|
+
font-size: 13px;
|
|
9362
|
+
}
|
|
9363
|
+
|
|
9364
|
+
.changelog-list-item-description {
|
|
9365
|
+
font-size: 11px;
|
|
9366
|
+
}
|
|
9812
9367
|
}
|
|
9368
|
+
`;
|
|
9813
9369
|
|
|
9814
|
-
|
|
9815
|
-
|
|
9816
|
-
|
|
9370
|
+
const feedbackStyles = `
|
|
9371
|
+
.feedback-widget-button {
|
|
9372
|
+
position: fixed;
|
|
9373
|
+
z-index: 999999;
|
|
9817
9374
|
}
|
|
9818
9375
|
|
|
9819
|
-
.
|
|
9820
|
-
|
|
9821
|
-
|
|
9822
|
-
font-weight: 600;
|
|
9823
|
-
line-height: 1.3;
|
|
9824
|
-
color: #111827;
|
|
9376
|
+
.feedback-widget-button.position-bottom-right {
|
|
9377
|
+
bottom: 20px;
|
|
9378
|
+
right: 20px;
|
|
9825
9379
|
}
|
|
9826
9380
|
|
|
9827
|
-
.
|
|
9828
|
-
|
|
9381
|
+
.feedback-widget-button.position-bottom-left {
|
|
9382
|
+
bottom: 20px;
|
|
9383
|
+
left: 20px;
|
|
9829
9384
|
}
|
|
9830
9385
|
|
|
9831
|
-
.
|
|
9832
|
-
|
|
9833
|
-
|
|
9834
|
-
line-height: 1.6;
|
|
9835
|
-
color: #4B5563;
|
|
9386
|
+
.feedback-widget-button.position-top-right {
|
|
9387
|
+
top: 20px;
|
|
9388
|
+
right: 20px;
|
|
9836
9389
|
}
|
|
9837
9390
|
|
|
9838
|
-
.
|
|
9839
|
-
|
|
9391
|
+
.feedback-widget-button.position-top-left {
|
|
9392
|
+
top: 20px;
|
|
9393
|
+
left: 20px;
|
|
9840
9394
|
}
|
|
9841
9395
|
|
|
9842
|
-
.
|
|
9843
|
-
|
|
9396
|
+
.feedback-trigger-btn {
|
|
9397
|
+
position: relative;
|
|
9398
|
+
display: flex;
|
|
9844
9399
|
align-items: center;
|
|
9845
9400
|
justify-content: center;
|
|
9846
|
-
|
|
9847
|
-
|
|
9848
|
-
|
|
9849
|
-
|
|
9850
|
-
background: #155EEF;
|
|
9401
|
+
gap: 8px;
|
|
9402
|
+
height: 48px;
|
|
9403
|
+
overflow: visible;
|
|
9404
|
+
border-radius: 9999px;
|
|
9851
9405
|
border: none;
|
|
9852
|
-
|
|
9406
|
+
padding: 12px 20px;
|
|
9407
|
+
font-size: 14px;
|
|
9408
|
+
font-weight: 500;
|
|
9409
|
+
font-family: inherit;
|
|
9853
9410
|
cursor: pointer;
|
|
9854
|
-
transition: all 0.
|
|
9411
|
+
transition: all 0.3s ease;
|
|
9412
|
+
color: white;
|
|
9413
|
+
background: #155EEF;
|
|
9414
|
+
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
|
|
9415
|
+
width: fit-content;
|
|
9855
9416
|
}
|
|
9856
9417
|
|
|
9857
|
-
.
|
|
9858
|
-
background: #1249CA;
|
|
9418
|
+
.feedback-trigger-btn:hover:not(:disabled) {
|
|
9859
9419
|
transform: translateY(-2px);
|
|
9860
|
-
box-shadow: 0
|
|
9420
|
+
box-shadow: 0 6px 12px rgba(0, 0, 0, 0.15);
|
|
9861
9421
|
}
|
|
9862
9422
|
|
|
9863
|
-
.
|
|
9423
|
+
.feedback-trigger-btn:disabled {
|
|
9424
|
+
opacity: 0.7;
|
|
9425
|
+
cursor: not-allowed;
|
|
9426
|
+
}
|
|
9427
|
+
|
|
9428
|
+
.feedback-trigger-btn:focus-visible {
|
|
9864
9429
|
outline: 2px solid #155EEF;
|
|
9865
9430
|
outline-offset: 2px;
|
|
9866
9431
|
}
|
|
9867
9432
|
|
|
9868
|
-
|
|
9869
|
-
|
|
9870
|
-
padding: 0 32px 24px;
|
|
9871
|
-
display: flex;
|
|
9872
|
-
flex-direction: column;
|
|
9873
|
-
align-items: center;
|
|
9874
|
-
gap: 16px;
|
|
9433
|
+
.feedback-icon {
|
|
9434
|
+
flex-shrink: 0;
|
|
9875
9435
|
}
|
|
9876
9436
|
|
|
9877
|
-
.
|
|
9437
|
+
.feedback-minimize-icon,
|
|
9438
|
+
.feedback-expand-icon {
|
|
9439
|
+
position: absolute;
|
|
9440
|
+
top: -6px;
|
|
9441
|
+
right: -6px;
|
|
9442
|
+
width: 24px;
|
|
9443
|
+
height: 24px;
|
|
9444
|
+
padding: 4px;
|
|
9878
9445
|
display: flex;
|
|
9879
|
-
|
|
9880
|
-
|
|
9881
|
-
|
|
9882
|
-
.changelog-dot {
|
|
9883
|
-
width: 10px;
|
|
9884
|
-
height: 10px;
|
|
9446
|
+
align-items: center;
|
|
9447
|
+
justify-content: center;
|
|
9448
|
+
background: white;
|
|
9885
9449
|
border-radius: 50%;
|
|
9886
|
-
|
|
9450
|
+
opacity: 0;
|
|
9451
|
+
transition: opacity 0.2s ease;
|
|
9452
|
+
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
|
9887
9453
|
cursor: pointer;
|
|
9888
|
-
transition: all 0.2s ease;
|
|
9889
9454
|
}
|
|
9890
9455
|
|
|
9891
|
-
.
|
|
9892
|
-
|
|
9456
|
+
.feedback-minimize-icon svg,
|
|
9457
|
+
.feedback-expand-icon svg {
|
|
9458
|
+
width: 16px;
|
|
9459
|
+
height: 16px;
|
|
9460
|
+
display: block;
|
|
9461
|
+
fill: #155EEF;
|
|
9893
9462
|
}
|
|
9894
9463
|
|
|
9895
|
-
.
|
|
9896
|
-
|
|
9897
|
-
transform: scale(1.2);
|
|
9464
|
+
.feedback-widget-button:not(.minimized) .feedback-trigger-btn:hover .feedback-minimize-icon {
|
|
9465
|
+
opacity: 1;
|
|
9898
9466
|
}
|
|
9899
9467
|
|
|
9900
|
-
.
|
|
9901
|
-
|
|
9902
|
-
|
|
9903
|
-
|
|
9904
|
-
|
|
9905
|
-
border: none;
|
|
9906
|
-
color: #155EEF;
|
|
9907
|
-
font-size: 14px;
|
|
9908
|
-
font-weight: 500;
|
|
9909
|
-
cursor: pointer;
|
|
9910
|
-
padding: 8px 12px;
|
|
9911
|
-
border-radius: 6px;
|
|
9912
|
-
transition: all 0.2s ease;
|
|
9468
|
+
.feedback-widget-button.minimized .feedback-trigger-btn {
|
|
9469
|
+
padding: 12px;
|
|
9470
|
+
width: 48px;
|
|
9471
|
+
height: 48px;
|
|
9472
|
+
justify-content: center;
|
|
9913
9473
|
}
|
|
9914
9474
|
|
|
9915
|
-
.
|
|
9916
|
-
|
|
9475
|
+
.feedback-widget-button.minimized .feedback-text {
|
|
9476
|
+
display: none;
|
|
9917
9477
|
}
|
|
9918
9478
|
|
|
9919
|
-
.
|
|
9920
|
-
|
|
9479
|
+
.feedback-widget-button.minimized .feedback-minimize-icon {
|
|
9480
|
+
display: none;
|
|
9921
9481
|
}
|
|
9922
9482
|
|
|
9923
|
-
.
|
|
9924
|
-
|
|
9483
|
+
.feedback-widget-button.minimized .feedback-trigger-btn:hover .feedback-expand-icon {
|
|
9484
|
+
opacity: 1;
|
|
9925
9485
|
}
|
|
9926
9486
|
|
|
9927
|
-
.
|
|
9928
|
-
|
|
9487
|
+
.feedback-panel {
|
|
9488
|
+
position: fixed;
|
|
9489
|
+
bottom: 80px;
|
|
9490
|
+
right: 24px;
|
|
9491
|
+
width: 420px;
|
|
9492
|
+
max-height: 500px;
|
|
9493
|
+
z-index: 1000000;
|
|
9494
|
+
transform: translateX(calc(100% + 24px));
|
|
9495
|
+
transition: transform 0.35s cubic-bezier(0.4, 0, 0.2, 1);
|
|
9496
|
+
font-family: inherit;
|
|
9929
9497
|
}
|
|
9930
9498
|
|
|
9931
|
-
.
|
|
9932
|
-
|
|
9499
|
+
.feedback-panel.open {
|
|
9500
|
+
transform: translateX(0);
|
|
9933
9501
|
}
|
|
9934
9502
|
|
|
9935
|
-
|
|
9936
|
-
.changelog-list-modal-backdrop {
|
|
9503
|
+
.feedback-panel-backdrop {
|
|
9937
9504
|
position: fixed;
|
|
9938
9505
|
top: 0;
|
|
9939
9506
|
left: 0;
|
|
9940
9507
|
right: 0;
|
|
9941
9508
|
bottom: 0;
|
|
9942
|
-
background: rgba(0, 0, 0, 0.
|
|
9509
|
+
background: rgba(0, 0, 0, 0.1);
|
|
9943
9510
|
opacity: 0;
|
|
9944
9511
|
transition: opacity 0.3s ease;
|
|
9945
9512
|
pointer-events: none;
|
|
9946
|
-
z-index: 999998;
|
|
9947
|
-
}
|
|
9948
|
-
|
|
9949
|
-
.changelog-list-modal-backdrop.show {
|
|
9950
|
-
opacity: 1;
|
|
9951
|
-
pointer-events: auto;
|
|
9952
|
-
}
|
|
9953
|
-
|
|
9954
|
-
.changelog-list-modal {
|
|
9955
|
-
position: fixed;
|
|
9956
|
-
top: 0;
|
|
9957
|
-
left: 0;
|
|
9958
|
-
right: 0;
|
|
9959
|
-
bottom: 0;
|
|
9960
9513
|
z-index: 999999;
|
|
9961
|
-
|
|
9962
|
-
align-items: center;
|
|
9963
|
-
justify-content: center;
|
|
9964
|
-
padding: 20px;
|
|
9965
|
-
pointer-events: none;
|
|
9966
|
-
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', Oxygen, Ubuntu, Cantarell, sans-serif;
|
|
9514
|
+
animation: fadeIn 0.3s ease;
|
|
9967
9515
|
}
|
|
9968
9516
|
|
|
9969
|
-
.
|
|
9517
|
+
.feedback-panel-backdrop.show {
|
|
9518
|
+
opacity: 1;
|
|
9970
9519
|
pointer-events: auto;
|
|
9971
9520
|
}
|
|
9972
9521
|
|
|
9973
|
-
.
|
|
9974
|
-
position: relative;
|
|
9975
|
-
width: 100%;
|
|
9976
|
-
max-width: 460px;
|
|
9977
|
-
max-height: 85vh;
|
|
9522
|
+
.feedback-panel-content {
|
|
9978
9523
|
background: white;
|
|
9979
|
-
|
|
9980
|
-
overflow: hidden;
|
|
9981
|
-
box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.25);
|
|
9982
|
-
transform: scale(0.9) translateY(20px);
|
|
9983
|
-
opacity: 0;
|
|
9984
|
-
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
|
9524
|
+
height: 100%;
|
|
9985
9525
|
display: flex;
|
|
9986
9526
|
flex-direction: column;
|
|
9527
|
+
border-radius: 16px;
|
|
9528
|
+
box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1),
|
|
9529
|
+
0 10px 10px -5px rgba(0, 0, 0, 0.04),
|
|
9530
|
+
0 0 0 1px rgba(0, 0, 0, 0.05);
|
|
9987
9531
|
}
|
|
9988
9532
|
|
|
9989
|
-
.
|
|
9990
|
-
transform: scale(1) translateY(0);
|
|
9991
|
-
opacity: 1;
|
|
9992
|
-
}
|
|
9993
|
-
|
|
9994
|
-
.changelog-list-modal.theme-dark .changelog-list-modal-container {
|
|
9533
|
+
.feedback-panel.theme-dark .feedback-panel-content {
|
|
9995
9534
|
background: #1F2937;
|
|
9996
9535
|
color: white;
|
|
9997
9536
|
}
|
|
9998
9537
|
|
|
9999
|
-
.
|
|
9538
|
+
.feedback-panel-header {
|
|
10000
9539
|
display: flex;
|
|
10001
9540
|
align-items: center;
|
|
10002
9541
|
justify-content: space-between;
|
|
10003
|
-
padding:
|
|
9542
|
+
padding: 24px;
|
|
10004
9543
|
border-bottom: 1px solid #E5E7EB;
|
|
10005
9544
|
flex-shrink: 0;
|
|
10006
|
-
background: white;
|
|
10007
9545
|
}
|
|
10008
9546
|
|
|
10009
|
-
.
|
|
9547
|
+
.feedback-panel.theme-dark .feedback-panel-header {
|
|
10010
9548
|
border-bottom-color: #374151;
|
|
10011
|
-
background: #1F2937;
|
|
10012
9549
|
}
|
|
10013
9550
|
|
|
10014
|
-
.
|
|
9551
|
+
.feedback-panel-header h3 {
|
|
10015
9552
|
margin: 0;
|
|
10016
|
-
font-size:
|
|
9553
|
+
font-size: 18px;
|
|
10017
9554
|
font-weight: 600;
|
|
10018
9555
|
color: #111827;
|
|
10019
9556
|
}
|
|
10020
9557
|
|
|
10021
|
-
.
|
|
9558
|
+
.feedback-panel.theme-dark .feedback-panel-header h3 {
|
|
10022
9559
|
color: white;
|
|
10023
9560
|
}
|
|
10024
9561
|
|
|
10025
|
-
.
|
|
9562
|
+
.feedback-panel-close {
|
|
10026
9563
|
background: none;
|
|
10027
9564
|
border: none;
|
|
10028
|
-
font-size:
|
|
9565
|
+
font-size: 24px;
|
|
10029
9566
|
cursor: pointer;
|
|
10030
9567
|
color: #6B7280;
|
|
10031
9568
|
padding: 4px;
|
|
10032
|
-
width:
|
|
10033
|
-
height:
|
|
9569
|
+
width: 32px;
|
|
9570
|
+
height: 32px;
|
|
10034
9571
|
display: flex;
|
|
10035
9572
|
align-items: center;
|
|
10036
9573
|
justify-content: center;
|
|
10037
9574
|
border-radius: 6px;
|
|
10038
9575
|
transition: all 0.2s ease;
|
|
10039
|
-
line-height: 1;
|
|
10040
9576
|
}
|
|
10041
9577
|
|
|
10042
|
-
.
|
|
9578
|
+
.feedback-panel-close:hover {
|
|
10043
9579
|
background: #F3F4F6;
|
|
10044
9580
|
color: #111827;
|
|
10045
9581
|
}
|
|
10046
9582
|
|
|
10047
|
-
.
|
|
9583
|
+
.feedback-panel-close:focus-visible {
|
|
9584
|
+
outline: 2px solid #155EEF;
|
|
9585
|
+
outline-offset: 2px;
|
|
9586
|
+
}
|
|
9587
|
+
|
|
9588
|
+
.feedback-panel.theme-dark .feedback-panel-close {
|
|
10048
9589
|
color: #9CA3AF;
|
|
10049
9590
|
}
|
|
10050
9591
|
|
|
10051
|
-
.
|
|
9592
|
+
.feedback-panel.theme-dark .feedback-panel-close:hover {
|
|
10052
9593
|
background: #374151;
|
|
10053
9594
|
color: white;
|
|
10054
9595
|
}
|
|
10055
9596
|
|
|
10056
|
-
.
|
|
9597
|
+
.feedback-panel-body {
|
|
10057
9598
|
flex: 1;
|
|
10058
9599
|
overflow-y: auto;
|
|
9600
|
+
padding: 24px;
|
|
10059
9601
|
}
|
|
10060
9602
|
|
|
10061
|
-
|
|
10062
|
-
.changelog-list {
|
|
9603
|
+
.feedback-form {
|
|
10063
9604
|
display: flex;
|
|
10064
9605
|
flex-direction: column;
|
|
9606
|
+
height: 100%;
|
|
10065
9607
|
}
|
|
10066
9608
|
|
|
10067
|
-
.
|
|
9609
|
+
.feedback-form-group {
|
|
10068
9610
|
display: flex;
|
|
10069
|
-
flex-direction:
|
|
10070
|
-
|
|
10071
|
-
|
|
10072
|
-
border-bottom: 1px solid #E5E7EB;
|
|
10073
|
-
cursor: pointer;
|
|
10074
|
-
transition: background-color 0.2s ease;
|
|
10075
|
-
position: relative;
|
|
9611
|
+
flex-direction: column;
|
|
9612
|
+
gap: 8px;
|
|
9613
|
+
margin-bottom: 20px;
|
|
10076
9614
|
}
|
|
10077
9615
|
|
|
10078
|
-
.
|
|
10079
|
-
|
|
9616
|
+
.feedback-form-group:last-child {
|
|
9617
|
+
margin-bottom: 0;
|
|
10080
9618
|
}
|
|
10081
9619
|
|
|
10082
|
-
.
|
|
10083
|
-
|
|
9620
|
+
.feedback-form-group label {
|
|
9621
|
+
font-size: 14px;
|
|
9622
|
+
font-weight: 500;
|
|
9623
|
+
line-height: 1.25;
|
|
9624
|
+
color: #374151;
|
|
10084
9625
|
}
|
|
10085
9626
|
|
|
10086
|
-
.
|
|
10087
|
-
|
|
9627
|
+
.feedback-panel.theme-dark .feedback-form-group label {
|
|
9628
|
+
color: #D1D5DB;
|
|
10088
9629
|
}
|
|
10089
9630
|
|
|
10090
|
-
.
|
|
10091
|
-
|
|
9631
|
+
.feedback-form-group input {
|
|
9632
|
+
height: 44px;
|
|
9633
|
+
width: 100%;
|
|
9634
|
+
border-radius: 8px;
|
|
9635
|
+
border: 1px solid #D1D5DB;
|
|
9636
|
+
padding: 10px 14px;
|
|
9637
|
+
font-size: 15px;
|
|
9638
|
+
font-weight: 400;
|
|
9639
|
+
line-height: 1.5;
|
|
9640
|
+
color: #1F2937;
|
|
9641
|
+
font-family: inherit;
|
|
9642
|
+
outline: none;
|
|
9643
|
+
transition: all 0.2s ease;
|
|
10092
9644
|
}
|
|
10093
9645
|
|
|
10094
|
-
.
|
|
9646
|
+
.feedback-form-group input::placeholder {
|
|
9647
|
+
font-size: 15px;
|
|
9648
|
+
color: #9CA3AF;
|
|
9649
|
+
}
|
|
9650
|
+
|
|
9651
|
+
.feedback-form-group input:focus {
|
|
9652
|
+
border-color: #155EEF;
|
|
9653
|
+
box-shadow: 0 0 0 3px rgba(79, 70, 229, 0.1);
|
|
9654
|
+
}
|
|
9655
|
+
|
|
9656
|
+
.feedback-form-group input:focus-visible {
|
|
9657
|
+
outline: none;
|
|
9658
|
+
}
|
|
9659
|
+
|
|
9660
|
+
.feedback-form-group textarea {
|
|
9661
|
+
min-height: 200px;
|
|
10095
9662
|
width: 100%;
|
|
10096
|
-
|
|
10097
|
-
border-radius:
|
|
9663
|
+
resize: vertical;
|
|
9664
|
+
border-radius: 8px;
|
|
9665
|
+
border: 1px solid #D1D5DB;
|
|
9666
|
+
padding: 10px 14px;
|
|
9667
|
+
font-size: 15px;
|
|
9668
|
+
font-weight: 400;
|
|
9669
|
+
line-height: 1.5;
|
|
9670
|
+
color: #1F2937;
|
|
9671
|
+
font-family: inherit;
|
|
9672
|
+
outline: none;
|
|
9673
|
+
transition: all 0.2s ease;
|
|
9674
|
+
}
|
|
9675
|
+
|
|
9676
|
+
.feedback-form-group textarea::placeholder {
|
|
9677
|
+
font-size: 15px;
|
|
9678
|
+
color: #9CA3AF;
|
|
9679
|
+
}
|
|
9680
|
+
|
|
9681
|
+
.feedback-form-group textarea:focus {
|
|
9682
|
+
border-color: #155EEF;
|
|
9683
|
+
box-shadow: 0 0 0 3px rgba(79, 70, 229, 0.1);
|
|
9684
|
+
}
|
|
9685
|
+
|
|
9686
|
+
.feedback-form-group textarea:focus-visible {
|
|
9687
|
+
outline: none;
|
|
9688
|
+
}
|
|
9689
|
+
|
|
9690
|
+
.feedback-panel.theme-dark .feedback-form-group input,
|
|
9691
|
+
.feedback-panel.theme-dark .feedback-form-group textarea {
|
|
9692
|
+
background: #374151;
|
|
9693
|
+
border-color: #4B5563;
|
|
9694
|
+
color: white;
|
|
9695
|
+
}
|
|
9696
|
+
|
|
9697
|
+
.feedback-panel.theme-dark .feedback-form-group input::placeholder,
|
|
9698
|
+
.feedback-panel.theme-dark .feedback-form-group textarea::placeholder {
|
|
9699
|
+
color: #6B7280;
|
|
9700
|
+
}
|
|
9701
|
+
|
|
9702
|
+
.feedback-btn {
|
|
9703
|
+
position: relative;
|
|
9704
|
+
display: inline-flex;
|
|
9705
|
+
align-items: center;
|
|
9706
|
+
justify-content: center;
|
|
10098
9707
|
overflow: hidden;
|
|
10099
|
-
border:
|
|
9708
|
+
border-radius: 8px;
|
|
9709
|
+
border: none;
|
|
9710
|
+
height: 44px;
|
|
9711
|
+
padding: 10px 18px;
|
|
9712
|
+
font-size: 15px;
|
|
9713
|
+
font-weight: 500;
|
|
9714
|
+
font-family: inherit;
|
|
9715
|
+
cursor: pointer;
|
|
9716
|
+
transition: all 0.2s ease;
|
|
10100
9717
|
}
|
|
10101
9718
|
|
|
10102
|
-
.
|
|
9719
|
+
.feedback-btn:disabled {
|
|
9720
|
+
opacity: 0.6;
|
|
9721
|
+
cursor: not-allowed;
|
|
9722
|
+
}
|
|
9723
|
+
|
|
9724
|
+
.feedback-btn:focus-visible {
|
|
9725
|
+
outline: 2px solid #155EEF;
|
|
9726
|
+
outline-offset: 2px;
|
|
9727
|
+
}
|
|
9728
|
+
|
|
9729
|
+
.feedback-btn-submit {
|
|
9730
|
+
background: #155EEF;
|
|
9731
|
+
color: white;
|
|
10103
9732
|
width: 100%;
|
|
10104
|
-
height: 100px;
|
|
10105
|
-
display: block;
|
|
10106
|
-
object-fit: cover;
|
|
10107
9733
|
}
|
|
10108
9734
|
|
|
10109
|
-
.
|
|
10110
|
-
|
|
10111
|
-
|
|
9735
|
+
.feedback-btn-submit:hover:not(:disabled) {
|
|
9736
|
+
background: #4338ca;
|
|
9737
|
+
}
|
|
9738
|
+
|
|
9739
|
+
.feedback-btn-submit:active:not(:disabled) {
|
|
9740
|
+
background: #3730a3;
|
|
10112
9741
|
}
|
|
10113
9742
|
|
|
10114
|
-
.
|
|
10115
|
-
|
|
10116
|
-
|
|
10117
|
-
|
|
9743
|
+
.feedback-btn-cancel {
|
|
9744
|
+
background: transparent;
|
|
9745
|
+
color: #6B7280;
|
|
9746
|
+
border: 1px solid #D1D5DB;
|
|
10118
9747
|
}
|
|
10119
9748
|
|
|
10120
|
-
.
|
|
10121
|
-
|
|
10122
|
-
color: #
|
|
10123
|
-
|
|
9749
|
+
.feedback-btn-cancel:hover:not(:disabled) {
|
|
9750
|
+
background: #F9FAFB;
|
|
9751
|
+
border-color: #9CA3AF;
|
|
9752
|
+
color: #374151;
|
|
10124
9753
|
}
|
|
10125
9754
|
|
|
10126
|
-
.
|
|
10127
|
-
color: #
|
|
9755
|
+
.feedback-panel.theme-dark .feedback-btn-cancel {
|
|
9756
|
+
color: #D1D5DB;
|
|
9757
|
+
border-color: #4B5563;
|
|
10128
9758
|
}
|
|
10129
9759
|
|
|
10130
|
-
.
|
|
9760
|
+
.feedback-panel.theme-dark .feedback-btn-cancel:hover:not(:disabled) {
|
|
9761
|
+
background: #374151;
|
|
9762
|
+
}
|
|
9763
|
+
|
|
9764
|
+
.feedback-form-actions {
|
|
10131
9765
|
display: flex;
|
|
10132
|
-
flex-
|
|
10133
|
-
gap:
|
|
10134
|
-
margin-
|
|
9766
|
+
flex-direction: column;
|
|
9767
|
+
gap: 12px;
|
|
9768
|
+
margin-top: auto;
|
|
9769
|
+
padding-top: 24px;
|
|
10135
9770
|
}
|
|
10136
9771
|
|
|
10137
|
-
.
|
|
10138
|
-
|
|
9772
|
+
.feedback-error {
|
|
9773
|
+
color: #DC2626;
|
|
10139
9774
|
font-size: 14px;
|
|
10140
|
-
font-weight:
|
|
10141
|
-
|
|
10142
|
-
|
|
9775
|
+
font-weight: 400;
|
|
9776
|
+
margin-top: 8px;
|
|
9777
|
+
padding: 12px;
|
|
9778
|
+
background: #FEE2E2;
|
|
9779
|
+
border: 1px solid #FECACA;
|
|
9780
|
+
border-radius: 8px;
|
|
9781
|
+
display: none;
|
|
10143
9782
|
}
|
|
10144
9783
|
|
|
10145
|
-
.
|
|
10146
|
-
|
|
9784
|
+
.feedback-error.show {
|
|
9785
|
+
display: block;
|
|
10147
9786
|
}
|
|
10148
9787
|
|
|
10149
|
-
.
|
|
10150
|
-
|
|
10151
|
-
|
|
10152
|
-
|
|
10153
|
-
color: #6B7280;
|
|
10154
|
-
display: -webkit-box;
|
|
10155
|
-
-webkit-line-clamp: 2;
|
|
10156
|
-
-webkit-box-orient: vertical;
|
|
10157
|
-
overflow: hidden;
|
|
9788
|
+
.feedback-panel.theme-dark .feedback-error {
|
|
9789
|
+
background: #7F1D1D;
|
|
9790
|
+
border-color: #991B1B;
|
|
9791
|
+
color: #FCA5A5;
|
|
10158
9792
|
}
|
|
10159
9793
|
|
|
10160
|
-
|
|
10161
|
-
|
|
9794
|
+
/* ==================== SUCCESS NOTIFICATION ==================== */
|
|
9795
|
+
.feedback-success-notification {
|
|
9796
|
+
position: fixed;
|
|
9797
|
+
top: 24px;
|
|
9798
|
+
right: 24px;
|
|
9799
|
+
z-index: 1000002;
|
|
9800
|
+
background: white;
|
|
9801
|
+
border: 1px solid #D1FAE5;
|
|
9802
|
+
border-radius: 12px;
|
|
9803
|
+
box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05);
|
|
9804
|
+
animation: slideInRight 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
|
9805
|
+
min-width: 320px;
|
|
10162
9806
|
}
|
|
10163
9807
|
|
|
10164
|
-
.
|
|
9808
|
+
.feedback-success-content {
|
|
9809
|
+
display: flex;
|
|
9810
|
+
align-items: center;
|
|
9811
|
+
padding: 16px 20px;
|
|
9812
|
+
gap: 12px;
|
|
9813
|
+
}
|
|
9814
|
+
|
|
9815
|
+
.feedback-success-icon {
|
|
9816
|
+
width: 20px;
|
|
9817
|
+
height: 20px;
|
|
9818
|
+
border-radius: 50%;
|
|
9819
|
+
background: #10B981;
|
|
9820
|
+
color: white;
|
|
9821
|
+
display: flex;
|
|
9822
|
+
align-items: center;
|
|
9823
|
+
justify-content: center;
|
|
9824
|
+
font-size: 12px;
|
|
9825
|
+
font-weight: 600;
|
|
10165
9826
|
flex-shrink: 0;
|
|
10166
|
-
margin-left: 12px;
|
|
10167
|
-
color: #9CA3AF;
|
|
10168
|
-
transition: all 0.2s ease;
|
|
10169
9827
|
}
|
|
10170
9828
|
|
|
10171
|
-
.
|
|
10172
|
-
color: #
|
|
10173
|
-
|
|
9829
|
+
.feedback-success-content span {
|
|
9830
|
+
color: #065F46;
|
|
9831
|
+
font-weight: 500;
|
|
9832
|
+
font-size: 14px;
|
|
9833
|
+
flex: 1;
|
|
10174
9834
|
}
|
|
10175
9835
|
|
|
10176
|
-
.
|
|
9836
|
+
.feedback-success-close {
|
|
9837
|
+
background: none;
|
|
9838
|
+
border: none;
|
|
10177
9839
|
color: #6B7280;
|
|
9840
|
+
cursor: pointer;
|
|
9841
|
+
font-size: 20px;
|
|
9842
|
+
padding: 0;
|
|
9843
|
+
width: 24px;
|
|
9844
|
+
height: 24px;
|
|
9845
|
+
display: flex;
|
|
9846
|
+
align-items: center;
|
|
9847
|
+
justify-content: center;
|
|
9848
|
+
transition: all 0.2s ease;
|
|
9849
|
+
border-radius: 4px;
|
|
9850
|
+
flex-shrink: 0;
|
|
10178
9851
|
}
|
|
10179
9852
|
|
|
10180
|
-
.
|
|
10181
|
-
|
|
9853
|
+
.feedback-success-close:hover {
|
|
9854
|
+
background: #F3F4F6;
|
|
9855
|
+
color: #374151;
|
|
10182
9856
|
}
|
|
10183
9857
|
|
|
10184
|
-
|
|
10185
|
-
|
|
10186
|
-
|
|
10187
|
-
|
|
10188
|
-
}
|
|
10189
|
-
|
|
10190
|
-
.changelog-modal-container {
|
|
10191
|
-
max-width: 100%;
|
|
10192
|
-
border-radius: 20px;
|
|
10193
|
-
}
|
|
9858
|
+
.feedback-success-close:focus-visible {
|
|
9859
|
+
outline: 2px solid #155EEF;
|
|
9860
|
+
outline-offset: 2px;
|
|
9861
|
+
}
|
|
10194
9862
|
|
|
10195
|
-
|
|
9863
|
+
@media (max-width: 768px) {
|
|
9864
|
+
.feedback-widget-button {
|
|
10196
9865
|
bottom: 16px;
|
|
10197
9866
|
right: 16px;
|
|
10198
9867
|
}
|
|
10199
|
-
|
|
10200
|
-
.
|
|
9868
|
+
|
|
9869
|
+
.feedback-widget-button.position-bottom-left {
|
|
10201
9870
|
left: 16px;
|
|
10202
9871
|
}
|
|
10203
|
-
|
|
10204
|
-
.
|
|
10205
|
-
|
|
10206
|
-
|
|
10207
|
-
|
|
10208
|
-
|
|
10209
|
-
|
|
10210
|
-
}
|
|
10211
|
-
|
|
10212
|
-
.changelog-popup-title {
|
|
10213
|
-
font-size: 22px;
|
|
9872
|
+
|
|
9873
|
+
.feedback-minimize-icon,
|
|
9874
|
+
.feedback-expand-icon {
|
|
9875
|
+
top: -4px;
|
|
9876
|
+
right: -4px;
|
|
9877
|
+
width: 20px;
|
|
9878
|
+
height: 20px;
|
|
10214
9879
|
}
|
|
10215
|
-
|
|
10216
|
-
.
|
|
10217
|
-
|
|
9880
|
+
|
|
9881
|
+
.feedback-minimize-icon svg,
|
|
9882
|
+
.feedback-expand-icon svg {
|
|
9883
|
+
width: 14px;
|
|
9884
|
+
height: 14px;
|
|
10218
9885
|
}
|
|
10219
9886
|
|
|
10220
|
-
.
|
|
10221
|
-
padding: 12px 28px;
|
|
10222
|
-
font-size: 15px;
|
|
9887
|
+
.feedback-panel {
|
|
10223
9888
|
width: 100%;
|
|
9889
|
+
top: auto;
|
|
9890
|
+
bottom: 0;
|
|
9891
|
+
right: 0;
|
|
9892
|
+
left: 0;
|
|
9893
|
+
height: 85vh;
|
|
9894
|
+
max-height: 85vh;
|
|
9895
|
+
transform: translateY(100%);
|
|
9896
|
+
border-radius: 20px 20px 0 0;
|
|
10224
9897
|
}
|
|
10225
|
-
|
|
10226
|
-
.
|
|
10227
|
-
|
|
9898
|
+
|
|
9899
|
+
.feedback-panel.open {
|
|
9900
|
+
transform: translateY(0);
|
|
10228
9901
|
}
|
|
10229
|
-
|
|
10230
|
-
|
|
10231
|
-
|
|
10232
|
-
padding: 16px;
|
|
9902
|
+
|
|
9903
|
+
.feedback-panel-content {
|
|
9904
|
+
border-radius: 20px 20px 0 0;
|
|
10233
9905
|
}
|
|
10234
|
-
|
|
10235
|
-
.
|
|
10236
|
-
|
|
10237
|
-
|
|
10238
|
-
border-radius: 16px;
|
|
9906
|
+
|
|
9907
|
+
.feedback-panel-header {
|
|
9908
|
+
padding: 20px;
|
|
9909
|
+
position: relative;
|
|
10239
9910
|
}
|
|
10240
|
-
|
|
10241
|
-
.
|
|
10242
|
-
|
|
9911
|
+
|
|
9912
|
+
.feedback-panel-header::before {
|
|
9913
|
+
content: '';
|
|
9914
|
+
position: absolute;
|
|
9915
|
+
top: 8px;
|
|
9916
|
+
left: 50%;
|
|
9917
|
+
transform: translateX(-50%);
|
|
9918
|
+
width: 40px;
|
|
9919
|
+
height: 4px;
|
|
9920
|
+
background: #D1D5DB;
|
|
9921
|
+
border-radius: 2px;
|
|
10243
9922
|
}
|
|
10244
|
-
|
|
10245
|
-
.
|
|
10246
|
-
|
|
9923
|
+
|
|
9924
|
+
.feedback-panel.theme-dark .feedback-panel-header::before {
|
|
9925
|
+
background: #4B5563;
|
|
10247
9926
|
}
|
|
10248
|
-
|
|
10249
|
-
.
|
|
10250
|
-
|
|
9927
|
+
|
|
9928
|
+
.feedback-panel-body {
|
|
9929
|
+
padding: 20px;
|
|
10251
9930
|
}
|
|
10252
|
-
|
|
10253
|
-
.
|
|
10254
|
-
|
|
9931
|
+
|
|
9932
|
+
.feedback-form-group textarea {
|
|
9933
|
+
min-height: 150px;
|
|
10255
9934
|
}
|
|
10256
|
-
}
|
|
10257
9935
|
|
|
10258
|
-
|
|
10259
|
-
|
|
10260
|
-
|
|
10261
|
-
|
|
10262
|
-
|
|
10263
|
-
.changelog-list-modal-container,
|
|
10264
|
-
.changelog-list-modal-backdrop,
|
|
10265
|
-
.changelog-trigger-btn,
|
|
10266
|
-
.changelog-popup-btn,
|
|
10267
|
-
.changelog-view-all-btn,
|
|
10268
|
-
.changelog-loading-spinner,
|
|
10269
|
-
.changelog-dot,
|
|
10270
|
-
.changelog-list-item,
|
|
10271
|
-
.changelog-list-item-arrow {
|
|
10272
|
-
transition: none;
|
|
10273
|
-
animation: none;
|
|
9936
|
+
.feedback-success-notification {
|
|
9937
|
+
top: 16px;
|
|
9938
|
+
right: 16px;
|
|
9939
|
+
left: 16px;
|
|
9940
|
+
min-width: auto;
|
|
10274
9941
|
}
|
|
10275
9942
|
}
|
|
10276
9943
|
`;
|
|
10277
9944
|
|
|
9945
|
+
const CSS_STYLES = baseStyles + feedbackStyles + changelogStyles;
|
|
9946
|
+
|
|
10278
9947
|
function injectStyles() {
|
|
10279
9948
|
if (
|
|
10280
9949
|
typeof document !== 'undefined' &&
|