@product7/feedback-sdk 1.3.4 → 1.3.6
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 +164 -109
- 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 +40 -48
- 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,43 +194,47 @@ 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
|
+
if (!this.messengerState.userContext) {
|
|
208
|
+
this.messengerState.userContext = {};
|
|
209
|
+
}
|
|
210
|
+
this.messengerState.userContext.name = contactData.name;
|
|
211
|
+
this.messengerState.userContext.email = contactData.email;
|
|
212
|
+
this.messengerState.isIdentified = true;
|
|
213
|
+
|
|
214
|
+
const pendingMessage = this.messengerState.pendingMessage;
|
|
215
|
+
if (pendingMessage) {
|
|
216
|
+
this.messengerState.pendingMessage = null;
|
|
217
|
+
|
|
218
|
+
// SET VIEW FIRST
|
|
219
|
+
this.messengerState.setView('chat');
|
|
220
|
+
|
|
221
|
+
// THEN start conversation
|
|
222
|
+
await this.startNewConversation(
|
|
223
|
+
pendingMessage.content,
|
|
224
|
+
'',
|
|
225
|
+
pendingMessage.attachments
|
|
226
|
+
);
|
|
227
|
+
} else {
|
|
228
|
+
this.messengerState.setView('chat');
|
|
237
229
|
}
|
|
238
|
-
|
|
239
|
-
return response;
|
|
240
|
-
} catch (error) {
|
|
241
|
-
console.error('[MessengerWidget] Failed to identify contact:', error);
|
|
242
|
-
throw error;
|
|
243
230
|
}
|
|
244
|
-
}
|
|
245
231
|
|
|
232
|
+
return response;
|
|
233
|
+
} catch (error) {
|
|
234
|
+
console.error('[MessengerWidget] Failed to identify contact:', error);
|
|
235
|
+
throw error;
|
|
236
|
+
}
|
|
237
|
+
}
|
|
246
238
|
async _handleUploadFile(base64Data, filename) {
|
|
247
239
|
try {
|
|
248
240
|
const response = await this.apiService.uploadFile(base64Data, filename);
|
|
@@ -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
|
*/
|