@robylon/react-native-sdk 2.0.16-staging.2 → 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/constants.js +1 -1
- package/lib/commonjs/constants.js.map +1 -1
- 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/constants.js +1 -1
- package/lib/module/constants.js.map +1 -1
- 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/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 -151
- 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,29 +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
|
});
|
|
141
|
-
console.log("BASE_CHATBOT_URL", BASE_CHATBOT_URL);
|
|
381
|
+
console.log("BASE_CHATBOT_URL SDK_VERSION", BASE_CHATBOT_URL, SDK_VERSION);
|
|
142
382
|
return `${BASE_CHATBOT_URL}?${params.toString()}`;
|
|
143
383
|
}
|
|
144
384
|
|
|
145
|
-
|
|
385
|
+
// Handle opening the chatbot
|
|
386
|
+
const openWebView = useCallback(() => {
|
|
146
387
|
setIsWebViewVisible(true);
|
|
147
388
|
if (enableAnimation) {
|
|
148
389
|
Animated.timing(fadeAnim, {
|
|
@@ -151,8 +392,8 @@ const ChatbotSDK: React.FC<ChatbotSDKProps> = ({
|
|
|
151
392
|
useNativeDriver: true,
|
|
152
393
|
}).start(() => {
|
|
153
394
|
onOpen?.();
|
|
395
|
+
emitEvent(ChatbotEventType.CHATBOT_OPENED);
|
|
154
396
|
if (!isFirstLoadRef.current) {
|
|
155
|
-
// If not first load, manually trigger initialization
|
|
156
397
|
setTimeout(triggerAppInit, 100);
|
|
157
398
|
}
|
|
158
399
|
});
|
|
@@ -160,16 +401,17 @@ const ChatbotSDK: React.FC<ChatbotSDKProps> = ({
|
|
|
160
401
|
fadeAnim.setValue(1);
|
|
161
402
|
requestAnimationFrame(() => {
|
|
162
403
|
onOpen?.();
|
|
404
|
+
emitEvent(ChatbotEventType.CHATBOT_OPENED);
|
|
163
405
|
if (!isFirstLoadRef.current) {
|
|
164
406
|
setTimeout(triggerAppInit, 100);
|
|
165
407
|
}
|
|
166
408
|
});
|
|
167
409
|
}
|
|
168
|
-
};
|
|
410
|
+
}, [enableAnimation, fadeAnim, onOpen, emitEvent]);
|
|
169
411
|
|
|
170
|
-
|
|
412
|
+
// Handle closing the chatbot
|
|
413
|
+
const closeWebView = useCallback(() => {
|
|
171
414
|
if (webViewRef.current) {
|
|
172
|
-
console.log("closeWebView");
|
|
173
415
|
webViewRef.current.postMessage(
|
|
174
416
|
JSON.stringify({
|
|
175
417
|
name: "closeFrame",
|
|
@@ -181,6 +423,7 @@ const ChatbotSDK: React.FC<ChatbotSDKProps> = ({
|
|
|
181
423
|
const complete = () => {
|
|
182
424
|
setIsWebViewVisible(false);
|
|
183
425
|
onClose?.();
|
|
426
|
+
emitEvent(ChatbotEventType.CHATBOT_CLOSED);
|
|
184
427
|
};
|
|
185
428
|
|
|
186
429
|
if (enableAnimation) {
|
|
@@ -193,58 +436,14 @@ const ChatbotSDK: React.FC<ChatbotSDKProps> = ({
|
|
|
193
436
|
fadeAnim.setValue(0);
|
|
194
437
|
requestAnimationFrame(complete);
|
|
195
438
|
}
|
|
196
|
-
};
|
|
197
|
-
|
|
198
|
-
const handleMessage = (event: WebViewMessageEvent) => {
|
|
199
|
-
const { data } = event.nativeEvent;
|
|
200
|
-
|
|
201
|
-
try {
|
|
202
|
-
const parsedData: ChatbotMessage = JSON.parse(data);
|
|
439
|
+
}, [enableAnimation, fadeAnim, onClose, emitEvent]);
|
|
203
440
|
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
window.postMessage(${JSON.stringify({
|
|
209
|
-
name: "openFrame",
|
|
210
|
-
domain: "app-domain.com",
|
|
211
|
-
})}, '*');
|
|
212
|
-
window.postMessage(${JSON.stringify({
|
|
213
|
-
name: "registerUserId",
|
|
214
|
-
action: "registerUserId",
|
|
215
|
-
domain: "app-domain.com",
|
|
216
|
-
data: {
|
|
217
|
-
userId: `${user_id}`,
|
|
218
|
-
token: `${user_token}`,
|
|
219
|
-
user_info: {
|
|
220
|
-
...user_info,
|
|
221
|
-
platform: Platform.OS,
|
|
222
|
-
SDK_VERSION: "${SDK_VERSION}",
|
|
223
|
-
OS: Platform.OS,
|
|
224
|
-
browser: Platform.OS,
|
|
225
|
-
},
|
|
226
|
-
},
|
|
227
|
-
})}, '*');
|
|
228
|
-
`);
|
|
229
|
-
}
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
if (typeof parsedData !== "object" || !parsedData.type) {
|
|
233
|
-
console.warn("Invalid message structure");
|
|
234
|
-
return;
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
switch (parsedData.type) {
|
|
238
|
-
case "close_chatbot":
|
|
239
|
-
closeWebView();
|
|
240
|
-
break;
|
|
241
|
-
default:
|
|
242
|
-
if (onMessage) onMessage(parsedData);
|
|
243
|
-
}
|
|
244
|
-
} catch (error) {
|
|
245
|
-
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);
|
|
246
445
|
}
|
|
247
|
-
};
|
|
446
|
+
}, [show_floating_button, chatbotConfig, emitEvent]);
|
|
248
447
|
|
|
249
448
|
const getScreenDimensions = () => {
|
|
250
449
|
const windowHeight = Dimensions.get("window").height;
|
|
@@ -260,60 +459,89 @@ const ChatbotSDK: React.FC<ChatbotSDKProps> = ({
|
|
|
260
459
|
|
|
261
460
|
const screenDimensions = getScreenDimensions();
|
|
262
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
|
+
|
|
263
486
|
return (
|
|
264
|
-
<
|
|
265
|
-
{
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
<FloatingButton
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
<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
|
|
282
504
|
style={[
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
: styles.inlineContainer,
|
|
286
|
-
{ opacity: fadeAnim },
|
|
505
|
+
styles.webViewWrapper,
|
|
506
|
+
{ height: isWebViewVisible ? "100%" : 0 },
|
|
287
507
|
]}
|
|
508
|
+
pointerEvents={isWebViewVisible ? "auto" : "none"}
|
|
288
509
|
>
|
|
289
|
-
<
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
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);
|
|
299
543
|
}
|
|
300
|
-
|
|
301
|
-
}
|
|
302
|
-
allowsInlineMediaPlayback={true}
|
|
303
|
-
mediaPlaybackRequiresUserAction={false}
|
|
304
|
-
allowFileAccess={false}
|
|
305
|
-
geolocationEnabled={false}
|
|
306
|
-
javaScriptEnabled={true}
|
|
307
|
-
domStorageEnabled={true}
|
|
308
|
-
cacheEnabled={true}
|
|
309
|
-
scrollEnabled={true}
|
|
310
|
-
bounces={false}
|
|
311
|
-
onShouldStartLoadWithRequest={(request) => {
|
|
312
|
-
return request.url.startsWith(BASE_CHATBOT_URL);
|
|
313
|
-
}}
|
|
314
|
-
startInLoadingState={isFirstLoadRef.current}
|
|
315
|
-
onLoadEnd={() => {
|
|
316
|
-
webViewRef.current?.injectJavaScript(`
|
|
544
|
+
webViewRef.current?.injectJavaScript(`
|
|
317
545
|
if (!document.querySelector('meta[name="viewport"]')) {
|
|
318
546
|
var meta = document.createElement('meta');
|
|
319
547
|
meta.name = 'viewport';
|
|
@@ -338,28 +566,75 @@ const ChatbotSDK: React.FC<ChatbotSDKProps> = ({
|
|
|
338
566
|
window.ReactNativeWebView.postMessage(JSON.stringify(message));
|
|
339
567
|
};
|
|
340
568
|
|
|
341
|
-
|
|
342
|
-
if (
|
|
343
|
-
|
|
344
|
-
|
|
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
|
|
345
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
|
+
}
|
|
346
608
|
}
|
|
347
|
-
|
|
609
|
+
|
|
348
610
|
true;
|
|
349
611
|
`);
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
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>
|
|
363
638
|
);
|
|
364
639
|
};
|
|
365
640
|
|
|
@@ -396,4 +671,4 @@ const styles = StyleSheet.create({
|
|
|
396
671
|
},
|
|
397
672
|
});
|
|
398
673
|
|
|
399
|
-
export default
|
|
674
|
+
export default Chatbot;
|