@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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@product7/feedback-sdk",
3
- "version": "1.3.4",
3
+ "version": "1.3.5",
4
4
  "description": "JavaScript SDK for integrating Product7 feedback widgets into any website",
5
5
  "main": "dist/feedback-sdk.js",
6
6
  "module": "src/index.js",
@@ -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
- await this.api._ensureSession();
222
+ await this.api._ensureSession();
200
223
 
201
- if (this.api.mock) {
202
- return { status: true, data: { identified: true } };
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
- return this.api._makeRequest('/widget/messenger/identify', {
206
- method: 'POST',
207
- headers: {
208
- 'Content-Type': 'application/json',
209
- Authorization: `Bearer ${this.api.sessionToken}`,
210
- },
211
- body: JSON.stringify({
212
- name: data.name,
213
- email: data.email,
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
- const userContext = this.messengerState.userContext;
138
- const isAuthenticated = userContext?.email && userContext?.name;
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
- async _handleIdentifyContact(contactData) {
210
- try {
211
- const response = await this.apiService.identifyContact({
212
- name: contactData.name,
213
- email: contactData.email,
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
- const pendingMessage = this.messengerState.pendingMessage;
226
- if (pendingMessage) {
227
- this.messengerState.pendingMessage = null;
204
+ if (response.status) {
205
+ console.log('[MessengerWidget] Contact identified:', response.data.contact_id);
228
206
 
229
- await this.startNewConversation(
230
- pendingMessage.content,
231
- '',
232
- pendingMessage.attachments
233
- );
234
- } else {
235
- this.messengerState.setView('chat');
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
- constructor(options = {}) {
6
- this.currentView = 'home'; // 'home', 'messages', 'chat', 'help', 'changelog'
7
- this.isOpen = false;
8
- this.unreadCount = 0;
9
- this.activeConversationId = null;
10
-
11
- // Conversations
12
- this.conversations = [];
13
- this.messages = {}; // { conversationId: [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
- // Feature flags
32
- this.enableHelp = options.enableHelp !== false;
33
- this.enableChangelog = options.enableChangelog !== false;
34
-
35
- // Agent availability
36
- this.agentsOnline = false;
37
- this.onlineCount = 0;
38
- this.responseTime = 'Usually replies within a few minutes';
39
-
40
- // Typing indicators
41
- this.typingUsers = {}; // { conversationId: { userName, timestamp } }
42
-
43
- // Loading states
44
- this.isLoading = false;
45
- this.isLoadingMessages = false;
46
-
47
- // Listeners
48
- this._listeners = new Set();
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
  */