@onairos/react-native 3.1.16 → 3.1.18

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 (207) hide show
  1. package/README.md +404 -0
  2. package/lib/commonjs/assets/images/Checkbox.svg +3 -3
  3. package/lib/commonjs/assets/images/EnochE.svg +19 -19
  4. package/lib/commonjs/assets/images/Personalityprofile.svg +3 -3
  5. package/lib/commonjs/assets/images/Personalitytraits.svg +3 -3
  6. package/lib/commonjs/assets/images/Userpreferences.svg +3 -3
  7. package/lib/commonjs/assets/images/arrow.svg +20 -20
  8. package/lib/commonjs/assets/images/basicproficon.svg +43 -43
  9. package/lib/commonjs/assets/images/basicprofile.svg +3 -3
  10. package/lib/commonjs/assets/images/checkmark.svg +4 -4
  11. package/lib/commonjs/assets/images/contentanalysis.svg +3 -3
  12. package/lib/commonjs/assets/images/contenticon.svg +23 -23
  13. package/lib/commonjs/assets/images/personalityicon.svg +18 -18
  14. package/lib/commonjs/assets/images/x-close.svg +3 -3
  15. package/lib/commonjs/components/ModalSheet.js +8 -2
  16. package/lib/commonjs/components/ModalSheet.js.map +1 -1
  17. package/lib/commonjs/components/OnairosButton.js +290 -0
  18. package/lib/commonjs/components/OnairosButton.js.map +1 -0
  19. package/lib/commonjs/components/OnairosSignInButton.js +32 -8
  20. package/lib/commonjs/components/OnairosSignInButton.js.map +1 -1
  21. package/lib/commonjs/components/UniversalOnboarding.js +4 -4
  22. package/lib/commonjs/components/WelcomeScreen.js +29 -13
  23. package/lib/commonjs/components/WelcomeScreen.js.map +1 -1
  24. package/lib/commonjs/config/api.js +2 -2
  25. package/lib/commonjs/hooks/useConnections.js +6 -6
  26. package/lib/commonjs/hooks/useUserConnections.js +10 -10
  27. package/lib/commonjs/index.js +13 -6
  28. package/lib/commonjs/index.js.map +1 -1
  29. package/lib/commonjs/services/apiClient.js +35 -35
  30. package/lib/commonjs/services/apiKeyService.js +99 -99
  31. package/lib/commonjs/services/authService.js +82 -82
  32. package/lib/commonjs/services/biometricPinService.js +10 -10
  33. package/lib/commonjs/services/connectedAccountsService.js +32 -32
  34. package/lib/commonjs/services/googleAuthService.js +15 -15
  35. package/lib/commonjs/services/imageCompressionService.js +15 -15
  36. package/lib/commonjs/services/jwtStorageService.js +59 -59
  37. package/lib/commonjs/services/mobileTrainingService.js +14 -14
  38. package/lib/commonjs/services/pinEncryptionService.js +10 -10
  39. package/lib/commonjs/services/pinStorageUtils.js +15 -15
  40. package/lib/commonjs/services/platformAuthService.js +47 -47
  41. package/lib/commonjs/services/storageService.js +31 -31
  42. package/lib/commonjs/services/trainingApiHelpers.js +33 -33
  43. package/lib/commonjs/services/userConnectionsService.js +24 -24
  44. package/lib/commonjs/utils/Portal.js +4 -4
  45. package/lib/commonjs/utils/api.js +24 -24
  46. package/lib/commonjs/utils/auth.js +18 -18
  47. package/lib/commonjs/utils/crypto.js +13 -13
  48. package/lib/commonjs/utils/encryption.js +12 -12
  49. package/lib/commonjs/utils/eventUtils.js +52 -52
  50. package/lib/commonjs/utils/programmaticFlow.js +16 -16
  51. package/lib/commonjs/utils/retryHelper.js +27 -27
  52. package/lib/module/assets/images/Checkbox.svg +3 -3
  53. package/lib/module/assets/images/EnochE.svg +19 -19
  54. package/lib/module/assets/images/Personalityprofile.svg +3 -3
  55. package/lib/module/assets/images/Personalitytraits.svg +3 -3
  56. package/lib/module/assets/images/Userpreferences.svg +3 -3
  57. package/lib/module/assets/images/arrow.svg +20 -20
  58. package/lib/module/assets/images/basicproficon.svg +43 -43
  59. package/lib/module/assets/images/basicprofile.svg +3 -3
  60. package/lib/module/assets/images/checkmark.svg +4 -4
  61. package/lib/module/assets/images/contentanalysis.svg +3 -3
  62. package/lib/module/assets/images/contenticon.svg +23 -23
  63. package/lib/module/assets/images/personalityicon.svg +18 -18
  64. package/lib/module/assets/images/x-close.svg +3 -3
  65. package/lib/module/components/ModalSheet.js +7 -2
  66. package/lib/module/components/ModalSheet.js.map +1 -1
  67. package/lib/module/components/OnairosButton.js +282 -0
  68. package/lib/module/components/OnairosButton.js.map +1 -0
  69. package/lib/module/components/OnairosSignInButton.js +32 -8
  70. package/lib/module/components/OnairosSignInButton.js.map +1 -1
  71. package/lib/module/components/UniversalOnboarding.js +4 -4
  72. package/lib/module/components/WelcomeScreen.js +25 -10
  73. package/lib/module/components/WelcomeScreen.js.map +1 -1
  74. package/lib/module/config/api.js +2 -2
  75. package/lib/module/hooks/useConnections.js +6 -6
  76. package/lib/module/hooks/useUserConnections.js +10 -10
  77. package/lib/module/index.js +11 -11
  78. package/lib/module/index.js.map +1 -1
  79. package/lib/module/services/apiClient.js +35 -35
  80. package/lib/module/services/apiKeyService.js +99 -99
  81. package/lib/module/services/authService.js +82 -82
  82. package/lib/module/services/biometricPinService.js +10 -10
  83. package/lib/module/services/connectedAccountsService.js +32 -32
  84. package/lib/module/services/googleAuthService.js +15 -15
  85. package/lib/module/services/imageCompressionService.js +15 -15
  86. package/lib/module/services/jwtStorageService.js +59 -59
  87. package/lib/module/services/mobileTrainingService.js +14 -14
  88. package/lib/module/services/pinEncryptionService.js +10 -10
  89. package/lib/module/services/pinStorageUtils.js +15 -15
  90. package/lib/module/services/platformAuthService.js +47 -47
  91. package/lib/module/services/storageService.js +31 -31
  92. package/lib/module/services/trainingApiHelpers.js +33 -33
  93. package/lib/module/services/userConnectionsService.js +24 -24
  94. package/lib/module/utils/Portal.js +4 -4
  95. package/lib/module/utils/api.js +24 -24
  96. package/lib/module/utils/auth.js +18 -18
  97. package/lib/module/utils/crypto.js +13 -13
  98. package/lib/module/utils/encryption.js +12 -12
  99. package/lib/module/utils/eventUtils.js +52 -52
  100. package/lib/module/utils/programmaticFlow.js +16 -16
  101. package/lib/module/utils/retryHelper.js +27 -27
  102. package/lib/typescript/components/ModalSheet.d.ts.map +1 -1
  103. package/lib/typescript/components/OnairosButton.d.ts +37 -0
  104. package/lib/typescript/components/OnairosButton.d.ts.map +1 -0
  105. package/lib/typescript/components/OnairosSignInButton.d.ts.map +1 -1
  106. package/lib/typescript/components/WelcomeScreen.d.ts.map +1 -1
  107. package/lib/typescript/index.d.ts +3 -1
  108. package/lib/typescript/index.d.ts.map +1 -1
  109. package/package.json +145 -163
  110. package/src/api/index.ts +151 -151
  111. package/src/assets/images/Checkbox.svg +3 -3
  112. package/src/assets/images/EnochE.svg +19 -19
  113. package/src/assets/images/Personalityprofile.svg +3 -3
  114. package/src/assets/images/Personalitytraits.svg +3 -3
  115. package/src/assets/images/Userpreferences.svg +3 -3
  116. package/src/assets/images/arrow.svg +20 -20
  117. package/src/assets/images/basicproficon.svg +43 -43
  118. package/src/assets/images/basicprofile.svg +3 -3
  119. package/src/assets/images/checkmark.svg +4 -4
  120. package/src/assets/images/contentanalysis.svg +3 -3
  121. package/src/assets/images/contenticon.svg +23 -23
  122. package/src/assets/images/personalityicon.svg +18 -18
  123. package/src/assets/images/x-close.svg +3 -3
  124. package/src/components/BodyText.tsx +33 -33
  125. package/src/components/BrandMark.tsx +62 -62
  126. package/src/components/CodeInput.tsx +32 -32
  127. package/src/components/DataRequestScreen.tsx +355 -355
  128. package/src/components/EmailInput.tsx +31 -31
  129. package/src/components/EmailVerificationModal.tsx +363 -363
  130. package/src/components/ExistingUserDataConfirmation.tsx +506 -506
  131. package/src/components/GoogleButton.tsx +55 -55
  132. package/src/components/HeadingGroup.tsx +49 -49
  133. package/src/components/ModalHeader.tsx +125 -125
  134. package/src/components/ModalSheet.tsx +59 -57
  135. package/src/components/Onairos.tsx +422 -422
  136. package/src/components/OnairosButton.tsx +339 -0
  137. package/src/components/OnairosSignInButton.tsx +31 -9
  138. package/src/components/Overlay.tsx +506 -506
  139. package/src/components/PersonaImage.tsx +79 -79
  140. package/src/components/PersonaLoadingScreen.tsx +201 -201
  141. package/src/components/PersonalizationConsentScreen.tsx +410 -410
  142. package/src/components/PinCreationScreen.tsx +492 -492
  143. package/src/components/PinInput.tsx +555 -555
  144. package/src/components/PlatformConnectorsStep.tsx +891 -891
  145. package/src/components/PlatformList.tsx +144 -144
  146. package/src/components/PlatformToggle.tsx +226 -226
  147. package/src/components/PrimaryButton.tsx +213 -213
  148. package/src/components/SignInMatchAnimation.tsx +225 -225
  149. package/src/components/SignInStep.tsx +217 -217
  150. package/src/components/TrainingModal.tsx +1047 -1047
  151. package/src/components/UniversalOnboarding.tsx +2887 -2887
  152. package/src/components/VerificationStep.tsx +198 -198
  153. package/src/components/WelcomeScreen.tsx +490 -473
  154. package/src/components/icons/Basicproficon.tsx +30 -30
  155. package/src/components/icons/Basicprofile.tsx +17 -17
  156. package/src/components/icons/Checkbox.tsx +17 -17
  157. package/src/components/icons/Checkmark.tsx +24 -24
  158. package/src/components/icons/Contentanalysis.tsx +17 -17
  159. package/src/components/icons/Contenticon.tsx +30 -30
  160. package/src/components/icons/EnochE.tsx +39 -39
  161. package/src/components/icons/Personalityicon.tsx +22 -22
  162. package/src/components/icons/Personalityprofile.tsx +17 -17
  163. package/src/components/icons/Personalitytraits.tsx +17 -17
  164. package/src/components/icons/Userpreferences.tsx +17 -17
  165. package/src/components/icons/index.ts +12 -12
  166. package/src/components/onboarding/OAuthWebView.tsx +232 -232
  167. package/src/config/api.ts +25 -25
  168. package/src/context/AuthContext.tsx +393 -393
  169. package/src/hooks/useConnectedAccounts.ts +138 -138
  170. package/src/hooks/useConnections.ts +161 -161
  171. package/src/hooks/useCredentials.ts +174 -174
  172. package/src/hooks/useUserConnections.ts +165 -165
  173. package/src/index.js +14 -0
  174. package/src/index.ts +99 -96
  175. package/src/services/apiClient.ts +336 -336
  176. package/src/services/apiKeyService.ts +919 -919
  177. package/src/services/authService.ts +1008 -1008
  178. package/src/services/biometricPinService.ts +192 -192
  179. package/src/services/connectedAccountsService.ts +289 -289
  180. package/src/services/googleAuthService.ts +279 -279
  181. package/src/services/imageCompressionService.ts +302 -302
  182. package/src/services/jwtStorageService.ts +256 -256
  183. package/src/services/mobileTrainingService.ts +203 -203
  184. package/src/services/pinEncryptionService.ts +75 -75
  185. package/src/services/pinStorageUtils.ts +96 -96
  186. package/src/services/platformAuthService.ts +1346 -1346
  187. package/src/services/storageService.ts +451 -451
  188. package/src/services/trainingApiHelpers.ts +66 -66
  189. package/src/services/userConnectionsService.ts +556 -556
  190. package/src/services/youtubeMigrationService.ts +453 -453
  191. package/src/theme/index.ts +239 -239
  192. package/src/types/ambient.d.ts +28 -28
  193. package/src/types/index.ts +265 -265
  194. package/src/types/node-fix.d.ts +18 -18
  195. package/src/types/node-override.d.ts +23 -23
  196. package/src/types/opacity.d.ts +15 -15
  197. package/src/types/types.d.ts +17 -17
  198. package/src/utils/Portal.tsx +82 -82
  199. package/src/utils/api.js +111 -111
  200. package/src/utils/auth.js +103 -103
  201. package/src/utils/crypto.js +59 -59
  202. package/src/utils/encryption.ts +68 -68
  203. package/src/utils/eventUtils.ts +302 -302
  204. package/src/utils/haptics.ts +58 -58
  205. package/src/utils/imagePreloader.ts +2 -2
  206. package/src/utils/programmaticFlow.ts +112 -112
  207. package/src/utils/retryHelper.ts +274 -274
@@ -1,506 +1,506 @@
1
- import React, { useState, useEffect, useCallback, useRef } from 'react';
2
- import {
3
- View,
4
- Text,
5
- StyleSheet,
6
- TouchableOpacity,
7
- ScrollView,
8
- Alert,
9
- Platform,
10
- Dimensions,
11
- Modal,
12
- Animated,
13
- TouchableWithoutFeedback,
14
- SafeAreaView,
15
- Image,
16
- Switch,
17
- } from 'react-native';
18
- import Icon from 'react-native-vector-icons/MaterialIcons';
19
- import { onairosApi } from '../api';
20
- import { encryptModelKey } from '../utils/encryption';
21
- import { COLORS } from '../constants';
22
-
23
- const { width: SCREEN_WIDTH, height: SCREEN_HEIGHT } = Dimensions.get('window');
24
-
25
- import type { OverlayProps } from '../types';
26
-
27
- export const Overlay: React.FC<OverlayProps> = ({
28
- data,
29
- username,
30
- modelKey,
31
- onResolved,
32
- appName = 'Your App',
33
- darkMode = false,
34
- platforms = [
35
- { id: 'instagram', name: 'Instagram', icon: require('../assets/icons/instagram.png') },
36
- { id: 'youtube', name: 'YouTube', icon: require('../assets/icons/YouTubeicon2.png') },
37
- { id: 'reddit', name: 'Reddit', icon: require('../assets/icons/Redditicon.png') },
38
- { id: 'pinterest', name: 'Pinterest', icon: require('../assets/icons/pinterest.png') },
39
- { id: 'email', name: 'Email', icon: require('../assets/icons/Gmail.png') },
40
- ],
41
- }) => {
42
- const [selections, setSelections] = useState<{ [key: string]: boolean }>({});
43
- const [details, setDetails] = useState<string>('');
44
- const [visible, setVisible] = useState(true);
45
- const [platformToggles, setPlatformToggles] = useState<{[key: string]: boolean}>({});
46
- const bottomSheetAnim = useRef(new Animated.Value(0)).current;
47
-
48
- // Initialize selection state on mount
49
- useEffect(() => {
50
- // Initialize selection state
51
- const initialSelections: { [key: string]: boolean } = {};
52
- Object.keys(data).forEach((key) => {
53
- initialSelections[key] = false;
54
- });
55
- setSelections(initialSelections);
56
-
57
- // Initialize platform toggles
58
- const initialToggles: { [key: string]: boolean } = {};
59
- platforms.forEach((platform) => {
60
- initialToggles[platform.id] = false;
61
- });
62
- setPlatformToggles(initialToggles);
63
-
64
- getDetails();
65
-
66
- // Animate the bottom sheet sliding up
67
- Animated.spring(bottomSheetAnim, {
68
- toValue: 1,
69
- useNativeDriver: true,
70
- bounciness: 0,
71
- }).start();
72
- }, []);
73
-
74
- const getDetails = async () => {
75
- try {
76
- // In Expo or development, use mock data
77
- if (__DEV__) {
78
- setDetails('Development mode - mock account info');
79
- return;
80
- }
81
-
82
- const response = await onairosApi.post('getAccountInfo', {
83
- Info: {
84
- username: username,
85
- },
86
- });
87
- // Handle response data properly based on API structure
88
- if (response && response.data) {
89
- const accountInfo = typeof response.data === 'object' && response.data.AccountInfo
90
- ? response.data.AccountInfo
91
- : `User: ${username}`;
92
- setDetails(accountInfo);
93
- } else {
94
- setDetails(`User: ${username}`);
95
- }
96
- } catch (e) {
97
- console.error('Error getting account info:', e);
98
- setDetails(`User: ${username}`);
99
- }
100
- };
101
-
102
- const closeOverlay = useCallback(() => {
103
- // Animate the overlay sliding down
104
- Animated.timing(bottomSheetAnim, {
105
- toValue: 0,
106
- duration: 250,
107
- useNativeDriver: true,
108
- }).start(() => {
109
- setVisible(false);
110
- });
111
- }, [bottomSheetAnim]);
112
-
113
- const togglePlatform = useCallback((platformId: string) => {
114
- setPlatformToggles(prev => ({
115
- ...prev,
116
- [platformId]: !prev[platformId]
117
- }));
118
- }, []);
119
-
120
- const confirmSelection = useCallback(async () => {
121
- try {
122
- // Mock app identifier
123
- const appId = Platform.select({
124
- ios: 'com.onairos.mock',
125
- android: 'com.onairos.mock',
126
- default: 'unknown'
127
- });
128
-
129
- // In development mode, use mock data
130
- if (__DEV__) {
131
- onResolved('https://api2.onairos.uk', 'mock-token', {
132
- username,
133
- selections,
134
- platforms: platformToggles
135
- });
136
- closeOverlay();
137
- return;
138
- }
139
-
140
- // Get server public key for encryption
141
- let serverPublicKey = 'mock-key';
142
- try {
143
- const keyResponse = await onairosApi.get('public/key');
144
- if (keyResponse && keyResponse.data && typeof keyResponse.data === 'object') {
145
- serverPublicKey = keyResponse.data.publicKey || 'mock-key';
146
- }
147
- } catch (e) {
148
- console.error('Error getting server public key:', e);
149
- }
150
-
151
- // Encrypt the model key - only if the function exists and server key is valid
152
- let encryptedModelKey = modelKey;
153
- if (typeof encryptModelKey === 'function' && serverPublicKey) {
154
- try {
155
- encryptedModelKey = encryptModelKey(serverPublicKey, modelKey);
156
- } catch (e) {
157
- console.error('Error encrypting model key:', e);
158
- }
159
- }
160
-
161
- const response = await onairosApi.post('getAPIUrlMobile', {
162
- Info: {
163
- storage: 'local',
164
- appId: appId,
165
- confirmations: selections,
166
- developerURL: 'devURL',
167
- EncryptedUserPin: encryptedModelKey,
168
- username: username,
169
- platforms: platformToggles
170
- },
171
- });
172
-
173
- if (response && response.data && response.data.APIUrl && response.data.token) {
174
- onResolved(response.data.APIUrl, response.data.token, {
175
- username,
176
- selections,
177
- platforms: platformToggles
178
- });
179
- closeOverlay();
180
- } else {
181
- // If response doesn't have expected format, use fallbacks
182
- onResolved('https://api2.onairos.uk', 'fallback-token', {
183
- username,
184
- selections,
185
- platforms: platformToggles
186
- });
187
- closeOverlay();
188
- }
189
- } catch (e) {
190
- console.error('Error confirming selection:', e);
191
- // In case of error, provide fallback (development mode)
192
- if (__DEV__) {
193
- onResolved('https://api2.onairos.uk', 'error-fallback-token', {
194
- username,
195
- selections,
196
- platforms: platformToggles,
197
- error: true
198
- });
199
- closeOverlay();
200
- } else {
201
- showErrorModal('Failed to confirm selection. Please try again.');
202
- }
203
- }
204
- }, [selections, username, modelKey, onResolved, closeOverlay, platformToggles]);
205
-
206
- const showErrorModal = (errorMessage: string) => {
207
- Alert.alert('Error', errorMessage, [{ text: 'OK' }]);
208
- };
209
-
210
- return (
211
- <Modal
212
- visible={visible}
213
- transparent
214
- animationType="none"
215
- statusBarTranslucent
216
- onRequestClose={closeOverlay}
217
- >
218
- <TouchableOpacity
219
- style={styles.modalOverlay}
220
- activeOpacity={1}
221
- onPress={closeOverlay}
222
- >
223
- <TouchableWithoutFeedback onPress={(e) => e.stopPropagation()}>
224
- <Animated.View
225
- style={[
226
- styles.bottomSheet,
227
- darkMode && styles.darkContainer,
228
- {
229
- transform: [
230
- {
231
- translateY: bottomSheetAnim.interpolate({
232
- inputRange: [0, 1],
233
- outputRange: [SCREEN_HEIGHT, 0],
234
- }),
235
- },
236
- ],
237
- },
238
- ]}
239
- >
240
- <View style={styles.handleContainer}>
241
- <View style={[styles.handle, darkMode && styles.darkHandle]} />
242
- </View>
243
-
244
- <SafeAreaView style={[styles.container, darkMode && styles.darkContainer]}>
245
- {/* Header with app icon and arrow to Onairos icon */}
246
- <View style={[styles.header, darkMode && styles.darkHeader]}>
247
- <View style={styles.headerContent}>
248
- <View style={[styles.appIcon, darkMode && styles.darkAppIcon]}>
249
- <Text style={[styles.appIconText, darkMode && styles.darkText]}>
250
- {appName.charAt(0)}
251
- </Text>
252
- </View>
253
- <Icon name="arrow_forward" size={24} color={darkMode ? '#999' : '#666'} style={styles.arrow} />
254
- <View style={[styles.onairosIcon, darkMode && styles.darkOnairosIcon]}>
255
- <Text style={[styles.onairosIconText, darkMode && styles.darkText]}>O</Text>
256
- </View>
257
- </View>
258
- </View>
259
-
260
- <ScrollView style={styles.content}>
261
- {/* Main title and description */}
262
- <View style={styles.titleContainer}>
263
- <Text style={[styles.mainTitle, darkMode && styles.darkText]}>
264
- Connect your data to create a Persona of you, to connect to Cosmos
265
- </Text>
266
- <Text style={[styles.privacyMessage, darkMode && styles.darkSubText]}>
267
- None of your app data is shared with ANYONE
268
- </Text>
269
- </View>
270
-
271
- {/* Platform connection options */}
272
- <View style={styles.platformsContainer}>
273
- {platforms.map((platform) => (
274
- <View key={platform.id} style={[styles.platformItem, darkMode && styles.darkPlatformItem]}>
275
- <View style={styles.platformInfo}>
276
- <Image
277
- source={platform.icon}
278
- style={styles.platformIcon}
279
- resizeMode="contain"
280
- />
281
- <Text style={[styles.platformName, darkMode && styles.darkText]}>
282
- {platform.name}
283
- </Text>
284
- </View>
285
- <Switch
286
- value={platformToggles[platform.id]}
287
- onValueChange={() => togglePlatform(platform.id)}
288
- trackColor={{ false: '#767577', true: '#81b0ff' }}
289
- thumbColor={platformToggles[platform.id] ? '#2196F3' : '#f4f3f4'}
290
- />
291
- </View>
292
- ))}
293
- </View>
294
- </ScrollView>
295
-
296
- <View style={[styles.footer, darkMode && styles.darkFooter]}>
297
- <TouchableOpacity
298
- style={styles.footerButtonCancel}
299
- onPress={closeOverlay}
300
- >
301
- <Text style={[styles.footerButtonText, darkMode && styles.darkSubText]}>Cancel</Text>
302
- </TouchableOpacity>
303
-
304
- <TouchableOpacity
305
- style={[styles.footerButtonConfirm, darkMode && styles.darkFooterButtonConfirm]}
306
- onPress={confirmSelection}
307
- >
308
- <Text style={[styles.footerButtonTextConfirm, darkMode && { color: '#000' }]}>Connect</Text>
309
- </TouchableOpacity>
310
- </View>
311
- </SafeAreaView>
312
- </Animated.View>
313
- </TouchableWithoutFeedback>
314
- </TouchableOpacity>
315
- </Modal>
316
- );
317
- };
318
-
319
- const styles = StyleSheet.create({
320
- modalOverlay: {
321
- flex: 1,
322
- backgroundColor: 'rgba(0, 0, 0, 0.5)',
323
- justifyContent: 'flex-end',
324
- },
325
- bottomSheet: {
326
- backgroundColor: '#fff',
327
- borderTopLeftRadius: 24,
328
- borderTopRightRadius: 24,
329
- width: SCREEN_WIDTH,
330
- height: SCREEN_HEIGHT * 0.8,
331
- overflow: 'hidden',
332
- },
333
- handleContainer: {
334
- width: '100%',
335
- alignItems: 'center',
336
- paddingTop: 12,
337
- paddingBottom: 8,
338
- },
339
- handle: {
340
- width: 40,
341
- height: 5,
342
- borderRadius: 3,
343
- backgroundColor: '#E0E0E0',
344
- },
345
- darkHandle: {
346
- backgroundColor: '#666',
347
- },
348
- container: {
349
- flex: 1,
350
- backgroundColor: '#fff',
351
- },
352
- darkContainer: {
353
- backgroundColor: '#1A1A1A',
354
- },
355
- header: {
356
- padding: 24,
357
- alignItems: 'center',
358
- },
359
- darkHeader: {
360
- backgroundColor: '#1A1A1A',
361
- },
362
- headerContent: {
363
- flexDirection: 'row',
364
- alignItems: 'center',
365
- justifyContent: 'center',
366
- marginBottom: 16,
367
- },
368
- appIcon: {
369
- width: 48,
370
- height: 48,
371
- borderRadius: 16,
372
- backgroundColor: '#F5F5F5',
373
- alignItems: 'center',
374
- justifyContent: 'center',
375
- },
376
- darkAppIcon: {
377
- backgroundColor: '#2A2A2A',
378
- },
379
- appIconText: {
380
- fontSize: 24,
381
- color: '#000',
382
- },
383
- darkText: {
384
- color: '#fff',
385
- },
386
- arrow: {
387
- marginHorizontal: 16,
388
- },
389
- onairosIcon: {
390
- width: 48,
391
- height: 48,
392
- borderRadius: 16,
393
- backgroundColor: '#F5F5F5',
394
- alignItems: 'center',
395
- justifyContent: 'center',
396
- },
397
- darkOnairosIcon: {
398
- backgroundColor: '#2A2A2A',
399
- },
400
- onairosIconText: {
401
- fontSize: 24,
402
- color: '#000',
403
- },
404
- darkSubText: {
405
- color: '#999',
406
- },
407
- titleContainer: {
408
- marginBottom: 30,
409
- },
410
- mainTitle: {
411
- fontSize: 22,
412
- fontWeight: '600',
413
- color: '#000',
414
- textAlign: 'center',
415
- marginBottom: 16,
416
- },
417
- privacyMessage: {
418
- fontSize: 14,
419
- color: '#666',
420
- textAlign: 'center',
421
- marginBottom: 16,
422
- },
423
- content: {
424
- flex: 1,
425
- paddingHorizontal: 24,
426
- },
427
- platformsContainer: {
428
- marginTop: 16,
429
- },
430
- platformItem: {
431
- flexDirection: 'row',
432
- justifyContent: 'space-between',
433
- alignItems: 'center',
434
- padding: 16,
435
- backgroundColor: '#fff',
436
- borderRadius: 16,
437
- marginBottom: 16,
438
- borderWidth: 1,
439
- borderColor: '#eee',
440
- },
441
- darkPlatformItem: {
442
- backgroundColor: '#2A2A2A',
443
- borderColor: '#333',
444
- },
445
- platformInfo: {
446
- flexDirection: 'row',
447
- alignItems: 'center',
448
- },
449
- platformIcon: {
450
- width: 32,
451
- height: 32,
452
- marginRight: 12,
453
- },
454
- platformName: {
455
- fontSize: 16,
456
- fontWeight: '500',
457
- color: '#000',
458
- },
459
- footer: {
460
- flexDirection: 'row',
461
- alignItems: 'center',
462
- justifyContent: 'space-between',
463
- padding: 24,
464
- borderTopWidth: 1,
465
- borderTopColor: '#eee',
466
- backgroundColor: '#fff',
467
- },
468
- darkFooter: {
469
- backgroundColor: '#2A2A2A',
470
- borderTopColor: '#333',
471
- },
472
- footerButtonCancel: {
473
- paddingVertical: 8,
474
- paddingHorizontal: 16,
475
- },
476
- darkFooterButton: {
477
- backgroundColor: 'transparent',
478
- },
479
- footerButtonConfirm: {
480
- paddingVertical: 16,
481
- paddingHorizontal: 32,
482
- borderRadius: 16,
483
- backgroundColor: '#fff',
484
- borderWidth: 1,
485
- borderColor: '#000',
486
- },
487
- darkFooterButtonConfirm: {
488
- backgroundColor: '#fff',
489
- borderColor: '#fff',
490
- },
491
- footerButtonText: {
492
- color: '#666',
493
- fontSize: 16,
494
- },
495
- footerButtonTextConfirm: {
496
- color: '#000',
497
- fontSize: 16,
498
- fontWeight: '600',
499
- },
500
- lightBackground: {
501
- backgroundColor: '#fff',
502
- },
503
- darkBackground: {
504
- backgroundColor: '#1A1A1A',
505
- },
506
- });
1
+ import React, { useState, useEffect, useCallback, useRef } from 'react';
2
+ import {
3
+ View,
4
+ Text,
5
+ StyleSheet,
6
+ TouchableOpacity,
7
+ ScrollView,
8
+ Alert,
9
+ Platform,
10
+ Dimensions,
11
+ Modal,
12
+ Animated,
13
+ TouchableWithoutFeedback,
14
+ SafeAreaView,
15
+ Image,
16
+ Switch,
17
+ } from 'react-native';
18
+ import Icon from 'react-native-vector-icons/MaterialIcons';
19
+ import { onairosApi } from '../api';
20
+ import { encryptModelKey } from '../utils/encryption';
21
+ import { COLORS } from '../constants';
22
+
23
+ const { width: SCREEN_WIDTH, height: SCREEN_HEIGHT } = Dimensions.get('window');
24
+
25
+ import type { OverlayProps } from '../types';
26
+
27
+ export const Overlay: React.FC<OverlayProps> = ({
28
+ data,
29
+ username,
30
+ modelKey,
31
+ onResolved,
32
+ appName = 'Your App',
33
+ darkMode = false,
34
+ platforms = [
35
+ { id: 'instagram', name: 'Instagram', icon: require('../assets/icons/instagram.png') },
36
+ { id: 'youtube', name: 'YouTube', icon: require('../assets/icons/YouTubeicon2.png') },
37
+ { id: 'reddit', name: 'Reddit', icon: require('../assets/icons/Redditicon.png') },
38
+ { id: 'pinterest', name: 'Pinterest', icon: require('../assets/icons/pinterest.png') },
39
+ { id: 'email', name: 'Email', icon: require('../assets/icons/Gmail.png') },
40
+ ],
41
+ }) => {
42
+ const [selections, setSelections] = useState<{ [key: string]: boolean }>({});
43
+ const [details, setDetails] = useState<string>('');
44
+ const [visible, setVisible] = useState(true);
45
+ const [platformToggles, setPlatformToggles] = useState<{[key: string]: boolean}>({});
46
+ const bottomSheetAnim = useRef(new Animated.Value(0)).current;
47
+
48
+ // Initialize selection state on mount
49
+ useEffect(() => {
50
+ // Initialize selection state
51
+ const initialSelections: { [key: string]: boolean } = {};
52
+ Object.keys(data).forEach((key) => {
53
+ initialSelections[key] = false;
54
+ });
55
+ setSelections(initialSelections);
56
+
57
+ // Initialize platform toggles
58
+ const initialToggles: { [key: string]: boolean } = {};
59
+ platforms.forEach((platform) => {
60
+ initialToggles[platform.id] = false;
61
+ });
62
+ setPlatformToggles(initialToggles);
63
+
64
+ getDetails();
65
+
66
+ // Animate the bottom sheet sliding up
67
+ Animated.spring(bottomSheetAnim, {
68
+ toValue: 1,
69
+ useNativeDriver: true,
70
+ bounciness: 0,
71
+ }).start();
72
+ }, []);
73
+
74
+ const getDetails = async () => {
75
+ try {
76
+ // In Expo or development, use mock data
77
+ if (__DEV__) {
78
+ setDetails('Development mode - mock account info');
79
+ return;
80
+ }
81
+
82
+ const response = await onairosApi.post('getAccountInfo', {
83
+ Info: {
84
+ username: username,
85
+ },
86
+ });
87
+ // Handle response data properly based on API structure
88
+ if (response && response.data) {
89
+ const accountInfo = typeof response.data === 'object' && response.data.AccountInfo
90
+ ? response.data.AccountInfo
91
+ : `User: ${username}`;
92
+ setDetails(accountInfo);
93
+ } else {
94
+ setDetails(`User: ${username}`);
95
+ }
96
+ } catch (e) {
97
+ console.error('Error getting account info:', e);
98
+ setDetails(`User: ${username}`);
99
+ }
100
+ };
101
+
102
+ const closeOverlay = useCallback(() => {
103
+ // Animate the overlay sliding down
104
+ Animated.timing(bottomSheetAnim, {
105
+ toValue: 0,
106
+ duration: 250,
107
+ useNativeDriver: true,
108
+ }).start(() => {
109
+ setVisible(false);
110
+ });
111
+ }, [bottomSheetAnim]);
112
+
113
+ const togglePlatform = useCallback((platformId: string) => {
114
+ setPlatformToggles(prev => ({
115
+ ...prev,
116
+ [platformId]: !prev[platformId]
117
+ }));
118
+ }, []);
119
+
120
+ const confirmSelection = useCallback(async () => {
121
+ try {
122
+ // Mock app identifier
123
+ const appId = Platform.select({
124
+ ios: 'com.onairos.mock',
125
+ android: 'com.onairos.mock',
126
+ default: 'unknown'
127
+ });
128
+
129
+ // In development mode, use mock data
130
+ if (__DEV__) {
131
+ onResolved('https://api2.onairos.uk', 'mock-token', {
132
+ username,
133
+ selections,
134
+ platforms: platformToggles
135
+ });
136
+ closeOverlay();
137
+ return;
138
+ }
139
+
140
+ // Get server public key for encryption
141
+ let serverPublicKey = 'mock-key';
142
+ try {
143
+ const keyResponse = await onairosApi.get('public/key');
144
+ if (keyResponse && keyResponse.data && typeof keyResponse.data === 'object') {
145
+ serverPublicKey = keyResponse.data.publicKey || 'mock-key';
146
+ }
147
+ } catch (e) {
148
+ console.error('Error getting server public key:', e);
149
+ }
150
+
151
+ // Encrypt the model key - only if the function exists and server key is valid
152
+ let encryptedModelKey = modelKey;
153
+ if (typeof encryptModelKey === 'function' && serverPublicKey) {
154
+ try {
155
+ encryptedModelKey = encryptModelKey(serverPublicKey, modelKey);
156
+ } catch (e) {
157
+ console.error('Error encrypting model key:', e);
158
+ }
159
+ }
160
+
161
+ const response = await onairosApi.post('getAPIUrlMobile', {
162
+ Info: {
163
+ storage: 'local',
164
+ appId: appId,
165
+ confirmations: selections,
166
+ developerURL: 'devURL',
167
+ EncryptedUserPin: encryptedModelKey,
168
+ username: username,
169
+ platforms: platformToggles
170
+ },
171
+ });
172
+
173
+ if (response && response.data && response.data.APIUrl && response.data.token) {
174
+ onResolved(response.data.APIUrl, response.data.token, {
175
+ username,
176
+ selections,
177
+ platforms: platformToggles
178
+ });
179
+ closeOverlay();
180
+ } else {
181
+ // If response doesn't have expected format, use fallbacks
182
+ onResolved('https://api2.onairos.uk', 'fallback-token', {
183
+ username,
184
+ selections,
185
+ platforms: platformToggles
186
+ });
187
+ closeOverlay();
188
+ }
189
+ } catch (e) {
190
+ console.error('Error confirming selection:', e);
191
+ // In case of error, provide fallback (development mode)
192
+ if (__DEV__) {
193
+ onResolved('https://api2.onairos.uk', 'error-fallback-token', {
194
+ username,
195
+ selections,
196
+ platforms: platformToggles,
197
+ error: true
198
+ });
199
+ closeOverlay();
200
+ } else {
201
+ showErrorModal('Failed to confirm selection. Please try again.');
202
+ }
203
+ }
204
+ }, [selections, username, modelKey, onResolved, closeOverlay, platformToggles]);
205
+
206
+ const showErrorModal = (errorMessage: string) => {
207
+ Alert.alert('Error', errorMessage, [{ text: 'OK' }]);
208
+ };
209
+
210
+ return (
211
+ <Modal
212
+ visible={visible}
213
+ transparent
214
+ animationType="none"
215
+ statusBarTranslucent
216
+ onRequestClose={closeOverlay}
217
+ >
218
+ <TouchableOpacity
219
+ style={styles.modalOverlay}
220
+ activeOpacity={1}
221
+ onPress={closeOverlay}
222
+ >
223
+ <TouchableWithoutFeedback onPress={(e) => e.stopPropagation()}>
224
+ <Animated.View
225
+ style={[
226
+ styles.bottomSheet,
227
+ darkMode && styles.darkContainer,
228
+ {
229
+ transform: [
230
+ {
231
+ translateY: bottomSheetAnim.interpolate({
232
+ inputRange: [0, 1],
233
+ outputRange: [SCREEN_HEIGHT, 0],
234
+ }),
235
+ },
236
+ ],
237
+ },
238
+ ]}
239
+ >
240
+ <View style={styles.handleContainer}>
241
+ <View style={[styles.handle, darkMode && styles.darkHandle]} />
242
+ </View>
243
+
244
+ <SafeAreaView style={[styles.container, darkMode && styles.darkContainer]}>
245
+ {/* Header with app icon and arrow to Onairos icon */}
246
+ <View style={[styles.header, darkMode && styles.darkHeader]}>
247
+ <View style={styles.headerContent}>
248
+ <View style={[styles.appIcon, darkMode && styles.darkAppIcon]}>
249
+ <Text style={[styles.appIconText, darkMode && styles.darkText]}>
250
+ {appName.charAt(0)}
251
+ </Text>
252
+ </View>
253
+ <Icon name="arrow_forward" size={24} color={darkMode ? '#999' : '#666'} style={styles.arrow} />
254
+ <View style={[styles.onairosIcon, darkMode && styles.darkOnairosIcon]}>
255
+ <Text style={[styles.onairosIconText, darkMode && styles.darkText]}>O</Text>
256
+ </View>
257
+ </View>
258
+ </View>
259
+
260
+ <ScrollView style={styles.content}>
261
+ {/* Main title and description */}
262
+ <View style={styles.titleContainer}>
263
+ <Text style={[styles.mainTitle, darkMode && styles.darkText]}>
264
+ Connect your data to create a Persona of you, to connect to Cosmos
265
+ </Text>
266
+ <Text style={[styles.privacyMessage, darkMode && styles.darkSubText]}>
267
+ None of your app data is shared with ANYONE
268
+ </Text>
269
+ </View>
270
+
271
+ {/* Platform connection options */}
272
+ <View style={styles.platformsContainer}>
273
+ {platforms.map((platform) => (
274
+ <View key={platform.id} style={[styles.platformItem, darkMode && styles.darkPlatformItem]}>
275
+ <View style={styles.platformInfo}>
276
+ <Image
277
+ source={platform.icon}
278
+ style={styles.platformIcon}
279
+ resizeMode="contain"
280
+ />
281
+ <Text style={[styles.platformName, darkMode && styles.darkText]}>
282
+ {platform.name}
283
+ </Text>
284
+ </View>
285
+ <Switch
286
+ value={platformToggles[platform.id]}
287
+ onValueChange={() => togglePlatform(platform.id)}
288
+ trackColor={{ false: '#767577', true: '#81b0ff' }}
289
+ thumbColor={platformToggles[platform.id] ? '#2196F3' : '#f4f3f4'}
290
+ />
291
+ </View>
292
+ ))}
293
+ </View>
294
+ </ScrollView>
295
+
296
+ <View style={[styles.footer, darkMode && styles.darkFooter]}>
297
+ <TouchableOpacity
298
+ style={styles.footerButtonCancel}
299
+ onPress={closeOverlay}
300
+ >
301
+ <Text style={[styles.footerButtonText, darkMode && styles.darkSubText]}>Cancel</Text>
302
+ </TouchableOpacity>
303
+
304
+ <TouchableOpacity
305
+ style={[styles.footerButtonConfirm, darkMode && styles.darkFooterButtonConfirm]}
306
+ onPress={confirmSelection}
307
+ >
308
+ <Text style={[styles.footerButtonTextConfirm, darkMode && { color: '#000' }]}>Connect</Text>
309
+ </TouchableOpacity>
310
+ </View>
311
+ </SafeAreaView>
312
+ </Animated.View>
313
+ </TouchableWithoutFeedback>
314
+ </TouchableOpacity>
315
+ </Modal>
316
+ );
317
+ };
318
+
319
+ const styles = StyleSheet.create({
320
+ modalOverlay: {
321
+ flex: 1,
322
+ backgroundColor: 'rgba(0, 0, 0, 0.5)',
323
+ justifyContent: 'flex-end',
324
+ },
325
+ bottomSheet: {
326
+ backgroundColor: '#fff',
327
+ borderTopLeftRadius: 24,
328
+ borderTopRightRadius: 24,
329
+ width: SCREEN_WIDTH,
330
+ height: SCREEN_HEIGHT * 0.8,
331
+ overflow: 'hidden',
332
+ },
333
+ handleContainer: {
334
+ width: '100%',
335
+ alignItems: 'center',
336
+ paddingTop: 12,
337
+ paddingBottom: 8,
338
+ },
339
+ handle: {
340
+ width: 40,
341
+ height: 5,
342
+ borderRadius: 3,
343
+ backgroundColor: '#E0E0E0',
344
+ },
345
+ darkHandle: {
346
+ backgroundColor: '#666',
347
+ },
348
+ container: {
349
+ flex: 1,
350
+ backgroundColor: '#fff',
351
+ },
352
+ darkContainer: {
353
+ backgroundColor: '#1A1A1A',
354
+ },
355
+ header: {
356
+ padding: 24,
357
+ alignItems: 'center',
358
+ },
359
+ darkHeader: {
360
+ backgroundColor: '#1A1A1A',
361
+ },
362
+ headerContent: {
363
+ flexDirection: 'row',
364
+ alignItems: 'center',
365
+ justifyContent: 'center',
366
+ marginBottom: 16,
367
+ },
368
+ appIcon: {
369
+ width: 48,
370
+ height: 48,
371
+ borderRadius: 16,
372
+ backgroundColor: '#F5F5F5',
373
+ alignItems: 'center',
374
+ justifyContent: 'center',
375
+ },
376
+ darkAppIcon: {
377
+ backgroundColor: '#2A2A2A',
378
+ },
379
+ appIconText: {
380
+ fontSize: 24,
381
+ color: '#000',
382
+ },
383
+ darkText: {
384
+ color: '#fff',
385
+ },
386
+ arrow: {
387
+ marginHorizontal: 16,
388
+ },
389
+ onairosIcon: {
390
+ width: 48,
391
+ height: 48,
392
+ borderRadius: 16,
393
+ backgroundColor: '#F5F5F5',
394
+ alignItems: 'center',
395
+ justifyContent: 'center',
396
+ },
397
+ darkOnairosIcon: {
398
+ backgroundColor: '#2A2A2A',
399
+ },
400
+ onairosIconText: {
401
+ fontSize: 24,
402
+ color: '#000',
403
+ },
404
+ darkSubText: {
405
+ color: '#999',
406
+ },
407
+ titleContainer: {
408
+ marginBottom: 30,
409
+ },
410
+ mainTitle: {
411
+ fontSize: 22,
412
+ fontWeight: '600',
413
+ color: '#000',
414
+ textAlign: 'center',
415
+ marginBottom: 16,
416
+ },
417
+ privacyMessage: {
418
+ fontSize: 14,
419
+ color: '#666',
420
+ textAlign: 'center',
421
+ marginBottom: 16,
422
+ },
423
+ content: {
424
+ flex: 1,
425
+ paddingHorizontal: 24,
426
+ },
427
+ platformsContainer: {
428
+ marginTop: 16,
429
+ },
430
+ platformItem: {
431
+ flexDirection: 'row',
432
+ justifyContent: 'space-between',
433
+ alignItems: 'center',
434
+ padding: 16,
435
+ backgroundColor: '#fff',
436
+ borderRadius: 16,
437
+ marginBottom: 16,
438
+ borderWidth: 1,
439
+ borderColor: '#eee',
440
+ },
441
+ darkPlatformItem: {
442
+ backgroundColor: '#2A2A2A',
443
+ borderColor: '#333',
444
+ },
445
+ platformInfo: {
446
+ flexDirection: 'row',
447
+ alignItems: 'center',
448
+ },
449
+ platformIcon: {
450
+ width: 32,
451
+ height: 32,
452
+ marginRight: 12,
453
+ },
454
+ platformName: {
455
+ fontSize: 16,
456
+ fontWeight: '500',
457
+ color: '#000',
458
+ },
459
+ footer: {
460
+ flexDirection: 'row',
461
+ alignItems: 'center',
462
+ justifyContent: 'space-between',
463
+ padding: 24,
464
+ borderTopWidth: 1,
465
+ borderTopColor: '#eee',
466
+ backgroundColor: '#fff',
467
+ },
468
+ darkFooter: {
469
+ backgroundColor: '#2A2A2A',
470
+ borderTopColor: '#333',
471
+ },
472
+ footerButtonCancel: {
473
+ paddingVertical: 8,
474
+ paddingHorizontal: 16,
475
+ },
476
+ darkFooterButton: {
477
+ backgroundColor: 'transparent',
478
+ },
479
+ footerButtonConfirm: {
480
+ paddingVertical: 16,
481
+ paddingHorizontal: 32,
482
+ borderRadius: 16,
483
+ backgroundColor: '#fff',
484
+ borderWidth: 1,
485
+ borderColor: '#000',
486
+ },
487
+ darkFooterButtonConfirm: {
488
+ backgroundColor: '#fff',
489
+ borderColor: '#fff',
490
+ },
491
+ footerButtonText: {
492
+ color: '#666',
493
+ fontSize: 16,
494
+ },
495
+ footerButtonTextConfirm: {
496
+ color: '#000',
497
+ fontSize: 16,
498
+ fontWeight: '600',
499
+ },
500
+ lightBackground: {
501
+ backgroundColor: '#fff',
502
+ },
503
+ darkBackground: {
504
+ backgroundColor: '#1A1A1A',
505
+ },
506
+ });