@robylon/react-native-sdk 2.0.25-staging.9 → 2.0.26

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.
Files changed (58) hide show
  1. package/README.md +10 -10
  2. package/lib/commonjs/Chatbotsdk.js +2 -2
  3. package/lib/commonjs/Chatbotsdk.js.map +1 -1
  4. package/lib/commonjs/config.js +1 -1
  5. package/lib/commonjs/config.js.map +1 -1
  6. package/lib/commonjs/constants.js +1 -1
  7. package/lib/commonjs/constants.js.map +1 -1
  8. package/lib/commonjs/versions/version.staging.js +1 -1
  9. package/lib/commonjs/versions/version.staging.js.map +1 -1
  10. package/lib/module/Chatbotsdk.js +2 -2
  11. package/lib/module/Chatbotsdk.js.map +1 -1
  12. package/lib/module/config.js +1 -1
  13. package/lib/module/config.js.map +1 -1
  14. package/lib/module/constants.js +1 -1
  15. package/lib/module/constants.js.map +1 -1
  16. package/lib/module/versions/version.staging.js +1 -1
  17. package/lib/module/versions/version.staging.js.map +1 -1
  18. package/lib/typescript/Chatbotsdk.d.ts +2 -1
  19. package/lib/typescript/Chatbotsdk.d.ts.map +1 -1
  20. package/lib/typescript/versions/version.staging.d.ts +1 -1
  21. package/lib/typescript/versions/version.staging.d.ts.map +1 -1
  22. package/package.json +1 -1
  23. package/src/Chatbotsdk.tsx +0 -870
  24. package/src/FloatingButton/launchers/ImageLauncher.tsx +0 -75
  25. package/src/FloatingButton/launchers/TextLauncher.tsx +0 -84
  26. package/src/FloatingButton/launchers/TextualImageLauncher.tsx +0 -133
  27. package/src/FloatingButton.tsx +0 -97
  28. package/src/LoadingIndicator.tsx +0 -11
  29. package/src/Toast.tsx +0 -65
  30. package/src/components/DebugButton.tsx +0 -46
  31. package/src/components/ErrorBoundary.tsx +0 -38
  32. package/src/config.ts +0 -4
  33. package/src/constants/errorConstants.ts +0 -21
  34. package/src/constants/fontStyles.ts +0 -3
  35. package/src/constants.ts +0 -5
  36. package/src/global.d.ts +0 -11
  37. package/src/hooks/useChatbotEvents.ts +0 -93
  38. package/src/index.tsx +0 -10
  39. package/src/openChatbot.ts +0 -11
  40. package/src/openChatbot.tsx +0 -0
  41. package/src/services/ErrorTrackingService.ts +0 -217
  42. package/src/types/events.ts +0 -25
  43. package/src/types/react-native-flipper-performance-plugin.d.ts +0 -3
  44. package/src/types/react-native-globals.d.ts +0 -10
  45. package/src/utils/animations.ts +0 -120
  46. package/src/utils/colorUtils.ts +0 -35
  47. package/src/utils/cookieUtils.ts +0 -7
  48. package/src/utils/debugConfig.ts +0 -56
  49. package/src/utils/debugMenu.ts +0 -14
  50. package/src/utils/errorHandler.ts +0 -58
  51. package/src/utils/fileDownload.ts +0 -70
  52. package/src/utils/logger.ts +0 -14
  53. package/src/utils/systemInfo.ts +0 -84
  54. package/src/utils/webViewStorage.ts +0 -62
  55. package/src/version.ts +0 -2
  56. package/src/versions/version.dev.ts +0 -2
  57. package/src/versions/version.production.ts +0 -2
  58. package/src/versions/version.staging.ts +0 -2
@@ -1,870 +0,0 @@
1
- import React, {
2
- useState,
3
- useEffect,
4
- useRef,
5
- useMemo,
6
- useCallback,
7
- useImperativeHandle,
8
- forwardRef,
9
- } from "react";
10
- import {
11
- View,
12
- StyleSheet,
13
- Animated,
14
- Dimensions,
15
- Platform,
16
- StatusBar,
17
- PixelRatio,
18
- FlexAlignType,
19
- } from "react-native";
20
- import { WebView, WebViewMessageEvent } from "react-native-webview";
21
- import FloatingButton from "./FloatingButton";
22
- import { API_URL, BASE_CHATBOT_URL, DEFAULT_LAUNCHER_IMAGE } from "./constants";
23
- import { getSystemInfo, getBrowserAndOSInfoScript } from "./utils/systemInfo";
24
- import { useChatbotEvents } from "./hooks/useChatbotEvents";
25
- import { ChatbotEventType, ChatbotEventHandler } from "./types/events";
26
- import { logger } from "./utils/logger";
27
- import { enableNetworkDebug, enableWebViewDebug } from "./utils/debugConfig";
28
- import DebugButton from "./components/DebugButton";
29
- import { ErrorBoundary } from "./components/ErrorBoundary";
30
- import {
31
- ErrorCodes,
32
- ErrorTypes,
33
- ErrorMessages,
34
- } from "./constants/errorConstants";
35
- import { setupGlobalErrorHandlers } from "./utils/errorHandler";
36
- import { errorTracker } from "./services/ErrorTrackingService";
37
- import { generateUUID } from "./utils/cookieUtils";
38
- import {
39
- StorageMessageType,
40
- StorageMessage,
41
- getStorageScript,
42
- createStorageMessage,
43
- } from "./utils/webViewStorage";
44
- import { animateWebViewOpen, animateWebViewClose } from "./utils/animations";
45
- import { handleDownloadRequest, DownloadRequest } from "./utils/fileDownload";
46
-
47
- export interface ChatbotProps {
48
- api_key: string;
49
- user_id?: string | null | number;
50
- user_token?: string;
51
- user_profile?: {
52
- email?: string;
53
- name?: string;
54
- mobile?: string;
55
- is_test_user?: boolean;
56
- };
57
- onEvent?: ChatbotEventHandler;
58
- onOpen?: () => void;
59
- onClose?: () => void;
60
- onReady?: () => void;
61
- }
62
-
63
- export interface ChatbotRef {
64
- open: () => void;
65
- close: () => void;
66
- toggle: () => void;
67
- isReady: () => boolean;
68
- }
69
-
70
- interface InternalChatbotProps extends ChatbotProps {
71
- show_floating_button?: boolean;
72
- onMessage?: (message: any) => void;
73
- isFullScreen?: boolean;
74
- enableAnimation?: boolean;
75
- }
76
-
77
- interface ChatbotMessage {
78
- type: string;
79
- data?: any;
80
- level?: string;
81
- url?: string;
82
- filename?: string;
83
- }
84
-
85
- export enum ChatbotInterfaceType {
86
- WIDGET = "WIDGET",
87
- POPOVER = "POPOVER",
88
- EMBED = "EMBED",
89
- }
90
-
91
- export enum WidgetPositionEnums {
92
- RIGHT = "Right",
93
- LEFT = "Left",
94
- }
95
-
96
- export interface WidgetInterfaceProperties {
97
- position: WidgetPositionEnums;
98
- side_spacing?: number;
99
- bottom_spacing?: number;
100
- }
101
-
102
- export enum LauncherType {
103
- TEXT = "TEXT",
104
- IMAGE = "IMAGE",
105
- TEXTUAL_IMAGE = "TEXTUAL_IMAGE",
106
- }
107
-
108
- export interface ChatbotConfig {
109
- brand_colour: string;
110
- image_url?: string;
111
- chat_interface_config?: {
112
- chat_bubble_prompts?: string[];
113
- display_name?: string;
114
- welcome_message?: string;
115
- redirect_url?: string;
116
- };
117
- interface_type?: ChatbotInterfaceType;
118
- interface_properties?: WidgetInterfaceProperties;
119
- launcher_type: LauncherType;
120
- launcher_properties: {
121
- text?: string;
122
- };
123
- images: {
124
- launcher_image_url?: {
125
- url: string;
126
- };
127
- };
128
- chat_iframe_url: string;
129
- }
130
-
131
- const Chatbot = forwardRef<ChatbotRef, InternalChatbotProps>(
132
- (
133
- {
134
- api_key,
135
- user_id,
136
- user_token,
137
- show_floating_button = true,
138
- onEvent,
139
- onMessage,
140
- isFullScreen = true,
141
- enableAnimation = true,
142
- onOpen: externalOnOpen,
143
- onClose: externalOnClose,
144
- onReady,
145
- user_profile,
146
- },
147
- ref
148
- ) => {
149
- const [isWebViewVisible, setIsWebViewVisible] = useState(false);
150
- const [chatbotConfig, setChatbotConfig] = useState<ChatbotConfig | null>(
151
- null
152
- );
153
- const [loading, setLoading] = useState(true);
154
- const [isInitialized, setIsInitialized] = useState(false);
155
- const webViewRef = useRef<WebView>(null);
156
- const isFirstLoadRef = useRef(true);
157
- const [toastVisible, setToastVisible] = useState(false);
158
- const [toastMessage, setToastMessage] = useState("");
159
- const [effectiveUserId, setEffectiveUserId] = useState<string>();
160
- const [isStorageReady, setIsStorageReady] = useState(false);
161
- const pendingStorageOps = useRef<Array<() => void>>([]);
162
- const memoryCache = useRef<Record<string, string>>({});
163
- const [systemInfo, setSystemInfo] = useState({ os: "", browser: "" });
164
- console.log("Webview rerendered===============>");
165
-
166
- // Initialize animated values
167
- const animatedValues = useRef({
168
- scale: new Animated.Value(1),
169
- translateY: new Animated.Value(0),
170
- opacity: new Animated.Value(1),
171
- }).current;
172
-
173
- // Create chatbotConfig object for events
174
- const chatbotConfigForEvents = useMemo(
175
- () => ({
176
- userId: effectiveUserId,
177
- isAnonymous: !user_id && user_id !== 0,
178
- // Add other config properties as needed
179
- }),
180
- [effectiveUserId, user_id]
181
- );
182
-
183
- // Initialize event handling
184
- const { emitEvent, onInternalEvent } = useChatbotEvents({
185
- api_key,
186
- chatbotConfig: chatbotConfigForEvents ?? {},
187
- user_profile: user_profile,
188
- onEvent: onEvent,
189
- systemInfo: systemInfo ?? { os: "", browser: "" },
190
- });
191
-
192
- // Expose ref methods
193
- useImperativeHandle(
194
- ref,
195
- () => ({
196
- open: () => {
197
- if (isInitialized) {
198
- openWebView();
199
- }
200
- },
201
- close: () => {
202
- if (isInitialized) {
203
- closeWebView();
204
- }
205
- },
206
- toggle: () => {
207
- if (isInitialized) {
208
- if (isWebViewVisible) {
209
- closeWebView();
210
- } else {
211
- openWebView();
212
- }
213
- }
214
- },
215
- isReady: () => isInitialized,
216
- }),
217
- [isInitialized, isWebViewVisible]
218
- );
219
-
220
- const triggerAppInit = () => {
221
- if (webViewRef.current) {
222
- webViewRef.current.injectJavaScript(`
223
- // Trigger APP_READY equivalent
224
- window.ReactNativeWebView.postMessage(JSON.stringify({ type: 'APP_READY' }));
225
- true;
226
- `);
227
- }
228
- };
229
-
230
- const executeStorageOp = useCallback(
231
- (operation: () => void) => {
232
- if (isStorageReady) {
233
- operation();
234
- } else {
235
- pendingStorageOps.current.push(operation);
236
- }
237
- },
238
- [isStorageReady]
239
- );
240
-
241
- // Handle WebView messages
242
- const handleMessage = useCallback(
243
- (event: WebViewMessageEvent) => {
244
- const { data } = event.nativeEvent;
245
-
246
- try {
247
- const parsedData: ChatbotMessage = JSON.parse(data);
248
-
249
- // Handle storage messages
250
- if (
251
- Object.values(StorageMessageType).includes(
252
- parsedData.type as StorageMessageType
253
- )
254
- ) {
255
- const storageMessage = parsedData as StorageMessage;
256
- switch (storageMessage.type) {
257
- case StorageMessageType.STORAGE_READY:
258
- setIsStorageReady(true);
259
- pendingStorageOps.current.forEach((op) => op());
260
- pendingStorageOps.current = [];
261
- // Try to get stored ID immediately after storage is ready
262
- webViewRef.current?.injectJavaScript(
263
- createStorageMessage(
264
- StorageMessageType.GET_STORAGE,
265
- "rblyn_anon"
266
- )
267
- );
268
- break;
269
- case StorageMessageType.STORAGE_RESPONSE:
270
- if (storageMessage.key && storageMessage.value) {
271
- memoryCache.current[storageMessage.key] =
272
- storageMessage.value;
273
- if (storageMessage.key === "rblyn_anon") {
274
- setEffectiveUserId(storageMessage.value);
275
- }
276
- }
277
- break;
278
- case StorageMessageType.STORAGE_ERROR:
279
- logger.error("WebView storage error:", storageMessage.error);
280
- break;
281
- }
282
- return;
283
- }
284
-
285
- // Add debug logging
286
- if (__DEV__) {
287
- if (parsedData?.type === "CONSOLE") {
288
- console.log(`WebView ${parsedData?.level}:`, parsedData?.data);
289
- return;
290
- }
291
- if (parsedData?.type === "ERROR") {
292
- console.error("WebView Error:", parsedData?.data);
293
- return;
294
- }
295
- }
296
-
297
- if (parsedData?.type === "SYSTEM_INFO") {
298
- setSystemInfo(parsedData?.data ?? { os: "", browser: "" });
299
- return;
300
- }
301
-
302
- if (parsedData?.type === "APP_READY") {
303
- emitEvent(ChatbotEventType.CHATBOT_APP_READY);
304
- if (webViewRef.current && isWebViewVisible) {
305
- webViewRef.current?.injectJavaScript(getBrowserAndOSInfoScript());
306
-
307
- const messageData = {
308
- name: "registerUserId",
309
- action: "registerUserId",
310
- data: {
311
- userId: effectiveUserId,
312
- token: user_token ? `${user_token}` : undefined,
313
- userProfile: {
314
- ...user_profile,
315
- ...getSystemInfo(systemInfo),
316
- },
317
- },
318
- };
319
- logger.debug("messageData====>", JSON.stringify(messageData));
320
- webViewRef.current?.injectJavaScript(`
321
- window.postMessage(${JSON.stringify({
322
- name: "openFrame",
323
- domain: "app-domain.com",
324
- })}, '*');
325
- window.postMessage(${JSON.stringify(messageData)}, '*');
326
- `);
327
- }
328
- }
329
-
330
- // Handle other message types
331
- switch (parsedData?.type) {
332
- case "close_chatbot":
333
- closeWebView();
334
- break;
335
- case "download_file":
336
- if (
337
- parsedData?.data ||
338
- (parsedData?.url && parsedData?.filename)
339
- ) {
340
- // Handle both formats: { data: { url, filename } } or { url, filename }
341
- const downloadData: DownloadRequest = parsedData?.data || {
342
- url: parsedData?.url,
343
- filename: parsedData?.filename,
344
- };
345
- handleDownloadRequest(downloadData);
346
- }
347
- break;
348
- case "CHATBOT_LOADED":
349
- emitEvent(ChatbotEventType.CHATBOT_LOADED, parsedData?.data);
350
- break;
351
- case "CHAT_INITIALIZED":
352
- emitEvent(ChatbotEventType.CHAT_INITIALIZED, parsedData?.data);
353
- break;
354
- case "SESSION_REFRESHED":
355
- emitEvent(ChatbotEventType.SESSION_REFRESHED, parsedData?.data);
356
- break;
357
- case "CHAT_INITIALIZATION_FAILED":
358
- emitEvent(
359
- ChatbotEventType.CHAT_INITIALIZATION_FAILED,
360
- parsedData?.data
361
- );
362
- break;
363
- default:
364
- if (onMessage) onMessage(parsedData ?? {});
365
- }
366
- } catch (error) {
367
- errorTracker.trackError(
368
- error instanceof Error
369
- ? error
370
- : new Error("Failed to parse WebView message"),
371
- "ChatbotSDK",
372
- {
373
- type: ErrorTypes.RUNTIME_ERROR,
374
- context: { messageData: data },
375
- }
376
- );
377
- }
378
- },
379
- [
380
- emitEvent,
381
- isWebViewVisible,
382
- onMessage,
383
- systemInfo,
384
- effectiveUserId,
385
- user_token,
386
- user_profile,
387
- ]
388
- );
389
-
390
- // Initialize user ID
391
- useEffect(() => {
392
- const initializeUserId = async () => {
393
- let userId = user_id ? String(user_id) : undefined;
394
-
395
- if (!userId) {
396
- // Try memory cache first
397
- userId = memoryCache.current["rblyn_anon"];
398
-
399
- if (!userId) {
400
- userId = generateUUID();
401
- executeStorageOp(() => {
402
- webViewRef.current?.injectJavaScript(
403
- createStorageMessage(
404
- StorageMessageType.SET_STORAGE,
405
- "rblyn_anon",
406
- userId!
407
- )
408
- );
409
- });
410
- }
411
- }
412
-
413
- setEffectiveUserId(userId);
414
- };
415
-
416
- initializeUserId();
417
- }, [user_id, executeStorageOp]);
418
-
419
- // Removed controlled isOpen syncing to avoid desync issues. Using ref API instead.
420
-
421
- // Initialize WebView storage
422
- useEffect(() => {
423
- if (webViewRef.current) {
424
- webViewRef.current.injectJavaScript(getStorageScript());
425
- // Try to get stored ID once storage is ready
426
- executeStorageOp(() => {
427
- webViewRef.current?.injectJavaScript(
428
- createStorageMessage(StorageMessageType.GET_STORAGE, "rblyn_anon")
429
- );
430
- });
431
- }
432
- }, []);
433
-
434
- useEffect(() => {
435
- const fetchChatbotConfig = async () => {
436
- try {
437
- const endpointUrl = `${API_URL}/chat/chatbot/get/`;
438
- const payload = {
439
- client_user_id: effectiveUserId,
440
- org_id: api_key,
441
- token: user_token,
442
- extra_info: {},
443
- };
444
-
445
- // setToastMessage(endpointUrl + " : " + BASE_CHATBOT_URL);
446
- // setToastVisible(true);
447
-
448
- const response = await fetch(endpointUrl, {
449
- method: "POST",
450
- headers: {
451
- "Content-Type": "application/json",
452
- },
453
- body: JSON.stringify(payload),
454
- });
455
-
456
- if (!response.ok) {
457
- throw new Error("Failed to fetch chatbot configuration");
458
- }
459
-
460
- const data = await response.json();
461
- const orgInfo = data?.user?.org_info;
462
-
463
- if (orgInfo) {
464
- const config: ChatbotConfig = {
465
- brand_colour: orgInfo.brand_config?.colors?.brand_color || "",
466
- image_url: orgInfo.brand_config?.launcher_logo_url || "",
467
- chat_interface_config: {
468
- chat_bubble_prompts: [],
469
- display_name: orgInfo.brand_config?.display_name || "",
470
- welcome_message:
471
- orgInfo.brand_config?.welcome_message ||
472
- "Hey! What can we help you with today?",
473
- redirect_url: orgInfo.brand_config?.redirect_url || "",
474
- },
475
- interface_properties: {
476
- position:
477
- orgInfo.brand_config?.interface_properties?.position ||
478
- WidgetPositionEnums.RIGHT,
479
- side_spacing:
480
- orgInfo.brand_config?.interface_properties?.side_spacing ??
481
- 20,
482
- bottom_spacing:
483
- orgInfo.brand_config?.interface_properties?.bottom_spacing ??
484
- 20,
485
- },
486
- interface_type:
487
- orgInfo.brand_config?.interface_type ||
488
- ChatbotInterfaceType.WIDGET,
489
- launcher_type:
490
- orgInfo.brand_config?.launcher_type || LauncherType.IMAGE,
491
- launcher_properties: {
492
- text: orgInfo.brand_config?.launcher_properties?.text || "",
493
- },
494
- images: {
495
- launcher_image_url: {
496
- url:
497
- orgInfo.brand_config?.images?.launcher_image_url?.url ||
498
- DEFAULT_LAUNCHER_IMAGE,
499
- },
500
- },
501
- chat_iframe_url: orgInfo.brand_config?.chat_iframe_url || "",
502
- };
503
- setChatbotConfig(config);
504
- }
505
- } catch (error) {
506
- errorTracker.trackError(
507
- error instanceof Error
508
- ? error
509
- : new Error("Failed to fetch chatbot configuration"),
510
- "ChatbotSDK",
511
- {
512
- type: ErrorTypes.NETWORK_ERROR,
513
- context: { api_key, user_id },
514
- }
515
- );
516
- } finally {
517
- setLoading(false);
518
- }
519
- };
520
-
521
- if (api_key && effectiveUserId) {
522
- fetchChatbotConfig();
523
- }
524
- }, [api_key, effectiveUserId, user_token]);
525
-
526
- function constructUrl(): string {
527
- if (!effectiveUserId) return "";
528
- const params = new URLSearchParams({
529
- id: api_key,
530
- });
531
- const iFrameUrlFromBackend = chatbotConfig?.chat_iframe_url;
532
- // if (iFrameUrlFromBackend) {
533
- // return `${iFrameUrlFromBackend}`;
534
- // }
535
- return `${BASE_CHATBOT_URL}?${params.toString()}`;
536
- }
537
-
538
- // Handle opening the chatbot
539
- const openWebView = useCallback(() => {
540
- setIsWebViewVisible(true);
541
- if (enableAnimation) {
542
- animateWebViewOpen(animatedValues, () => {
543
- externalOnOpen?.();
544
- emitEvent(ChatbotEventType.CHATBOT_OPENED);
545
- if (!isFirstLoadRef.current) {
546
- setTimeout(triggerAppInit, 100);
547
- }
548
- });
549
- } else {
550
- requestAnimationFrame(() => {
551
- externalOnOpen?.();
552
- emitEvent(ChatbotEventType.CHATBOT_OPENED);
553
- if (!isFirstLoadRef.current) {
554
- setTimeout(triggerAppInit, 100);
555
- }
556
- });
557
- }
558
- }, [enableAnimation, animatedValues, externalOnOpen, emitEvent]);
559
-
560
- // Handle closing the chatbot
561
- const closeWebView = useCallback(() => {
562
- if (webViewRef.current) {
563
- webViewRef.current.postMessage(
564
- JSON.stringify({
565
- name: "closeFrame",
566
- domain: "app-domain.com",
567
- })
568
- );
569
- }
570
-
571
- if (enableAnimation) {
572
- animateWebViewClose(animatedValues, () => {
573
- setIsWebViewVisible(false);
574
- externalOnClose?.();
575
- emitEvent(ChatbotEventType.CHATBOT_CLOSED);
576
- });
577
- } else {
578
- setIsWebViewVisible(false);
579
- externalOnClose?.();
580
- emitEvent(ChatbotEventType.CHATBOT_CLOSED);
581
- }
582
- }, [enableAnimation, animatedValues, externalOnClose, emitEvent]);
583
-
584
- // Emit button loaded event when component mounts
585
- useEffect(() => {
586
- if (show_floating_button && chatbotConfig) {
587
- emitEvent(ChatbotEventType.CHATBOT_BUTTON_LOADED);
588
- }
589
- }, [show_floating_button, chatbotConfig, emitEvent]);
590
-
591
- // Set initialization state when chatbot is ready
592
- useEffect(() => {
593
- if (!loading && chatbotConfig && effectiveUserId && !isInitialized) {
594
- setIsInitialized(true);
595
- onReady?.();
596
- }
597
- }, [loading, chatbotConfig, effectiveUserId, isInitialized, onReady]);
598
-
599
- const getScreenDimensions = () => {
600
- const windowHeight = Dimensions.get("window").height;
601
- const windowWidth = Dimensions.get("window").width;
602
- const statusBarHeight =
603
- Platform.OS === "ios" ? 0 : StatusBar.currentHeight || 0;
604
-
605
- return {
606
- height: windowHeight - statusBarHeight,
607
- width: windowWidth,
608
- };
609
- };
610
-
611
- const screenDimensions = getScreenDimensions();
612
-
613
- useEffect(() => {
614
- if (__DEV__) {
615
- enableNetworkDebug();
616
- }
617
- }, []);
618
-
619
- // Deliberate error for testing error boundary
620
- // useEffect(() => {
621
- // if (__DEV__) {
622
- // // Set up global error handlers
623
- // setupGlobalErrorHandlers();
624
-
625
- // // Test async error
626
- // setTimeout(() => {
627
- // Promise.reject(new Error("Test async error"));
628
- // }, 1000);
629
-
630
- // // Test sync error
631
- // setTimeout(() => {
632
- // throw new Error("Test sync error");
633
- // }, 2000);
634
- // }
635
- // }, []);
636
-
637
- const position = chatbotConfig?.interface_properties?.position || "Right";
638
- const sideSpacing = chatbotConfig?.interface_properties?.side_spacing ?? 20;
639
- const bottomSpacing =
640
- chatbotConfig?.interface_properties?.bottom_spacing ?? 20;
641
-
642
- // const mainContainerStyle = useMemo(() => {
643
- // return {
644
- // ...styles.mainContainer,
645
- // [position.toLowerCase()]: `${sideSpacing ?? 20}px`,
646
- // alignItems:
647
- // position === "Right" ? "flex-end" : ("flex-start" as FlexAlignType),
648
- // // Explicitly clear mobile-specific styles
649
- // top: undefined,
650
- // [position === "Right" ? "left" : "right"]: undefined,
651
- // backgroundColor: "green",
652
- // };
653
- // }, [position, sideSpacing, styles.mainContainer]);
654
-
655
- return (
656
- <ErrorBoundary componentName="ChatbotSDK">
657
- <View style={styles?.mainContainer}>
658
- {!loading && (
659
- <>
660
- <ErrorBoundary componentName="FloatingButton">
661
- {show_floating_button && api_key && chatbotConfig && (
662
- <FloatingButton
663
- chatbotConfig={chatbotConfig}
664
- isWebViewVisible={isWebViewVisible}
665
- onPress={() => {
666
- emitEvent(ChatbotEventType.CHATBOT_BUTTON_CLICKED);
667
- openWebView();
668
- }}
669
- brandColor={chatbotConfig.brand_colour}
670
- imageUrl={chatbotConfig.image_url}
671
- />
672
- )}
673
- </ErrorBoundary>
674
- <View
675
- style={[
676
- styles.webViewWrapper,
677
- { height: isWebViewVisible ? "100%" : 0 },
678
- ]}
679
- pointerEvents={isWebViewVisible ? "auto" : "none"}
680
- >
681
- <Animated.View
682
- style={[
683
- styles.fullScreenContainer,
684
- {
685
- opacity: animatedValues.opacity,
686
- transform: [
687
- { scale: animatedValues.scale },
688
- { translateY: animatedValues.translateY },
689
- ],
690
- },
691
- ]}
692
- >
693
- <ErrorBoundary componentName="ChatbotWebView">
694
- <WebView
695
- webviewDebuggingEnabled={true}
696
- ref={webViewRef}
697
- source={{
698
- uri: constructUrl(),
699
- }}
700
- onMessage={handleMessage}
701
- style={styles.webview}
702
- containerStyle={
703
- isFullScreen
704
- ? {
705
- width: screenDimensions.width,
706
- height: screenDimensions.height - 40,
707
- }
708
- : undefined
709
- }
710
- allowsInlineMediaPlayback={true}
711
- mediaPlaybackRequiresUserAction={false}
712
- allowFileAccess={false}
713
- geolocationEnabled={false}
714
- javaScriptEnabled={true}
715
- domStorageEnabled={true}
716
- cacheEnabled={true}
717
- scrollEnabled={true}
718
- bounces={false}
719
- onShouldStartLoadWithRequest={(request) => {
720
- return (
721
- request.url.startsWith(BASE_CHATBOT_URL) ||
722
- request.url.startsWith(
723
- chatbotConfig?.chat_iframe_url || ""
724
- )
725
- );
726
- }}
727
- startInLoadingState={isFirstLoadRef.current}
728
- onLoadEnd={() => {
729
- if (__DEV__) {
730
- enableWebViewDebug(webViewRef);
731
- }
732
- webViewRef.current?.injectJavaScript(`
733
- if (!document.querySelector('meta[name="viewport"]')) {
734
- var meta = document.createElement('meta');
735
- meta.name = 'viewport';
736
- meta.content = 'width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no';
737
- document.getElementsByTagName('head')[0].appendChild(meta);
738
- }
739
-
740
- if (!document.querySelector('#injectedStyle')) {
741
- const style = document.createElement('style');
742
- style.id = 'injectedStyle';
743
- style.textContent = \`
744
- html, body, #root, #__next {
745
- height: 100% !important;
746
- min-height: 100% !important;
747
- overflow: hidden !important;
748
- }
749
- \`;
750
- document.head.appendChild(style);
751
- }
752
-
753
- window.sendToChatbot = function(message) {
754
- window.ReactNativeWebView.postMessage(JSON.stringify(message));
755
- };
756
-
757
- // Only create observer if it doesn't exist
758
- if (!window.closeButtonObserver) {
759
- // Setup mutation observer to watch for close button
760
- window.closeButtonObserver = new MutationObserver(function(mutations) {
761
- const closeButton = document.querySelector('.chatbot-close-button');
762
- if (closeButton && !closeButton.hasAttribute('listener-attached')) {
763
- closeButton.setAttribute('listener-attached', 'true');
764
- closeButton.addEventListener('click', () => {
765
- try {
766
- const message = { type: 'close_chatbot' };
767
- window.ReactNativeWebView.postMessage(JSON.stringify(message));
768
- } catch (error) {
769
- console.error('Error sending close message:', error);
770
- }
771
- });
772
- console.log('Close button listener attached');
773
- }
774
- });
775
-
776
- // Start observing
777
- window.closeButtonObserver.observe(document.body, {
778
- childList: true,
779
- subtree: true
780
- });
781
-
782
- // Initial check for existing button
783
- const existingButton = document.querySelector('.chatbot-close-button');
784
- if (existingButton && !existingButton.hasAttribute('listener-attached')) {
785
- existingButton.setAttribute('listener-attached', 'true');
786
- existingButton.addEventListener('click', () => {
787
- try {
788
- const message = { type: 'close_chatbot' };
789
- window.ReactNativeWebView.postMessage(JSON.stringify(message));
790
- } catch (error) {
791
- console.error('Error sending close message:', error);
792
- }
793
- });
794
- console.log('Close button listener attached to existing button');
795
- }
796
- }
797
-
798
- true;
799
- `);
800
- isFirstLoadRef.current = false;
801
- }}
802
- onError={(syntheticEvent) => {
803
- const { nativeEvent } = syntheticEvent;
804
- errorTracker.trackError(
805
- new Error(nativeEvent.description),
806
- "ChatbotWebView",
807
- {
808
- type: ErrorTypes.RUNTIME_ERROR,
809
- context: {
810
- url: nativeEvent.url,
811
- code: nativeEvent.code,
812
- },
813
- }
814
- );
815
- }}
816
- />
817
- </ErrorBoundary>
818
- </Animated.View>
819
- </View>
820
- </>
821
- )}
822
- {/* <Toast message={toastMessage} visible={toastVisible} duration={10000} /> */}
823
- {__DEV__ && <DebugButton />}
824
- </View>
825
- </ErrorBoundary>
826
- );
827
- }
828
- );
829
-
830
- Chatbot.displayName = "Chatbot";
831
-
832
- const styles = StyleSheet.create({
833
- mainContainer: {
834
- flex: 1,
835
- position: "relative",
836
- overflow: "visible",
837
- },
838
- webViewWrapper: {
839
- position: "absolute",
840
- top: 0,
841
- left: 0,
842
- right: 0,
843
- bottom: 0,
844
- overflow: "visible",
845
- zIndex: 10000,
846
- backgroundColor: "#ffffff",
847
- },
848
- fullScreenContainer: {
849
- position: "absolute",
850
- top: 0,
851
- left: 0,
852
- right: 0,
853
- bottom: 0,
854
- backgroundColor: "white",
855
- zIndex: 10000,
856
- overflow: "visible",
857
- // height: Platform.OS === "android" ? "100%" : "100%",
858
- },
859
- inlineContainer: {
860
- flex: 1,
861
- backgroundColor: "white",
862
- },
863
- webview: {
864
- flex: 1,
865
- backgroundColor: "white",
866
- zIndex: 10000,
867
- },
868
- });
869
-
870
- export default Chatbot;