partner_react_native_sdk 0.1.0 → 0.1.2

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 (36) hide show
  1. package/lib/module/helpers/ServiceNames.js +3 -0
  2. package/lib/module/helpers/ServiceNames.js.map +1 -1
  3. package/lib/module/helpers/analytics/analytics_event_model.js +37 -0
  4. package/lib/module/helpers/analytics/analytics_event_model.js.map +1 -0
  5. package/lib/module/helpers/analytics/analytics_logger.js +72 -0
  6. package/lib/module/helpers/analytics/analytics_logger.js.map +1 -0
  7. package/lib/module/helpers/analytics/event_storage.js +35 -0
  8. package/lib/module/helpers/analytics/event_storage.js.map +1 -0
  9. package/lib/module/helpers/partner_library_react_native.js +23 -2
  10. package/lib/module/helpers/partner_library_react_native.js.map +1 -1
  11. package/lib/module/helpers/webview.js +31 -10
  12. package/lib/module/helpers/webview.js.map +1 -1
  13. package/lib/module/index.js +1 -0
  14. package/lib/module/index.js.map +1 -1
  15. package/lib/typescript/src/helpers/ServiceNames.d.ts +1 -0
  16. package/lib/typescript/src/helpers/ServiceNames.d.ts.map +1 -1
  17. package/lib/typescript/src/helpers/analytics/analytics_event_model.d.ts +16 -0
  18. package/lib/typescript/src/helpers/analytics/analytics_event_model.d.ts.map +1 -0
  19. package/lib/typescript/src/helpers/analytics/analytics_logger.d.ts +17 -0
  20. package/lib/typescript/src/helpers/analytics/analytics_logger.d.ts.map +1 -0
  21. package/lib/typescript/src/helpers/analytics/event_storage.d.ts +8 -0
  22. package/lib/typescript/src/helpers/analytics/event_storage.d.ts.map +1 -0
  23. package/lib/typescript/src/helpers/partner_library_react_native.d.ts +1 -0
  24. package/lib/typescript/src/helpers/partner_library_react_native.d.ts.map +1 -1
  25. package/lib/typescript/src/helpers/webview.d.ts.map +1 -1
  26. package/lib/typescript/src/index.d.ts +1 -0
  27. package/lib/typescript/src/index.d.ts.map +1 -1
  28. package/package.json +2 -5
  29. package/src/helpers/ServiceNames.tsx +4 -0
  30. package/src/helpers/analytics/analytics_event_model.tsx +47 -0
  31. package/src/helpers/analytics/analytics_logger.tsx +90 -0
  32. package/src/helpers/analytics/event_storage.tsx +44 -0
  33. package/src/helpers/partner_library_react_native.tsx +26 -4
  34. package/src/helpers/webview.tsx +346 -306
  35. package/src/index.tsx +2 -1
  36. package/lib/typescript/package.json +0 -1
@@ -1,231 +1,260 @@
1
1
  import { WebView as RNWebView } from 'react-native-webview';
2
2
  import {
3
- BackHandler,
4
- Platform,
5
- Linking,
6
- SafeAreaView,
7
- ActivityIndicator,
8
- View,
9
- ToastAndroid,
10
- StatusBar,
3
+ BackHandler,
4
+ Platform,
5
+ Linking,
6
+ SafeAreaView,
7
+ ActivityIndicator,
8
+ View,
9
+ ToastAndroid,
10
+ StatusBar,
11
11
  } from 'react-native';
12
12
  import { useEffect, useRef, useState } from 'react';
13
13
 
14
- import { type WebViewProps, type WebViewNavigation } from 'react-native-webview';
15
- import { WebViewCallback, type WebViewCallbackFunction } from './utils/webviewCallback';
16
- import { check, PERMISSIONS, request, RESULTS, type Permission } from 'react-native-permissions';
14
+ import {
15
+ type WebViewProps,
16
+ type WebViewNavigation,
17
+ } from 'react-native-webview';
18
+ import {
19
+ WebViewCallback,
20
+ type WebViewCallbackFunction,
21
+ } from './utils/webviewCallback';
22
+ import {
23
+ check,
24
+ PERMISSIONS,
25
+ request,
26
+ RESULTS,
27
+ type Permission,
28
+ } from 'react-native-permissions';
17
29
  import FileViewer from 'react-native-file-viewer';
18
30
  import RNFS from 'react-native-fs';
19
31
  import CookieManager from '@react-native-cookies/cookies';
32
+ import { AnalyticsLogger } from './analytics/analytics_logger';
20
33
 
21
34
  interface ExtendedWebViewProps extends WebViewProps {
22
- onPermissionRequest?: (event: any) => void;
23
- androidPermissions?: {
24
- camera?: boolean;
25
- microphone?: boolean;
26
- geolocation?: boolean;
27
- };
35
+ onPermissionRequest?: (event: any) => void;
36
+ androidPermissions?: {
37
+ camera?: boolean;
38
+ microphone?: boolean;
39
+ geolocation?: boolean;
40
+ };
28
41
  }
29
42
  interface WebViewCustomProps {
30
- url: string;
31
- options?: Partial<ExtendedWebViewProps>;
32
- onCallback?: WebViewCallbackFunction
33
- hostName?: string;
34
- whitelistedUrls?: string[];
35
- onPageFinished?: () => void;
43
+ url: string;
44
+ options?: Partial<ExtendedWebViewProps>;
45
+ onCallback?: WebViewCallbackFunction;
46
+ hostName?: string;
47
+ whitelistedUrls?: string[];
48
+ onPageFinished?: () => void;
36
49
  }
37
50
 
38
51
  export const WebView = ({
39
- url,
40
- options,
41
- onCallback,
42
- hostName,
43
- whitelistedUrls = [],
44
- onPageFinished,
52
+ url,
53
+ options,
54
+ onCallback,
55
+ hostName,
56
+ whitelistedUrls = [],
57
+ onPageFinished,
45
58
  }: WebViewCustomProps) => {
46
- const webviewRef = useRef<RNWebView | null>(null);;
47
- const [canGoBack, setCanGoBack] = useState(false);
48
- // const [hasRedirected, setHasRedirected] = useState(false);
49
- const [, setToast] = useState<{ visible: boolean; message: string } | null>(null);
50
-
51
- const handleExternalUrl = async (url: string) => {
52
- try {
53
- await new Promise(resolve => setTimeout(resolve, 200));
54
- await Linking.openURL(url);
55
- } catch (error) {
56
- // Implement your toast here
57
- if (Platform.OS === 'android') {
58
- ToastAndroid.show("Oops! Something went wrong. Please try again.", ToastAndroid.LONG);
59
- }
60
- console.log('Application not found to open link');
61
- }
62
- };
63
- const showToast_with_code_message = (syntheticEvent: any) => {
64
- const { nativeEvent } = syntheticEvent;
65
- const errorCodesToHandle = [-6, -8, -10];
66
- if (errorCodesToHandle.includes(nativeEvent.code)) {
67
- const message = `WebView Error: [${nativeEvent.code}] ${nativeEvent.description}`;
68
- setToast({ visible: true, message });
69
- if (Platform.OS === 'android') {
70
- ToastAndroid.show("Oops! Something went wrong. Please try again.", ToastAndroid.LONG);
71
- }
72
- setTimeout(() => setToast(null), 5000);
73
- onCallback?.(
74
- WebViewCallback.redirect("WEBVIEW_ERROR")
75
- )
76
- }
77
- };
78
-
79
- const getQueryParam = (url: string, param: string): string | null => {
80
- const match = url.match(new RegExp('[?&]' + param + '=([^&#]*)'));
81
- return match && match[1] ? decodeURIComponent(match[1]) : null;
82
- };
83
-
84
- const downloadAndOpenFile = async (fileUrl: string) => {
85
- try {
86
- console.log('Starting file download...', fileUrl);
87
-
88
- // Get cookies using CookieManager
89
- let cookieString = '';
90
- try {
91
- const cookies = await CookieManager.get(fileUrl);
92
- cookieString = Object.keys(cookies)
93
- .map(key => `${key}=${cookies[key]?.value ?? ''}`)
94
- .join('; ');
95
- } catch (e) {
96
- console.error('Failed to get cookies:', e);
97
- }
98
-
99
- // Create a clean filename from the URL
100
- const timestamp = new Date().getTime();
101
- // Extract only the last part of the path for the filename
102
- const urlParts = fileUrl.split('/');
103
- const lastPart = urlParts[urlParts.length - 1];
104
- const fileExt = lastPart?.split('.').pop() || 'pdf';
105
- const fileName = `${timestamp}.${fileExt}`;
106
-
107
- const downloadPath = Platform.select({
108
- ios: `${RNFS.DocumentDirectoryPath}/${fileName}`,
109
- android: `${RNFS.DownloadDirectoryPath}/${fileName}`
110
- });
111
-
112
- if (!downloadPath) {
113
- throw new Error('Could not determine download path');
114
- }
115
-
116
- console.log('Downloading to:', downloadPath);
117
-
118
- const options = {
119
- fromUrl: fileUrl,
120
- toFile: downloadPath,
121
- headers: {
122
- 'Cookie': cookieString,
123
- 'Accept': 'application/pdf',
124
- 'Content-Type': 'application/pdf'
125
- },
126
- background: true,
127
- begin: (res: any) => {
128
- console.log('Download started with headers:', res);
129
- },
130
-
131
- };
132
-
133
- const response = await RNFS.downloadFile(options).promise;
134
-
135
- if (response.statusCode === 200) {
136
- console.log('File downloaded to:', downloadPath);
137
-
138
- if (Platform.OS === 'android') {
139
- ToastAndroid.show('File downloaded successfully', ToastAndroid.SHORT);
140
- }
141
-
142
- await FileViewer.open(downloadPath, {
143
- showOpenWithDialog: true,
144
- onDismiss: () => {
145
- if (Platform.OS === 'ios') {
146
- RNFS.unlink(downloadPath).catch(console.error);
147
- }
148
- }
149
- });
150
- } else {
151
- throw new Error(`Download failed with status ${response.statusCode}`);
152
- }
153
-
154
- } catch (error) {
155
- console.error('File download/open error:', error);
156
-
157
- }
158
- };
159
-
160
-
161
- const handleOnShouldStartLoadWithRequest = (event: WebViewNavigation) => {
162
- const { url } = event;
163
- console.log('URL:', url);
164
- if (url === 'about:blank' || url === 'about:srcdoc') {
165
- return true;
166
- }
167
-
168
-
169
- if (url?.includes('/session-expired?status=') || url?.includes("/redirect?status=")) {
170
- const status = getQueryParam(url, 'status');
59
+ const webviewRef = useRef<RNWebView | null>(null);
60
+ const [canGoBack, setCanGoBack] = useState(false);
61
+ const _analyticsLogger = new AnalyticsLogger();
62
+ // const [hasRedirected, setHasRedirected] = useState(false);
63
+ const [, setToast] = useState<{ visible: boolean; message: string } | null>(
64
+ null
65
+ );
66
+ const handleExternalUrl = async (url: string) => {
67
+ try {
68
+ await new Promise((resolve) => setTimeout(resolve, 200));
69
+ await Linking.openURL(url);
70
+ // _analyticsLogger.logEvent({ event: 'REACT_NATIVE_OPEN_URL_EXTERNALLY' });
71
+ } catch (error) {
72
+ // Implement your toast here
73
+ if (Platform.OS === 'android') {
74
+ ToastAndroid.show(
75
+ 'Oops! Something went wrong. Please try again.',
76
+ ToastAndroid.LONG
77
+ );
78
+ }
79
+ console.log('Application not found to open link');
80
+ }
81
+ };
82
+ const showToast_with_code_message = (syntheticEvent: any) => {
83
+ const { nativeEvent } = syntheticEvent;
84
+ const errorCodesToHandle = [-6, -8, -10];
85
+ if (errorCodesToHandle.includes(nativeEvent.code)) {
86
+ const message = `WebView Error: [${nativeEvent.code}] ${nativeEvent.description}`;
87
+ setToast({ visible: true, message });
88
+ if (Platform.OS === 'android') {
89
+ ToastAndroid.show(
90
+ 'Oops! Something went wrong. Please try again.',
91
+ ToastAndroid.LONG
92
+ );
93
+ }
94
+ setTimeout(() => setToast(null), 5000);
95
+ onCallback?.(WebViewCallback.redirect('WEBVIEW_ERROR'));
96
+ }
97
+ };
98
+
99
+ const getQueryParam = (url: string, param: string): string | null => {
100
+ const match = url.match(new RegExp('[?&]' + param + '=([^&#]*)'));
101
+ return match && match[1] ? decodeURIComponent(match[1]) : null;
102
+ };
103
+
104
+ const downloadAndOpenFile = async (fileUrl: string) => {
105
+ try {
106
+ console.log('Starting file download...', fileUrl);
107
+
108
+ // Get cookies using CookieManager
109
+ let cookieString = '';
110
+ try {
111
+ const cookies = await CookieManager.get(fileUrl);
112
+ cookieString = Object.keys(cookies)
113
+ .map((key) => `${key}=${cookies[key]?.value ?? ''}`)
114
+ .join('; ');
115
+ } catch (e) {
116
+ console.error('Failed to get cookies:', e);
117
+ }
171
118
 
172
- console.log('Status thrown from webview ', status);
173
- // navigation.pop();
174
- StatusBar.setBackgroundColor('#7E7E7EFF');
175
- onCallback?.(
176
- WebViewCallback.redirect(status ?? undefined)
177
- );
178
- return false;
179
- }
119
+ // Create a clean filename from the URL
120
+ const timestamp = new Date().getTime();
121
+ // Extract only the last part of the path for the filename
122
+ const urlParts = fileUrl.split('/');
123
+ const lastPart = urlParts[urlParts.length - 1];
124
+ const fileExt = lastPart?.split('.').pop() || 'pdf';
125
+ const fileName = `${timestamp}.${fileExt}`;
126
+
127
+ const downloadPath = Platform.select({
128
+ ios: `${RNFS.DocumentDirectoryPath}/${fileName}`,
129
+ android: `${RNFS.DownloadDirectoryPath}/${fileName}`,
130
+ });
131
+
132
+ if (!downloadPath) {
133
+ throw new Error('Could not determine download path');
134
+ }
180
135
 
181
- // Handle whitelisted URLs
182
- const isWhitelisted = whitelistedUrls.some(white => url.includes(white)) ||
183
- (hostName && url.includes(hostName));
184
-
185
- if (!isWhitelisted &&
186
- url &&
187
- url !== 'about:blank' &&
188
- url !== 'about:srcdoc') {
189
- console.log('External URL detected:', url);
190
- handleExternalUrl(url);
191
- return false;
192
- }
193
- if (url.includes('.pdf') ||
194
- url.includes('/statements/') ||
195
- url.includes('/download_statements')
196
- ) {
197
- console.log('File download URL detected:', url);
198
- downloadAndOpenFile(url);
199
- return false;
136
+ console.log('Downloading to:', downloadPath);
137
+
138
+ const options = {
139
+ fromUrl: fileUrl,
140
+ toFile: downloadPath,
141
+ headers: {
142
+ 'Cookie': cookieString,
143
+ 'Accept': 'application/pdf',
144
+ 'Content-Type': 'application/pdf',
145
+ },
146
+ background: true,
147
+ begin: (res: any) => {
148
+ console.log('Download started with headers:', res);
149
+ },
150
+ };
151
+
152
+ const response = await RNFS.downloadFile(options).promise;
153
+
154
+ if (response.statusCode === 200) {
155
+ console.log('File downloaded to:', downloadPath);
156
+
157
+ if (Platform.OS === 'android') {
158
+ ToastAndroid.show('File downloaded successfully', ToastAndroid.SHORT);
200
159
  }
201
160
 
202
- return true;
203
- };
204
-
205
- const handleBackButton = () => {
206
- if (canGoBack && webviewRef.current) {
207
- webviewRef.current.goBack();
208
- return true;
209
- }
210
- return false;
161
+ await FileViewer.open(downloadPath, {
162
+ showOpenWithDialog: true,
163
+ onDismiss: () => {
164
+ if (Platform.OS === 'ios') {
165
+ RNFS.unlink(downloadPath).catch(console.error);
166
+ }
167
+ },
168
+ });
169
+ } else {
170
+ throw new Error(`Download failed with status ${response.statusCode}`);
171
+ }
172
+ } catch (error) {
173
+ console.error('File download/open error:', error);
174
+ }
175
+ };
176
+
177
+ const handleOnShouldStartLoadWithRequest = (event: WebViewNavigation) => {
178
+ const { url } = event;
179
+ console.log('URL:', url);
180
+ if (url === 'about:blank' || url === 'about:srcdoc') {
181
+ return true;
182
+ }
183
+ // _analyticsLogger.logEvent({ event: 'REACT_NATIVE_LOADING_URL ', url });
184
+
185
+ if (
186
+ url?.includes('/session-expired?status=') ||
187
+ url?.includes('/redirect?status=')
188
+ ) {
189
+ console.log('overriding url');
190
+ const status = getQueryParam(url, 'status');
191
+
192
+ console.log('Status thrown from webview ', status);
193
+ // _analyticsLogger.logEvent({
194
+ // event: 'REACT_NATIVE_WEBVIEW_CALLBACK ',
195
+ // status,
196
+ // });
197
+
198
+ StatusBar.setBackgroundColor('#7E7E7EFF');
199
+ onCallback?.(WebViewCallback.redirect(status ?? undefined));
200
+ return false;
201
+ }
202
+
203
+ // Handle whitelisted URLs
204
+ const isWhitelisted =
205
+ whitelistedUrls.some((white) => url.includes(white)) ||
206
+ (hostName && url.includes(hostName));
207
+
208
+ if (
209
+ !isWhitelisted &&
210
+ url &&
211
+ url !== 'about:blank' &&
212
+ url !== 'about:srcdoc'
213
+ ) {
214
+ console.log('External URL detected:', url);
215
+ handleExternalUrl(url);
216
+ return false;
217
+ }
218
+ if (
219
+ url.includes('.pdf') ||
220
+ url.includes('/statements/') ||
221
+ url.includes('/download_statements')
222
+ ) {
223
+ console.log('File download URL detected:', url);
224
+ downloadAndOpenFile(url);
225
+ return false;
226
+ }
227
+
228
+ return true;
229
+ };
230
+
231
+ const handleBackButton = () => {
232
+ if (canGoBack && webviewRef.current) {
233
+ webviewRef.current.goBack();
234
+ return true;
235
+ }
236
+ return false;
237
+ };
238
+
239
+ useEffect(() => {
240
+ const backHandler = BackHandler.addEventListener(
241
+ 'hardwareBackPress',
242
+ handleBackButton
243
+ );
244
+ return () => {
245
+ backHandler.remove();
211
246
  };
247
+ }, [canGoBack]);
212
248
 
213
- useEffect(() => {
214
- const backHandler = BackHandler.addEventListener('hardwareBackPress', handleBackButton);
215
- return () => {
216
- backHandler.remove();
217
- };
218
- }, [canGoBack]);
219
-
220
- const Loading = () => (
221
- <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
222
- <ActivityIndicator size="large" />
223
- </View>
224
- );
249
+ const Loading = () => (
250
+ <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
251
+ <ActivityIndicator size="large" />
252
+ </View>
253
+ );
225
254
 
226
- // Cookie injection script
255
+ // Cookie injection script
227
256
 
228
- const injectedJavaScript = `
257
+ const injectedJavaScript = `
229
258
  window.onerror = function(message, source, lineno, colno, error) {
230
259
  if (message.includes('RATE_LIMIT_USER')) {
231
260
  window.ReactNativeWebView.postMessage(JSON.stringify({
@@ -236,108 +265,119 @@ export const WebView = ({
236
265
  true;
237
266
  `;
238
267
 
239
- const requestPermission = async (permission: Permission) => {
240
- try {
241
- const result = await check(permission);
242
-
243
- if (result === RESULTS.DENIED) {
244
- const requestResult = await request(permission);
245
- return requestResult === RESULTS.GRANTED;
246
- }
247
-
248
- return result === RESULTS.GRANTED;
249
- } catch (error) {
250
- console.error('Permission request failed:', error);
251
- return false;
252
- }
253
- };
254
-
255
- const handlePermissionRequest = async (event: any) => {
256
- const { resources } = event.nativeEvent;
257
- console.log('Permission requested:', resources);
258
-
259
- const permissionsToRequest: Permission[] = [];
268
+ const requestPermission = async (permission: Permission) => {
269
+ try {
270
+ const result = await check(permission);
260
271
 
261
- if (resources.includes('video')) {
262
- permissionsToRequest.push(
263
- Platform.OS === 'ios'
264
- ? PERMISSIONS.IOS.CAMERA
265
- : PERMISSIONS.ANDROID.CAMERA
266
- );
267
- }
268
- if (resources.includes('microphone')) {
269
- permissionsToRequest.push(
270
- Platform.OS === 'ios'
271
- ? PERMISSIONS.IOS.MICROPHONE
272
- : PERMISSIONS.ANDROID.RECORD_AUDIO
273
- );
274
- }
275
- if (resources.includes('geolocation')) {
276
- permissionsToRequest.push(
277
- Platform.OS === 'ios'
278
- ? PERMISSIONS.IOS.LOCATION_WHEN_IN_USE
279
- : PERMISSIONS.ANDROID.ACCESS_FINE_LOCATION
280
- );
281
- }
272
+ if (result === RESULTS.DENIED) {
273
+ const requestResult = await request(permission);
274
+ return requestResult === RESULTS.GRANTED;
275
+ }
282
276
 
283
- try {
284
- const results = await Promise.all(
285
- permissionsToRequest.map(permission => requestPermission(permission))
286
- );
287
-
288
- const granted = results.every(result => result === true);
289
- if (granted) {
290
- // @ts-ignore - grant exists on the event
291
- event.nativeEvent.grant();
292
- } else {
293
- // @ts-ignore - deny exists on the event
294
- event.nativeEvent.deny();
295
- }
296
- } catch (error) {
297
- console.error('Permission handling failed:', error);
298
- // @ts-ignore - deny exists on the event
299
- event.nativeEvent.deny();
277
+ return result === RESULTS.GRANTED;
278
+ } catch (error) {
279
+ console.error('Permission request failed:', error);
280
+ return false;
281
+ }
282
+ };
283
+
284
+ const handlePermissionRequest = async (event: any) => {
285
+ const { resources } = event.nativeEvent;
286
+ console.log('Permission requested:', resources);
287
+
288
+ const permissionsToRequest: Permission[] = [];
289
+
290
+ if (resources.includes('video')) {
291
+ permissionsToRequest.push(
292
+ Platform.OS === 'ios'
293
+ ? PERMISSIONS.IOS.CAMERA
294
+ : PERMISSIONS.ANDROID.CAMERA
295
+ );
296
+ }
297
+ if (resources.includes('microphone')) {
298
+ permissionsToRequest.push(
299
+ Platform.OS === 'ios'
300
+ ? PERMISSIONS.IOS.MICROPHONE
301
+ : PERMISSIONS.ANDROID.RECORD_AUDIO
302
+ );
303
+ }
304
+ if (resources.includes('geolocation')) {
305
+ permissionsToRequest.push(
306
+ Platform.OS === 'ios'
307
+ ? PERMISSIONS.IOS.LOCATION_WHEN_IN_USE
308
+ : PERMISSIONS.ANDROID.ACCESS_FINE_LOCATION
309
+ );
310
+ }
311
+
312
+ try {
313
+ const results = await Promise.all(
314
+ permissionsToRequest.map((permission) => requestPermission(permission))
315
+ );
316
+
317
+ const granted = results.every((result) => result === true);
318
+ if (granted) {
319
+ // @ts-ignore - grant exists on the event
320
+ event.nativeEvent.grant();
321
+ } else {
322
+ // @ts-ignore - deny exists on the event
323
+ event.nativeEvent.deny();
324
+ }
325
+ } catch (error) {
326
+ console.error('Permission handling failed:', error);
327
+ // @ts-ignore - deny exists on the event
328
+ event.nativeEvent.deny();
329
+ }
330
+ };
331
+
332
+ const handleWebViewLoadEnd = (syntheticEvent: any) => {
333
+ const loadedUrl = syntheticEvent?.nativeEvent?.url || url;
334
+ // _analyticsLogger.logEvent({
335
+ // event: 'REACT_NATIVE_WEBVIEW_LOADED',
336
+ // url: loadedUrl,
337
+ // });
338
+
339
+ onPageFinished?.();
340
+ };
341
+
342
+ return (
343
+ <SafeAreaView style={{ flex: 1, backgroundColor: 'white' }}>
344
+ <RNWebView
345
+ ref={webviewRef}
346
+ source={{ uri: url }}
347
+ onPermissionRequest={
348
+ handlePermissionRequest as ExtendedWebViewProps['onPermissionRequest']
300
349
  }
301
- };
302
-
303
-
304
- return (
305
- <SafeAreaView style={{ flex: 1, backgroundColor: 'white' }}>
306
- <RNWebView
307
- ref={webviewRef}
308
- source={{
309
- uri: url,
310
-
311
- }}
312
- onPermissionRequest={handlePermissionRequest as ExtendedWebViewProps['onPermissionRequest']}
313
- geolocationEnabled={true}
314
- androidPermissions={{
315
- camera: true,
316
- microphone: true,
317
- geolocation: true
318
- }}
319
- onError={showToast_with_code_message}
320
- startInLoadingState={true}
321
- renderLoading={() => <Loading />}
322
- onLoadEnd={onPageFinished}
323
- originWhitelist={['*']}
324
- javaScriptEnabled={true}
325
- domStorageEnabled={true}
326
- mediaPlaybackRequiresUserAction={false}
327
- allowsInlineMediaPlayback={true}
328
- onShouldStartLoadWithRequest={handleOnShouldStartLoadWithRequest}
329
- onNavigationStateChange={(navState) => {
330
- setCanGoBack(navState.canGoBack);
331
- }}
332
- injectedJavaScript={injectedJavaScript}
333
- decelerationRate={Platform.OS === 'ios' ? 'normal' : 0.9}
334
- allowsBackForwardNavigationGestures={Platform.OS === 'ios'}
335
- sharedCookiesEnabled={true}
336
- setSupportMultipleWindows={false}
337
- mixedContentMode="always"
338
- allowsLinkPreview={true}
339
- {...options}
340
- />
341
- </SafeAreaView>
342
- );
343
- };
350
+ geolocationEnabled={true}
351
+ androidPermissions={{
352
+ camera: true,
353
+ microphone: true,
354
+ geolocation: true,
355
+ }}
356
+ onError={(e) => {
357
+ showToast_with_code_message(e);
358
+ options?.onError?.(e as any);
359
+ }}
360
+ {...options}
361
+ startInLoadingState={true}
362
+ renderLoading={() => <Loading />}
363
+ onLoadEnd={handleWebViewLoadEnd}
364
+ originWhitelist={['*']}
365
+ javaScriptEnabled={true}
366
+ domStorageEnabled={true}
367
+ mediaPlaybackRequiresUserAction={false}
368
+ allowsInlineMediaPlayback={true}
369
+ onShouldStartLoadWithRequest={handleOnShouldStartLoadWithRequest}
370
+ onNavigationStateChange={(navState) => {
371
+ setCanGoBack(navState.canGoBack);
372
+ }}
373
+ injectedJavaScript={injectedJavaScript}
374
+ decelerationRate={Platform.OS === 'ios' ? 'normal' : 0.9}
375
+ allowsBackForwardNavigationGestures={Platform.OS === 'ios'}
376
+ sharedCookiesEnabled={true}
377
+ setSupportMultipleWindows={false}
378
+ mixedContentMode="always"
379
+ allowsLinkPreview={true}
380
+ />
381
+ </SafeAreaView>
382
+ );
383
+ };