@onairos/react-native 3.0.22 → 3.0.25

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 (39) hide show
  1. package/lib/commonjs/components/OnairosButton.js +2 -3
  2. package/lib/commonjs/components/OnairosButton.js.map +1 -1
  3. package/lib/commonjs/components/TrainingModal.js +120 -16
  4. package/lib/commonjs/components/TrainingModal.js.map +1 -1
  5. package/lib/commonjs/components/UniversalOnboarding.js +242 -39
  6. package/lib/commonjs/components/UniversalOnboarding.js.map +1 -1
  7. package/lib/commonjs/components/onboarding/OAuthWebView.js +138 -27
  8. package/lib/commonjs/components/onboarding/OAuthWebView.js.map +1 -1
  9. package/lib/commonjs/constants/index.js +3 -2
  10. package/lib/commonjs/constants/index.js.map +1 -1
  11. package/lib/commonjs/services/platformAuthService.js +227 -0
  12. package/lib/commonjs/services/platformAuthService.js.map +1 -0
  13. package/lib/module/components/OnairosButton.js +2 -3
  14. package/lib/module/components/OnairosButton.js.map +1 -1
  15. package/lib/module/components/TrainingModal.js +120 -17
  16. package/lib/module/components/TrainingModal.js.map +1 -1
  17. package/lib/module/components/UniversalOnboarding.js +243 -40
  18. package/lib/module/components/UniversalOnboarding.js.map +1 -1
  19. package/lib/module/components/onboarding/OAuthWebView.js +139 -28
  20. package/lib/module/components/onboarding/OAuthWebView.js.map +1 -1
  21. package/lib/module/constants/index.js +3 -2
  22. package/lib/module/constants/index.js.map +1 -1
  23. package/lib/module/services/platformAuthService.js +213 -0
  24. package/lib/module/services/platformAuthService.js.map +1 -0
  25. package/lib/typescript/components/OnairosButton.d.ts.map +1 -1
  26. package/lib/typescript/components/TrainingModal.d.ts.map +1 -1
  27. package/lib/typescript/components/UniversalOnboarding.d.ts.map +1 -1
  28. package/lib/typescript/components/onboarding/OAuthWebView.d.ts.map +1 -1
  29. package/lib/typescript/constants/index.d.ts +1 -0
  30. package/lib/typescript/constants/index.d.ts.map +1 -1
  31. package/lib/typescript/services/platformAuthService.d.ts +45 -0
  32. package/lib/typescript/services/platformAuthService.d.ts.map +1 -0
  33. package/package.json +2 -1
  34. package/src/components/OnairosButton.tsx +1 -4
  35. package/src/components/TrainingModal.tsx +202 -61
  36. package/src/components/UniversalOnboarding.tsx +232 -35
  37. package/src/components/onboarding/OAuthWebView.tsx +135 -25
  38. package/src/constants/index.ts +3 -2
  39. package/src/services/platformAuthService.ts +241 -0
@@ -14,13 +14,16 @@ import {
14
14
  ScrollView,
15
15
  Image,
16
16
  Switch,
17
+ Linking,
17
18
  } from 'react-native';
18
19
  import Icon from 'react-native-vector-icons/MaterialIcons';
19
20
  import { PlatformList } from './PlatformList';
20
21
  import { PinInput } from './PinInput';
21
22
  import { TrainingModal } from './TrainingModal';
23
+ import { OAuthWebView } from './onboarding/OAuthWebView';
22
24
  import { useConnections } from '../hooks/useConnections';
23
- import { COLORS } from '../constants';
25
+ import { COLORS, DEEP_LINK_CONFIG } from '../constants';
26
+ import { initiateOAuth, initiateNativeAuth, hasNativeSDK, isOAuthCallback } from '../services/platformAuthService';
24
27
  import type { UniversalOnboardingProps, ConnectionStatus } from '../types';
25
28
 
26
29
  const { height, width } = Dimensions.get('window');
@@ -37,7 +40,7 @@ export const UniversalOnboarding: React.FC<UniversalOnboardingProps> = ({
37
40
  test = false,
38
41
  preferredPlatform,
39
42
  }) => {
40
- const [step, setStep] = useState<'connect' | 'pin' | 'training'>('connect');
43
+ const [step, setStep] = useState<'connect' | 'pin' | 'training' | 'oauth'>('connect');
41
44
  const [connections, setConnections] = useState<ConnectionStatus>({});
42
45
  const [pin, setPin] = useState<string>('');
43
46
  const [selectedTier, setSelectedTier] = useState<'Small' | 'Medium' | 'Large'>('Medium');
@@ -47,6 +50,11 @@ export const UniversalOnboarding: React.FC<UniversalOnboardingProps> = ({
47
50
  }>({ progress: 0, eta: '' });
48
51
  const [slideAnim] = useState(new Animated.Value(height));
49
52
  const [platformToggles, setPlatformToggles] = useState<{[key: string]: boolean}>({});
53
+ const [oauthUrl, setOauthUrl] = useState<string>('');
54
+ const [currentPlatform, setCurrentPlatform] = useState<string>('');
55
+ const [userEmail, setUserEmail] = useState<string>('user@example.com'); // Use proper email instead of random username
56
+ const [isConnectingPlatform, setIsConnectingPlatform] = useState<boolean>(false);
57
+ const [connectingPlatform, setConnectingPlatform] = useState<string | null>(null);
50
58
 
51
59
  const platforms = [
52
60
  { id: 'instagram', name: 'Instagram', icon: require('../assets/images/instagram.png') },
@@ -73,6 +81,27 @@ export const UniversalOnboarding: React.FC<UniversalOnboardingProps> = ({
73
81
  bounciness: 0,
74
82
  }).start();
75
83
 
84
+ // Set up deep link listener for OAuth callbacks
85
+ // Using the subscription pattern for React Native's Linking API
86
+ const subscription = Linking.addListener('url', ({ url }) => {
87
+ if (isOAuthCallback(url)) {
88
+ handleOAuthCallback(url);
89
+ }
90
+ });
91
+
92
+ // Check for initial URL (app was opened via deep link)
93
+ Linking.getInitialURL().then(initialUrl => {
94
+ if (initialUrl && isOAuthCallback(initialUrl)) {
95
+ handleOAuthCallback(initialUrl);
96
+ }
97
+ });
98
+
99
+ // Return cleanup function
100
+ return () => {
101
+ // Remove event listener using the subscription
102
+ subscription.remove();
103
+ };
104
+
76
105
  // Initialize platform toggles
77
106
  const initialToggles: { [key: string]: boolean } = {};
78
107
  platforms.forEach((platform) => {
@@ -127,35 +156,156 @@ export const UniversalOnboarding: React.FC<UniversalOnboardingProps> = ({
127
156
  setConnections(status);
128
157
  }, [getConnectionStatus]);
129
158
 
130
- const togglePlatform = useCallback((platformId: string) => {
131
- setPlatformToggles(prev => ({
132
- ...prev,
133
- [platformId]: !prev[platformId]
134
- }));
135
- }, []);
159
+ const togglePlatform = useCallback(async (platformId: string) => {
160
+ if (!platformToggles[platformId]) {
161
+ // Attempt to connect platform
162
+ try {
163
+ setIsConnectingPlatform(true);
164
+ setConnectingPlatform(platformId);
165
+ console.log(`Initiating connection for ${platformId}`);
166
+
167
+ // Check if platform has a native SDK
168
+ if (hasNativeSDK(platformId)) {
169
+ console.log(`Using native SDK for ${platformId}`);
170
+ // Use native SDK for authentication
171
+ const success = await initiateNativeAuth(platformId);
172
+ if (success) {
173
+ console.log(`Native authentication successful for ${platformId}`);
174
+ // Update platform toggle state
175
+ setPlatformToggles(prev => ({
176
+ ...prev,
177
+ [platformId]: true
178
+ }));
179
+
180
+ // Update connections state
181
+ setConnections(prev => ({
182
+ ...prev,
183
+ [platformId]: { userName: userEmail, connected: true }
184
+ }));
185
+ }
186
+ } else {
187
+ console.log(`Initiating OAuth flow for ${platformId}`);
188
+ // Use OAuth flow through proxy server
189
+ const oauthUrl = await initiateOAuth(platformId, userEmail);
190
+ if (oauthUrl) {
191
+ console.log(`Received OAuth URL for ${platformId}: ${oauthUrl}`);
192
+ setCurrentPlatform(platformId);
193
+ setOauthUrl(oauthUrl);
194
+ setStep('oauth');
195
+ } else {
196
+ console.error(`No OAuth URL returned for ${platformId}`);
197
+ }
198
+ }
199
+ } catch (error) {
200
+ console.error(`Error connecting ${platformId}:`, error);
201
+ // Reset toggle state on error
202
+ setPlatformToggles(prev => ({
203
+ ...prev,
204
+ [platformId]: false
205
+ }));
206
+ } finally {
207
+ setIsConnectingPlatform(false);
208
+ setConnectingPlatform(null);
209
+ }
210
+ } else {
211
+ // Disconnect platform
212
+ console.log(`Disconnecting ${platformId}`);
213
+ setPlatformToggles(prev => ({
214
+ ...prev,
215
+ [platformId]: false
216
+ }));
217
+
218
+ // Update connections state
219
+ setConnections(prev => {
220
+ const newConnections = { ...prev };
221
+ delete newConnections[platformId];
222
+ return newConnections;
223
+ });
224
+ }
225
+ }, [platformToggles, userEmail]);
226
+
227
+ /**
228
+ * Handles OAuth callback URLs
229
+ */
230
+ const handleOAuthCallback = useCallback((url: string) => {
231
+ try {
232
+ // Extract the authorization code from the URL
233
+ const parsedUrl = new URL(url);
234
+ const code = parsedUrl.searchParams.get('code');
235
+ const platform = parsedUrl.searchParams.get('platform') || currentPlatform;
236
+
237
+ if (code && platform) {
238
+ // Update connections state
239
+ setConnections(prev => ({
240
+ ...prev,
241
+ [platform]: { userName: userEmail, connected: true }
242
+ }));
243
+
244
+ // Update platform toggles
245
+ setPlatformToggles(prev => ({
246
+ ...prev,
247
+ [platform]: true
248
+ }));
249
+
250
+ // Return to the connect step
251
+ setStep('connect');
252
+ }
253
+ } catch (error) {
254
+ console.error('Error handling OAuth callback:', error);
255
+ }
256
+ }, [currentPlatform, userEmail]);
257
+
258
+ /**
259
+ * Handles completion of the OAuth flow
260
+ */
261
+ const handleOAuthSuccess = useCallback((code: string) => {
262
+ console.log(`OAuth success for ${currentPlatform} with code: ${code}`);
263
+
264
+ // Update connections for the current platform
265
+ if (currentPlatform) {
266
+ // Update connections state
267
+ setConnections(prev => ({
268
+ ...prev,
269
+ [currentPlatform]: { userName: userEmail, connected: true }
270
+ }));
271
+
272
+ // Update platform toggles
273
+ setPlatformToggles(prev => ({
274
+ ...prev,
275
+ [currentPlatform]: true
276
+ }));
277
+
278
+ // In a real implementation, we would send the code to our server
279
+ // to exchange it for an access token and store it securely
280
+ console.log(`Simulating token exchange for ${currentPlatform}`);
281
+
282
+ // For demo purposes, we'll just simulate a successful token exchange
283
+ if (debug || test) {
284
+ console.log('Debug mode: Simulating successful token exchange');
285
+ }
286
+ }
287
+
288
+ // Close OAuth window and return to connect step
289
+ setOauthUrl('');
290
+ setStep('connect');
291
+ }, [currentPlatform, userEmail, debug, test]);
136
292
 
137
293
  const handlePinSubmit = useCallback(async (userPin: string) => {
138
294
  setPin(userPin);
139
295
  setStep('training');
140
- // Simulate training progress
296
+ // Simulate training progress over 10 seconds
141
297
  let progress = 0;
142
298
  const interval = setInterval(() => {
143
- progress += 0.1;
299
+ progress += 1; // 10% progress every second for 1 seconds total
144
300
  setTraining({
145
301
  progress,
146
- eta: `${Math.round((1 - progress) * 100)} seconds remaining`,
302
+ eta: `${Math.round((1 - progress) * 10)} seconds remaining`,
147
303
  });
148
304
  if (progress >= 1) {
149
305
  clearInterval(interval);
150
- onComplete('https://api2.onairos.uk', 'dummy-token', {
151
- pin: userPin,
152
- connections,
153
- platformToggles,
154
- selectedTier,
155
- tierData: requestData?.[selectedTier],
156
- });
306
+ // Training complete - TrainingModal will handle email input and final completion
157
307
  }
158
- }, 1000);
308
+ }, 1000); // 1 second intervals for 10 total seconds
159
309
  }, [connections, onComplete, selectedTier, requestData, platformToggles]);
160
310
 
161
311
  const canProceedToPin = useCallback(() => {
@@ -223,26 +373,41 @@ export const UniversalOnboarding: React.FC<UniversalOnboardingProps> = ({
223
373
 
224
374
  {/* Platform connection options */}
225
375
  <View style={styles.platformsContainer}>
226
- {platforms.map((platform) => (
227
- <View key={platform.id} style={styles.platformItem}>
228
- <View style={styles.platformInfo}>
229
- <Image
230
- source={platform.icon}
231
- style={styles.platformIcon}
232
- resizeMode="contain"
233
- />
376
+ {platforms.map((platform) => (
377
+ <View key={platform.id} style={[
378
+ styles.platformItem,
379
+ connections[platform.id]?.connected && styles.platformItemConnected
380
+ ]}>
381
+ <View style={styles.platformInfo}>
382
+ <Image
383
+ source={platform.icon}
384
+ style={styles.platformIcon}
385
+ resizeMode="contain"
386
+ />
387
+ <View style={styles.platformTextContainer}>
234
388
  <Text style={styles.platformName}>
235
389
  {platform.name}
236
390
  </Text>
391
+ {connections[platform.id]?.connected && (
392
+ <Text style={styles.connectedText}>Connected</Text>
393
+ )}
237
394
  </View>
238
- <Switch
239
- value={platformToggles[platform.id]}
240
- onValueChange={() => togglePlatform(platform.id)}
241
- trackColor={{ false: '#767577', true: '#81b0ff' }}
242
- thumbColor={platformToggles[platform.id] ? '#2196F3' : '#f4f3f4'}
243
- />
244
395
  </View>
245
- ))}
396
+ <View style={styles.platformActions}>
397
+ {connectingPlatform === platform.id ? (
398
+ <ActivityIndicator size="small" color={COLORS.primary} />
399
+ ) : (
400
+ <Switch
401
+ value={platformToggles[platform.id] || connections[platform.id]?.connected || false}
402
+ onValueChange={() => togglePlatform(platform.id)}
403
+ trackColor={{ false: '#767577', true: '#81b0ff' }}
404
+ thumbColor={platformToggles[platform.id] || connections[platform.id]?.connected ? '#2196F3' : '#f4f3f4'}
405
+ disabled={connectingPlatform !== null}
406
+ />
407
+ )}
408
+ </View>
409
+ </View>
410
+ ))}
246
411
  </View>
247
412
  </ScrollView>
248
413
 
@@ -291,10 +456,24 @@ export const UniversalOnboarding: React.FC<UniversalOnboardingProps> = ({
291
456
  platformToggles,
292
457
  selectedTier,
293
458
  tierData: requestData?.[selectedTier],
459
+ userEmail,
294
460
  });
295
461
  }}
296
462
  modelKey="onairosTrainingModel"
297
- username="demo_user"
463
+ username={userEmail}
464
+ />
465
+ )}
466
+
467
+ {step === 'oauth' && oauthUrl && (
468
+ <OAuthWebView
469
+ url={oauthUrl}
470
+ platform={currentPlatform}
471
+ onClose={() => {
472
+ setStep('connect');
473
+ setOauthUrl('');
474
+ }}
475
+ onSuccess={handleOAuthSuccess}
476
+ onComplete={() => setStep('connect')}
298
477
  />
299
478
  )}
300
479
  </SafeAreaView>
@@ -422,6 +601,24 @@ const styles = StyleSheet.create({
422
601
  fontWeight: '500',
423
602
  color: '#000',
424
603
  },
604
+ platformTextContainer: {
605
+ flex: 1,
606
+ },
607
+ connectedText: {
608
+ fontSize: 12,
609
+ color: '#4CAF50',
610
+ fontWeight: '500',
611
+ marginTop: 2,
612
+ },
613
+ platformActions: {
614
+ alignItems: 'center',
615
+ justifyContent: 'center',
616
+ },
617
+ platformItemConnected: {
618
+ backgroundColor: '#F8F9FA',
619
+ borderColor: '#4CAF50',
620
+ borderWidth: 1,
621
+ },
425
622
  footer: {
426
623
  flexDirection: 'row',
427
624
  alignItems: 'center',
@@ -1,8 +1,9 @@
1
1
  import React, { useCallback, useState } from 'react';
2
- import { View, StyleSheet, ActivityIndicator, SafeAreaView, TouchableOpacity } from 'react-native';
2
+ import { View, StyleSheet, ActivityIndicator, SafeAreaView, TouchableOpacity, Text } 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';
6
7
  import type { OAuthWebViewProps } from '../../types';
7
8
 
8
9
  export const OAuthWebView: React.FC<OAuthWebViewProps> = ({
@@ -13,41 +14,83 @@ export const OAuthWebView: React.FC<OAuthWebViewProps> = ({
13
14
  onSuccess,
14
15
  }) => {
15
16
  const [loading, setLoading] = useState(true);
17
+ const [currentUrl, setCurrentUrl] = useState(url);
16
18
 
17
19
  const handleNavigationStateChange = useCallback(
18
20
  (navState: WebViewNavigation) => {
19
- // Check if the URL includes our redirect URI
20
- if (navState.url.startsWith('onairosanime://auth/')) {
21
- // Extract the authorization code from the URL
22
- const authCode = extractAuthCode(navState.url);
23
- if (authCode) {
24
- onSuccess(authCode);
21
+ console.log(`[OAuthWebView] Navigation state changed for ${platform}:`, navState.url);
22
+ setCurrentUrl(navState.url);
23
+
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
+ }
37
+
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;
25
47
  }
26
48
 
27
- // OAuth flow is complete
28
- if (onComplete) {
29
- onComplete();
49
+ // For other platforms, close immediately
50
+ setTimeout(() => {
51
+ onSuccess('success');
52
+ if (onComplete) {
53
+ onComplete();
54
+ }
55
+ }, 300);
56
+ return;
57
+ }
58
+
59
+ // 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
+
63
+ // Extract the authorization code
64
+ const authCode = handleOAuthCallback(navState.url);
65
+ if (authCode) {
66
+ console.log(`[OAuthWebView] Extracted auth code for ${platform}:`, authCode);
67
+ onSuccess(authCode);
68
+ if (onComplete) {
69
+ onComplete();
70
+ }
30
71
  }
31
72
  return;
32
73
  }
33
74
  },
34
- [onComplete, onSuccess]
75
+ [platform, onComplete, onSuccess]
35
76
  );
36
77
 
78
+ const handleLoadStart = useCallback(() => {
79
+ setLoading(true);
80
+ }, []);
81
+
37
82
  const handleLoadEnd = useCallback(() => {
38
83
  setLoading(false);
39
84
  }, []);
40
85
 
41
- // Extract auth code from redirect URL
42
- const extractAuthCode = (redirectUrl: string): string => {
43
- try {
44
- const url = new URL(redirectUrl);
45
- return url.searchParams.get('code') || '';
46
- } catch (error) {
47
- console.error('Error extracting auth code:', error);
48
- return '';
49
- }
50
- };
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';
51
94
 
52
95
  return (
53
96
  <SafeAreaView style={styles.container}>
@@ -61,21 +104,56 @@ export const OAuthWebView: React.FC<OAuthWebViewProps> = ({
61
104
  size={20}
62
105
  color={getPlatformColor(platform || 'default')}
63
106
  />
107
+ <Text style={styles.platformTitle}>
108
+ Connect {platform ? platform.charAt(0).toUpperCase() + platform.slice(1) : 'Account'}
109
+ </Text>
64
110
  </View>
111
+ <View style={styles.placeholder} />
65
112
  </View>
66
113
 
67
114
  <WebView
68
115
  source={{ uri: url }}
69
116
  onNavigationStateChange={handleNavigationStateChange}
117
+ onLoadStart={handleLoadStart}
70
118
  onLoadEnd={handleLoadEnd}
119
+ onError={handleError}
71
120
  startInLoadingState={true}
72
121
  renderLoading={() => <View />}
73
122
  style={styles.webView}
123
+ // Essential WebView configuration for OAuth
124
+ javaScriptEnabled={true}
125
+ 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
132
+ allowsInlineMediaPlayback={true}
133
+ mediaPlaybackRequiresUserAction={false}
134
+ allowsBackForwardNavigationGestures={true}
135
+ // Security settings
136
+ allowsLinkPreview={false}
137
+ allowFileAccess={false}
138
+ allowUniversalAccessFromFileURLs={false}
139
+ mixedContentMode="compatibility"
74
140
  />
75
141
 
76
142
  {loading && (
77
143
  <View style={styles.loadingContainer}>
78
144
  <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>
79
157
  </View>
80
158
  )}
81
159
  </SafeAreaView>
@@ -95,6 +173,8 @@ const getPlatformIcon = (platform: string): string => {
95
173
  return 'push-pin';
96
174
  case 'reddit':
97
175
  return 'forum';
176
+ case 'email':
177
+ return 'email';
98
178
  default:
99
179
  return 'link';
100
180
  }
@@ -113,6 +193,8 @@ const getPlatformColor = (platform: string): string => {
113
193
  return '#E60023';
114
194
  case 'reddit':
115
195
  return '#FF4500';
196
+ case 'email':
197
+ return '#4285F4';
116
198
  default:
117
199
  return COLORS.primary;
118
200
  }
@@ -134,21 +216,49 @@ const styles = StyleSheet.create({
134
216
  },
135
217
  titleContainer: {
136
218
  flex: 1,
219
+ flexDirection: 'row',
137
220
  alignItems: 'center',
221
+ justifyContent: 'center',
222
+ },
223
+ platformTitle: {
224
+ fontSize: 16,
225
+ fontWeight: '600',
226
+ color: '#000',
227
+ marginLeft: 8,
138
228
  },
139
229
  closeButton: {
140
230
  padding: 8,
141
- position: 'absolute',
142
- left: 16,
143
- zIndex: 10,
231
+ width: 40,
232
+ },
233
+ placeholder: {
234
+ width: 40,
144
235
  },
145
236
  webView: {
146
237
  flex: 1,
147
238
  },
148
239
  loadingContainer: {
149
240
  ...StyleSheet.absoluteFillObject,
150
- backgroundColor: 'rgba(255, 255, 255, 0.8)',
241
+ backgroundColor: 'rgba(255, 255, 255, 0.9)',
151
242
  alignItems: 'center',
152
243
  justifyContent: 'center',
153
244
  },
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
+ },
154
264
  });
@@ -77,6 +77,7 @@ export const PIN_REQUIREMENTS = {
77
77
  };
78
78
 
79
79
  export const DEEP_LINK_CONFIG = {
80
- scheme: 'onairosanime',
81
- host: 'authenticate',
80
+ scheme: 'onairosevents',
81
+ host: 'auth',
82
+ redirectUri: 'onairosevents://auth/callback',
82
83
  };