@onairos/react-native 3.0.26 → 3.0.27

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 (33) hide show
  1. package/lib/commonjs/components/TrainingModal.js +16 -120
  2. package/lib/commonjs/components/TrainingModal.js.map +1 -1
  3. package/lib/commonjs/components/UniversalOnboarding.js +98 -186
  4. package/lib/commonjs/components/UniversalOnboarding.js.map +1 -1
  5. package/lib/commonjs/components/onboarding/OAuthWebView.js +49 -124
  6. package/lib/commonjs/components/onboarding/OAuthWebView.js.map +1 -1
  7. package/lib/commonjs/constants/index.js +3 -3
  8. package/lib/commonjs/constants/index.js.map +1 -1
  9. package/lib/commonjs/services/platformAuthService.js +81 -99
  10. package/lib/commonjs/services/platformAuthService.js.map +1 -1
  11. package/lib/module/components/TrainingModal.js +17 -120
  12. package/lib/module/components/TrainingModal.js.map +1 -1
  13. package/lib/module/components/UniversalOnboarding.js +99 -187
  14. package/lib/module/components/UniversalOnboarding.js.map +1 -1
  15. package/lib/module/components/onboarding/OAuthWebView.js +50 -125
  16. package/lib/module/components/onboarding/OAuthWebView.js.map +1 -1
  17. package/lib/module/constants/index.js +3 -3
  18. package/lib/module/constants/index.js.map +1 -1
  19. package/lib/module/index.js +9 -10
  20. package/lib/module/index.js.map +1 -1
  21. package/lib/module/services/platformAuthService.js +80 -97
  22. package/lib/module/services/platformAuthService.js.map +1 -1
  23. package/lib/typescript/components/TrainingModal.d.ts.map +1 -1
  24. package/lib/typescript/components/UniversalOnboarding.d.ts.map +1 -1
  25. package/lib/typescript/components/onboarding/OAuthWebView.d.ts.map +1 -1
  26. package/lib/typescript/services/platformAuthService.d.ts +5 -11
  27. package/lib/typescript/services/platformAuthService.d.ts.map +1 -1
  28. package/package.json +1 -1
  29. package/src/components/TrainingModal.tsx +61 -202
  30. package/src/components/UniversalOnboarding.tsx +86 -179
  31. package/src/components/onboarding/OAuthWebView.tsx +59 -121
  32. package/src/constants/index.ts +3 -3
  33. package/src/services/platformAuthService.ts +80 -115
@@ -15,7 +15,6 @@ import {
15
15
  Image,
16
16
  Switch,
17
17
  Linking,
18
- Alert,
19
18
  } from 'react-native';
20
19
  import Icon from 'react-native-vector-icons/MaterialIcons';
21
20
  import { PlatformList } from './PlatformList';
@@ -53,9 +52,8 @@ export const UniversalOnboarding: React.FC<UniversalOnboardingProps> = ({
53
52
  const [platformToggles, setPlatformToggles] = useState<{[key: string]: boolean}>({});
54
53
  const [oauthUrl, setOauthUrl] = useState<string>('');
55
54
  const [currentPlatform, setCurrentPlatform] = useState<string>('');
56
- const [userEmail, setUserEmail] = useState<string>('user@example.com'); // Use proper email instead of random username
55
+ const [username, setUsername] = useState<string>('Avatar');
57
56
  const [isConnectingPlatform, setIsConnectingPlatform] = useState<boolean>(false);
58
- const [connectingPlatform, setConnectingPlatform] = useState<string | null>(null);
59
57
 
60
58
  const platforms = [
61
59
  { id: 'instagram', name: 'Instagram', icon: require('../assets/images/instagram.png') },
@@ -158,8 +156,50 @@ export const UniversalOnboarding: React.FC<UniversalOnboardingProps> = ({
158
156
  }, [getConnectionStatus]);
159
157
 
160
158
  const togglePlatform = useCallback(async (platformId: string) => {
161
- // Check if already connected or connecting
162
- if (connections[platformId]?.connected) {
159
+ if (!platformToggles[platformId]) {
160
+ // Attempt to connect platform
161
+ try {
162
+ setIsConnectingPlatform(true);
163
+ console.log(`Initiating connection for ${platformId}`);
164
+
165
+ // Check if platform has a native SDK
166
+ if (hasNativeSDK(platformId)) {
167
+ console.log(`Using native SDK for ${platformId}`);
168
+ // Use native SDK for authentication
169
+ const success = await initiateNativeAuth(platformId);
170
+ if (success) {
171
+ console.log(`Native authentication successful for ${platformId}`);
172
+ // Update platform toggle state
173
+ setPlatformToggles(prev => ({
174
+ ...prev,
175
+ [platformId]: true
176
+ }));
177
+
178
+ // Update connections state
179
+ setConnections(prev => ({
180
+ ...prev,
181
+ [platformId]: { userName: username, connected: true }
182
+ }));
183
+ }
184
+ } else {
185
+ console.log(`Initiating OAuth flow for ${platformId}`);
186
+ // Use OAuth flow through proxy server
187
+ const oauthUrl = await initiateOAuth(platformId, username, AppName);
188
+ if (oauthUrl) {
189
+ console.log(`Received OAuth URL for ${platformId}: ${oauthUrl}`);
190
+ setCurrentPlatform(platformId);
191
+ setOauthUrl(oauthUrl);
192
+ setStep('oauth');
193
+ } else {
194
+ console.error(`No OAuth URL returned for ${platformId}`);
195
+ }
196
+ }
197
+ } catch (error) {
198
+ console.error(`Error connecting ${platformId}:`, error);
199
+ } finally {
200
+ setIsConnectingPlatform(false);
201
+ }
202
+ } else {
163
203
  // Disconnect platform
164
204
  console.log(`Disconnecting ${platformId}`);
165
205
  setPlatformToggles(prev => ({
@@ -173,70 +213,8 @@ export const UniversalOnboarding: React.FC<UniversalOnboardingProps> = ({
173
213
  delete newConnections[platformId];
174
214
  return newConnections;
175
215
  });
176
- return;
177
- }
178
-
179
- if (connectingPlatform === platformId) {
180
- console.log(`Already connecting to ${platformId}, ignoring...`);
181
- return;
182
216
  }
183
-
184
- // Attempt to connect platform
185
- try {
186
- setIsConnectingPlatform(true);
187
- setConnectingPlatform(platformId);
188
- console.log(`[OAuth] Initiating connection for ${platformId} with email: ${userEmail}`);
189
-
190
- // Check if platform has a native SDK
191
- if (hasNativeSDK(platformId)) {
192
- console.log(`[OAuth] Using native SDK for ${platformId}`);
193
- // Use native SDK for authentication
194
- const success = await initiateNativeAuth(platformId);
195
- if (success) {
196
- console.log(`[OAuth] Native authentication successful for ${platformId}`);
197
- // Update platform toggle state
198
- setPlatformToggles(prev => ({
199
- ...prev,
200
- [platformId]: true
201
- }));
202
-
203
- // Update connections state
204
- setConnections(prev => ({
205
- ...prev,
206
- [platformId]: { userName: userEmail, connected: true }
207
- }));
208
- }
209
- } else {
210
- console.log(`[OAuth] Initiating OAuth flow for ${platformId}`);
211
- console.log(`[OAuth] Making request to: https://api2.onairos.uk/${platformId}/authorize`);
212
-
213
- // Use OAuth flow through proxy server
214
- const oauthUrl = await initiateOAuth(platformId, userEmail);
215
- if (oauthUrl) {
216
- console.log(`[OAuth] Received OAuth URL for ${platformId}: ${oauthUrl}`);
217
- setCurrentPlatform(platformId);
218
- setOauthUrl(oauthUrl);
219
- setStep('oauth');
220
- } else {
221
- console.error(`[OAuth] No OAuth URL returned for ${platformId}`);
222
- throw new Error(`No OAuth URL returned for ${platformId}`);
223
- }
224
- }
225
- } catch (error) {
226
- console.error(`[OAuth] Error connecting ${platformId}:`, error);
227
- // Reset toggle state on error
228
- setPlatformToggles(prev => ({
229
- ...prev,
230
- [platformId]: false
231
- }));
232
-
233
- // Show error to user
234
- Alert.alert('Connection Error', `Failed to connect to ${platformId}. Please try again.`);
235
- } finally {
236
- setIsConnectingPlatform(false);
237
- setConnectingPlatform(null);
238
- }
239
- }, [platformToggles, userEmail, connections, connectingPlatform]);
217
+ }, [platformToggles, username]);
240
218
 
241
219
  /**
242
220
  * Handles OAuth callback URLs
@@ -252,7 +230,7 @@ export const UniversalOnboarding: React.FC<UniversalOnboardingProps> = ({
252
230
  // Update connections state
253
231
  setConnections(prev => ({
254
232
  ...prev,
255
- [platform]: { userName: userEmail, connected: true }
233
+ [platform]: { userName: username, connected: true }
256
234
  }));
257
235
 
258
236
  // Update platform toggles
@@ -267,7 +245,7 @@ export const UniversalOnboarding: React.FC<UniversalOnboardingProps> = ({
267
245
  } catch (error) {
268
246
  console.error('Error handling OAuth callback:', error);
269
247
  }
270
- }, [currentPlatform, userEmail]);
248
+ }, [currentPlatform, username]);
271
249
 
272
250
  /**
273
251
  * Handles completion of the OAuth flow
@@ -275,13 +253,13 @@ export const UniversalOnboarding: React.FC<UniversalOnboardingProps> = ({
275
253
  const handleOAuthSuccess = useCallback((code: string) => {
276
254
  console.log(`OAuth success for ${currentPlatform} with code: ${code}`);
277
255
 
278
- // Update connections for the current platform
279
- if (currentPlatform) {
280
- // Update connections state
281
- setConnections(prev => ({
282
- ...prev,
283
- [currentPlatform]: { userName: userEmail, connected: true }
284
- }));
256
+ // Update connections for the current platform
257
+ if (currentPlatform) {
258
+ // Update connections state
259
+ setConnections(prev => ({
260
+ ...prev,
261
+ [currentPlatform]: { userName: username, connected: true }
262
+ }));
285
263
 
286
264
  // Update platform toggles
287
265
  setPlatformToggles(prev => ({
@@ -289,20 +267,14 @@ export const UniversalOnboarding: React.FC<UniversalOnboardingProps> = ({
289
267
  [currentPlatform]: true
290
268
  }));
291
269
 
292
- // In a real implementation, we would send the code to our server
293
- // to exchange it for an access token and store it securely
294
- console.log(`Simulating token exchange for ${currentPlatform}`);
295
-
296
- // For demo purposes, we'll just simulate a successful token exchange
297
- if (debug || test) {
298
- console.log('Debug mode: Simulating successful token exchange');
299
- }
270
+ console.log(`Successfully connected ${currentPlatform} for user ${username}`);
300
271
  }
301
272
 
302
273
  // Close OAuth window and return to connect step
303
274
  setOauthUrl('');
275
+ setCurrentPlatform('');
304
276
  setStep('connect');
305
- }, [currentPlatform, userEmail, debug, test]);
277
+ }, [currentPlatform, username]);
306
278
 
307
279
  const handlePinSubmit = useCallback(async (userPin: string) => {
308
280
  setPin(userPin);
@@ -310,16 +282,23 @@ export const UniversalOnboarding: React.FC<UniversalOnboardingProps> = ({
310
282
  // Simulate training progress over 10 seconds
311
283
  let progress = 0;
312
284
  const interval = setInterval(() => {
313
- progress += 1; // 10% progress every second for 1 seconds total
285
+ progress += 0.1; // 10% every second for 10 seconds total
314
286
  setTraining({
315
287
  progress,
316
288
  eta: `${Math.round((1 - progress) * 10)} seconds remaining`,
317
289
  });
318
290
  if (progress >= 1) {
319
291
  clearInterval(interval);
320
- // Training complete - TrainingModal will handle email input and final completion
292
+ // Close overlay and call the original onResolved callback
293
+ onComplete('https://api2.onairos.uk', 'dummy-token', {
294
+ pin: userPin,
295
+ connections,
296
+ platformToggles,
297
+ selectedTier,
298
+ tierData: requestData?.[selectedTier],
299
+ });
321
300
  }
322
- }, 1000); // 1 second intervals for 10 total seconds
301
+ }, 1000); // Update every 1 second
323
302
  }, [connections, onComplete, selectedTier, requestData, platformToggles]);
324
303
 
325
304
  const canProceedToPin = useCallback(() => {
@@ -372,20 +351,13 @@ export const UniversalOnboarding: React.FC<UniversalOnboardingProps> = ({
372
351
  <Text style={styles.onairosIconText}>O</Text>
373
352
  </View>
374
353
  </View>
375
- <Text style={styles.headerDescription}>
376
- Generate insights from your data to send to {AppName}
377
- </Text>
378
354
  </View>
379
355
 
380
- <ScrollView
381
- style={styles.content}
382
- contentContainerStyle={styles.contentContainer}
383
- showsVerticalScrollIndicator={false}
384
- >
356
+ <ScrollView style={styles.content}>
385
357
  {/* Main title and description */}
386
358
  <View style={styles.titleContainer}>
387
359
  <Text style={styles.mainTitle}>
388
- Connect your data to create a Persona of you
360
+ Connect your data to create a Persona of you, to connect to Cosmos
389
361
  </Text>
390
362
  <Text style={styles.privacyMessage}>
391
363
  None of your app data is shared with ANYONE
@@ -395,41 +367,23 @@ export const UniversalOnboarding: React.FC<UniversalOnboardingProps> = ({
395
367
  {/* Platform connection options */}
396
368
  <View style={styles.platformsContainer}>
397
369
  {platforms.map((platform) => (
398
- <View key={platform.id} style={[
399
- styles.platformItem,
400
- connections[platform.id]?.connected && styles.platformItemConnected
401
- ]}>
370
+ <View key={platform.id} style={styles.platformItem}>
402
371
  <View style={styles.platformInfo}>
403
372
  <Image
404
373
  source={platform.icon}
405
374
  style={styles.platformIcon}
406
375
  resizeMode="contain"
407
376
  />
408
- <View style={styles.platformTextContainer}>
409
- <Text style={styles.platformName}>
410
- {platform.name}
411
- </Text>
412
- {connections[platform.id]?.connected && (
413
- <Text style={styles.connectedText}>Connected</Text>
414
- )}
415
- {connectingPlatform === platform.id && (
416
- <Text style={styles.connectingText}>Connecting...</Text>
417
- )}
418
- </View>
419
- </View>
420
- <View style={styles.platformActions}>
421
- {connectingPlatform === platform.id ? (
422
- <ActivityIndicator size="small" color={COLORS.primary} />
423
- ) : (
424
- <Switch
425
- value={platformToggles[platform.id] || connections[platform.id]?.connected || false}
426
- onValueChange={() => togglePlatform(platform.id)}
427
- trackColor={{ false: '#767577', true: '#4CAF50' }}
428
- thumbColor={platformToggles[platform.id] || connections[platform.id]?.connected ? '#4CAF50' : '#f4f3f4'}
429
- disabled={connectingPlatform !== null}
430
- />
431
- )}
377
+ <Text style={styles.platformName}>
378
+ {platform.name}
379
+ </Text>
432
380
  </View>
381
+ <Switch
382
+ value={platformToggles[platform.id]}
383
+ onValueChange={() => togglePlatform(platform.id)}
384
+ trackColor={{ false: '#767577', true: '#81b0ff' }}
385
+ thumbColor={platformToggles[platform.id] ? '#2196F3' : '#f4f3f4'}
386
+ />
433
387
  </View>
434
388
  ))}
435
389
  </View>
@@ -480,11 +434,10 @@ export const UniversalOnboarding: React.FC<UniversalOnboardingProps> = ({
480
434
  platformToggles,
481
435
  selectedTier,
482
436
  tierData: requestData?.[selectedTier],
483
- userEmail,
484
437
  });
485
438
  }}
486
439
  modelKey="onairosTrainingModel"
487
- username={userEmail}
440
+ username={username}
488
441
  />
489
442
  )}
490
443
 
@@ -519,7 +472,7 @@ const styles = StyleSheet.create({
519
472
  bottomSheet: {
520
473
  backgroundColor: '#fff',
521
474
  width: width,
522
- height: height * 0.85,
475
+ height: height * 0.6,
523
476
  borderTopLeftRadius: 24,
524
477
  borderTopRightRadius: 24,
525
478
  overflow: 'hidden',
@@ -541,12 +494,8 @@ const styles = StyleSheet.create({
541
494
  backgroundColor: '#E0E0E0',
542
495
  },
543
496
  header: {
544
- paddingHorizontal: 24,
545
- paddingTop: 16,
546
- paddingBottom: 8,
497
+ padding: 24,
547
498
  alignItems: 'center',
548
- borderBottomWidth: 1,
549
- borderBottomColor: '#F0F0F0',
550
499
  },
551
500
  headerContent: {
552
501
  flexDirection: 'row',
@@ -581,13 +530,6 @@ const styles = StyleSheet.create({
581
530
  fontSize: 24,
582
531
  color: '#000',
583
532
  },
584
- headerDescription: {
585
- fontSize: 14,
586
- color: '#666',
587
- textAlign: 'center',
588
- marginTop: 12,
589
- paddingHorizontal: 16,
590
- },
591
533
  titleContainer: {
592
534
  marginBottom: 30,
593
535
  },
@@ -606,10 +548,7 @@ const styles = StyleSheet.create({
606
548
  },
607
549
  content: {
608
550
  flex: 1,
609
- },
610
- contentContainer: {
611
551
  paddingHorizontal: 24,
612
- paddingBottom: 20,
613
552
  },
614
553
  platformsContainer: {
615
554
  marginTop: 16,
@@ -620,18 +559,10 @@ const styles = StyleSheet.create({
620
559
  alignItems: 'center',
621
560
  padding: 16,
622
561
  backgroundColor: '#fff',
623
- borderRadius: 12,
624
- marginBottom: 12,
562
+ borderRadius: 16,
563
+ marginBottom: 16,
625
564
  borderWidth: 1,
626
- borderColor: '#E0E0E0',
627
- shadowColor: '#000',
628
- shadowOffset: {
629
- width: 0,
630
- height: 1,
631
- },
632
- shadowOpacity: 0.05,
633
- shadowRadius: 2,
634
- elevation: 1,
565
+ borderColor: '#eee',
635
566
  },
636
567
  platformInfo: {
637
568
  flexDirection: 'row',
@@ -647,30 +578,6 @@ const styles = StyleSheet.create({
647
578
  fontWeight: '500',
648
579
  color: '#000',
649
580
  },
650
- platformTextContainer: {
651
- flex: 1,
652
- },
653
- connectedText: {
654
- fontSize: 12,
655
- color: '#4CAF50',
656
- fontWeight: '500',
657
- marginTop: 2,
658
- },
659
- connectingText: {
660
- fontSize: 12,
661
- color: '#FF9800',
662
- fontWeight: '500',
663
- marginTop: 2,
664
- },
665
- platformActions: {
666
- alignItems: 'center',
667
- justifyContent: 'center',
668
- },
669
- platformItemConnected: {
670
- backgroundColor: '#F8F9FA',
671
- borderColor: '#4CAF50',
672
- borderWidth: 1,
673
- },
674
581
  footer: {
675
582
  flexDirection: 'row',
676
583
  alignItems: 'center',
@@ -1,9 +1,8 @@
1
1
  import React, { useCallback, useState } from 'react';
2
- import { View, StyleSheet, ActivityIndicator, SafeAreaView, TouchableOpacity, Text } from 'react-native';
2
+ import { View, StyleSheet, ActivityIndicator, SafeAreaView, TouchableOpacity } from 'react-native';
3
3
  import { WebView, WebViewNavigation } from 'react-native-webview';
4
4
  import Icon from 'react-native-vector-icons/MaterialIcons';
5
5
  import { COLORS } from '../../constants';
6
- import { isOAuthSuccess, handleOAuthCallback } from '../../services/platformAuthService';
7
6
  import type { OAuthWebViewProps } from '../../types';
8
7
 
9
8
  export const OAuthWebView: React.FC<OAuthWebViewProps> = ({
@@ -14,56 +13,47 @@ export const OAuthWebView: React.FC<OAuthWebViewProps> = ({
14
13
  onSuccess,
15
14
  }) => {
16
15
  const [loading, setLoading] = useState(true);
17
- const [currentUrl, setCurrentUrl] = useState(url);
18
16
 
19
17
  const handleNavigationStateChange = useCallback(
20
18
  (navState: WebViewNavigation) => {
21
- console.log(`[OAuthWebView] Navigation state changed for ${platform}:`, navState.url);
22
- setCurrentUrl(navState.url);
19
+ console.log('Navigation state changed:', navState.url);
23
20
 
24
- // Check for final redirect to onairos.uk/Home (indicates proxy has processed the callback)
25
- if (navState.url.includes('onairos.uk/Home')) {
26
- console.log(`[OAuthWebView] Detected final redirect to onairos.uk/Home for ${platform}`);
27
-
28
- // Add a small delay to ensure the redirect is fully processed
29
- setTimeout(() => {
30
- onSuccess('success');
31
- if (onComplete) {
32
- onComplete();
33
- }
34
- }, 500);
35
- return;
36
- }
21
+ // Check for the final redirect to onairos.uk/Home
22
+ const isFinalRedirect = navState.url.includes('onairos.uk/Home');
37
23
 
38
- // Check for platform-specific success patterns using the service
39
- if (platform && isOAuthSuccess(navState.url, platform)) {
40
- console.log(`[OAuthWebView] Detected platform-specific success pattern for ${platform}`);
41
-
42
- // For YouTube/Google, wait for the final redirect
43
- if (platform === 'youtube') {
44
- console.log(`[OAuthWebView] YouTube success detected, waiting for final redirect...`);
45
- // Don't close immediately for YouTube, wait for the onairos.uk/Home redirect
46
- return;
47
- }
48
-
49
- // For other platforms, close immediately
50
- setTimeout(() => {
51
- onSuccess('success');
52
- if (onComplete) {
53
- onComplete();
54
- }
55
- }, 300);
56
- return;
57
- }
24
+ // Check for Instagram-specific success patterns
25
+ const isInstagramSuccess = (
26
+ platform === 'instagram' &&
27
+ (navState.url.includes('instagram.com/oauth/authorize') ||
28
+ navState.url.includes('instagram.com/accounts/login') ||
29
+ navState.url.includes('code='))
30
+ );
31
+
32
+ // Check for platform-specific success patterns
33
+ const isYouTubeSuccess = (
34
+ platform === 'youtube' &&
35
+ navState.url.includes('accounts.google.com/o/oauth2/approval')
36
+ );
37
+
38
+ const isLinkedInSuccess = (
39
+ platform === 'linkedin' &&
40
+ navState.url.includes('linkedin.com/oauth/v2/authorization/success')
41
+ );
58
42
 
59
43
  // Check for callback URLs with authorization codes
60
- if (navState.url.includes('/callback') || navState.url.includes('code=')) {
61
- console.log(`[OAuthWebView] Detected callback URL for ${platform}:`, navState.url);
62
-
44
+ const isCallbackUrl = navState.url.includes('/callback') || navState.url.includes('code=');
45
+
46
+ // If we detect success, close the window and update connection status
47
+ if (isFinalRedirect || isInstagramSuccess || isYouTubeSuccess || isLinkedInSuccess) {
48
+ onSuccess('success');
49
+ if (onComplete) {
50
+ onComplete();
51
+ }
52
+ return;
53
+ } else if (isCallbackUrl) {
63
54
  // Extract the authorization code
64
- const authCode = handleOAuthCallback(navState.url);
55
+ const authCode = extractAuthCode(navState.url);
65
56
  if (authCode) {
66
- console.log(`[OAuthWebView] Extracted auth code for ${platform}:`, authCode);
67
57
  onSuccess(authCode);
68
58
  if (onComplete) {
69
59
  onComplete();
@@ -75,22 +65,27 @@ export const OAuthWebView: React.FC<OAuthWebViewProps> = ({
75
65
  [platform, onComplete, onSuccess]
76
66
  );
77
67
 
78
- const handleLoadStart = useCallback(() => {
79
- setLoading(true);
80
- }, []);
81
-
82
68
  const handleLoadEnd = useCallback(() => {
83
69
  setLoading(false);
84
70
  }, []);
85
71
 
86
- const handleError = useCallback((syntheticEvent: any) => {
87
- const { nativeEvent } = syntheticEvent;
88
- console.error(`[OAuthWebView] WebView error for ${platform}:`, nativeEvent);
89
- setLoading(false);
90
- }, [platform]);
91
-
92
- // Get iOS Safari user agent for better compatibility
93
- const userAgent = 'Mozilla/5.0 (iPhone; CPU iPhone OS 15_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.0 Mobile/15E148 Safari/604.1';
72
+ // Extract auth code from redirect URL
73
+ const extractAuthCode = (redirectUrl: string): string => {
74
+ try {
75
+ // First try to extract code from URL parameters
76
+ const codeMatch = redirectUrl.match(/code=([^&]+)/);
77
+ if (codeMatch && codeMatch[1]) {
78
+ return codeMatch[1];
79
+ }
80
+
81
+ // If that fails, try parsing as URL
82
+ const url = new URL(redirectUrl);
83
+ return url.searchParams.get('code') || '';
84
+ } catch (error) {
85
+ console.error('Error extracting auth code:', error);
86
+ return '';
87
+ }
88
+ };
94
89
 
95
90
  return (
96
91
  <SafeAreaView style={styles.container}>
@@ -104,56 +99,31 @@ export const OAuthWebView: React.FC<OAuthWebViewProps> = ({
104
99
  size={20}
105
100
  color={getPlatformColor(platform || 'default')}
106
101
  />
107
- <Text style={styles.platformTitle}>
108
- Connect {platform ? platform.charAt(0).toUpperCase() + platform.slice(1) : 'Account'}
109
- </Text>
110
102
  </View>
111
- <View style={styles.placeholder} />
112
103
  </View>
113
104
 
114
105
  <WebView
115
106
  source={{ uri: url }}
116
107
  onNavigationStateChange={handleNavigationStateChange}
117
- onLoadStart={handleLoadStart}
118
108
  onLoadEnd={handleLoadEnd}
119
- onError={handleError}
120
109
  startInLoadingState={true}
121
110
  renderLoading={() => <View />}
122
111
  style={styles.webView}
123
- // Essential WebView configuration for OAuth
124
112
  javaScriptEnabled={true}
125
113
  domStorageEnabled={true}
126
- cacheEnabled={true}
127
- incognito={false} // Allow session persistence
128
- sharedCookiesEnabled={true} // Critical for Google/YouTube OAuth
129
- thirdPartyCookiesEnabled={true} // Required for OAuth flows
130
- userAgent={userAgent} // iOS Safari for better compatibility
131
- // Additional settings for better OAuth support
114
+ cacheEnabled={false}
115
+ incognito={false}
116
+ sharedCookiesEnabled={true}
117
+ thirdPartyCookiesEnabled={true}
132
118
  allowsInlineMediaPlayback={true}
133
119
  mediaPlaybackRequiresUserAction={false}
134
120
  allowsBackForwardNavigationGestures={true}
135
- // Security settings
136
- allowsLinkPreview={false}
137
- allowFileAccess={false}
138
- allowUniversalAccessFromFileURLs={false}
139
- mixedContentMode="compatibility"
121
+ userAgent="Mozilla/5.0 (iPhone; CPU iPhone OS 14_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.0 Mobile/15E148 Safari/604.1"
140
122
  />
141
123
 
142
124
  {loading && (
143
125
  <View style={styles.loadingContainer}>
144
126
  <ActivityIndicator size="large" color={COLORS.primary} />
145
- <Text style={styles.loadingText}>
146
- Connecting to {platform ? platform.charAt(0).toUpperCase() + platform.slice(1) : 'platform'}...
147
- </Text>
148
- </View>
149
- )}
150
-
151
- {/* Debug info in development */}
152
- {__DEV__ && (
153
- <View style={styles.debugContainer}>
154
- <Text style={styles.debugText} numberOfLines={1}>
155
- {currentUrl}
156
- </Text>
157
127
  </View>
158
128
  )}
159
129
  </SafeAreaView>
@@ -173,8 +143,6 @@ const getPlatformIcon = (platform: string): string => {
173
143
  return 'push-pin';
174
144
  case 'reddit':
175
145
  return 'forum';
176
- case 'email':
177
- return 'email';
178
146
  default:
179
147
  return 'link';
180
148
  }
@@ -193,8 +161,6 @@ const getPlatformColor = (platform: string): string => {
193
161
  return '#E60023';
194
162
  case 'reddit':
195
163
  return '#FF4500';
196
- case 'email':
197
- return '#4285F4';
198
164
  default:
199
165
  return COLORS.primary;
200
166
  }
@@ -216,49 +182,21 @@ const styles = StyleSheet.create({
216
182
  },
217
183
  titleContainer: {
218
184
  flex: 1,
219
- flexDirection: 'row',
220
185
  alignItems: 'center',
221
- justifyContent: 'center',
222
- },
223
- platformTitle: {
224
- fontSize: 16,
225
- fontWeight: '600',
226
- color: '#000',
227
- marginLeft: 8,
228
186
  },
229
187
  closeButton: {
230
188
  padding: 8,
231
- width: 40,
232
- },
233
- placeholder: {
234
- width: 40,
189
+ position: 'absolute',
190
+ left: 16,
191
+ zIndex: 10,
235
192
  },
236
193
  webView: {
237
194
  flex: 1,
238
195
  },
239
196
  loadingContainer: {
240
197
  ...StyleSheet.absoluteFillObject,
241
- backgroundColor: 'rgba(255, 255, 255, 0.9)',
198
+ backgroundColor: 'rgba(255, 255, 255, 0.8)',
242
199
  alignItems: 'center',
243
200
  justifyContent: 'center',
244
201
  },
245
- loadingText: {
246
- fontSize: 16,
247
- color: '#666',
248
- marginTop: 16,
249
- textAlign: 'center',
250
- },
251
- debugContainer: {
252
- position: 'absolute',
253
- bottom: 0,
254
- left: 0,
255
- right: 0,
256
- backgroundColor: 'rgba(0, 0, 0, 0.8)',
257
- padding: 8,
258
- },
259
- debugText: {
260
- color: '#fff',
261
- fontSize: 12,
262
- fontFamily: 'monospace',
263
- },
264
202
  });