@product7/product7-js 0.3.1 → 0.3.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +53 -29
- package/dist/README.md +53 -29
- package/dist/product7-js.js +495 -132
- package/dist/product7-js.js.map +1 -1
- package/dist/product7-js.min.js +1 -1
- package/dist/product7-js.min.js.map +1 -1
- package/package.json +1 -1
- package/src/api/services/MessengerService.js +1 -30
- package/src/core/APIService.js +35 -1
- package/src/core/BaseAPIService.js +124 -11
- package/src/core/Product7.js +182 -18
- package/src/docs/api.md +253 -89
- package/src/docs/example.md +203 -153
- package/src/docs/framework-integrations.md +236 -358
- package/src/docs/installation.md +171 -143
- package/src/index.js +48 -41
- package/src/widgets/MessengerWidget.js +67 -22
- package/src/widgets/SurveyWidget.js +20 -0
- package/src/widgets/messenger/views/ChatView.js +14 -8
- package/src/widgets/messenger/views/HomeView.js +5 -2
- package/types/index.d.ts +34 -0
package/dist/product7-js.js
CHANGED
|
@@ -737,36 +737,7 @@
|
|
|
737
737
|
}
|
|
738
738
|
|
|
739
739
|
async identifyContact(data) {
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
if (this.api.mock) {
|
|
743
|
-
await delay$1(300);
|
|
744
|
-
return {
|
|
745
|
-
status: true,
|
|
746
|
-
data: {
|
|
747
|
-
contact_id: 'mock_contact_' + Date.now(),
|
|
748
|
-
email: data.email,
|
|
749
|
-
name: data.name || '',
|
|
750
|
-
is_new: true,
|
|
751
|
-
},
|
|
752
|
-
};
|
|
753
|
-
}
|
|
754
|
-
|
|
755
|
-
return this.api._makeRequest('/widget/messenger/identify', {
|
|
756
|
-
method: 'POST',
|
|
757
|
-
headers: {
|
|
758
|
-
'Content-Type': 'application/json',
|
|
759
|
-
Authorization: `Bearer ${this.api.sessionToken}`,
|
|
760
|
-
},
|
|
761
|
-
body: JSON.stringify({
|
|
762
|
-
email: data.email,
|
|
763
|
-
name: data.name || '',
|
|
764
|
-
phone: data.phone || '',
|
|
765
|
-
company: data.company || '',
|
|
766
|
-
avatar_url: data.avatar_url || '',
|
|
767
|
-
metadata: data.metadata || {},
|
|
768
|
-
}),
|
|
769
|
-
});
|
|
740
|
+
return this.api.identify(data);
|
|
770
741
|
}
|
|
771
742
|
|
|
772
743
|
async sendTypingIndicator(conversationId, isTyping) {
|
|
@@ -995,11 +966,16 @@
|
|
|
995
966
|
this.sessionToken = null;
|
|
996
967
|
this.sessionExpiry = null;
|
|
997
968
|
this.metadata = config.metadata || null;
|
|
969
|
+
this.identitySyncedToken = null;
|
|
998
970
|
this.mock = config.mock || false;
|
|
999
971
|
this.env = config.env || 'production';
|
|
1000
972
|
this.baseURL = this._getBaseURL(config);
|
|
1001
973
|
|
|
1002
974
|
this._loadStoredSession();
|
|
975
|
+
this._loadStoredMetadata();
|
|
976
|
+
if (this.isSessionValid() && this.metadata) {
|
|
977
|
+
this.identitySyncedToken = this.sessionToken;
|
|
978
|
+
}
|
|
1003
979
|
}
|
|
1004
980
|
|
|
1005
981
|
_getBaseURL(config) {
|
|
@@ -1039,20 +1015,17 @@
|
|
|
1039
1015
|
: envConfig.base;
|
|
1040
1016
|
}
|
|
1041
1017
|
|
|
1042
|
-
async init(metadata =
|
|
1043
|
-
if (metadata) {
|
|
1044
|
-
this.metadata
|
|
1018
|
+
async init(metadata = undefined) {
|
|
1019
|
+
if (metadata !== undefined) {
|
|
1020
|
+
this.setMetadata(metadata);
|
|
1045
1021
|
}
|
|
1046
1022
|
|
|
1047
1023
|
if (this.isSessionValid()) {
|
|
1048
1024
|
return { sessionToken: this.sessionToken };
|
|
1049
1025
|
}
|
|
1050
1026
|
|
|
1051
|
-
if (!this.workspace
|
|
1052
|
-
throw new APIError$1(
|
|
1053
|
-
400,
|
|
1054
|
-
`Missing ${!this.workspace ? 'workspace' : 'user context'} for initialization`
|
|
1055
|
-
);
|
|
1027
|
+
if (!this.workspace) {
|
|
1028
|
+
throw new APIError$1(400, 'Missing workspace for initialization');
|
|
1056
1029
|
}
|
|
1057
1030
|
|
|
1058
1031
|
if (this.mock) {
|
|
@@ -1065,6 +1038,7 @@
|
|
|
1065
1038
|
async _initMockSession() {
|
|
1066
1039
|
this.sessionToken = 'mock_session_' + Date.now();
|
|
1067
1040
|
this.sessionExpiry = new Date(Date.now() + 3600 * 1000);
|
|
1041
|
+
this.identitySyncedToken = null;
|
|
1068
1042
|
this._storeSession();
|
|
1069
1043
|
return {
|
|
1070
1044
|
sessionToken: this.sessionToken,
|
|
@@ -1083,7 +1057,6 @@
|
|
|
1083
1057
|
async _initRealSession() {
|
|
1084
1058
|
const payload = {
|
|
1085
1059
|
workspace: this.workspace,
|
|
1086
|
-
user: this.metadata,
|
|
1087
1060
|
};
|
|
1088
1061
|
|
|
1089
1062
|
try {
|
|
@@ -1096,6 +1069,7 @@
|
|
|
1096
1069
|
|
|
1097
1070
|
this.sessionToken = initData.sessionToken;
|
|
1098
1071
|
this.sessionExpiry = new Date(Date.now() + initData.expiresIn * 1000);
|
|
1072
|
+
this.identitySyncedToken = null;
|
|
1099
1073
|
this._storeSession();
|
|
1100
1074
|
|
|
1101
1075
|
return {
|
|
@@ -1162,12 +1136,52 @@
|
|
|
1162
1136
|
this.sessionToken = null;
|
|
1163
1137
|
this.sessionExpiry = null;
|
|
1164
1138
|
await this.init();
|
|
1139
|
+
await this._restoreIdentity();
|
|
1165
1140
|
return await method.apply(this, args);
|
|
1166
1141
|
}
|
|
1167
1142
|
throw error;
|
|
1168
1143
|
}
|
|
1169
1144
|
}
|
|
1170
1145
|
|
|
1146
|
+
async identify(metadata = this.metadata) {
|
|
1147
|
+
if (metadata !== undefined) {
|
|
1148
|
+
this.setMetadata(metadata);
|
|
1149
|
+
}
|
|
1150
|
+
|
|
1151
|
+
if (!this.metadata) {
|
|
1152
|
+
throw new APIError$1(400, 'Missing user context for identify');
|
|
1153
|
+
}
|
|
1154
|
+
|
|
1155
|
+
await this._ensureSession();
|
|
1156
|
+
|
|
1157
|
+
const payload = this._buildIdentifyPayload(this.metadata);
|
|
1158
|
+
|
|
1159
|
+
if (this.mock) {
|
|
1160
|
+
this.identitySyncedToken = this.sessionToken;
|
|
1161
|
+
return {
|
|
1162
|
+
status: true,
|
|
1163
|
+
identified: true,
|
|
1164
|
+
data: {
|
|
1165
|
+
user_id: payload.user_id || null,
|
|
1166
|
+
email: payload.email || null,
|
|
1167
|
+
name: payload.name || null,
|
|
1168
|
+
},
|
|
1169
|
+
};
|
|
1170
|
+
}
|
|
1171
|
+
|
|
1172
|
+
const response = await this._makeRequest('/widget/identify', {
|
|
1173
|
+
method: 'POST',
|
|
1174
|
+
body: JSON.stringify(payload),
|
|
1175
|
+
headers: {
|
|
1176
|
+
'Content-Type': 'application/json',
|
|
1177
|
+
Authorization: `Bearer ${this.sessionToken}`,
|
|
1178
|
+
},
|
|
1179
|
+
});
|
|
1180
|
+
|
|
1181
|
+
this.identitySyncedToken = this.sessionToken;
|
|
1182
|
+
return response;
|
|
1183
|
+
}
|
|
1184
|
+
|
|
1171
1185
|
isSessionValid() {
|
|
1172
1186
|
return (
|
|
1173
1187
|
this.sessionToken && this.sessionExpiry && new Date() < this.sessionExpiry
|
|
@@ -1175,8 +1189,13 @@
|
|
|
1175
1189
|
}
|
|
1176
1190
|
|
|
1177
1191
|
setMetadata(metadata) {
|
|
1178
|
-
this.metadata = metadata;
|
|
1179
|
-
this.
|
|
1192
|
+
this.metadata = metadata || null;
|
|
1193
|
+
this.identitySyncedToken = null;
|
|
1194
|
+
if (this.metadata) {
|
|
1195
|
+
this._storeData('product7_metadata', this.metadata);
|
|
1196
|
+
} else {
|
|
1197
|
+
this._removeData('product7_metadata');
|
|
1198
|
+
}
|
|
1180
1199
|
}
|
|
1181
1200
|
|
|
1182
1201
|
getMetadata() {
|
|
@@ -1186,6 +1205,7 @@
|
|
|
1186
1205
|
clearSession() {
|
|
1187
1206
|
this.sessionToken = null;
|
|
1188
1207
|
this.sessionExpiry = null;
|
|
1208
|
+
this.identitySyncedToken = null;
|
|
1189
1209
|
this._removeData('product7_session');
|
|
1190
1210
|
this._removeData('product7_metadata');
|
|
1191
1211
|
}
|
|
@@ -1211,6 +1231,14 @@
|
|
|
1211
1231
|
if (!stored) return false;
|
|
1212
1232
|
|
|
1213
1233
|
const sessionData = JSON.parse(stored);
|
|
1234
|
+
if (
|
|
1235
|
+
this.workspace &&
|
|
1236
|
+
sessionData.workspace &&
|
|
1237
|
+
sessionData.workspace !== this.workspace
|
|
1238
|
+
) {
|
|
1239
|
+
localStorage.removeItem('product7_session');
|
|
1240
|
+
return false;
|
|
1241
|
+
}
|
|
1214
1242
|
this.sessionToken = sessionData.token;
|
|
1215
1243
|
this.sessionExpiry = new Date(sessionData.expiry);
|
|
1216
1244
|
|
|
@@ -1220,6 +1248,32 @@
|
|
|
1220
1248
|
}
|
|
1221
1249
|
}
|
|
1222
1250
|
|
|
1251
|
+
_loadStoredMetadata() {
|
|
1252
|
+
if (this.metadata || typeof localStorage === 'undefined') return false;
|
|
1253
|
+
|
|
1254
|
+
try {
|
|
1255
|
+
const session = localStorage.getItem('product7_session');
|
|
1256
|
+
if (session) {
|
|
1257
|
+
const sessionData = JSON.parse(session);
|
|
1258
|
+
if (
|
|
1259
|
+
this.workspace &&
|
|
1260
|
+
sessionData.workspace &&
|
|
1261
|
+
sessionData.workspace !== this.workspace
|
|
1262
|
+
) {
|
|
1263
|
+
return false;
|
|
1264
|
+
}
|
|
1265
|
+
}
|
|
1266
|
+
|
|
1267
|
+
const stored = localStorage.getItem('product7_metadata');
|
|
1268
|
+
if (!stored) return false;
|
|
1269
|
+
|
|
1270
|
+
this.metadata = JSON.parse(stored);
|
|
1271
|
+
return true;
|
|
1272
|
+
} catch (error) {
|
|
1273
|
+
return false;
|
|
1274
|
+
}
|
|
1275
|
+
}
|
|
1276
|
+
|
|
1223
1277
|
_storeData(key, value) {
|
|
1224
1278
|
if (typeof localStorage !== 'undefined') {
|
|
1225
1279
|
localStorage.setItem(key, JSON.stringify(value));
|
|
@@ -1282,6 +1336,36 @@
|
|
|
1282
1336
|
const queryString = this._buildQueryParams(params);
|
|
1283
1337
|
return `${endpoint}${queryString ? '?' + queryString : ''}`;
|
|
1284
1338
|
}
|
|
1339
|
+
|
|
1340
|
+
_buildIdentifyPayload(metadata = {}) {
|
|
1341
|
+
const payload = {
|
|
1342
|
+
user_id: metadata.user_id,
|
|
1343
|
+
email: metadata.email,
|
|
1344
|
+
name: metadata.name,
|
|
1345
|
+
avatar:
|
|
1346
|
+
metadata.profile_picture || metadata.avatar_url || metadata.avatar,
|
|
1347
|
+
attributes: metadata.custom_fields || {},
|
|
1348
|
+
};
|
|
1349
|
+
|
|
1350
|
+
if (metadata.company) {
|
|
1351
|
+
payload.company = metadata.company;
|
|
1352
|
+
}
|
|
1353
|
+
|
|
1354
|
+
return payload;
|
|
1355
|
+
}
|
|
1356
|
+
|
|
1357
|
+
async _restoreIdentity() {
|
|
1358
|
+
if (
|
|
1359
|
+
!this.metadata ||
|
|
1360
|
+
!this.sessionToken ||
|
|
1361
|
+
!this.identitySyncedToken ||
|
|
1362
|
+
this.identitySyncedToken === this.sessionToken
|
|
1363
|
+
) {
|
|
1364
|
+
return;
|
|
1365
|
+
}
|
|
1366
|
+
|
|
1367
|
+
await this.identify(this.metadata);
|
|
1368
|
+
}
|
|
1285
1369
|
}
|
|
1286
1370
|
|
|
1287
1371
|
class APIService extends BaseAPIService {
|
|
@@ -1503,8 +1587,42 @@
|
|
|
1503
1587
|
return this.messenger.submitRating(conversationId, data);
|
|
1504
1588
|
}
|
|
1505
1589
|
|
|
1590
|
+
async identify(metadata) {
|
|
1591
|
+
await this._ensureSession();
|
|
1592
|
+
|
|
1593
|
+
if (this.mock) {
|
|
1594
|
+
await new Promise((r) => setTimeout(r, 300));
|
|
1595
|
+
return {
|
|
1596
|
+
status: true,
|
|
1597
|
+
data: {
|
|
1598
|
+
contact_id: 'mock_contact_' + Date.now(),
|
|
1599
|
+
email: metadata.email,
|
|
1600
|
+
name: metadata.name || '',
|
|
1601
|
+
is_new: true,
|
|
1602
|
+
},
|
|
1603
|
+
};
|
|
1604
|
+
}
|
|
1605
|
+
|
|
1606
|
+
return this._makeRequest('/widget/messenger/identify', {
|
|
1607
|
+
method: 'POST',
|
|
1608
|
+
headers: {
|
|
1609
|
+
'Content-Type': 'application/json',
|
|
1610
|
+
Authorization: `Bearer ${this.sessionToken}`,
|
|
1611
|
+
},
|
|
1612
|
+
body: JSON.stringify({
|
|
1613
|
+
user_id: metadata.user_id || null,
|
|
1614
|
+
email: metadata.email || '',
|
|
1615
|
+
name: metadata.name || '',
|
|
1616
|
+
phone: metadata.phone || '',
|
|
1617
|
+
company: metadata.company || '',
|
|
1618
|
+
avatar_url: metadata.avatar_url || '',
|
|
1619
|
+
metadata: metadata.custom_fields || {},
|
|
1620
|
+
}),
|
|
1621
|
+
});
|
|
1622
|
+
}
|
|
1623
|
+
|
|
1506
1624
|
async identifyContact(data) {
|
|
1507
|
-
return this.
|
|
1625
|
+
return this.identify(data);
|
|
1508
1626
|
}
|
|
1509
1627
|
|
|
1510
1628
|
async getHelpCollections(options) {
|
|
@@ -9492,7 +9610,9 @@
|
|
|
9492
9610
|
|
|
9493
9611
|
this._unsubscribe = this.state.subscribe((type, data) => {
|
|
9494
9612
|
if (type === 'connectionChange') {
|
|
9495
|
-
const banner = this.element?.querySelector(
|
|
9613
|
+
const banner = this.element?.querySelector(
|
|
9614
|
+
'.messenger-connection-banner'
|
|
9615
|
+
);
|
|
9496
9616
|
if (banner) {
|
|
9497
9617
|
banner.style.display = data.connected ? 'none' : 'flex';
|
|
9498
9618
|
}
|
|
@@ -9542,9 +9662,10 @@
|
|
|
9542
9662
|
? this._renderEmptyState(isNewConversation)
|
|
9543
9663
|
: this._renderGroupedMessages(messages);
|
|
9544
9664
|
|
|
9545
|
-
const defaultPlaceholder =
|
|
9665
|
+
const defaultPlaceholder =
|
|
9666
|
+
this.options.composePlaceholder || 'Write a message...';
|
|
9546
9667
|
const placeholder = isNewConversation
|
|
9547
|
-
?
|
|
9668
|
+
? this.options.composePlaceholder || 'Start typing your message...'
|
|
9548
9669
|
: isClosed
|
|
9549
9670
|
? 'Conversation closed'
|
|
9550
9671
|
: defaultPlaceholder;
|
|
@@ -9565,7 +9686,7 @@
|
|
|
9565
9686
|
</div>
|
|
9566
9687
|
<div class="messenger-chat-header-info">
|
|
9567
9688
|
<span class="messenger-chat-title">${this._escapeHtml(teamName)}</span>
|
|
9568
|
-
<span class="messenger-chat-subtitle">${isClosed ? 'Conversation resolved' :
|
|
9689
|
+
<span class="messenger-chat-subtitle">${isClosed ? 'Conversation resolved' : this.state.responseTime || 'Typically replies within minutes'}</span>
|
|
9569
9690
|
</div>
|
|
9570
9691
|
<div class="messenger-chat-header-actions">
|
|
9571
9692
|
<button class="sdk-btn-icon sdk-close-btn messenger-mobile-close-btn" aria-label="Close">
|
|
@@ -9682,7 +9803,9 @@
|
|
|
9682
9803
|
const messageClass = isOwn
|
|
9683
9804
|
? 'messenger-message-own'
|
|
9684
9805
|
: 'messenger-message-received';
|
|
9685
|
-
const timeStr = isLastInGroup
|
|
9806
|
+
const timeStr = isLastInGroup
|
|
9807
|
+
? this._formatMessageTime(message.timestamp)
|
|
9808
|
+
: '';
|
|
9686
9809
|
const attachmentsHtml = this._renderMessageAttachments(message.attachments);
|
|
9687
9810
|
const isOptimistic = message.isOptimistic;
|
|
9688
9811
|
|
|
@@ -9696,9 +9819,10 @@
|
|
|
9696
9819
|
if (isOwn) {
|
|
9697
9820
|
const sentIndicator = isLastInGroup
|
|
9698
9821
|
? `<div class="messenger-message-meta messenger-message-meta-own">
|
|
9699
|
-
${
|
|
9700
|
-
|
|
9701
|
-
|
|
9822
|
+
${
|
|
9823
|
+
isOptimistic
|
|
9824
|
+
? `<span class="messenger-message-sent-status">Sending…</span>`
|
|
9825
|
+
: `<span class="messenger-message-sent-status">Sent</span>`
|
|
9702
9826
|
}
|
|
9703
9827
|
${timeStr ? `<span>·</span><span>${timeStr}</span>` : ''}
|
|
9704
9828
|
</div>`
|
|
@@ -10929,7 +11053,8 @@
|
|
|
10929
11053
|
const title = conversation.title || teamName;
|
|
10930
11054
|
const timeAgo = this._formatTimeAgo(conversation.lastMessageTime);
|
|
10931
11055
|
const preview = conversation.lastMessage
|
|
10932
|
-
? conversation.lastMessage.substring(0, 48) +
|
|
11056
|
+
? conversation.lastMessage.substring(0, 48) +
|
|
11057
|
+
(conversation.lastMessage.length > 48 ? '...' : '')
|
|
10933
11058
|
: '';
|
|
10934
11059
|
const hasUnread = conversation.unread > 0;
|
|
10935
11060
|
|
|
@@ -11045,7 +11170,9 @@
|
|
|
11045
11170
|
}
|
|
11046
11171
|
|
|
11047
11172
|
_attachEvents() {
|
|
11048
|
-
const recentCard = this.element.querySelector(
|
|
11173
|
+
const recentCard = this.element.querySelector(
|
|
11174
|
+
'.messenger-home-recent-card'
|
|
11175
|
+
);
|
|
11049
11176
|
if (recentCard) {
|
|
11050
11177
|
recentCard.addEventListener('click', () => {
|
|
11051
11178
|
const convId = recentCard.dataset.conversationId;
|
|
@@ -11243,6 +11370,7 @@
|
|
|
11243
11370
|
class MessengerWidget extends BaseWidget {
|
|
11244
11371
|
constructor(options) {
|
|
11245
11372
|
super({ ...options, type: 'messenger' });
|
|
11373
|
+
this._explicitOptions = options || {};
|
|
11246
11374
|
const resolvedTheme = options.theme || 'light';
|
|
11247
11375
|
const hasExplicitTextColor = Object.prototype.hasOwnProperty.call(
|
|
11248
11376
|
options,
|
|
@@ -11325,6 +11453,10 @@
|
|
|
11325
11453
|
this._handleConversationClosed = this._handleConversationClosed.bind(this);
|
|
11326
11454
|
}
|
|
11327
11455
|
|
|
11456
|
+
_hasTrigger() {
|
|
11457
|
+
return this.options.trigger === true || this.options.trigger === undefined;
|
|
11458
|
+
}
|
|
11459
|
+
|
|
11328
11460
|
_createInternalFeedbackWidget() {
|
|
11329
11461
|
try {
|
|
11330
11462
|
const widget = this.sdk.createWidget('button', {
|
|
@@ -11360,11 +11492,13 @@
|
|
|
11360
11492
|
this._feedbackWidget = this._createInternalFeedbackWidget();
|
|
11361
11493
|
}
|
|
11362
11494
|
|
|
11363
|
-
|
|
11364
|
-
|
|
11365
|
-
|
|
11366
|
-
|
|
11367
|
-
|
|
11495
|
+
if (this._hasTrigger()) {
|
|
11496
|
+
this.launcher = new MessengerLauncher(this.messengerState, {
|
|
11497
|
+
position: this.messengerOptions.position,
|
|
11498
|
+
primaryColor: this.messengerOptions.primaryColor,
|
|
11499
|
+
});
|
|
11500
|
+
container.appendChild(this.launcher.render());
|
|
11501
|
+
}
|
|
11368
11502
|
|
|
11369
11503
|
this.panel = new MessengerPanel(this.messengerState, {
|
|
11370
11504
|
position: this.messengerOptions.position,
|
|
@@ -11499,23 +11633,13 @@
|
|
|
11499
11633
|
|
|
11500
11634
|
async _handleIdentifyContact(contactData) {
|
|
11501
11635
|
try {
|
|
11502
|
-
|
|
11503
|
-
|
|
11636
|
+
// Route through sdk.identify() so the SDK-level identity state is updated
|
|
11637
|
+
// and applyIdentity() handles the messenger state + WebSocket as a side effect.
|
|
11638
|
+
const result = await this.sdk.identify({
|
|
11504
11639
|
email: contactData.email,
|
|
11640
|
+
name: contactData.name,
|
|
11505
11641
|
});
|
|
11506
|
-
|
|
11507
|
-
if (response.status) {
|
|
11508
|
-
console.log(
|
|
11509
|
-
'[MessengerWidget] Contact identified:',
|
|
11510
|
-
response.data.contact_id
|
|
11511
|
-
);
|
|
11512
|
-
this.messengerState.setIdentified(true, {
|
|
11513
|
-
name: contactData.name,
|
|
11514
|
-
email: contactData.email,
|
|
11515
|
-
});
|
|
11516
|
-
}
|
|
11517
|
-
|
|
11518
|
-
return response;
|
|
11642
|
+
return result;
|
|
11519
11643
|
} catch (error) {
|
|
11520
11644
|
console.error('[MessengerWidget] Failed to identify contact:', error);
|
|
11521
11645
|
throw error;
|
|
@@ -11523,8 +11647,17 @@
|
|
|
11523
11647
|
}
|
|
11524
11648
|
|
|
11525
11649
|
markAsIdentified(name, email) {
|
|
11526
|
-
|
|
11527
|
-
|
|
11650
|
+
// Called externally by the app when the user is already known.
|
|
11651
|
+
// No API call needed — identity was already established via sdk.identify().
|
|
11652
|
+
this.applyIdentity({ name, email });
|
|
11653
|
+
}
|
|
11654
|
+
|
|
11655
|
+
applyIdentity(metadata = {}) {
|
|
11656
|
+
this.messengerState.setIdentified(true, metadata);
|
|
11657
|
+
|
|
11658
|
+
if (this.apiService?.sessionToken && !this.wsService?.isConnected) {
|
|
11659
|
+
this._initWebSocket();
|
|
11660
|
+
}
|
|
11528
11661
|
}
|
|
11529
11662
|
|
|
11530
11663
|
async _handleUploadFile(base64Data, filename) {
|
|
@@ -12035,6 +12168,42 @@
|
|
|
12035
12168
|
}
|
|
12036
12169
|
}
|
|
12037
12170
|
|
|
12171
|
+
async _fetchAndApplySettings() {
|
|
12172
|
+
try {
|
|
12173
|
+
const response = await this.apiService.getMessengerSettings();
|
|
12174
|
+
if (!response?.status || !response?.data) return;
|
|
12175
|
+
|
|
12176
|
+
const s = response.data;
|
|
12177
|
+
|
|
12178
|
+
// Only apply values that were NOT explicitly passed in options
|
|
12179
|
+
if (s.team_name && !this._hasExplicitOption('teamName')) {
|
|
12180
|
+
this.messengerOptions.teamName = s.team_name;
|
|
12181
|
+
this.messengerState.teamName = s.team_name;
|
|
12182
|
+
}
|
|
12183
|
+
if (s.logo_url && !this._hasExplicitOption('logoUrl')) {
|
|
12184
|
+
this.messengerOptions.logoUrl = s.logo_url;
|
|
12185
|
+
}
|
|
12186
|
+
if (s.greeting_message && !this._hasExplicitOption('greetingMessage')) {
|
|
12187
|
+
this.messengerState.greetingMessage = s.greeting_message;
|
|
12188
|
+
}
|
|
12189
|
+
if (s.response_time && !this._hasExplicitOption('responseTime')) {
|
|
12190
|
+
this.messengerState.responseTime = s.response_time;
|
|
12191
|
+
}
|
|
12192
|
+
|
|
12193
|
+
// Notify views to re-render with new values
|
|
12194
|
+
this.messengerState._notify('availabilityUpdate', {});
|
|
12195
|
+
} catch (e) {
|
|
12196
|
+
// non-fatal
|
|
12197
|
+
}
|
|
12198
|
+
}
|
|
12199
|
+
|
|
12200
|
+
_hasExplicitOption(key) {
|
|
12201
|
+
return Object.prototype.hasOwnProperty.call(
|
|
12202
|
+
this._explicitOptions || {},
|
|
12203
|
+
key
|
|
12204
|
+
);
|
|
12205
|
+
}
|
|
12206
|
+
|
|
12038
12207
|
async checkAgentAvailability() {
|
|
12039
12208
|
try {
|
|
12040
12209
|
const response = await this.apiService.checkAgentsOnline();
|
|
@@ -12180,6 +12349,9 @@
|
|
|
12180
12349
|
this._applyPreviewData();
|
|
12181
12350
|
|
|
12182
12351
|
if (this.messengerOptions.autoLoadData) {
|
|
12352
|
+
// Fetch workspace settings and apply only if not explicitly configured
|
|
12353
|
+
this._fetchAndApplySettings();
|
|
12354
|
+
|
|
12183
12355
|
this.loadInitialData();
|
|
12184
12356
|
|
|
12185
12357
|
if (this.apiService?.sessionToken) {
|
|
@@ -12324,6 +12496,7 @@
|
|
|
12324
12496
|
|
|
12325
12497
|
SurveyWidget.removeDanglingElements();
|
|
12326
12498
|
this._renderSurvey();
|
|
12499
|
+
this.state.isOpen = true;
|
|
12327
12500
|
this.surveyState.isVisible = true;
|
|
12328
12501
|
this.sdk.eventBus.emit('survey:shown', {
|
|
12329
12502
|
widget: this,
|
|
@@ -12333,6 +12506,7 @@
|
|
|
12333
12506
|
}
|
|
12334
12507
|
|
|
12335
12508
|
hide() {
|
|
12509
|
+
this.state.isOpen = false;
|
|
12336
12510
|
this._closeSurvey();
|
|
12337
12511
|
return this;
|
|
12338
12512
|
}
|
|
@@ -12407,6 +12581,7 @@
|
|
|
12407
12581
|
this._attachSurveyEvents();
|
|
12408
12582
|
|
|
12409
12583
|
requestAnimationFrame(() => {
|
|
12584
|
+
if (!this.surveyElement) return;
|
|
12410
12585
|
this.surveyElement.style.opacity = '1';
|
|
12411
12586
|
this.surveyElement.style.transform =
|
|
12412
12587
|
this.surveyOptions.position === 'center'
|
|
@@ -13544,6 +13719,7 @@
|
|
|
13544
13719
|
}
|
|
13545
13720
|
|
|
13546
13721
|
_closeSurvey(resetState = true, immediate = false) {
|
|
13722
|
+
this.state.isOpen = false;
|
|
13547
13723
|
if (this._escapeHandler) {
|
|
13548
13724
|
document.removeEventListener('keydown', this._escapeHandler);
|
|
13549
13725
|
this._escapeHandler = null;
|
|
@@ -13606,6 +13782,22 @@
|
|
|
13606
13782
|
this.sdk.eventBus.emit('survey:closed', { widget: this });
|
|
13607
13783
|
}
|
|
13608
13784
|
|
|
13785
|
+
open() {
|
|
13786
|
+
return this.show();
|
|
13787
|
+
}
|
|
13788
|
+
|
|
13789
|
+
close() {
|
|
13790
|
+
return this.hide();
|
|
13791
|
+
}
|
|
13792
|
+
|
|
13793
|
+
toggle() {
|
|
13794
|
+
if (this.surveyState.isVisible) {
|
|
13795
|
+
return this.hide();
|
|
13796
|
+
}
|
|
13797
|
+
|
|
13798
|
+
return this.show();
|
|
13799
|
+
}
|
|
13800
|
+
|
|
13609
13801
|
destroy() {
|
|
13610
13802
|
this._closeSurvey(true, true);
|
|
13611
13803
|
super.destroy();
|
|
@@ -13723,6 +13915,7 @@
|
|
|
13723
13915
|
constructor(config = {}) {
|
|
13724
13916
|
this.config = this._validateAndMergeConfig(config);
|
|
13725
13917
|
this.initialized = false;
|
|
13918
|
+
this.identified = false;
|
|
13726
13919
|
this.widgets = new Map();
|
|
13727
13920
|
this.eventBus = new EventBus();
|
|
13728
13921
|
|
|
@@ -13767,13 +13960,14 @@
|
|
|
13767
13960
|
this._injectStyles();
|
|
13768
13961
|
|
|
13769
13962
|
try {
|
|
13770
|
-
const initData = await this.apiService.init(
|
|
13963
|
+
const initData = await this.apiService.init();
|
|
13771
13964
|
|
|
13772
13965
|
if (initData.config) {
|
|
13773
13966
|
this.config = deepMerge(initData.config, this.config);
|
|
13774
13967
|
}
|
|
13775
13968
|
|
|
13776
13969
|
this.initialized = true;
|
|
13970
|
+
const identifyResult = await this._syncConfiguredMetadataAfterInit();
|
|
13777
13971
|
this.eventBus.emit('sdk:initialized', {
|
|
13778
13972
|
config: this.config,
|
|
13779
13973
|
sessionToken: initData.sessionToken,
|
|
@@ -13784,6 +13978,7 @@
|
|
|
13784
13978
|
config: initData.config || {},
|
|
13785
13979
|
sessionToken: initData.sessionToken,
|
|
13786
13980
|
expiresIn: initData.expiresIn,
|
|
13981
|
+
identified: Boolean(identifyResult?.identified),
|
|
13787
13982
|
};
|
|
13788
13983
|
} catch (error) {
|
|
13789
13984
|
this.eventBus.emit('sdk:error', { error });
|
|
@@ -13798,10 +13993,14 @@
|
|
|
13798
13993
|
);
|
|
13799
13994
|
}
|
|
13800
13995
|
|
|
13996
|
+
const requestedType = type || 'button';
|
|
13997
|
+
const normalizedType = this._normalizeWidgetType(requestedType);
|
|
13801
13998
|
const widgetId = generateId('widget');
|
|
13802
|
-
const widgetConfig = this._getWidgetTypeConfig(
|
|
13803
|
-
const explicitOptions = this._omitUndefined(
|
|
13804
|
-
|
|
13999
|
+
const widgetConfig = this._getWidgetTypeConfig(normalizedType);
|
|
14000
|
+
const explicitOptions = this._omitUndefined(
|
|
14001
|
+
this._normalizeWidgetOptions(normalizedType, options)
|
|
14002
|
+
);
|
|
14003
|
+
const widgetEnabled = this._isWidgetEnabled(normalizedType, {
|
|
13805
14004
|
...widgetConfig,
|
|
13806
14005
|
...explicitOptions,
|
|
13807
14006
|
});
|
|
@@ -13816,15 +14015,35 @@
|
|
|
13816
14015
|
};
|
|
13817
14016
|
|
|
13818
14017
|
try {
|
|
13819
|
-
const widget = WidgetFactory.create(
|
|
14018
|
+
const widget = WidgetFactory.create(normalizedType, widgetOptions);
|
|
13820
14019
|
this.widgets.set(widgetId, widget);
|
|
13821
|
-
this.eventBus.emit('widget:created', {
|
|
14020
|
+
this.eventBus.emit('widget:created', {
|
|
14021
|
+
widget,
|
|
14022
|
+
type: requestedType,
|
|
14023
|
+
internalType: normalizedType,
|
|
14024
|
+
});
|
|
13822
14025
|
return widget;
|
|
13823
14026
|
} catch (error) {
|
|
13824
14027
|
throw new SDKError(`Failed to create widget: ${error.message}`, error);
|
|
13825
14028
|
}
|
|
13826
14029
|
}
|
|
13827
14030
|
|
|
14031
|
+
createFeedbackWidget(options = {}) {
|
|
14032
|
+
return this.createWidget('feedback', options);
|
|
14033
|
+
}
|
|
14034
|
+
|
|
14035
|
+
createMessengerWidget(options = {}) {
|
|
14036
|
+
return this.createWidget('messenger', options);
|
|
14037
|
+
}
|
|
14038
|
+
|
|
14039
|
+
createChangelogWidget(options = {}) {
|
|
14040
|
+
return this.createWidget('changelog', options);
|
|
14041
|
+
}
|
|
14042
|
+
|
|
14043
|
+
createSurveyWidget(options = {}) {
|
|
14044
|
+
return this.createWidget('survey', options);
|
|
14045
|
+
}
|
|
14046
|
+
|
|
13828
14047
|
getWidget(id) {
|
|
13829
14048
|
return this.widgets.get(id);
|
|
13830
14049
|
}
|
|
@@ -13943,7 +14162,7 @@
|
|
|
13943
14162
|
return null;
|
|
13944
14163
|
}
|
|
13945
14164
|
|
|
13946
|
-
const surveyWidget = this.
|
|
14165
|
+
const surveyWidget = this.createSurveyWidget({
|
|
13947
14166
|
surveyId: normalizedOptions.surveyId,
|
|
13948
14167
|
surveyType:
|
|
13949
14168
|
normalizedOptions.surveyType || normalizedOptions.type || 'nps',
|
|
@@ -14177,18 +14396,34 @@
|
|
|
14177
14396
|
? this.config.widgets
|
|
14178
14397
|
: {};
|
|
14179
14398
|
|
|
14180
|
-
const
|
|
14181
|
-
|
|
14182
|
-
|
|
14399
|
+
const mergedTypeConfig = this._getWidgetTypeAliases(type).reduce(
|
|
14400
|
+
(config, alias) => {
|
|
14401
|
+
const legacyTypeConfig = this._isPlainObject(this.config?.[alias])
|
|
14402
|
+
? this.config[alias]
|
|
14403
|
+
: {};
|
|
14183
14404
|
|
|
14184
|
-
|
|
14185
|
-
|
|
14186
|
-
|
|
14405
|
+
const namespacedTypeConfig = this._isPlainObject(widgetsConfig?.[alias])
|
|
14406
|
+
? widgetsConfig[alias]
|
|
14407
|
+
: {};
|
|
14187
14408
|
|
|
14188
|
-
|
|
14409
|
+
return deepMerge(
|
|
14410
|
+
config,
|
|
14411
|
+
deepMerge(legacyTypeConfig, namespacedTypeConfig)
|
|
14412
|
+
);
|
|
14413
|
+
},
|
|
14414
|
+
{}
|
|
14415
|
+
);
|
|
14189
14416
|
return this._toCamelCaseObject(mergedTypeConfig);
|
|
14190
14417
|
}
|
|
14191
14418
|
|
|
14419
|
+
_getWidgetTypeAliases(type) {
|
|
14420
|
+
if (type === 'button') {
|
|
14421
|
+
return ['button', 'feedback'];
|
|
14422
|
+
}
|
|
14423
|
+
|
|
14424
|
+
return [type];
|
|
14425
|
+
}
|
|
14426
|
+
|
|
14192
14427
|
_isWidgetEnabled(type, options = {}) {
|
|
14193
14428
|
const typeConfig = this._getWidgetTypeConfig(type);
|
|
14194
14429
|
if (typeConfig.enabled === false) {
|
|
@@ -14231,6 +14466,31 @@
|
|
|
14231
14466
|
return normalized;
|
|
14232
14467
|
}
|
|
14233
14468
|
|
|
14469
|
+
_normalizeWidgetType(type) {
|
|
14470
|
+
if (type === 'feedback') {
|
|
14471
|
+
return 'button';
|
|
14472
|
+
}
|
|
14473
|
+
|
|
14474
|
+
return type;
|
|
14475
|
+
}
|
|
14476
|
+
|
|
14477
|
+
_normalizeWidgetOptions(type, options = {}) {
|
|
14478
|
+
if (!this._isPlainObject(options)) {
|
|
14479
|
+
return options;
|
|
14480
|
+
}
|
|
14481
|
+
|
|
14482
|
+
const normalizedOptions = { ...options };
|
|
14483
|
+
if (
|
|
14484
|
+
normalizedOptions.headless === true &&
|
|
14485
|
+
normalizedOptions.trigger === undefined &&
|
|
14486
|
+
type !== 'survey'
|
|
14487
|
+
) {
|
|
14488
|
+
normalizedOptions.trigger = false;
|
|
14489
|
+
}
|
|
14490
|
+
|
|
14491
|
+
return normalizedOptions;
|
|
14492
|
+
}
|
|
14493
|
+
|
|
14234
14494
|
_omitUndefined(value) {
|
|
14235
14495
|
if (!this._isPlainObject(value)) {
|
|
14236
14496
|
return value;
|
|
@@ -14275,7 +14535,7 @@
|
|
|
14275
14535
|
return null;
|
|
14276
14536
|
}
|
|
14277
14537
|
|
|
14278
|
-
const changelogWidget = this.
|
|
14538
|
+
const changelogWidget = this.createChangelogWidget({
|
|
14279
14539
|
...defaults,
|
|
14280
14540
|
...configDefaults,
|
|
14281
14541
|
...explicitOptions,
|
|
@@ -14342,10 +14602,15 @@
|
|
|
14342
14602
|
}
|
|
14343
14603
|
|
|
14344
14604
|
setMetadata(metadata) {
|
|
14605
|
+
if (metadata) {
|
|
14606
|
+
this._validateMetadata(metadata);
|
|
14607
|
+
}
|
|
14608
|
+
|
|
14345
14609
|
this.config.metadata = metadata;
|
|
14346
14610
|
if (this.apiService) {
|
|
14347
14611
|
this.apiService.setMetadata(metadata);
|
|
14348
14612
|
}
|
|
14613
|
+
this.identified = false;
|
|
14349
14614
|
this.eventBus.emit('metadata:updated', { metadata });
|
|
14350
14615
|
}
|
|
14351
14616
|
|
|
@@ -14356,11 +14621,53 @@
|
|
|
14356
14621
|
);
|
|
14357
14622
|
}
|
|
14358
14623
|
|
|
14624
|
+
async identify(metadata = this.config.metadata) {
|
|
14625
|
+
if (!this.initialized) {
|
|
14626
|
+
throw new SDKError(
|
|
14627
|
+
'SDK must be initialized before identifying users. Call init() first.'
|
|
14628
|
+
);
|
|
14629
|
+
}
|
|
14630
|
+
|
|
14631
|
+
if (!metadata) {
|
|
14632
|
+
throw new SDKError(
|
|
14633
|
+
'Identify requires metadata. Provide at least user_id or email.'
|
|
14634
|
+
);
|
|
14635
|
+
}
|
|
14636
|
+
|
|
14637
|
+
this._validateMetadata(metadata);
|
|
14638
|
+
this.setMetadata(metadata);
|
|
14639
|
+
|
|
14640
|
+
try {
|
|
14641
|
+
const response = await this.apiService.identify(metadata);
|
|
14642
|
+
const configPatch = this._extractIdentifyConfig(response);
|
|
14643
|
+
if (Object.keys(configPatch).length > 0) {
|
|
14644
|
+
this.updateConfig(configPatch);
|
|
14645
|
+
}
|
|
14646
|
+
|
|
14647
|
+
this.identified = true;
|
|
14648
|
+
this._applyIdentityToWidgets(metadata);
|
|
14649
|
+
|
|
14650
|
+
const result = {
|
|
14651
|
+
identified: true,
|
|
14652
|
+
metadata: this.getMetadata(),
|
|
14653
|
+
response,
|
|
14654
|
+
};
|
|
14655
|
+
|
|
14656
|
+
this.eventBus.emit('sdk:identified', result);
|
|
14657
|
+
return result;
|
|
14658
|
+
} catch (error) {
|
|
14659
|
+
this.identified = false;
|
|
14660
|
+
this.eventBus.emit('sdk:error', { error, phase: 'identify' });
|
|
14661
|
+
throw new SDKError(`Failed to identify user: ${error.message}`, error);
|
|
14662
|
+
}
|
|
14663
|
+
}
|
|
14664
|
+
|
|
14359
14665
|
async reinitialize(newMetadata = null) {
|
|
14360
14666
|
this.apiService.clearSession();
|
|
14361
14667
|
this.initialized = false;
|
|
14668
|
+
this.identified = false;
|
|
14362
14669
|
|
|
14363
|
-
if (newMetadata) {
|
|
14670
|
+
if (newMetadata !== null) {
|
|
14364
14671
|
this.setMetadata(newMetadata);
|
|
14365
14672
|
}
|
|
14366
14673
|
|
|
@@ -14389,10 +14696,11 @@
|
|
|
14389
14696
|
|
|
14390
14697
|
destroy() {
|
|
14391
14698
|
this.destroyAllWidgets();
|
|
14392
|
-
this.eventBus.
|
|
14699
|
+
this.eventBus.emit('sdk:destroyed');
|
|
14700
|
+
this.eventBus.clear();
|
|
14393
14701
|
this.apiService.clearSession();
|
|
14394
14702
|
this.initialized = false;
|
|
14395
|
-
this.
|
|
14703
|
+
this.identified = false;
|
|
14396
14704
|
}
|
|
14397
14705
|
|
|
14398
14706
|
hasFeedbackBeenSubmitted(cooldownDays = 30) {
|
|
@@ -14511,7 +14819,12 @@
|
|
|
14511
14819
|
|
|
14512
14820
|
_bindMethods() {
|
|
14513
14821
|
this.createWidget = this.createWidget.bind(this);
|
|
14822
|
+
this.createFeedbackWidget = this.createFeedbackWidget.bind(this);
|
|
14823
|
+
this.createMessengerWidget = this.createMessengerWidget.bind(this);
|
|
14824
|
+
this.createChangelogWidget = this.createChangelogWidget.bind(this);
|
|
14825
|
+
this.createSurveyWidget = this.createSurveyWidget.bind(this);
|
|
14514
14826
|
this.destroyWidget = this.destroyWidget.bind(this);
|
|
14827
|
+
this.identify = this.identify.bind(this);
|
|
14515
14828
|
this.updateConfig = this.updateConfig.bind(this);
|
|
14516
14829
|
}
|
|
14517
14830
|
|
|
@@ -14547,6 +14860,49 @@
|
|
|
14547
14860
|
: undefined,
|
|
14548
14861
|
};
|
|
14549
14862
|
}
|
|
14863
|
+
|
|
14864
|
+
async _syncConfiguredMetadataAfterInit() {
|
|
14865
|
+
if (
|
|
14866
|
+
!this.config.metadata ||
|
|
14867
|
+
this.apiService.identitySyncedToken === this.apiService.sessionToken
|
|
14868
|
+
) {
|
|
14869
|
+
return null;
|
|
14870
|
+
}
|
|
14871
|
+
|
|
14872
|
+
try {
|
|
14873
|
+
return await this.identify(this.config.metadata);
|
|
14874
|
+
} catch (error) {
|
|
14875
|
+
if (this.config.debug) {
|
|
14876
|
+
console.warn('[Product7] Initial identify failed:', error);
|
|
14877
|
+
}
|
|
14878
|
+
return null;
|
|
14879
|
+
}
|
|
14880
|
+
}
|
|
14881
|
+
|
|
14882
|
+
_extractIdentifyConfig(response) {
|
|
14883
|
+
const payload = this._isPlainObject(response?.data)
|
|
14884
|
+
? response.data
|
|
14885
|
+
: response || {};
|
|
14886
|
+
const configPatch = this._isPlainObject(payload.config)
|
|
14887
|
+
? payload.config
|
|
14888
|
+
: {};
|
|
14889
|
+
|
|
14890
|
+
if (payload.last_feedback_at !== undefined) {
|
|
14891
|
+
configPatch.last_feedback_at = payload.last_feedback_at;
|
|
14892
|
+
} else if (payload.lastFeedbackAt !== undefined) {
|
|
14893
|
+
configPatch.last_feedback_at = payload.lastFeedbackAt;
|
|
14894
|
+
}
|
|
14895
|
+
|
|
14896
|
+
return this._omitUndefined(configPatch);
|
|
14897
|
+
}
|
|
14898
|
+
|
|
14899
|
+
_applyIdentityToWidgets(metadata) {
|
|
14900
|
+
for (const widget of this.widgets.values()) {
|
|
14901
|
+
if (typeof widget.applyIdentity === 'function') {
|
|
14902
|
+
widget.applyIdentity(metadata);
|
|
14903
|
+
}
|
|
14904
|
+
}
|
|
14905
|
+
}
|
|
14550
14906
|
};
|
|
14551
14907
|
|
|
14552
14908
|
// --- Identify: transform flat user data into internal format ---
|
|
@@ -14629,9 +14985,21 @@
|
|
|
14629
14985
|
return obj;
|
|
14630
14986
|
}
|
|
14631
14987
|
|
|
14988
|
+
function hasIdentifyMetadata(metadata = {}) {
|
|
14989
|
+
return Object.values(metadata).some((value) => value !== undefined);
|
|
14990
|
+
}
|
|
14991
|
+
|
|
14632
14992
|
// --- Ensure SDK is initialized (shared by widget inits) ---
|
|
14633
14993
|
|
|
14634
14994
|
async function ensureSDK(options) {
|
|
14995
|
+
if (
|
|
14996
|
+
Product7._sdk &&
|
|
14997
|
+
options.organization &&
|
|
14998
|
+
Product7._sdk.config.workspace !== options.organization
|
|
14999
|
+
) {
|
|
15000
|
+
Product7.destroy();
|
|
15001
|
+
}
|
|
15002
|
+
|
|
14635
15003
|
if (Product7._sdk) return Product7._sdk;
|
|
14636
15004
|
|
|
14637
15005
|
if (options.organization) {
|
|
@@ -14674,63 +15042,58 @@
|
|
|
14674
15042
|
async identify(data = {}, callback) {
|
|
14675
15043
|
try {
|
|
14676
15044
|
const transformed = transformIdentifyData(data);
|
|
14677
|
-
Product7._organization =
|
|
15045
|
+
Product7._organization =
|
|
15046
|
+
transformed.workspace || Product7._organization || null;
|
|
14678
15047
|
|
|
14679
15048
|
const config = cleanUndefined({
|
|
14680
|
-
workspace:
|
|
14681
|
-
metadata: transformed.metadata,
|
|
15049
|
+
workspace: Product7._organization,
|
|
14682
15050
|
debug: transformed.debug,
|
|
14683
15051
|
mock: transformed.mock,
|
|
14684
15052
|
env: transformed.env,
|
|
14685
15053
|
apiUrl: transformed.apiUrl,
|
|
14686
15054
|
});
|
|
14687
15055
|
|
|
14688
|
-
|
|
14689
|
-
const
|
|
14690
|
-
|
|
14691
|
-
Product7._sdk = sdk;
|
|
14692
|
-
Product7._identified = true;
|
|
15056
|
+
let sdk = Product7._sdk;
|
|
15057
|
+
const requiresNewSDK =
|
|
15058
|
+
!sdk || (config.workspace && sdk.config.workspace !== config.workspace);
|
|
14693
15059
|
|
|
14694
|
-
|
|
14695
|
-
|
|
14696
|
-
|
|
14697
|
-
|
|
14698
|
-
user_id: transformed.metadata.user_id,
|
|
14699
|
-
email: transformed.metadata.email,
|
|
14700
|
-
name: transformed.metadata.name,
|
|
14701
|
-
avatar: transformed.metadata.profile_picture,
|
|
14702
|
-
attributes: transformed.metadata.custom_fields || {},
|
|
14703
|
-
};
|
|
14704
|
-
if (transformed.metadata.company) {
|
|
14705
|
-
identifyPayload.company = transformed.metadata.company;
|
|
14706
|
-
}
|
|
14707
|
-
await sdk.apiService._makeRequest('/widget/identify', {
|
|
14708
|
-
method: 'POST',
|
|
14709
|
-
body: JSON.stringify(identifyPayload),
|
|
14710
|
-
headers: {
|
|
14711
|
-
'Content-Type': 'application/json',
|
|
14712
|
-
Authorization: `Bearer ${sdk.apiService.sessionToken}`,
|
|
14713
|
-
},
|
|
14714
|
-
});
|
|
14715
|
-
} catch (identifyErr) {
|
|
14716
|
-
if (config.debug) {
|
|
14717
|
-
console.warn('[Product7] Attribute sync failed:', identifyErr);
|
|
14718
|
-
}
|
|
15060
|
+
if (requiresNewSDK) {
|
|
15061
|
+
if (Product7._sdk) {
|
|
15062
|
+
Product7.destroy();
|
|
15063
|
+
Product7._organization = config.workspace || null;
|
|
14719
15064
|
}
|
|
15065
|
+
sdk = new Product7$1(config);
|
|
15066
|
+
Product7._sdk = sdk;
|
|
14720
15067
|
}
|
|
14721
15068
|
|
|
15069
|
+
const initData = sdk.initialized
|
|
15070
|
+
? {
|
|
15071
|
+
alreadyInitialized: true,
|
|
15072
|
+
sessionToken: sdk.apiService?.sessionToken,
|
|
15073
|
+
}
|
|
15074
|
+
: await sdk.init();
|
|
15075
|
+
|
|
15076
|
+
const identifyData = hasIdentifyMetadata(transformed.metadata)
|
|
15077
|
+
? await sdk.identify(transformed.metadata)
|
|
15078
|
+
: null;
|
|
15079
|
+
Product7._identified = Boolean(identifyData?.identified);
|
|
15080
|
+
|
|
14722
15081
|
Product7._flushQueue();
|
|
14723
15082
|
|
|
14724
15083
|
if (typeof window !== 'undefined' && typeof CustomEvent !== 'undefined') {
|
|
14725
15084
|
window.dispatchEvent(
|
|
14726
15085
|
new CustomEvent('Product7Ready', {
|
|
14727
|
-
detail: { sdk, config, initData },
|
|
15086
|
+
detail: { sdk, config: sdk.config, initData, identifyData },
|
|
14728
15087
|
})
|
|
14729
15088
|
);
|
|
14730
15089
|
}
|
|
14731
15090
|
|
|
14732
15091
|
if (typeof callback === 'function') callback(null);
|
|
14733
|
-
return
|
|
15092
|
+
return {
|
|
15093
|
+
...initData,
|
|
15094
|
+
identified: Product7._identified,
|
|
15095
|
+
identify: identifyData,
|
|
15096
|
+
};
|
|
14734
15097
|
} catch (error) {
|
|
14735
15098
|
console.error('[Product7] Identify failed:', error);
|
|
14736
15099
|
|
|
@@ -14789,7 +15152,7 @@
|
|
|
14789
15152
|
if (!options.placement) {
|
|
14790
15153
|
widgetOptions.autoShow = false;
|
|
14791
15154
|
widgetOptions.displayMode = 'modal';
|
|
14792
|
-
widgetOptions.
|
|
15155
|
+
widgetOptions.headless = true;
|
|
14793
15156
|
} else {
|
|
14794
15157
|
// Trigger button is always visible when placement is set
|
|
14795
15158
|
widgetOptions.suppressAfterSubmission = false;
|
|
@@ -14797,7 +15160,7 @@
|
|
|
14797
15160
|
}
|
|
14798
15161
|
|
|
14799
15162
|
try {
|
|
14800
|
-
const widget = sdk.
|
|
15163
|
+
const widget = sdk.createFeedbackWidget(widgetOptions);
|
|
14801
15164
|
widget.mount();
|
|
14802
15165
|
|
|
14803
15166
|
if (options.placement) {
|
|
@@ -14836,13 +15199,13 @@
|
|
|
14836
15199
|
if (options.setBoard) {
|
|
14837
15200
|
Product7._feedbackWidget.options.boardName = options.setBoard;
|
|
14838
15201
|
}
|
|
14839
|
-
Product7._feedbackWidget.
|
|
15202
|
+
Product7._feedbackWidget.open();
|
|
14840
15203
|
}
|
|
14841
15204
|
},
|
|
14842
15205
|
|
|
14843
15206
|
closeFeedback() {
|
|
14844
15207
|
if (Product7._feedbackWidget) {
|
|
14845
|
-
Product7._feedbackWidget.
|
|
15208
|
+
Product7._feedbackWidget.close();
|
|
14846
15209
|
}
|
|
14847
15210
|
},
|
|
14848
15211
|
|
|
@@ -14901,7 +15264,7 @@
|
|
|
14901
15264
|
widgetOptions.enabled = true;
|
|
14902
15265
|
|
|
14903
15266
|
try {
|
|
14904
|
-
const widget = sdk.
|
|
15267
|
+
const widget = sdk.createMessengerWidget(widgetOptions);
|
|
14905
15268
|
widget.mount();
|
|
14906
15269
|
widget.show();
|
|
14907
15270
|
|