@wabbit-dashboard/embed 1.0.12 → 1.0.14
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/wabbit-embed.cjs.js +189 -53
- package/dist/wabbit-embed.cjs.js.map +1 -1
- package/dist/wabbit-embed.d.ts +2 -1
- package/dist/wabbit-embed.esm.js +189 -53
- package/dist/wabbit-embed.esm.js.map +1 -1
- package/dist/wabbit-embed.umd.js +189 -53
- package/dist/wabbit-embed.umd.js.map +1 -1
- package/dist/wabbit-embed.umd.min.js +1 -1
- package/dist/wabbit-embed.umd.min.js.map +1 -1
- package/package.json +1 -1
package/dist/wabbit-embed.cjs.js
CHANGED
|
@@ -160,16 +160,71 @@ class Wabbit {
|
|
|
160
160
|
validateConfig(config);
|
|
161
161
|
const mergedConfig = mergeConfig(config);
|
|
162
162
|
Wabbit.instance = new Wabbit(mergedConfig);
|
|
163
|
+
// Store email capture widget reference for use in callbacks
|
|
164
|
+
// This allows chat widget to trigger email capture without tight coupling
|
|
165
|
+
let emailCaptureWidgetRef = null;
|
|
166
|
+
// Track if email capture is enabled (determined by server config)
|
|
167
|
+
let emailCaptureEnabled = false;
|
|
163
168
|
// Initialize widgets based on merged config
|
|
164
169
|
if (mergedConfig.chat?.enabled && mergedConfig.chat) {
|
|
170
|
+
const chat = mergedConfig.chat;
|
|
171
|
+
const apiUrl = chat.apiUrl || mergedConfig.apiUrl || 'https://platform.insourcedata.ai';
|
|
172
|
+
const collectionId = chat.collectionId;
|
|
173
|
+
// Fetch email capture config from server (in parallel with chat widget import)
|
|
174
|
+
const emailCaptureConfigPromise = fetch(`${apiUrl}/api/email-capture/config/${collectionId}`)
|
|
175
|
+
.then(res => res.json())
|
|
176
|
+
.then(data => {
|
|
177
|
+
if (data.success && data.config?.enabled) {
|
|
178
|
+
return data.config;
|
|
179
|
+
}
|
|
180
|
+
return null;
|
|
181
|
+
})
|
|
182
|
+
.catch(err => {
|
|
183
|
+
console.warn('[Wabbit] Failed to fetch email capture config:', err);
|
|
184
|
+
return null;
|
|
185
|
+
});
|
|
165
186
|
// Import ChatWidget dynamically to avoid circular dependencies
|
|
166
|
-
Promise.resolve().then(function () { return ChatWidget$1; }).then(({ ChatWidget }) => {
|
|
187
|
+
Promise.resolve().then(function () { return ChatWidget$1; }).then(async ({ ChatWidget }) => {
|
|
167
188
|
// Check if instance was destroyed during async import (e.g., React StrictMode)
|
|
168
189
|
if (!Wabbit.instance) {
|
|
169
190
|
console.warn('[Wabbit] Instance was destroyed before chat widget could initialize');
|
|
170
191
|
return;
|
|
171
192
|
}
|
|
172
|
-
|
|
193
|
+
// Wait for email capture config to be fetched
|
|
194
|
+
const serverEmailConfig = await emailCaptureConfigPromise;
|
|
195
|
+
emailCaptureEnabled = !!serverEmailConfig;
|
|
196
|
+
// Initialize email capture widget if server config says it's enabled
|
|
197
|
+
if (serverEmailConfig) {
|
|
198
|
+
const { EmailCaptureWidget } = await Promise.resolve().then(function () { return EmailCaptureWidget$1; });
|
|
199
|
+
if (!Wabbit.instance) {
|
|
200
|
+
console.warn('[Wabbit] Instance was destroyed before email capture widget could initialize');
|
|
201
|
+
return;
|
|
202
|
+
}
|
|
203
|
+
// Convert server config format to widget config format
|
|
204
|
+
const triggerAfterMessages = serverEmailConfig.trigger?.type === 'message_count'
|
|
205
|
+
? serverEmailConfig.trigger.messageCount
|
|
206
|
+
: 3;
|
|
207
|
+
// Build fields array from server config
|
|
208
|
+
const fields = ['email'];
|
|
209
|
+
if (serverEmailConfig.fields?.name?.enabled)
|
|
210
|
+
fields.push('name');
|
|
211
|
+
if (serverEmailConfig.fields?.company?.enabled)
|
|
212
|
+
fields.push('company');
|
|
213
|
+
const emailCaptureConfig = {
|
|
214
|
+
enabled: true,
|
|
215
|
+
triggerAfterMessages,
|
|
216
|
+
title: serverEmailConfig.modal?.title,
|
|
217
|
+
description: serverEmailConfig.modal?.description,
|
|
218
|
+
fields,
|
|
219
|
+
onCapture: mergedConfig.emailCapture?.onCapture
|
|
220
|
+
};
|
|
221
|
+
const emailCaptureWidget = new EmailCaptureWidget(emailCaptureConfig);
|
|
222
|
+
emailCaptureWidget.init();
|
|
223
|
+
Wabbit.instance.emailCaptureWidget = emailCaptureWidget;
|
|
224
|
+
emailCaptureWidgetRef = emailCaptureWidget;
|
|
225
|
+
console.log('[Wabbit] Email capture initialized from server config');
|
|
226
|
+
}
|
|
227
|
+
const userOnChatReady = chat.onChatReady || config.onChatReady;
|
|
173
228
|
const chatConfig = {
|
|
174
229
|
enabled: chat.enabled,
|
|
175
230
|
collectionId: chat.collectionId,
|
|
@@ -192,8 +247,28 @@ class Wabbit {
|
|
|
192
247
|
// Header customization
|
|
193
248
|
showHeader: chat.showHeader,
|
|
194
249
|
headerTitle: chat.headerTitle,
|
|
195
|
-
// Callbacks
|
|
196
|
-
onChatReady:
|
|
250
|
+
// Callbacks
|
|
251
|
+
onChatReady: () => {
|
|
252
|
+
// Set WebSocket client on email capture widget when chat is ready
|
|
253
|
+
if (emailCaptureWidgetRef && Wabbit.instance?.chatWidget) {
|
|
254
|
+
const chatWidget = Wabbit.instance.chatWidget;
|
|
255
|
+
if (chatWidget.wsClient) {
|
|
256
|
+
emailCaptureWidgetRef.setWebSocketClient(chatWidget.wsClient);
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
// Call user's callback
|
|
260
|
+
if (userOnChatReady) {
|
|
261
|
+
userOnChatReady();
|
|
262
|
+
}
|
|
263
|
+
},
|
|
264
|
+
// Trigger email capture when user sends a message (if enabled by server)
|
|
265
|
+
onUserMessage: emailCaptureEnabled
|
|
266
|
+
? () => {
|
|
267
|
+
if (emailCaptureWidgetRef) {
|
|
268
|
+
emailCaptureWidgetRef.handleMessage();
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
: undefined
|
|
197
272
|
};
|
|
198
273
|
const chatWidget = new ChatWidget(chatConfig);
|
|
199
274
|
chatWidget.init();
|
|
@@ -227,49 +302,8 @@ class Wabbit {
|
|
|
227
302
|
Wabbit.instance.formsWidget = formWidget;
|
|
228
303
|
});
|
|
229
304
|
}
|
|
230
|
-
//
|
|
231
|
-
//
|
|
232
|
-
if (mergedConfig.emailCapture?.enabled) {
|
|
233
|
-
const emailCapture = mergedConfig.emailCapture;
|
|
234
|
-
Promise.resolve().then(function () { return EmailCaptureWidget$1; }).then(({ EmailCaptureWidget }) => {
|
|
235
|
-
// Check if instance was destroyed during async import
|
|
236
|
-
if (!Wabbit.instance) {
|
|
237
|
-
console.warn('[Wabbit] Instance was destroyed before email capture widget could initialize');
|
|
238
|
-
return;
|
|
239
|
-
}
|
|
240
|
-
const emailCaptureConfig = {
|
|
241
|
-
enabled: emailCapture.enabled,
|
|
242
|
-
triggerAfterMessages: emailCapture.triggerAfterMessages,
|
|
243
|
-
title: emailCapture.title,
|
|
244
|
-
description: emailCapture.description,
|
|
245
|
-
fields: emailCapture.fields,
|
|
246
|
-
onCapture: emailCapture.onCapture
|
|
247
|
-
};
|
|
248
|
-
const emailCaptureWidget = new EmailCaptureWidget(emailCaptureConfig);
|
|
249
|
-
emailCaptureWidget.init();
|
|
250
|
-
Wabbit.instance.emailCaptureWidget = emailCaptureWidget;
|
|
251
|
-
// Connect to chat widget after it's initialized
|
|
252
|
-
// Use a small delay to ensure chat widget is ready
|
|
253
|
-
setTimeout(() => {
|
|
254
|
-
if (Wabbit.instance?.chatWidget) {
|
|
255
|
-
const chatWidget = Wabbit.instance.chatWidget;
|
|
256
|
-
// Set WebSocket client
|
|
257
|
-
if (chatWidget.wsClient) {
|
|
258
|
-
emailCaptureWidget.setWebSocketClient(chatWidget.wsClient);
|
|
259
|
-
}
|
|
260
|
-
// Hook into message sending by intercepting ChatWidget's handleSendMessage
|
|
261
|
-
const originalHandleSendMessage = chatWidget.handleSendMessage;
|
|
262
|
-
if (originalHandleSendMessage) {
|
|
263
|
-
chatWidget.handleSendMessage = function (content) {
|
|
264
|
-
originalHandleSendMessage.call(this, content);
|
|
265
|
-
// Notify email capture widget when user sends a message
|
|
266
|
-
emailCaptureWidget.handleMessage();
|
|
267
|
-
};
|
|
268
|
-
}
|
|
269
|
-
}
|
|
270
|
-
}, 100);
|
|
271
|
-
});
|
|
272
|
-
}
|
|
305
|
+
// Note: Email capture is now automatically initialized from server config
|
|
306
|
+
// when chat widget is enabled. The config is fetched from /api/email-capture/config/{collectionId}
|
|
273
307
|
// Auto-initialize forms with data-wabbit-form-id (backward compatibility)
|
|
274
308
|
if (Wabbit.instance) {
|
|
275
309
|
Wabbit.instance.initLegacyForms(config);
|
|
@@ -1965,6 +1999,10 @@ class ChatWidget {
|
|
|
1965
1999
|
}
|
|
1966
2000
|
// Send via WebSocket
|
|
1967
2001
|
this.wsClient.sendMessage(content);
|
|
2002
|
+
// Notify external listeners (for email capture, analytics, etc.)
|
|
2003
|
+
if (this.config.onUserMessage) {
|
|
2004
|
+
this.config.onUserMessage(content);
|
|
2005
|
+
}
|
|
1968
2006
|
}
|
|
1969
2007
|
/**
|
|
1970
2008
|
* Open the chat panel (no-op in inline mode)
|
|
@@ -2559,7 +2597,7 @@ class FormStyles {
|
|
|
2559
2597
|
class ApiClient {
|
|
2560
2598
|
constructor(options) {
|
|
2561
2599
|
this.baseUrl = options.baseUrl.replace(/\/$/, '');
|
|
2562
|
-
this.apiKey = options.apiKey;
|
|
2600
|
+
this.apiKey = options.apiKey || '';
|
|
2563
2601
|
this.timeout = options.timeout || 30000;
|
|
2564
2602
|
}
|
|
2565
2603
|
/**
|
|
@@ -2691,15 +2729,12 @@ class FormWidget {
|
|
|
2691
2729
|
this.themeCleanup = null;
|
|
2692
2730
|
this.formObserver = null;
|
|
2693
2731
|
this.config = config;
|
|
2694
|
-
// Validate apiKey (required for API client)
|
|
2695
|
-
if (!config.apiKey) {
|
|
2696
|
-
throw new Error('FormWidget requires apiKey. Provide it in FormConfig or WabbitConfig.');
|
|
2697
|
-
}
|
|
2698
2732
|
// Initialize API client
|
|
2733
|
+
// Note: apiKey is optional for forms since form endpoints are public
|
|
2699
2734
|
const apiUrl = config.apiUrl || this.getApiUrlFromScript();
|
|
2700
2735
|
this.apiClient = new ApiClient({
|
|
2701
2736
|
baseUrl: apiUrl,
|
|
2702
|
-
apiKey: config.apiKey,
|
|
2737
|
+
apiKey: config.apiKey, // Optional - forms don't require auth
|
|
2703
2738
|
});
|
|
2704
2739
|
// Initialize styles and renderer
|
|
2705
2740
|
// Pass containerId to FormStyles to generate unique style ID
|
|
@@ -3850,6 +3885,107 @@ const WabbitSDK = {
|
|
|
3850
3885
|
getChatPageUrl,
|
|
3851
3886
|
openChatPage
|
|
3852
3887
|
};
|
|
3888
|
+
/**
|
|
3889
|
+
* Auto-initialization for forms with data-wabbit-form-id attribute
|
|
3890
|
+
*
|
|
3891
|
+
* This provides backward compatibility with the legacy embed-form.js script.
|
|
3892
|
+
* Forms will auto-initialize without requiring Wabbit.init() to be called.
|
|
3893
|
+
*/
|
|
3894
|
+
function autoInitForms() {
|
|
3895
|
+
// Skip if Wabbit.init() was already called
|
|
3896
|
+
if (Wabbit.getInstance()) {
|
|
3897
|
+
return;
|
|
3898
|
+
}
|
|
3899
|
+
// Find all containers with data-wabbit-form-id
|
|
3900
|
+
const containers = document.querySelectorAll('[data-wabbit-form-id]');
|
|
3901
|
+
if (containers.length === 0) {
|
|
3902
|
+
return;
|
|
3903
|
+
}
|
|
3904
|
+
console.log('[Wabbit] Auto-initializing', containers.length, 'form(s)');
|
|
3905
|
+
// Get API URL from script src
|
|
3906
|
+
const getApiUrl = () => {
|
|
3907
|
+
const scriptTag = document.currentScript ||
|
|
3908
|
+
document.querySelector('script[src*="wabbit"]') ||
|
|
3909
|
+
document.querySelector('script[src*="embed"]');
|
|
3910
|
+
if (scriptTag && scriptTag instanceof HTMLScriptElement && scriptTag.src) {
|
|
3911
|
+
try {
|
|
3912
|
+
return new URL(scriptTag.src).origin;
|
|
3913
|
+
}
|
|
3914
|
+
catch {
|
|
3915
|
+
// Invalid URL
|
|
3916
|
+
}
|
|
3917
|
+
}
|
|
3918
|
+
return 'https://platform.insourcedata.ai';
|
|
3919
|
+
};
|
|
3920
|
+
const apiUrl = getApiUrl();
|
|
3921
|
+
// Import and initialize each form
|
|
3922
|
+
containers.forEach((container) => {
|
|
3923
|
+
const formId = container.getAttribute('data-wabbit-form-id');
|
|
3924
|
+
if (!formId)
|
|
3925
|
+
return;
|
|
3926
|
+
// Skip if already initialized
|
|
3927
|
+
if (container.__wabbitFormWidget) {
|
|
3928
|
+
return;
|
|
3929
|
+
}
|
|
3930
|
+
// Dynamically import FormWidget to avoid issues
|
|
3931
|
+
Promise.resolve().then(function () { return FormWidget$1; }).then(({ FormWidget }) => {
|
|
3932
|
+
try {
|
|
3933
|
+
const formWidget = new FormWidget({
|
|
3934
|
+
enabled: true,
|
|
3935
|
+
formId: formId,
|
|
3936
|
+
apiUrl: apiUrl,
|
|
3937
|
+
theme: 'auto',
|
|
3938
|
+
});
|
|
3939
|
+
// Override findContainer to use the specific container element
|
|
3940
|
+
formWidget.findContainer = () => container;
|
|
3941
|
+
formWidget.init();
|
|
3942
|
+
container.__wabbitFormWidget = formWidget;
|
|
3943
|
+
console.log('[Wabbit] Form auto-initialized:', formId);
|
|
3944
|
+
}
|
|
3945
|
+
catch (error) {
|
|
3946
|
+
console.error('[Wabbit] Failed to auto-initialize form:', formId, error);
|
|
3947
|
+
}
|
|
3948
|
+
});
|
|
3949
|
+
});
|
|
3950
|
+
}
|
|
3951
|
+
// Run auto-init when DOM is ready
|
|
3952
|
+
if (typeof document !== 'undefined') {
|
|
3953
|
+
if (document.readyState === 'loading') {
|
|
3954
|
+
document.addEventListener('DOMContentLoaded', autoInitForms);
|
|
3955
|
+
}
|
|
3956
|
+
else {
|
|
3957
|
+
// DOM already loaded, run immediately
|
|
3958
|
+
autoInitForms();
|
|
3959
|
+
}
|
|
3960
|
+
// Also watch for dynamically added forms (for SPAs)
|
|
3961
|
+
const formObserver = new MutationObserver((mutations) => {
|
|
3962
|
+
for (const mutation of mutations) {
|
|
3963
|
+
if (mutation.addedNodes.length) {
|
|
3964
|
+
const hasFormContainer = Array.from(mutation.addedNodes).some((node) => {
|
|
3965
|
+
if (node.nodeType !== 1)
|
|
3966
|
+
return false;
|
|
3967
|
+
const element = node;
|
|
3968
|
+
return (element.hasAttribute?.('data-wabbit-form-id') ||
|
|
3969
|
+
element.querySelector?.('[data-wabbit-form-id]'));
|
|
3970
|
+
});
|
|
3971
|
+
if (hasFormContainer) {
|
|
3972
|
+
console.log('[Wabbit] Detected dynamically added form container');
|
|
3973
|
+
autoInitForms();
|
|
3974
|
+
break;
|
|
3975
|
+
}
|
|
3976
|
+
}
|
|
3977
|
+
}
|
|
3978
|
+
});
|
|
3979
|
+
// Start observing once DOM is ready
|
|
3980
|
+
if (document.readyState === 'loading') {
|
|
3981
|
+
document.addEventListener('DOMContentLoaded', () => {
|
|
3982
|
+
formObserver.observe(document.body, { childList: true, subtree: true });
|
|
3983
|
+
});
|
|
3984
|
+
}
|
|
3985
|
+
else {
|
|
3986
|
+
formObserver.observe(document.body, { childList: true, subtree: true });
|
|
3987
|
+
}
|
|
3988
|
+
}
|
|
3853
3989
|
|
|
3854
3990
|
exports.ApiClient = ApiClient;
|
|
3855
3991
|
exports.ChatBubble = ChatBubble;
|