@robylon/react-native-sdk 2.0.16-staging.1 → 2.0.16-staging.3
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/.npmignore.development +18 -0
- package/babel.config.js +15 -15
- package/ios/Podfile +12 -0
- package/lib/commonjs/Chatbotsdk.js +1 -1
- package/lib/commonjs/Chatbotsdk.js.map +1 -1
- package/lib/commonjs/FloatingButton.js +1 -1
- package/lib/commonjs/FloatingButton.js.map +1 -1
- package/lib/commonjs/components/DebugButton.js +2 -0
- package/lib/commonjs/components/DebugButton.js.map +1 -0
- package/lib/commonjs/components/ErrorBoundary.js +2 -0
- package/lib/commonjs/components/ErrorBoundary.js.map +1 -0
- package/lib/commonjs/constants/errorConstants.js +2 -0
- package/lib/commonjs/constants/errorConstants.js.map +1 -0
- package/lib/commonjs/hooks/useChatbotEvents.js +2 -0
- package/lib/commonjs/hooks/useChatbotEvents.js.map +1 -0
- package/lib/commonjs/index.js +1 -1
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/services/ErrorTrackingService.js +2 -0
- package/lib/commonjs/services/ErrorTrackingService.js.map +1 -0
- package/lib/commonjs/types/events.js +2 -0
- package/lib/commonjs/types/events.js.map +1 -0
- package/lib/commonjs/types/react-native-flipper-performance-plugin.d.js +2 -0
- package/lib/commonjs/types/react-native-flipper-performance-plugin.d.js.map +1 -0
- package/lib/commonjs/types/react-native-globals.d.js +2 -0
- package/lib/commonjs/types/react-native-globals.d.js.map +1 -0
- package/lib/commonjs/utils/cookieUtils.js +2 -0
- package/lib/commonjs/utils/cookieUtils.js.map +1 -0
- package/lib/commonjs/utils/debugConfig.js +2 -0
- package/lib/commonjs/utils/debugConfig.js.map +1 -0
- package/lib/commonjs/utils/debugMenu.js +2 -0
- package/lib/commonjs/utils/debugMenu.js.map +1 -0
- package/lib/commonjs/utils/errorHandler.js +2 -0
- package/lib/commonjs/utils/errorHandler.js.map +1 -0
- package/lib/commonjs/utils/logger.js +2 -0
- package/lib/commonjs/utils/logger.js.map +1 -0
- package/lib/commonjs/utils/systemInfo.js +2 -0
- package/lib/commonjs/utils/systemInfo.js.map +1 -0
- package/lib/commonjs/utils/webViewStorage.js +2 -0
- package/lib/commonjs/utils/webViewStorage.js.map +1 -0
- package/lib/commonjs/version.js +2 -0
- package/lib/commonjs/version.js.map +1 -0
- package/lib/module/Chatbotsdk.js +1 -1
- package/lib/module/Chatbotsdk.js.map +1 -1
- package/lib/module/FloatingButton.js +1 -1
- package/lib/module/FloatingButton.js.map +1 -1
- package/lib/module/components/DebugButton.js +2 -0
- package/lib/module/components/DebugButton.js.map +1 -0
- package/lib/module/components/ErrorBoundary.js +2 -0
- package/lib/module/components/ErrorBoundary.js.map +1 -0
- package/lib/module/constants/errorConstants.js +2 -0
- package/lib/module/constants/errorConstants.js.map +1 -0
- package/lib/module/hooks/useChatbotEvents.js +2 -0
- package/lib/module/hooks/useChatbotEvents.js.map +1 -0
- package/lib/module/index.js +1 -1
- package/lib/module/index.js.map +1 -1
- package/lib/module/openChatbot.js +2 -1
- package/lib/module/services/ErrorTrackingService.js +2 -0
- package/lib/module/services/ErrorTrackingService.js.map +1 -0
- package/lib/module/types/events.js +2 -0
- package/lib/module/types/events.js.map +1 -0
- package/lib/module/types/react-native-flipper-performance-plugin.d.js +2 -0
- package/lib/module/types/react-native-flipper-performance-plugin.d.js.map +1 -0
- package/lib/module/types/react-native-globals.d.js +2 -0
- package/lib/module/types/react-native-globals.d.js.map +1 -0
- package/lib/module/utils/cookieUtils.js +2 -0
- package/lib/module/utils/cookieUtils.js.map +1 -0
- package/lib/module/utils/debugConfig.js +2 -0
- package/lib/module/utils/debugConfig.js.map +1 -0
- package/lib/module/utils/debugMenu.js +2 -0
- package/lib/module/utils/debugMenu.js.map +1 -0
- package/lib/module/utils/errorHandler.js +2 -0
- package/lib/module/utils/errorHandler.js.map +1 -0
- package/lib/module/utils/logger.js +2 -0
- package/lib/module/utils/logger.js.map +1 -0
- package/lib/module/utils/systemInfo.js +2 -0
- package/lib/module/utils/systemInfo.js.map +1 -0
- package/lib/module/utils/webViewStorage.js +2 -0
- package/lib/module/utils/webViewStorage.js.map +1 -0
- package/lib/module/version.js +2 -0
- package/lib/module/version.js.map +1 -0
- package/lib/typescript/Chatbotsdk.d.ts +9 -10
- package/lib/typescript/Chatbotsdk.d.ts.map +1 -1
- package/lib/typescript/FloatingButton.d.ts.map +1 -1
- package/lib/typescript/components/DebugButton.d.ts +4 -0
- package/lib/typescript/components/DebugButton.d.ts.map +1 -0
- package/lib/typescript/components/ErrorBoundary.d.ts +16 -0
- package/lib/typescript/components/ErrorBoundary.d.ts.map +1 -0
- package/lib/typescript/constants/errorConstants.d.ts +18 -0
- package/lib/typescript/constants/errorConstants.d.ts.map +1 -0
- package/lib/typescript/hooks/useChatbotEvents.d.ts +17 -0
- package/lib/typescript/hooks/useChatbotEvents.d.ts.map +1 -0
- package/lib/typescript/index.d.ts +5 -1
- package/lib/typescript/index.d.ts.map +1 -1
- package/lib/typescript/services/ErrorTrackingService.d.ts +34 -0
- package/lib/typescript/services/ErrorTrackingService.d.ts.map +1 -0
- package/lib/typescript/types/events.d.ts +22 -0
- package/lib/typescript/types/events.d.ts.map +1 -0
- package/lib/typescript/utils/cookieUtils.d.ts +2 -0
- package/lib/typescript/utils/cookieUtils.d.ts.map +1 -0
- package/lib/typescript/utils/debugConfig.d.ts +8 -0
- package/lib/typescript/utils/debugConfig.d.ts.map +1 -0
- package/lib/typescript/utils/debugMenu.d.ts +3 -0
- package/lib/typescript/utils/debugMenu.d.ts.map +1 -0
- package/lib/typescript/utils/errorHandler.d.ts +2 -0
- package/lib/typescript/utils/errorHandler.d.ts.map +1 -0
- package/lib/typescript/utils/logger.d.ts +7 -0
- package/lib/typescript/utils/logger.d.ts.map +1 -0
- package/lib/typescript/utils/systemInfo.d.ts +19 -0
- package/lib/typescript/utils/systemInfo.d.ts.map +1 -0
- package/lib/typescript/utils/webViewStorage.d.ts +16 -0
- package/lib/typescript/utils/webViewStorage.d.ts.map +1 -0
- package/lib/typescript/version.d.ts +2 -0
- package/lib/typescript/version.d.ts.map +1 -0
- package/package.json +8 -2
- package/scripts/generate-version.js +9 -0
- package/src/Chatbotsdk.tsx +426 -150
- package/src/FloatingButton.tsx +18 -1
- package/src/components/DebugButton.tsx +46 -0
- package/src/components/ErrorBoundary.tsx +38 -0
- package/src/constants/errorConstants.ts +21 -0
- package/src/hooks/useChatbotEvents.ts +93 -0
- package/src/index.tsx +9 -1
- package/src/services/ErrorTrackingService.ts +217 -0
- package/src/types/events.ts +25 -0
- package/src/types/react-native-flipper-performance-plugin.d.ts +3 -0
- package/src/types/react-native-globals.d.ts +10 -0
- package/src/utils/cookieUtils.ts +7 -0
- package/src/utils/debugConfig.ts +56 -0
- package/src/utils/debugMenu.ts +14 -0
- package/src/utils/errorHandler.ts +58 -0
- package/src/utils/logger.ts +14 -0
- package/src/utils/systemInfo.ts +84 -0
- package/src/utils/webViewStorage.ts +62 -0
- package/src/version.ts +2 -0
package/src/Chatbotsdk.tsx
CHANGED
|
@@ -1,4 +1,10 @@
|
|
|
1
|
-
import React, {
|
|
1
|
+
import React, {
|
|
2
|
+
useState,
|
|
3
|
+
useEffect,
|
|
4
|
+
useRef,
|
|
5
|
+
useMemo,
|
|
6
|
+
useCallback,
|
|
7
|
+
} from "react";
|
|
2
8
|
import {
|
|
3
9
|
View,
|
|
4
10
|
StyleSheet,
|
|
@@ -6,32 +12,55 @@ import {
|
|
|
6
12
|
Dimensions,
|
|
7
13
|
Platform,
|
|
8
14
|
StatusBar,
|
|
15
|
+
PixelRatio,
|
|
9
16
|
} from "react-native";
|
|
10
17
|
import { WebView, WebViewMessageEvent } from "react-native-webview";
|
|
11
18
|
import FloatingButton from "./FloatingButton";
|
|
12
19
|
import { API_URL, BASE_CHATBOT_URL } from "./constants";
|
|
20
|
+
import { SDK_VERSION } from "./version";
|
|
21
|
+
import { getSystemInfo, getBrowserAndOSInfoScript } from "./utils/systemInfo";
|
|
22
|
+
import { useChatbotEvents } from "./hooks/useChatbotEvents";
|
|
23
|
+
import { ChatbotEventType, ChatbotEventHandler } from "./types/events";
|
|
24
|
+
import { logger } from "./utils/logger";
|
|
25
|
+
import { enableNetworkDebug, enableWebViewDebug } from "./utils/debugConfig";
|
|
26
|
+
import DebugButton from "./components/DebugButton";
|
|
27
|
+
import { ErrorBoundary } from "./components/ErrorBoundary";
|
|
28
|
+
import {
|
|
29
|
+
ErrorCodes,
|
|
30
|
+
ErrorTypes,
|
|
31
|
+
ErrorMessages,
|
|
32
|
+
} from "./constants/errorConstants";
|
|
33
|
+
import { setupGlobalErrorHandlers } from "./utils/errorHandler";
|
|
34
|
+
import { errorTracker } from "./services/ErrorTrackingService";
|
|
35
|
+
import { generateUUID } from "./utils/cookieUtils";
|
|
36
|
+
import {
|
|
37
|
+
StorageMessageType,
|
|
38
|
+
StorageMessage,
|
|
39
|
+
getStorageScript,
|
|
40
|
+
createStorageMessage,
|
|
41
|
+
} from "./utils/webViewStorage";
|
|
13
42
|
|
|
14
|
-
interface
|
|
43
|
+
export interface ChatbotProps {
|
|
15
44
|
api_key: string;
|
|
16
|
-
user_id?: string;
|
|
45
|
+
user_id?: string | null | number;
|
|
17
46
|
user_token?: string;
|
|
18
|
-
|
|
47
|
+
user_profile?: Record<string, any>;
|
|
48
|
+
onEvent?: ChatbotEventHandler;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
interface InternalChatbotProps extends ChatbotProps {
|
|
19
52
|
show_floating_button?: boolean;
|
|
20
53
|
onMessage?: (message: any) => void;
|
|
21
54
|
isFullScreen?: boolean;
|
|
22
55
|
enableAnimation?: boolean;
|
|
23
56
|
onOpen?: () => void;
|
|
24
57
|
onClose?: () => void;
|
|
25
|
-
user_info?: {
|
|
26
|
-
name?: string;
|
|
27
|
-
email?: string;
|
|
28
|
-
mobile?: string;
|
|
29
|
-
};
|
|
30
58
|
}
|
|
31
59
|
|
|
32
60
|
interface ChatbotMessage {
|
|
33
61
|
type: string;
|
|
34
62
|
data?: any;
|
|
63
|
+
level?: string;
|
|
35
64
|
}
|
|
36
65
|
|
|
37
66
|
interface ChatbotConfig {
|
|
@@ -40,18 +69,18 @@ interface ChatbotConfig {
|
|
|
40
69
|
welcome_message: string;
|
|
41
70
|
}
|
|
42
71
|
|
|
43
|
-
const
|
|
72
|
+
const Chatbot: React.FC<InternalChatbotProps> = ({
|
|
44
73
|
api_key,
|
|
45
74
|
user_id,
|
|
46
75
|
user_token,
|
|
47
|
-
additional_params = {},
|
|
48
76
|
show_floating_button = true,
|
|
77
|
+
onEvent,
|
|
49
78
|
onMessage,
|
|
50
79
|
isFullScreen = true,
|
|
51
80
|
enableAnimation = true,
|
|
52
81
|
onOpen,
|
|
53
82
|
onClose,
|
|
54
|
-
|
|
83
|
+
user_profile,
|
|
55
84
|
}) => {
|
|
56
85
|
const [isWebViewVisible, setIsWebViewVisible] = useState(false);
|
|
57
86
|
const [chatbotConfig, setChatbotConfig] = useState<ChatbotConfig | null>(
|
|
@@ -63,15 +92,31 @@ const ChatbotSDK: React.FC<ChatbotSDKProps> = ({
|
|
|
63
92
|
const isFirstLoadRef = useRef(true);
|
|
64
93
|
const [toastVisible, setToastVisible] = useState(false);
|
|
65
94
|
const [toastMessage, setToastMessage] = useState("");
|
|
66
|
-
const
|
|
67
|
-
|
|
68
|
-
|
|
95
|
+
const [effectiveUserId, setEffectiveUserId] = useState<string>();
|
|
96
|
+
const [isStorageReady, setIsStorageReady] = useState(false);
|
|
97
|
+
const pendingStorageOps = useRef<Array<() => void>>([]);
|
|
98
|
+
const memoryCache = useRef<Record<string, string>>({});
|
|
99
|
+
|
|
100
|
+
const [systemInfo, setSystemInfo] = useState({ os: "", browser: "" });
|
|
101
|
+
|
|
102
|
+
// Create chatbotConfig object for events
|
|
103
|
+
const chatbotConfigForEvents = useMemo(
|
|
104
|
+
() => ({
|
|
105
|
+
userId: effectiveUserId,
|
|
106
|
+
isAnonymous: !user_id && user_id !== 0,
|
|
107
|
+
// Add other config properties as needed
|
|
108
|
+
}),
|
|
109
|
+
[effectiveUserId, user_id]
|
|
69
110
|
);
|
|
70
111
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
112
|
+
// Initialize event handling
|
|
113
|
+
const { emitEvent, onInternalEvent } = useChatbotEvents({
|
|
114
|
+
api_key,
|
|
115
|
+
chatbotConfig: chatbotConfigForEvents ?? {},
|
|
116
|
+
user_profile: user_profile,
|
|
117
|
+
onEvent: onEvent,
|
|
118
|
+
systemInfo: systemInfo ?? { os: "", browser: "" },
|
|
119
|
+
});
|
|
75
120
|
|
|
76
121
|
const triggerAppInit = () => {
|
|
77
122
|
if (webViewRef.current) {
|
|
@@ -83,15 +128,203 @@ const ChatbotSDK: React.FC<ChatbotSDKProps> = ({
|
|
|
83
128
|
}
|
|
84
129
|
};
|
|
85
130
|
|
|
131
|
+
const executeStorageOp = useCallback(
|
|
132
|
+
(operation: () => void) => {
|
|
133
|
+
if (isStorageReady) {
|
|
134
|
+
operation();
|
|
135
|
+
} else {
|
|
136
|
+
pendingStorageOps.current.push(operation);
|
|
137
|
+
}
|
|
138
|
+
},
|
|
139
|
+
[isStorageReady]
|
|
140
|
+
);
|
|
141
|
+
|
|
142
|
+
// Handle WebView messages
|
|
143
|
+
const handleMessage = useCallback(
|
|
144
|
+
(event: WebViewMessageEvent) => {
|
|
145
|
+
const { data } = event.nativeEvent;
|
|
146
|
+
|
|
147
|
+
try {
|
|
148
|
+
const parsedData: ChatbotMessage = JSON.parse(data);
|
|
149
|
+
|
|
150
|
+
// Handle storage messages
|
|
151
|
+
if (
|
|
152
|
+
Object.values(StorageMessageType).includes(
|
|
153
|
+
parsedData.type as StorageMessageType
|
|
154
|
+
)
|
|
155
|
+
) {
|
|
156
|
+
const storageMessage = parsedData as StorageMessage;
|
|
157
|
+
switch (storageMessage.type) {
|
|
158
|
+
case StorageMessageType.STORAGE_READY:
|
|
159
|
+
setIsStorageReady(true);
|
|
160
|
+
pendingStorageOps.current.forEach((op) => op());
|
|
161
|
+
pendingStorageOps.current = [];
|
|
162
|
+
// Try to get stored ID immediately after storage is ready
|
|
163
|
+
webViewRef.current?.injectJavaScript(
|
|
164
|
+
createStorageMessage(
|
|
165
|
+
StorageMessageType.GET_STORAGE,
|
|
166
|
+
"rblyn_anon"
|
|
167
|
+
)
|
|
168
|
+
);
|
|
169
|
+
break;
|
|
170
|
+
case StorageMessageType.STORAGE_RESPONSE:
|
|
171
|
+
if (storageMessage.key && storageMessage.value) {
|
|
172
|
+
memoryCache.current[storageMessage.key] = storageMessage.value;
|
|
173
|
+
if (storageMessage.key === "rblyn_anon") {
|
|
174
|
+
setEffectiveUserId(storageMessage.value);
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
break;
|
|
178
|
+
case StorageMessageType.STORAGE_ERROR:
|
|
179
|
+
logger.error("WebView storage error:", storageMessage.error);
|
|
180
|
+
break;
|
|
181
|
+
}
|
|
182
|
+
return;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
// Add debug logging
|
|
186
|
+
if (__DEV__) {
|
|
187
|
+
if (parsedData?.type === "CONSOLE") {
|
|
188
|
+
console.log(`WebView ${parsedData?.level}:`, parsedData?.data);
|
|
189
|
+
return;
|
|
190
|
+
}
|
|
191
|
+
if (parsedData?.type === "ERROR") {
|
|
192
|
+
console.error("WebView Error:", parsedData?.data);
|
|
193
|
+
return;
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
if (parsedData?.type === "SYSTEM_INFO") {
|
|
198
|
+
setSystemInfo(parsedData?.data ?? { os: "", browser: "" });
|
|
199
|
+
return;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
if (parsedData?.type === "APP_READY") {
|
|
203
|
+
emitEvent(ChatbotEventType.CHATBOT_APP_READY);
|
|
204
|
+
if (webViewRef.current && isWebViewVisible) {
|
|
205
|
+
webViewRef.current?.injectJavaScript(getBrowserAndOSInfoScript());
|
|
206
|
+
|
|
207
|
+
const messageData = {
|
|
208
|
+
name: "registerUserId",
|
|
209
|
+
action: "registerUserId",
|
|
210
|
+
data: {
|
|
211
|
+
userId: effectiveUserId,
|
|
212
|
+
token: user_token ? `${user_token}` : undefined,
|
|
213
|
+
userProfile: {
|
|
214
|
+
...user_profile,
|
|
215
|
+
...getSystemInfo(systemInfo),
|
|
216
|
+
},
|
|
217
|
+
},
|
|
218
|
+
};
|
|
219
|
+
logger.debug("messageData====>", JSON.stringify(messageData));
|
|
220
|
+
webViewRef.current?.injectJavaScript(`
|
|
221
|
+
window.postMessage(${JSON.stringify({
|
|
222
|
+
name: "openFrame",
|
|
223
|
+
domain: "app-domain.com",
|
|
224
|
+
})}, '*');
|
|
225
|
+
window.postMessage(${JSON.stringify(messageData)}, '*');
|
|
226
|
+
`);
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
// Handle other message types
|
|
231
|
+
switch (parsedData?.type) {
|
|
232
|
+
case "close_chatbot":
|
|
233
|
+
closeWebView();
|
|
234
|
+
break;
|
|
235
|
+
case "CHATBOT_LOADED":
|
|
236
|
+
emitEvent(ChatbotEventType.CHATBOT_LOADED, parsedData?.data);
|
|
237
|
+
break;
|
|
238
|
+
case "CHAT_INITIALIZED":
|
|
239
|
+
emitEvent(ChatbotEventType.CHAT_INITIALIZED, parsedData?.data);
|
|
240
|
+
break;
|
|
241
|
+
case "SESSION_REFRESHED":
|
|
242
|
+
emitEvent(ChatbotEventType.SESSION_REFRESHED, parsedData?.data);
|
|
243
|
+
break;
|
|
244
|
+
case "CHAT_INITIALIZATION_FAILED":
|
|
245
|
+
emitEvent(
|
|
246
|
+
ChatbotEventType.CHAT_INITIALIZATION_FAILED,
|
|
247
|
+
parsedData?.data
|
|
248
|
+
);
|
|
249
|
+
break;
|
|
250
|
+
default:
|
|
251
|
+
if (onMessage) onMessage(parsedData ?? {});
|
|
252
|
+
}
|
|
253
|
+
} catch (error) {
|
|
254
|
+
errorTracker.trackError(
|
|
255
|
+
error instanceof Error
|
|
256
|
+
? error
|
|
257
|
+
: new Error("Failed to parse WebView message"),
|
|
258
|
+
"ChatbotSDK",
|
|
259
|
+
{
|
|
260
|
+
type: ErrorTypes.RUNTIME_ERROR,
|
|
261
|
+
context: { messageData: data },
|
|
262
|
+
}
|
|
263
|
+
);
|
|
264
|
+
}
|
|
265
|
+
},
|
|
266
|
+
[
|
|
267
|
+
emitEvent,
|
|
268
|
+
isWebViewVisible,
|
|
269
|
+
onMessage,
|
|
270
|
+
systemInfo,
|
|
271
|
+
effectiveUserId,
|
|
272
|
+
user_token,
|
|
273
|
+
user_profile,
|
|
274
|
+
]
|
|
275
|
+
);
|
|
276
|
+
|
|
277
|
+
// Initialize user ID
|
|
278
|
+
useEffect(() => {
|
|
279
|
+
const initializeUserId = async () => {
|
|
280
|
+
let userId = user_id ? String(user_id) : undefined;
|
|
281
|
+
|
|
282
|
+
if (!userId) {
|
|
283
|
+
// Try memory cache first
|
|
284
|
+
userId = memoryCache.current["rblyn_anon"];
|
|
285
|
+
|
|
286
|
+
if (!userId) {
|
|
287
|
+
userId = generateUUID();
|
|
288
|
+
executeStorageOp(() => {
|
|
289
|
+
webViewRef.current?.injectJavaScript(
|
|
290
|
+
createStorageMessage(
|
|
291
|
+
StorageMessageType.SET_STORAGE,
|
|
292
|
+
"rblyn_anon",
|
|
293
|
+
userId!
|
|
294
|
+
)
|
|
295
|
+
);
|
|
296
|
+
});
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
setEffectiveUserId(userId);
|
|
301
|
+
};
|
|
302
|
+
|
|
303
|
+
initializeUserId();
|
|
304
|
+
}, [user_id, executeStorageOp]);
|
|
305
|
+
|
|
306
|
+
// Initialize WebView storage
|
|
307
|
+
useEffect(() => {
|
|
308
|
+
if (webViewRef.current) {
|
|
309
|
+
webViewRef.current.injectJavaScript(getStorageScript());
|
|
310
|
+
// Try to get stored ID once storage is ready
|
|
311
|
+
executeStorageOp(() => {
|
|
312
|
+
webViewRef.current?.injectJavaScript(
|
|
313
|
+
createStorageMessage(StorageMessageType.GET_STORAGE, "rblyn_anon")
|
|
314
|
+
);
|
|
315
|
+
});
|
|
316
|
+
}
|
|
317
|
+
}, []);
|
|
318
|
+
|
|
86
319
|
useEffect(() => {
|
|
87
320
|
const fetchChatbotConfig = async () => {
|
|
88
321
|
try {
|
|
89
322
|
const endpointUrl = `${API_URL}/chat/chatbot/get/`;
|
|
90
323
|
const payload = {
|
|
91
|
-
client_user_id:
|
|
324
|
+
client_user_id: effectiveUserId,
|
|
92
325
|
org_id: api_key,
|
|
93
326
|
token: user_token,
|
|
94
|
-
extra_info:
|
|
327
|
+
extra_info: {},
|
|
95
328
|
};
|
|
96
329
|
|
|
97
330
|
// setToastMessage(endpointUrl + " : " + BASE_CHATBOT_URL);
|
|
@@ -120,28 +353,37 @@ const ChatbotSDK: React.FC<ChatbotSDKProps> = ({
|
|
|
120
353
|
});
|
|
121
354
|
}
|
|
122
355
|
} catch (error) {
|
|
123
|
-
|
|
356
|
+
errorTracker.trackError(
|
|
357
|
+
error instanceof Error
|
|
358
|
+
? error
|
|
359
|
+
: new Error("Failed to fetch chatbot configuration"),
|
|
360
|
+
"ChatbotSDK",
|
|
361
|
+
{
|
|
362
|
+
type: ErrorTypes.NETWORK_ERROR,
|
|
363
|
+
context: { api_key, user_id },
|
|
364
|
+
}
|
|
365
|
+
);
|
|
124
366
|
} finally {
|
|
125
367
|
setLoading(false);
|
|
126
368
|
}
|
|
127
369
|
};
|
|
128
370
|
|
|
129
|
-
if (api_key &&
|
|
371
|
+
if (api_key && effectiveUserId) {
|
|
130
372
|
fetchChatbotConfig();
|
|
131
373
|
}
|
|
132
|
-
}, [api_key,
|
|
374
|
+
}, [api_key, effectiveUserId, user_token]);
|
|
133
375
|
|
|
134
376
|
function constructUrl(): string {
|
|
135
|
-
if (!
|
|
377
|
+
if (!effectiveUserId) return "";
|
|
136
378
|
const params = new URLSearchParams({
|
|
137
379
|
id: api_key,
|
|
138
|
-
user_id,
|
|
139
|
-
...additional_params,
|
|
140
380
|
});
|
|
381
|
+
console.log("BASE_CHATBOT_URL SDK_VERSION", BASE_CHATBOT_URL, SDK_VERSION);
|
|
141
382
|
return `${BASE_CHATBOT_URL}?${params.toString()}`;
|
|
142
383
|
}
|
|
143
384
|
|
|
144
|
-
|
|
385
|
+
// Handle opening the chatbot
|
|
386
|
+
const openWebView = useCallback(() => {
|
|
145
387
|
setIsWebViewVisible(true);
|
|
146
388
|
if (enableAnimation) {
|
|
147
389
|
Animated.timing(fadeAnim, {
|
|
@@ -150,8 +392,8 @@ const ChatbotSDK: React.FC<ChatbotSDKProps> = ({
|
|
|
150
392
|
useNativeDriver: true,
|
|
151
393
|
}).start(() => {
|
|
152
394
|
onOpen?.();
|
|
395
|
+
emitEvent(ChatbotEventType.CHATBOT_OPENED);
|
|
153
396
|
if (!isFirstLoadRef.current) {
|
|
154
|
-
// If not first load, manually trigger initialization
|
|
155
397
|
setTimeout(triggerAppInit, 100);
|
|
156
398
|
}
|
|
157
399
|
});
|
|
@@ -159,16 +401,17 @@ const ChatbotSDK: React.FC<ChatbotSDKProps> = ({
|
|
|
159
401
|
fadeAnim.setValue(1);
|
|
160
402
|
requestAnimationFrame(() => {
|
|
161
403
|
onOpen?.();
|
|
404
|
+
emitEvent(ChatbotEventType.CHATBOT_OPENED);
|
|
162
405
|
if (!isFirstLoadRef.current) {
|
|
163
406
|
setTimeout(triggerAppInit, 100);
|
|
164
407
|
}
|
|
165
408
|
});
|
|
166
409
|
}
|
|
167
|
-
};
|
|
410
|
+
}, [enableAnimation, fadeAnim, onOpen, emitEvent]);
|
|
168
411
|
|
|
169
|
-
|
|
412
|
+
// Handle closing the chatbot
|
|
413
|
+
const closeWebView = useCallback(() => {
|
|
170
414
|
if (webViewRef.current) {
|
|
171
|
-
console.log("closeWebView");
|
|
172
415
|
webViewRef.current.postMessage(
|
|
173
416
|
JSON.stringify({
|
|
174
417
|
name: "closeFrame",
|
|
@@ -180,6 +423,7 @@ const ChatbotSDK: React.FC<ChatbotSDKProps> = ({
|
|
|
180
423
|
const complete = () => {
|
|
181
424
|
setIsWebViewVisible(false);
|
|
182
425
|
onClose?.();
|
|
426
|
+
emitEvent(ChatbotEventType.CHATBOT_CLOSED);
|
|
183
427
|
};
|
|
184
428
|
|
|
185
429
|
if (enableAnimation) {
|
|
@@ -192,58 +436,14 @@ const ChatbotSDK: React.FC<ChatbotSDKProps> = ({
|
|
|
192
436
|
fadeAnim.setValue(0);
|
|
193
437
|
requestAnimationFrame(complete);
|
|
194
438
|
}
|
|
195
|
-
};
|
|
196
|
-
|
|
197
|
-
const handleMessage = (event: WebViewMessageEvent) => {
|
|
198
|
-
const { data } = event.nativeEvent;
|
|
199
|
-
|
|
200
|
-
try {
|
|
201
|
-
const parsedData: ChatbotMessage = JSON.parse(data);
|
|
439
|
+
}, [enableAnimation, fadeAnim, onClose, emitEvent]);
|
|
202
440
|
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
window.postMessage(${JSON.stringify({
|
|
208
|
-
name: "openFrame",
|
|
209
|
-
domain: "app-domain.com",
|
|
210
|
-
})}, '*');
|
|
211
|
-
window.postMessage(${JSON.stringify({
|
|
212
|
-
name: "registerUserId",
|
|
213
|
-
action: "registerUserId",
|
|
214
|
-
domain: "app-domain.com",
|
|
215
|
-
data: {
|
|
216
|
-
userId: `${user_id}`,
|
|
217
|
-
token: `${user_token}`,
|
|
218
|
-
user_info: {
|
|
219
|
-
...user_info,
|
|
220
|
-
platform: Platform.OS,
|
|
221
|
-
SDK_VERSION: "${SDK_VERSION}",
|
|
222
|
-
OS: Platform.OS,
|
|
223
|
-
browser: Platform.OS,
|
|
224
|
-
},
|
|
225
|
-
},
|
|
226
|
-
})}, '*');
|
|
227
|
-
`);
|
|
228
|
-
}
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
if (typeof parsedData !== "object" || !parsedData.type) {
|
|
232
|
-
console.warn("Invalid message structure");
|
|
233
|
-
return;
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
switch (parsedData.type) {
|
|
237
|
-
case "close_chatbot":
|
|
238
|
-
closeWebView();
|
|
239
|
-
break;
|
|
240
|
-
default:
|
|
241
|
-
if (onMessage) onMessage(parsedData);
|
|
242
|
-
}
|
|
243
|
-
} catch (error) {
|
|
244
|
-
console.error("Failed to parse or process WebView message:", error);
|
|
441
|
+
// Emit button loaded event when component mounts
|
|
442
|
+
useEffect(() => {
|
|
443
|
+
if (show_floating_button && chatbotConfig) {
|
|
444
|
+
emitEvent(ChatbotEventType.CHATBOT_BUTTON_LOADED);
|
|
245
445
|
}
|
|
246
|
-
};
|
|
446
|
+
}, [show_floating_button, chatbotConfig, emitEvent]);
|
|
247
447
|
|
|
248
448
|
const getScreenDimensions = () => {
|
|
249
449
|
const windowHeight = Dimensions.get("window").height;
|
|
@@ -259,60 +459,89 @@ const ChatbotSDK: React.FC<ChatbotSDKProps> = ({
|
|
|
259
459
|
|
|
260
460
|
const screenDimensions = getScreenDimensions();
|
|
261
461
|
|
|
462
|
+
useEffect(() => {
|
|
463
|
+
if (__DEV__) {
|
|
464
|
+
enableNetworkDebug();
|
|
465
|
+
}
|
|
466
|
+
}, []);
|
|
467
|
+
|
|
468
|
+
// Deliberate error for testing error boundary
|
|
469
|
+
// useEffect(() => {
|
|
470
|
+
// if (__DEV__) {
|
|
471
|
+
// // Set up global error handlers
|
|
472
|
+
// setupGlobalErrorHandlers();
|
|
473
|
+
|
|
474
|
+
// // Test async error
|
|
475
|
+
// setTimeout(() => {
|
|
476
|
+
// Promise.reject(new Error("Test async error"));
|
|
477
|
+
// }, 1000);
|
|
478
|
+
|
|
479
|
+
// // Test sync error
|
|
480
|
+
// setTimeout(() => {
|
|
481
|
+
// throw new Error("Test sync error");
|
|
482
|
+
// }, 2000);
|
|
483
|
+
// }
|
|
484
|
+
// }, []);
|
|
485
|
+
|
|
262
486
|
return (
|
|
263
|
-
<
|
|
264
|
-
{
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
<FloatingButton
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
<Animated.View
|
|
487
|
+
<ErrorBoundary componentName="ChatbotSDK">
|
|
488
|
+
<View style={styles.mainContainer}>
|
|
489
|
+
{!loading && (
|
|
490
|
+
<>
|
|
491
|
+
<ErrorBoundary componentName="FloatingButton">
|
|
492
|
+
{show_floating_button && api_key && chatbotConfig && (
|
|
493
|
+
<FloatingButton
|
|
494
|
+
onPress={() => {
|
|
495
|
+
emitEvent(ChatbotEventType.CHATBOT_BUTTON_CLICKED);
|
|
496
|
+
openWebView();
|
|
497
|
+
}}
|
|
498
|
+
brandColor={chatbotConfig.brand_color}
|
|
499
|
+
imageUrl={chatbotConfig.image_url}
|
|
500
|
+
/>
|
|
501
|
+
)}
|
|
502
|
+
</ErrorBoundary>
|
|
503
|
+
<View
|
|
281
504
|
style={[
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
: styles.inlineContainer,
|
|
285
|
-
{ opacity: fadeAnim },
|
|
505
|
+
styles.webViewWrapper,
|
|
506
|
+
{ height: isWebViewVisible ? "100%" : 0 },
|
|
286
507
|
]}
|
|
508
|
+
pointerEvents={isWebViewVisible ? "auto" : "none"}
|
|
287
509
|
>
|
|
288
|
-
<
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
510
|
+
<Animated.View
|
|
511
|
+
style={[styles.fullScreenContainer, { opacity: fadeAnim }]}
|
|
512
|
+
>
|
|
513
|
+
<ErrorBoundary componentName="ChatbotWebView">
|
|
514
|
+
<WebView
|
|
515
|
+
ref={webViewRef}
|
|
516
|
+
source={{ uri: constructUrl() }}
|
|
517
|
+
onMessage={handleMessage}
|
|
518
|
+
style={styles.webview}
|
|
519
|
+
containerStyle={
|
|
520
|
+
isFullScreen
|
|
521
|
+
? {
|
|
522
|
+
width: screenDimensions.width,
|
|
523
|
+
height: screenDimensions.height,
|
|
524
|
+
}
|
|
525
|
+
: undefined
|
|
526
|
+
}
|
|
527
|
+
allowsInlineMediaPlayback={true}
|
|
528
|
+
mediaPlaybackRequiresUserAction={false}
|
|
529
|
+
allowFileAccess={false}
|
|
530
|
+
geolocationEnabled={false}
|
|
531
|
+
javaScriptEnabled={true}
|
|
532
|
+
domStorageEnabled={true}
|
|
533
|
+
cacheEnabled={true}
|
|
534
|
+
scrollEnabled={true}
|
|
535
|
+
bounces={false}
|
|
536
|
+
onShouldStartLoadWithRequest={(request) => {
|
|
537
|
+
return request.url.startsWith(BASE_CHATBOT_URL);
|
|
538
|
+
}}
|
|
539
|
+
startInLoadingState={isFirstLoadRef.current}
|
|
540
|
+
onLoadEnd={() => {
|
|
541
|
+
if (__DEV__) {
|
|
542
|
+
enableWebViewDebug(webViewRef);
|
|
298
543
|
}
|
|
299
|
-
|
|
300
|
-
}
|
|
301
|
-
allowsInlineMediaPlayback={true}
|
|
302
|
-
mediaPlaybackRequiresUserAction={false}
|
|
303
|
-
allowFileAccess={false}
|
|
304
|
-
geolocationEnabled={false}
|
|
305
|
-
javaScriptEnabled={true}
|
|
306
|
-
domStorageEnabled={true}
|
|
307
|
-
cacheEnabled={true}
|
|
308
|
-
scrollEnabled={true}
|
|
309
|
-
bounces={false}
|
|
310
|
-
onShouldStartLoadWithRequest={(request) => {
|
|
311
|
-
return request.url.startsWith(BASE_CHATBOT_URL);
|
|
312
|
-
}}
|
|
313
|
-
startInLoadingState={isFirstLoadRef.current}
|
|
314
|
-
onLoadEnd={() => {
|
|
315
|
-
webViewRef.current?.injectJavaScript(`
|
|
544
|
+
webViewRef.current?.injectJavaScript(`
|
|
316
545
|
if (!document.querySelector('meta[name="viewport"]')) {
|
|
317
546
|
var meta = document.createElement('meta');
|
|
318
547
|
meta.name = 'viewport';
|
|
@@ -337,28 +566,75 @@ const ChatbotSDK: React.FC<ChatbotSDKProps> = ({
|
|
|
337
566
|
window.ReactNativeWebView.postMessage(JSON.stringify(message));
|
|
338
567
|
};
|
|
339
568
|
|
|
340
|
-
|
|
341
|
-
if (
|
|
342
|
-
|
|
343
|
-
|
|
569
|
+
// Only create observer if it doesn't exist
|
|
570
|
+
if (!window.closeButtonObserver) {
|
|
571
|
+
// Setup mutation observer to watch for close button
|
|
572
|
+
window.closeButtonObserver = new MutationObserver(function(mutations) {
|
|
573
|
+
const closeButton = document.querySelector('.chatbot-close-button');
|
|
574
|
+
if (closeButton && !closeButton.hasAttribute('listener-attached')) {
|
|
575
|
+
closeButton.setAttribute('listener-attached', 'true');
|
|
576
|
+
closeButton.addEventListener('click', () => {
|
|
577
|
+
try {
|
|
578
|
+
const message = { type: 'close_chatbot' };
|
|
579
|
+
window.ReactNativeWebView.postMessage(JSON.stringify(message));
|
|
580
|
+
} catch (error) {
|
|
581
|
+
console.error('Error sending close message:', error);
|
|
582
|
+
}
|
|
583
|
+
});
|
|
584
|
+
console.log('Close button listener attached');
|
|
585
|
+
}
|
|
586
|
+
});
|
|
587
|
+
|
|
588
|
+
// Start observing
|
|
589
|
+
window.closeButtonObserver.observe(document.body, {
|
|
590
|
+
childList: true,
|
|
591
|
+
subtree: true
|
|
344
592
|
});
|
|
593
|
+
|
|
594
|
+
// Initial check for existing button
|
|
595
|
+
const existingButton = document.querySelector('.chatbot-close-button');
|
|
596
|
+
if (existingButton && !existingButton.hasAttribute('listener-attached')) {
|
|
597
|
+
existingButton.setAttribute('listener-attached', 'true');
|
|
598
|
+
existingButton.addEventListener('click', () => {
|
|
599
|
+
try {
|
|
600
|
+
const message = { type: 'close_chatbot' };
|
|
601
|
+
window.ReactNativeWebView.postMessage(JSON.stringify(message));
|
|
602
|
+
} catch (error) {
|
|
603
|
+
console.error('Error sending close message:', error);
|
|
604
|
+
}
|
|
605
|
+
});
|
|
606
|
+
console.log('Close button listener attached to existing button');
|
|
607
|
+
}
|
|
345
608
|
}
|
|
346
|
-
|
|
609
|
+
|
|
347
610
|
true;
|
|
348
611
|
`);
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
612
|
+
isFirstLoadRef.current = false;
|
|
613
|
+
}}
|
|
614
|
+
onError={(syntheticEvent) => {
|
|
615
|
+
const { nativeEvent } = syntheticEvent;
|
|
616
|
+
errorTracker.trackError(
|
|
617
|
+
new Error(nativeEvent.description),
|
|
618
|
+
"ChatbotWebView",
|
|
619
|
+
{
|
|
620
|
+
type: ErrorTypes.RUNTIME_ERROR,
|
|
621
|
+
context: {
|
|
622
|
+
url: nativeEvent.url,
|
|
623
|
+
code: nativeEvent.code,
|
|
624
|
+
},
|
|
625
|
+
}
|
|
626
|
+
);
|
|
627
|
+
}}
|
|
628
|
+
/>
|
|
629
|
+
</ErrorBoundary>
|
|
630
|
+
</Animated.View>
|
|
631
|
+
</View>
|
|
632
|
+
</>
|
|
633
|
+
)}
|
|
634
|
+
{/* <Toast message={toastMessage} visible={toastVisible} duration={10000} /> */}
|
|
635
|
+
{__DEV__ && <DebugButton />}
|
|
636
|
+
</View>
|
|
637
|
+
</ErrorBoundary>
|
|
362
638
|
);
|
|
363
639
|
};
|
|
364
640
|
|
|
@@ -395,4 +671,4 @@ const styles = StyleSheet.create({
|
|
|
395
671
|
},
|
|
396
672
|
});
|
|
397
673
|
|
|
398
|
-
export default
|
|
674
|
+
export default Chatbot;
|