@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.
- package/lib/commonjs/components/TrainingModal.js +16 -120
- package/lib/commonjs/components/TrainingModal.js.map +1 -1
- package/lib/commonjs/components/UniversalOnboarding.js +98 -186
- package/lib/commonjs/components/UniversalOnboarding.js.map +1 -1
- package/lib/commonjs/components/onboarding/OAuthWebView.js +49 -124
- package/lib/commonjs/components/onboarding/OAuthWebView.js.map +1 -1
- package/lib/commonjs/constants/index.js +3 -3
- package/lib/commonjs/constants/index.js.map +1 -1
- package/lib/commonjs/services/platformAuthService.js +81 -99
- package/lib/commonjs/services/platformAuthService.js.map +1 -1
- package/lib/module/components/TrainingModal.js +17 -120
- package/lib/module/components/TrainingModal.js.map +1 -1
- package/lib/module/components/UniversalOnboarding.js +99 -187
- package/lib/module/components/UniversalOnboarding.js.map +1 -1
- package/lib/module/components/onboarding/OAuthWebView.js +50 -125
- package/lib/module/components/onboarding/OAuthWebView.js.map +1 -1
- package/lib/module/constants/index.js +3 -3
- package/lib/module/constants/index.js.map +1 -1
- package/lib/module/index.js +9 -10
- package/lib/module/index.js.map +1 -1
- package/lib/module/services/platformAuthService.js +80 -97
- package/lib/module/services/platformAuthService.js.map +1 -1
- package/lib/typescript/components/TrainingModal.d.ts.map +1 -1
- package/lib/typescript/components/UniversalOnboarding.d.ts.map +1 -1
- package/lib/typescript/components/onboarding/OAuthWebView.d.ts.map +1 -1
- package/lib/typescript/services/platformAuthService.d.ts +5 -11
- package/lib/typescript/services/platformAuthService.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/components/TrainingModal.tsx +61 -202
- package/src/components/UniversalOnboarding.tsx +86 -179
- package/src/components/onboarding/OAuthWebView.tsx +59 -121
- package/src/constants/index.ts +3 -3
- 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 [
|
|
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
|
-
|
|
162
|
-
|
|
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:
|
|
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,
|
|
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
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
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
|
-
|
|
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,
|
|
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%
|
|
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
|
-
//
|
|
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
|
|
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
|
-
<
|
|
409
|
-
|
|
410
|
-
|
|
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={
|
|
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.
|
|
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
|
-
|
|
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:
|
|
624
|
-
marginBottom:
|
|
562
|
+
borderRadius: 16,
|
|
563
|
+
marginBottom: 16,
|
|
625
564
|
borderWidth: 1,
|
|
626
|
-
borderColor: '#
|
|
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
|
|
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(
|
|
22
|
-
setCurrentUrl(navState.url);
|
|
19
|
+
console.log('Navigation state changed:', navState.url);
|
|
23
20
|
|
|
24
|
-
// Check for final redirect to onairos.uk/Home
|
|
25
|
-
|
|
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
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
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
|
-
|
|
61
|
-
|
|
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 =
|
|
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
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
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={
|
|
127
|
-
incognito={false}
|
|
128
|
-
sharedCookiesEnabled={true}
|
|
129
|
-
thirdPartyCookiesEnabled={true}
|
|
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
|
-
|
|
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
|
-
|
|
232
|
-
|
|
233
|
-
|
|
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.
|
|
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
|
});
|