@product7/feedback-sdk 1.3.4 → 1.3.5
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 +161 -108
- 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/services/MessengerService.js +71 -15
- package/src/core/BaseAPIService.js +4 -0
- package/src/widgets/MessengerWidget.js +37 -47
- package/src/widgets/messenger/MessengerState.js +49 -46
package/package.json
CHANGED
|
@@ -195,23 +195,79 @@ export class MessengerService {
|
|
|
195
195
|
);
|
|
196
196
|
}
|
|
197
197
|
|
|
198
|
+
async getMessages(conversationId, options = {}) {
|
|
199
|
+
await this.api._ensureSession();
|
|
200
|
+
|
|
201
|
+
if (this.api.mock) {
|
|
202
|
+
await delay(200);
|
|
203
|
+
return {
|
|
204
|
+
status: true,
|
|
205
|
+
data: MOCK_MESSAGES[conversationId] || [],
|
|
206
|
+
meta: { total: 0, page: 1, limit: 50 },
|
|
207
|
+
};
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
const params = { ...options };
|
|
211
|
+
const endpoint = this.api._getEndpointWithParams(
|
|
212
|
+
`/widget/messenger/conversations/${conversationId}/messages`,
|
|
213
|
+
params
|
|
214
|
+
);
|
|
215
|
+
return this.api._makeRequest(endpoint, {
|
|
216
|
+
method: 'GET',
|
|
217
|
+
headers: { Authorization: `Bearer ${this.api.sessionToken}` },
|
|
218
|
+
});
|
|
219
|
+
}
|
|
220
|
+
|
|
198
221
|
async identifyContact(data) {
|
|
199
|
-
|
|
222
|
+
await this.api._ensureSession();
|
|
200
223
|
|
|
201
|
-
|
|
202
|
-
|
|
224
|
+
if (this.api.mock) {
|
|
225
|
+
await delay(300);
|
|
226
|
+
return {
|
|
227
|
+
status: true,
|
|
228
|
+
data: {
|
|
229
|
+
contact_id: 'mock_contact_' + Date.now(),
|
|
230
|
+
email: data.email,
|
|
231
|
+
name: data.name || '',
|
|
232
|
+
is_new: true,
|
|
233
|
+
},
|
|
234
|
+
};
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
return this.api._makeRequest('/widget/messenger/identify', {
|
|
238
|
+
method: 'POST',
|
|
239
|
+
headers: {
|
|
240
|
+
'Content-Type': 'application/json',
|
|
241
|
+
Authorization: `Bearer ${this.api.sessionToken}`,
|
|
242
|
+
},
|
|
243
|
+
body: JSON.stringify({
|
|
244
|
+
email: data.email,
|
|
245
|
+
name: data.name || '',
|
|
246
|
+
phone: data.phone || '',
|
|
247
|
+
company: data.company || '',
|
|
248
|
+
avatar_url: data.avatar_url || '',
|
|
249
|
+
metadata: data.metadata || {},
|
|
250
|
+
}),
|
|
251
|
+
});
|
|
203
252
|
}
|
|
204
253
|
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
254
|
+
async sendTypingIndicator(conversationId, isTyping) {
|
|
255
|
+
await this.api._ensureSession();
|
|
256
|
+
|
|
257
|
+
if (this.api.mock) {
|
|
258
|
+
return { status: true };
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
return this.api._makeRequest(
|
|
262
|
+
`/widget/messenger/conversations/${conversationId}/typing`,
|
|
263
|
+
{
|
|
264
|
+
method: 'POST',
|
|
265
|
+
headers: {
|
|
266
|
+
'Content-Type': 'application/json',
|
|
267
|
+
Authorization: `Bearer ${this.api.sessionToken}`,
|
|
268
|
+
},
|
|
269
|
+
body: JSON.stringify({ is_typing: isTyping }),
|
|
270
|
+
}
|
|
271
|
+
);
|
|
272
|
+
}
|
|
217
273
|
}
|
|
@@ -25,6 +25,10 @@ export class BaseAPIService {
|
|
|
25
25
|
base: 'https://staging.api.product7.io/api/v1',
|
|
26
26
|
withWorkspace: (ws) => `https://${ws}.staging.api.product7.io/api/v1`,
|
|
27
27
|
},
|
|
28
|
+
localstack: {
|
|
29
|
+
base: 'http://localhost:1323/api/v1',
|
|
30
|
+
withWorkspace: (ws) => `http://${ws}.localhost:1323/api/v1`,
|
|
31
|
+
},
|
|
28
32
|
};
|
|
29
33
|
|
|
30
34
|
const envConfig = ENV_URLS[this.env] || ENV_URLS.production;
|
|
@@ -134,22 +134,9 @@ export class MessengerWidget extends BaseWidget {
|
|
|
134
134
|
|
|
135
135
|
async _handleStartConversation(messageContent, pendingAttachments) {
|
|
136
136
|
try {
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
if (isAuthenticated) {
|
|
141
|
-
try {
|
|
142
|
-
await this.apiService.identifyContact({
|
|
143
|
-
name: userContext.name,
|
|
144
|
-
email: userContext.email,
|
|
145
|
-
});
|
|
146
|
-
console.log('[MessengerWidget] User auto-identified for conversation');
|
|
147
|
-
} catch (error) {
|
|
148
|
-
if (error?.code !== 'ALREADY_IDENTIFIED') {
|
|
149
|
-
console.warn('[MessengerWidget] Auto-identification failed:', error);
|
|
150
|
-
}
|
|
151
|
-
}
|
|
152
|
-
} else {
|
|
137
|
+
// Check if already identified
|
|
138
|
+
if (!this.messengerState.isIdentified) {
|
|
139
|
+
// Not identified - show pre-chat form
|
|
153
140
|
this.messengerState.pendingMessage = {
|
|
154
141
|
content: messageContent,
|
|
155
142
|
attachments: pendingAttachments,
|
|
@@ -158,6 +145,7 @@ async _handleStartConversation(messageContent, pendingAttachments) {
|
|
|
158
145
|
return null;
|
|
159
146
|
}
|
|
160
147
|
|
|
148
|
+
// Already identified - proceed with conversation
|
|
161
149
|
const openConversation = this.messengerState.conversations.find(
|
|
162
150
|
(c) => c.status === 'open'
|
|
163
151
|
);
|
|
@@ -206,42 +194,44 @@ async _handleStartConversation(messageContent, pendingAttachments) {
|
|
|
206
194
|
}
|
|
207
195
|
}
|
|
208
196
|
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
if (response.status) {
|
|
217
|
-
console.log('[MessengerWidget] Contact identified:', contactData.email);
|
|
218
|
-
|
|
219
|
-
if (!this.messengerState.userContext) {
|
|
220
|
-
this.messengerState.userContext = {};
|
|
221
|
-
}
|
|
222
|
-
this.messengerState.userContext.name = contactData.name;
|
|
223
|
-
this.messengerState.userContext.email = contactData.email;
|
|
197
|
+
async _handleIdentifyContact(contactData) {
|
|
198
|
+
try {
|
|
199
|
+
const response = await this.apiService.identifyContact({
|
|
200
|
+
name: contactData.name,
|
|
201
|
+
email: contactData.email,
|
|
202
|
+
});
|
|
224
203
|
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
this.messengerState.pendingMessage = null;
|
|
204
|
+
if (response.status) {
|
|
205
|
+
console.log('[MessengerWidget] Contact identified:', response.data.contact_id);
|
|
228
206
|
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
207
|
+
// Update state
|
|
208
|
+
if (!this.messengerState.userContext) {
|
|
209
|
+
this.messengerState.userContext = {};
|
|
210
|
+
}
|
|
211
|
+
this.messengerState.userContext.name = contactData.name;
|
|
212
|
+
this.messengerState.userContext.email = contactData.email;
|
|
213
|
+
this.messengerState.isIdentified = true; // ADD THIS LINE
|
|
214
|
+
|
|
215
|
+
// Process pending message
|
|
216
|
+
const pendingMessage = this.messengerState.pendingMessage;
|
|
217
|
+
if (pendingMessage) {
|
|
218
|
+
this.messengerState.pendingMessage = null;
|
|
219
|
+
await this.startNewConversation(
|
|
220
|
+
pendingMessage.content,
|
|
221
|
+
'',
|
|
222
|
+
pendingMessage.attachments
|
|
223
|
+
);
|
|
224
|
+
} else {
|
|
225
|
+
this.messengerState.setView('chat');
|
|
237
226
|
}
|
|
238
|
-
|
|
239
|
-
return response;
|
|
240
|
-
} catch (error) {
|
|
241
|
-
console.error('[MessengerWidget] Failed to identify contact:', error);
|
|
242
|
-
throw error;
|
|
243
227
|
}
|
|
228
|
+
|
|
229
|
+
return response;
|
|
230
|
+
} catch (error) {
|
|
231
|
+
console.error('[MessengerWidget] Failed to identify contact:', error);
|
|
232
|
+
throw error;
|
|
244
233
|
}
|
|
234
|
+
}
|
|
245
235
|
|
|
246
236
|
async _handleUploadFile(base64Data, filename) {
|
|
247
237
|
try {
|
|
@@ -2,52 +2,55 @@
|
|
|
2
2
|
* MessengerState - State management for the Messenger widget
|
|
3
3
|
*/
|
|
4
4
|
export class MessengerState {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
5
|
+
constructor(options = {}) {
|
|
6
|
+
this.currentView = 'home';
|
|
7
|
+
this.isOpen = false;
|
|
8
|
+
this.unreadCount = 0;
|
|
9
|
+
this.activeConversationId = null;
|
|
10
|
+
|
|
11
|
+
// Conversations
|
|
12
|
+
this.conversations = [];
|
|
13
|
+
this.messages = {};
|
|
14
|
+
|
|
15
|
+
// Help articles
|
|
16
|
+
this.helpArticles = [];
|
|
17
|
+
this.helpSearchQuery = '';
|
|
18
|
+
|
|
19
|
+
// Changelog
|
|
20
|
+
this.homeChangelogItems = [];
|
|
21
|
+
this.changelogItems = [];
|
|
22
|
+
|
|
23
|
+
// Team info
|
|
24
|
+
this.teamName = options.teamName || 'Support';
|
|
25
|
+
this.teamAvatars = options.teamAvatars || [];
|
|
26
|
+
this.welcomeMessage = options.welcomeMessage || 'How can we help?';
|
|
27
|
+
|
|
28
|
+
// User info
|
|
29
|
+
this.userContext = options.userContext || null;
|
|
30
|
+
|
|
31
|
+
// ADD THESE TWO PROPERTIES
|
|
32
|
+
this.isIdentified = false; // Track if user has been identified
|
|
33
|
+
this.pendingMessage = null; // { content, attachments } - for pre-chat flow
|
|
34
|
+
|
|
35
|
+
// Feature flags
|
|
36
|
+
this.enableHelp = options.enableHelp !== false;
|
|
37
|
+
this.enableChangelog = options.enableChangelog !== false;
|
|
38
|
+
|
|
39
|
+
// Agent availability
|
|
40
|
+
this.agentsOnline = false;
|
|
41
|
+
this.onlineCount = 0;
|
|
42
|
+
this.responseTime = 'Usually replies within a few minutes';
|
|
43
|
+
|
|
44
|
+
// Typing indicators
|
|
45
|
+
this.typingUsers = {};
|
|
46
|
+
|
|
47
|
+
// Loading states
|
|
48
|
+
this.isLoading = false;
|
|
49
|
+
this.isLoadingMessages = false;
|
|
50
|
+
|
|
51
|
+
// Listeners
|
|
52
|
+
this._listeners = new Set();
|
|
53
|
+
}
|
|
51
54
|
/**
|
|
52
55
|
* Subscribe to state changes
|
|
53
56
|
*/
|