@onairos/react-native 3.0.57 → 3.0.59

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/README.md +2 -0
  2. package/lib/commonjs/components/DataRequestModal.js +87 -35
  3. package/lib/commonjs/components/DataRequestModal.js.map +1 -1
  4. package/lib/commonjs/components/OnairosButton.js +2 -0
  5. package/lib/commonjs/components/OnairosButton.js.map +1 -1
  6. package/lib/commonjs/components/Overlay.js.map +1 -1
  7. package/lib/commonjs/components/UniversalOnboarding.js +69 -50
  8. package/lib/commonjs/components/UniversalOnboarding.js.map +1 -1
  9. package/lib/commonjs/hooks/useConnections.js +28 -22
  10. package/lib/commonjs/hooks/useConnections.js.map +1 -1
  11. package/lib/module/components/DataRequestModal.js +88 -36
  12. package/lib/module/components/DataRequestModal.js.map +1 -1
  13. package/lib/module/components/OnairosButton.js +2 -0
  14. package/lib/module/components/OnairosButton.js.map +1 -1
  15. package/lib/module/components/Overlay.js.map +1 -1
  16. package/lib/module/components/UniversalOnboarding.js +69 -50
  17. package/lib/module/components/UniversalOnboarding.js.map +1 -1
  18. package/lib/module/hooks/useConnections.js +28 -22
  19. package/lib/module/hooks/useConnections.js.map +1 -1
  20. package/lib/typescript/components/DataRequestModal.d.ts +1 -1
  21. package/lib/typescript/components/DataRequestModal.d.ts.map +1 -1
  22. package/lib/typescript/components/OnairosButton.d.ts +1 -1
  23. package/lib/typescript/components/OnairosButton.d.ts.map +1 -1
  24. package/lib/typescript/components/Overlay.d.ts +1 -20
  25. package/lib/typescript/components/Overlay.d.ts.map +1 -1
  26. package/lib/typescript/components/UniversalOnboarding.d.ts.map +1 -1
  27. package/lib/typescript/hooks/useConnections.d.ts.map +1 -1
  28. package/lib/typescript/types.d.ts +32 -11
  29. package/lib/typescript/types.d.ts.map +1 -1
  30. package/package.json +1 -1
  31. package/src/components/DataRequestModal.tsx +226 -186
  32. package/src/components/OnairosButton.tsx +3 -1
  33. package/src/components/Overlay.tsx +1 -15
  34. package/src/components/UniversalOnboarding.tsx +73 -49
  35. package/src/hooks/useConnections.ts +26 -17
  36. package/src/types.ts +35 -11
@@ -50,6 +50,7 @@ export const UniversalOnboarding: React.FC<UniversalOnboardingProps> = ({
50
50
  visible,
51
51
  onClose,
52
52
  AppName,
53
+ appIcon,
53
54
  requestData,
54
55
  returnLink,
55
56
  onComplete,
@@ -217,8 +218,16 @@ export const UniversalOnboarding: React.FC<UniversalOnboardingProps> = ({
217
218
  };
218
219
 
219
220
  const loadInitialStatus = useCallback(async () => {
220
- const status = await getConnectionStatus();
221
- setConnections(status);
221
+ try {
222
+ console.log('🔄 Loading initial connection status...');
223
+ const status = await getConnectionStatus();
224
+ console.log('✅ Connection status loaded:', status);
225
+ setConnections(status || {});
226
+ } catch (error) {
227
+ console.error('❌ Failed to load connection status:', error);
228
+ // Set empty connections to prevent crashes
229
+ setConnections({});
230
+ }
222
231
  }, [getConnectionStatus]);
223
232
 
224
233
  const togglePlatform = useCallback(async (platformId: string) => {
@@ -454,32 +463,38 @@ export const UniversalOnboarding: React.FC<UniversalOnboardingProps> = ({
454
463
 
455
464
  // Function to handle email submission
456
465
  const handleEmailSubmit = useCallback(async () => {
457
- if (!email.trim()) {
458
- Alert.alert('Error', 'Please enter your email address');
459
- return;
460
- }
461
-
462
- // Basic email validation
463
- const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
464
- if (!emailRegex.test(email.trim())) {
465
- Alert.alert('Error', 'Please enter a valid email address');
466
- return;
467
- }
468
-
469
- console.log('📧 Email submitted:', email.trim());
470
-
471
- // Request verification code
472
466
  try {
473
- const result = await requestEmailVerification(email.trim());
474
- if (result.success) {
475
- console.log('✅ Verification code requested');
476
- setStep('verify');
477
- } else {
478
- Alert.alert('Error', result.error || 'Failed to send verification code');
467
+ if (!email || !email.trim()) {
468
+ Alert.alert('Error', 'Please enter your email address');
469
+ return;
470
+ }
471
+
472
+ // Basic email validation
473
+ const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
474
+ if (!emailRegex.test(email.trim())) {
475
+ Alert.alert('Error', 'Please enter a valid email address');
476
+ return;
477
+ }
478
+
479
+ console.log('📧 Email submitted:', email.trim());
480
+
481
+ // Request verification code
482
+ try {
483
+ const result = await requestEmailVerification(email.trim());
484
+ if (result && result.success) {
485
+ console.log('✅ Verification code requested');
486
+ setStep('verify');
487
+ } else {
488
+ console.warn('⚠️ Email verification request failed:', result);
489
+ Alert.alert('Error', result?.error || 'Failed to send verification code');
490
+ }
491
+ } catch (verificationError) {
492
+ console.error('❌ Error requesting verification:', verificationError);
493
+ Alert.alert('Error', 'Failed to send verification code. Please check your internet connection.');
479
494
  }
480
495
  } catch (error) {
481
- console.error('❌ Error requesting verification:', error);
482
- Alert.alert('Error', 'Failed to send verification code');
496
+ console.error('❌ Unexpected error in email submission:', error);
497
+ Alert.alert('Error', 'An unexpected error occurred. Please try again.');
483
498
  }
484
499
  }, [email]);
485
500
 
@@ -508,7 +523,18 @@ export const UniversalOnboarding: React.FC<UniversalOnboardingProps> = ({
508
523
  setShowDataRequestModal(true);
509
524
  } else {
510
525
  console.log('New user, proceeding to platform connection');
511
- setUsername(email.split('@')[0]); // Use email prefix as username
526
+ // Safely set username from email prefix
527
+ try {
528
+ const emailPrefix = email.trim().split('@')[0];
529
+ if (emailPrefix && emailPrefix.length > 0) {
530
+ setUsername(emailPrefix);
531
+ } else {
532
+ setUsername('User'); // Fallback username
533
+ }
534
+ } catch (usernameError) {
535
+ console.warn('Failed to extract username from email, using fallback:', usernameError);
536
+ setUsername('User');
537
+ }
512
538
  setStep('connect');
513
539
  }
514
540
  } else {
@@ -520,7 +546,7 @@ export const UniversalOnboarding: React.FC<UniversalOnboardingProps> = ({
520
546
  } finally {
521
547
  setIsVerifyingCode(false);
522
548
  }
523
- }, [email, verificationCode, onComplete]);
549
+ }, [email, verificationCode]);
524
550
 
525
551
  const handlePinSubmit = useCallback(async (userPin: string) => {
526
552
  setPin(userPin);
@@ -781,15 +807,9 @@ export const UniversalOnboarding: React.FC<UniversalOnboardingProps> = ({
781
807
 
782
808
  {step === 'connect' && (
783
809
  <>
784
- {/* Header with app icon and arrow to Onairos icon */}
810
+ {/* Header with Onairos icon and arrow to app icon */}
785
811
  <View style={styles.header}>
786
812
  <View style={styles.headerContent}>
787
- <View style={styles.appIcon}>
788
- <Text style={styles.appIconText}>
789
- {AppName.charAt(0)}
790
- </Text>
791
- </View>
792
- <Icon name="arrow-forward" size={24} color="#666" style={styles.arrow} />
793
813
  <View style={styles.onairosIcon}>
794
814
  <Image
795
815
  source={require('../assets/images/onairos_logo.png')}
@@ -797,6 +817,20 @@ export const UniversalOnboarding: React.FC<UniversalOnboardingProps> = ({
797
817
  resizeMode="contain"
798
818
  />
799
819
  </View>
820
+ <Icon name="arrow-forward" size={24} color="#666" style={styles.arrow} />
821
+ <View style={styles.appIcon}>
822
+ {appIcon ? (
823
+ <Image
824
+ source={appIcon}
825
+ style={styles.appIconImage}
826
+ resizeMode="contain"
827
+ />
828
+ ) : (
829
+ <Text style={styles.appIconText}>
830
+ {AppName.charAt(0)}
831
+ </Text>
832
+ )}
833
+ </View>
800
834
  </View>
801
835
 
802
836
 
@@ -959,21 +993,7 @@ export const UniversalOnboarding: React.FC<UniversalOnboardingProps> = ({
959
993
  visible={showDataRequestModal}
960
994
  onClose={handleDataRequestDecline}
961
995
  onAccept={handleDataRequestAccept}
962
- requestData={{
963
- // Convert DataTier format to expected format
964
- Small: {
965
- description: requestData.Small?.descriptions || 'Basic data access',
966
- type: requestData.Small?.type || 'basic'
967
- },
968
- Medium: {
969
- description: requestData.Medium?.descriptions || 'Standard data access',
970
- type: requestData.Medium?.type || 'standard'
971
- },
972
- Large: {
973
- description: requestData.Large?.descriptions || 'Full data access',
974
- type: requestData.Large?.type || 'full'
975
- }
976
- }}
996
+ requestData={requestData}
977
997
  AppName={AppName}
978
998
  />
979
999
  )}
@@ -1034,6 +1054,10 @@ const styles = StyleSheet.create({
1034
1054
  fontSize: 24,
1035
1055
  color: '#000',
1036
1056
  },
1057
+ appIconImage: {
1058
+ width: 32,
1059
+ height: 32,
1060
+ },
1037
1061
  arrow: {
1038
1062
  marginHorizontal: 16,
1039
1063
  },
@@ -30,28 +30,37 @@ export const useConnections = () => {
30
30
  const getConnectionStatus = useCallback(async (): Promise<ConnectionStatus> => {
31
31
  try {
32
32
  if (isKeychainAvailable()) {
33
- const stored = await Keychain.getGenericPassword({
34
- service: STORAGE_KEYS.connections
35
- });
36
- if (stored) {
37
- return JSON.parse(stored.password);
33
+ try {
34
+ const stored = await Keychain.getGenericPassword({
35
+ service: STORAGE_KEYS.connections
36
+ });
37
+ if (stored && stored.password) {
38
+ const parsed = JSON.parse(stored.password);
39
+ // Validate the parsed data structure
40
+ if (parsed && typeof parsed === 'object') {
41
+ return parsed;
42
+ }
43
+ }
44
+ } catch (keychainError) {
45
+ console.warn('Keychain access failed, using fallback:', keychainError);
46
+ // Clear corrupted data
47
+ try {
48
+ await Keychain.resetGenericPassword({ service: STORAGE_KEYS.connections });
49
+ } catch (resetError) {
50
+ console.warn('Failed to reset keychain:', resetError);
51
+ }
38
52
  }
39
- } else {
40
- // Use in-memory mock storage if Keychain is not available
41
- return mockConnectionStorage[STORAGE_KEYS.connections] || {};
42
53
  }
43
- return {};
54
+
55
+ // Use in-memory mock storage if Keychain is not available or failed
56
+ const mockData = mockConnectionStorage[STORAGE_KEYS.connections] || {};
57
+ console.log('Using mock connection storage:', mockData);
58
+ return mockData;
44
59
  } catch (error) {
45
60
  console.error('Error getting connection status:', error);
46
61
 
47
- // Return mock data in debug mode to prevent crashes
48
- if (__DEV__) {
49
- return {
50
- instagram: { userName: 'instagram_debug_user', connected: true },
51
- youtube: { userName: 'youtube_debug_user', connected: true }
52
- };
53
- }
54
-
62
+ // Always return empty object as safe fallback
63
+ console.log('Returning empty connections due to error');
55
64
  return {};
56
65
  }
57
66
  }, []);
package/src/types.ts CHANGED
@@ -4,14 +4,26 @@ export interface DataTier {
4
4
  reward: string;
5
5
  }
6
6
 
7
+ export interface DataRequest {
8
+ name: string;
9
+ description: string;
10
+ reward: string;
11
+ }
12
+
7
13
  export interface UniversalOnboardingProps {
8
14
  visible: boolean;
9
15
  onClose: () => void;
10
16
  AppName: string;
17
+ appIcon?: any; // Optional app icon (React Native ImageSourcePropType)
11
18
  requestData: {
12
- Small: DataTier;
13
- Medium: DataTier;
14
- Large: DataTier;
19
+ // Support both old format (for backward compatibility)
20
+ Small?: DataTier;
21
+ Medium?: DataTier;
22
+ Large?: DataTier;
23
+ // And new format
24
+ personality_traits?: DataRequest;
25
+ sentiment_analysis?: DataRequest;
26
+ [key: string]: DataTier | DataRequest | undefined;
15
27
  };
16
28
  returnLink: string;
17
29
  onComplete: (apiUrl: string, token: string, data: any) => void;
@@ -38,11 +50,17 @@ export interface OnairosButtonProps {
38
50
  returnLink?: string;
39
51
  prefillUrl?: string;
40
52
  AppName: string;
53
+ appIcon?: any; // Optional app icon (React Native ImageSourcePropType)
41
54
  buttonType?: 'normal' | 'pill';
42
55
  requestData?: {
43
- Small: DataTier;
44
- Medium: DataTier;
45
- Large: DataTier;
56
+ // Support both old format (for backward compatibility)
57
+ Small?: DataTier;
58
+ Medium?: DataTier;
59
+ Large?: DataTier;
60
+ // And new format
61
+ personality_traits?: DataRequest;
62
+ sentiment_analysis?: DataRequest;
63
+ [key: string]: DataTier | DataRequest | undefined;
46
64
  };
47
65
  buttonWidth?: number;
48
66
  buttonHeight?: number;
@@ -135,15 +153,21 @@ export interface CredentialsResult {
135
153
 
136
154
  export interface OverlayProps {
137
155
  data: {
138
- [key: string]: {
139
- type: string;
140
- descriptions: string;
141
- reward: string;
142
- };
156
+ // Support both old format (for backward compatibility)
157
+ Small?: DataTier;
158
+ Medium?: DataTier;
159
+ Large?: DataTier;
160
+ // And new format
161
+ personality_traits?: DataRequest;
162
+ sentiment_analysis?: DataRequest;
163
+ [key: string]: DataTier | DataRequest | undefined;
143
164
  };
144
165
  username: string;
145
166
  modelKey: string;
146
167
  onResolved: (apiUrl: string, accessToken: string, loginDetails: any) => void;
168
+ appName?: string;
169
+ darkMode?: boolean;
170
+ platforms?: Array<{id: string, name: string, icon: any}>;
147
171
  }
148
172
 
149
173
  export interface BiometricOptions {