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