@onairos/react-native 3.1.15 → 3.1.17

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 (191) 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/OnairosSignInButton.js +32 -74
  16. package/lib/commonjs/components/OnairosSignInButton.js.map +1 -1
  17. package/lib/commonjs/components/UniversalOnboarding.js +4 -4
  18. package/lib/commonjs/config/api.js +2 -2
  19. package/lib/commonjs/hooks/useConnections.js +6 -6
  20. package/lib/commonjs/hooks/useUserConnections.js +10 -10
  21. package/lib/commonjs/index.js +5 -12
  22. package/lib/commonjs/index.js.map +1 -1
  23. package/lib/commonjs/services/apiClient.js +35 -35
  24. package/lib/commonjs/services/apiKeyService.js +99 -99
  25. package/lib/commonjs/services/authService.js +82 -82
  26. package/lib/commonjs/services/biometricPinService.js +10 -10
  27. package/lib/commonjs/services/connectedAccountsService.js +32 -32
  28. package/lib/commonjs/services/googleAuthService.js +15 -15
  29. package/lib/commonjs/services/imageCompressionService.js +15 -15
  30. package/lib/commonjs/services/jwtStorageService.js +59 -59
  31. package/lib/commonjs/services/mobileTrainingService.js +14 -14
  32. package/lib/commonjs/services/pinEncryptionService.js +10 -10
  33. package/lib/commonjs/services/pinStorageUtils.js +15 -15
  34. package/lib/commonjs/services/platformAuthService.js +47 -47
  35. package/lib/commonjs/services/storageService.js +31 -31
  36. package/lib/commonjs/services/trainingApiHelpers.js +33 -33
  37. package/lib/commonjs/services/userConnectionsService.js +24 -24
  38. package/lib/commonjs/utils/Portal.js +4 -4
  39. package/lib/commonjs/utils/api.js +24 -24
  40. package/lib/commonjs/utils/auth.js +18 -18
  41. package/lib/commonjs/utils/crypto.js +13 -13
  42. package/lib/commonjs/utils/encryption.js +12 -12
  43. package/lib/commonjs/utils/eventUtils.js +52 -52
  44. package/lib/commonjs/utils/programmaticFlow.js +16 -16
  45. package/lib/commonjs/utils/retryHelper.js +27 -27
  46. package/lib/module/assets/images/Checkbox.svg +3 -3
  47. package/lib/module/assets/images/EnochE.svg +19 -19
  48. package/lib/module/assets/images/Personalityprofile.svg +3 -3
  49. package/lib/module/assets/images/Personalitytraits.svg +3 -3
  50. package/lib/module/assets/images/Userpreferences.svg +3 -3
  51. package/lib/module/assets/images/arrow.svg +20 -20
  52. package/lib/module/assets/images/basicproficon.svg +43 -43
  53. package/lib/module/assets/images/basicprofile.svg +3 -3
  54. package/lib/module/assets/images/checkmark.svg +4 -4
  55. package/lib/module/assets/images/contentanalysis.svg +3 -3
  56. package/lib/module/assets/images/contenticon.svg +23 -23
  57. package/lib/module/assets/images/personalityicon.svg +18 -18
  58. package/lib/module/assets/images/x-close.svg +3 -3
  59. package/lib/module/components/OnairosSignInButton.js +32 -74
  60. package/lib/module/components/OnairosSignInButton.js.map +1 -1
  61. package/lib/module/components/UniversalOnboarding.js +4 -4
  62. package/lib/module/config/api.js +2 -2
  63. package/lib/module/hooks/useConnections.js +6 -6
  64. package/lib/module/hooks/useUserConnections.js +10 -10
  65. package/lib/module/index.js +5 -6
  66. package/lib/module/index.js.map +1 -1
  67. package/lib/module/services/apiClient.js +35 -35
  68. package/lib/module/services/apiKeyService.js +99 -99
  69. package/lib/module/services/authService.js +82 -82
  70. package/lib/module/services/biometricPinService.js +10 -10
  71. package/lib/module/services/connectedAccountsService.js +32 -32
  72. package/lib/module/services/googleAuthService.js +15 -15
  73. package/lib/module/services/imageCompressionService.js +15 -15
  74. package/lib/module/services/jwtStorageService.js +59 -59
  75. package/lib/module/services/mobileTrainingService.js +14 -14
  76. package/lib/module/services/pinEncryptionService.js +10 -10
  77. package/lib/module/services/pinStorageUtils.js +15 -15
  78. package/lib/module/services/platformAuthService.js +47 -47
  79. package/lib/module/services/storageService.js +31 -31
  80. package/lib/module/services/trainingApiHelpers.js +33 -33
  81. package/lib/module/services/userConnectionsService.js +24 -24
  82. package/lib/module/utils/Portal.js +4 -4
  83. package/lib/module/utils/api.js +24 -24
  84. package/lib/module/utils/auth.js +18 -18
  85. package/lib/module/utils/crypto.js +13 -13
  86. package/lib/module/utils/encryption.js +12 -12
  87. package/lib/module/utils/eventUtils.js +52 -52
  88. package/lib/module/utils/programmaticFlow.js +16 -16
  89. package/lib/module/utils/retryHelper.js +27 -27
  90. package/lib/typescript/components/OnairosSignInButton.d.ts.map +1 -1
  91. package/lib/typescript/index.d.ts +0 -1
  92. package/lib/typescript/index.d.ts.map +1 -1
  93. package/package.json +163 -163
  94. package/src/api/index.ts +151 -151
  95. package/src/assets/images/Checkbox.svg +3 -3
  96. package/src/assets/images/EnochE.svg +19 -19
  97. package/src/assets/images/Personalityprofile.svg +3 -3
  98. package/src/assets/images/Personalitytraits.svg +3 -3
  99. package/src/assets/images/Userpreferences.svg +3 -3
  100. package/src/assets/images/arrow.svg +20 -20
  101. package/src/assets/images/basicproficon.svg +43 -43
  102. package/src/assets/images/basicprofile.svg +3 -3
  103. package/src/assets/images/checkmark.svg +4 -4
  104. package/src/assets/images/contentanalysis.svg +3 -3
  105. package/src/assets/images/contenticon.svg +23 -23
  106. package/src/assets/images/personalityicon.svg +18 -18
  107. package/src/assets/images/x-close.svg +3 -3
  108. package/src/components/BodyText.tsx +33 -33
  109. package/src/components/BrandMark.tsx +62 -62
  110. package/src/components/CodeInput.tsx +32 -32
  111. package/src/components/DataRequestScreen.tsx +355 -355
  112. package/src/components/EmailInput.tsx +31 -31
  113. package/src/components/EmailVerificationModal.tsx +363 -363
  114. package/src/components/ExistingUserDataConfirmation.tsx +506 -506
  115. package/src/components/GoogleButton.tsx +55 -55
  116. package/src/components/HeadingGroup.tsx +49 -49
  117. package/src/components/ModalHeader.tsx +125 -125
  118. package/src/components/ModalSheet.tsx +57 -57
  119. package/src/components/Onairos.tsx +422 -422
  120. package/src/components/OnairosButton.tsx +339 -339
  121. package/src/components/OnairosSignInButton.tsx +130 -166
  122. package/src/components/Overlay.tsx +506 -506
  123. package/src/components/PersonaImage.tsx +79 -79
  124. package/src/components/PersonaLoadingScreen.tsx +201 -201
  125. package/src/components/PersonalizationConsentScreen.tsx +410 -410
  126. package/src/components/PinCreationScreen.tsx +492 -492
  127. package/src/components/PinInput.tsx +555 -555
  128. package/src/components/PlatformConnectorsStep.tsx +891 -891
  129. package/src/components/PlatformList.tsx +144 -144
  130. package/src/components/PlatformToggle.tsx +226 -226
  131. package/src/components/PrimaryButton.tsx +213 -213
  132. package/src/components/SignInMatchAnimation.tsx +225 -225
  133. package/src/components/SignInStep.tsx +217 -217
  134. package/src/components/TrainingModal.tsx +1047 -1047
  135. package/src/components/UniversalOnboarding.tsx +2887 -2887
  136. package/src/components/VerificationStep.tsx +198 -198
  137. package/src/components/WelcomeScreen.tsx +473 -473
  138. package/src/components/icons/Basicproficon.tsx +30 -30
  139. package/src/components/icons/Basicprofile.tsx +17 -17
  140. package/src/components/icons/Checkbox.tsx +17 -17
  141. package/src/components/icons/Checkmark.tsx +24 -24
  142. package/src/components/icons/Contentanalysis.tsx +17 -17
  143. package/src/components/icons/Contenticon.tsx +30 -30
  144. package/src/components/icons/EnochE.tsx +39 -39
  145. package/src/components/icons/Personalityicon.tsx +22 -22
  146. package/src/components/icons/Personalityprofile.tsx +17 -17
  147. package/src/components/icons/Personalitytraits.tsx +17 -17
  148. package/src/components/icons/Userpreferences.tsx +17 -17
  149. package/src/components/icons/index.ts +12 -12
  150. package/src/components/onboarding/OAuthWebView.tsx +232 -232
  151. package/src/config/api.ts +25 -25
  152. package/src/context/AuthContext.tsx +393 -393
  153. package/src/hooks/useConnectedAccounts.ts +138 -138
  154. package/src/hooks/useConnections.ts +161 -161
  155. package/src/hooks/useCredentials.ts +174 -174
  156. package/src/hooks/useUserConnections.ts +165 -165
  157. package/src/index.js +14 -14
  158. package/src/index.ts +94 -95
  159. package/src/services/apiClient.ts +336 -336
  160. package/src/services/apiKeyService.ts +919 -919
  161. package/src/services/authService.ts +1008 -1008
  162. package/src/services/biometricPinService.ts +192 -192
  163. package/src/services/connectedAccountsService.ts +289 -289
  164. package/src/services/googleAuthService.ts +279 -279
  165. package/src/services/imageCompressionService.ts +302 -302
  166. package/src/services/jwtStorageService.ts +256 -256
  167. package/src/services/mobileTrainingService.ts +203 -203
  168. package/src/services/pinEncryptionService.ts +75 -75
  169. package/src/services/pinStorageUtils.ts +96 -96
  170. package/src/services/platformAuthService.ts +1346 -1346
  171. package/src/services/storageService.ts +451 -451
  172. package/src/services/trainingApiHelpers.ts +66 -66
  173. package/src/services/userConnectionsService.ts +556 -556
  174. package/src/services/youtubeMigrationService.ts +453 -453
  175. package/src/theme/index.ts +239 -239
  176. package/src/types/ambient.d.ts +28 -28
  177. package/src/types/index.ts +265 -265
  178. package/src/types/node-fix.d.ts +18 -18
  179. package/src/types/node-override.d.ts +23 -23
  180. package/src/types/opacity.d.ts +15 -15
  181. package/src/types/types.d.ts +17 -17
  182. package/src/utils/Portal.tsx +82 -82
  183. package/src/utils/api.js +111 -111
  184. package/src/utils/auth.js +103 -103
  185. package/src/utils/crypto.js +59 -59
  186. package/src/utils/encryption.ts +68 -68
  187. package/src/utils/eventUtils.ts +302 -302
  188. package/src/utils/haptics.ts +58 -58
  189. package/src/utils/imagePreloader.ts +2 -2
  190. package/src/utils/programmaticFlow.ts +112 -112
  191. package/src/utils/retryHelper.ts +274 -274
@@ -1,452 +1,452 @@
1
- import AsyncStorage from '@react-native-async-storage/async-storage';
2
- import { clearStoredPin } from './pinStorageUtils';
3
-
4
- // Storage keys
5
- export const STORAGE_KEYS = {
6
- // Authentication
7
- AUTH_TOKEN: 'auth_token',
8
- ONAIROS_JWT_TOKEN: 'onairos_jwt_token',
9
- ENOCH_TOKEN: 'enoch_token',
10
-
11
- // User data
12
- USER: 'user',
13
- USER_PROFILE: 'userProfile',
14
- USER_PROFILE_FALLBACK: 'userProfileFallback',
15
-
16
- // App state
17
- USER_PROGRESS: 'user_progress',
18
- ONBOARDING_COMPLETED: 'onboardingCompleted',
19
- IS_FIRST_TIME_USER: 'isFirstTimeUser',
20
- USER_ATTENDANCE_CONFIRMED: 'userAttendanceConfirmed',
21
-
22
- // New: Token for completed onboarding with Results access
23
- ONBOARDING_COMPLETE_TOKEN: 'onboarding_complete_token',
24
- EVENT_ACCESS_TOKEN: 'event_access_token',
25
-
26
- // Authentication method tracking
27
- ONAIROS_USER: 'onairos_user',
28
- APPLE_USER: 'apple_user',
29
- AUTH_METHOD: 'auth_method',
30
-
31
- // Session data
32
- CURRENT_EVENT_DATA: 'currentEventData',
33
- CONNECTED_PLATFORMS: 'connectedPlatforms',
34
- PROFILE_IMAGE: 'profileImage',
35
-
36
- // Admin status
37
- USER_ADMIN_STATUS: 'user_admin_status',
38
- } as const;
39
-
40
- // User progress tracking
41
- export interface UserProgress {
42
- lastScreen: string;
43
- completedSteps: string[];
44
- authMethod: 'apple' | 'onairos' | null;
45
- hasProfilePhoto: boolean;
46
- hasCompletedProfile: boolean;
47
- hasSelectedIntentions: boolean;
48
- hasViewedResults: boolean;
49
- eventCode?: string;
50
- hasEnteredEventCode: boolean;
51
- hasRegisteredForEvent?: boolean;
52
- // New: Flag to indicate user has completed entire onboarding flow
53
- hasReachedEventPage: boolean;
54
- // Store event data for returning users
55
- eventData?: {
56
- eventType?: string;
57
- eventCode?: string;
58
- photo?: string;
59
- userProfile?: any;
60
- inferenceData?: any;
61
- };
62
- timestamp: number;
63
- }
64
-
65
- // Authentication state
66
- export interface AuthState {
67
- isAuthenticated: boolean;
68
- authMethod: 'apple' | 'onairos' | null;
69
- hasValidToken: boolean;
70
- userEmail?: string;
71
- userName?: string;
72
- }
73
-
74
- /**
75
- * Save user progress to track where they left off
76
- */
77
- export const saveUserProgress = async (progress: Partial<UserProgress>): Promise<void> => {
78
- try {
79
- const existingProgress = await getUserProgress();
80
- const updatedProgress: UserProgress = {
81
- ...existingProgress,
82
- ...progress,
83
- timestamp: Date.now(),
84
- };
85
-
86
- await AsyncStorage.setItem(STORAGE_KEYS.USER_PROGRESS, JSON.stringify(updatedProgress));
87
- console.log('✅ User progress saved:', updatedProgress);
88
- } catch (error) {
89
- console.error('❌ Error saving user progress:', error);
90
- }
91
- };
92
-
93
- /**
94
- * Get user progress to determine where to resume
95
- */
96
- export const getUserProgress = async (): Promise<UserProgress> => {
97
- try {
98
- const progressData = await AsyncStorage.getItem(STORAGE_KEYS.USER_PROGRESS);
99
- if (progressData) {
100
- return JSON.parse(progressData);
101
- }
102
- } catch (error) {
103
- console.error('❌ Error getting user progress:', error);
104
- }
105
-
106
- // Return default progress
107
- return {
108
- lastScreen: 'Welcome',
109
- completedSteps: [],
110
- authMethod: null,
111
- hasProfilePhoto: false,
112
- hasCompletedProfile: false,
113
- hasSelectedIntentions: false,
114
- hasViewedResults: false,
115
- hasEnteredEventCode: false,
116
- hasRegisteredForEvent: false,
117
- hasReachedEventPage: false,
118
- timestamp: Date.now(),
119
- };
120
- };
121
-
122
- /**
123
- * Save authentication state
124
- */
125
- export const saveAuthState = async (authState: Partial<AuthState>): Promise<void> => {
126
- try {
127
- const existingState = await getAuthState();
128
- const updatedState: AuthState = {
129
- ...existingState,
130
- ...authState,
131
- };
132
-
133
- // Also save the auth method separately for quick access
134
- if (authState.authMethod) {
135
- await AsyncStorage.setItem(STORAGE_KEYS.AUTH_METHOD, authState.authMethod);
136
- }
137
-
138
- console.log('✅ Auth state saved:', updatedState);
139
- } catch (error) {
140
- console.error('❌ Error saving auth state:', error);
141
- }
142
- };
143
-
144
- /**
145
- * Get authentication state
146
- */
147
- export const getAuthState = async (): Promise<AuthState> => {
148
- try {
149
- const authMethod = await AsyncStorage.getItem(STORAGE_KEYS.AUTH_METHOD) as 'apple' | 'onairos' | null;
150
- const hasToken = !!(await AsyncStorage.getItem(STORAGE_KEYS.AUTH_TOKEN));
151
-
152
- return {
153
- isAuthenticated: hasToken,
154
- authMethod,
155
- hasValidToken: hasToken,
156
- };
157
- } catch (error) {
158
- console.error('❌ Error getting auth state:', error);
159
- return {
160
- isAuthenticated: false,
161
- authMethod: null,
162
- hasValidToken: false,
163
- };
164
- }
165
- };
166
-
167
- /**
168
- * Clear all user data (for logout)
169
- */
170
- export const clearUserData = async (): Promise<void> => {
171
- try {
172
- const keysToRemove = [
173
- STORAGE_KEYS.USER,
174
- STORAGE_KEYS.USER_PROFILE,
175
- STORAGE_KEYS.USER_PROFILE_FALLBACK,
176
- STORAGE_KEYS.USER_PROGRESS,
177
- STORAGE_KEYS.AUTH_TOKEN,
178
- STORAGE_KEYS.ONAIROS_JWT_TOKEN,
179
- STORAGE_KEYS.ENOCH_TOKEN,
180
- STORAGE_KEYS.ONAIROS_USER,
181
- STORAGE_KEYS.APPLE_USER,
182
- STORAGE_KEYS.AUTH_METHOD,
183
- STORAGE_KEYS.IS_FIRST_TIME_USER,
184
- STORAGE_KEYS.USER_ATTENDANCE_CONFIRMED,
185
- STORAGE_KEYS.PROFILE_IMAGE,
186
- STORAGE_KEYS.ONBOARDING_COMPLETED,
187
- // Clear the new onboarding completion tokens
188
- STORAGE_KEYS.ONBOARDING_COMPLETE_TOKEN,
189
- STORAGE_KEYS.EVENT_ACCESS_TOKEN,
190
- ];
191
-
192
- await AsyncStorage.multiRemove(keysToRemove);
193
-
194
- // Also clear biometrically stored PIN
195
- try {
196
- await clearStoredPin();
197
- console.log('✅ Biometrically stored PIN cleared');
198
- } catch (error) {
199
- console.warn('⚠️ Error clearing stored PIN (continuing):', error);
200
- }
201
-
202
- console.log('✅ User data cleared including onboarding completion tokens');
203
- } catch (error) {
204
- console.error('❌ Error clearing user data:', error);
205
- }
206
- };
207
-
208
- /**
209
- * Get resume navigation target based on user progress
210
- */
211
- export const getResumeTarget = async (): Promise<{ screen: string; params?: any }> => {
212
- try {
213
- const progress = await getUserProgress();
214
- const authState = await getAuthState();
215
-
216
- // HIGHEST PRIORITY: Check event access token first (regardless of auth state)
217
- // This ensures release mode reliability when network auth fails
218
- const hasEventToken = await hasEventAccessToken();
219
- if (hasEventToken || (progress.hasReachedEventPage && progress.hasViewedResults)) {
220
- console.log('🎯 User has completed onboarding (verified by token) - returning to Home screen');
221
-
222
- // After completing first event, users go to Home screen instead of Results
223
- // This provides a better post-event experience and central hub
224
- return {
225
- screen: 'Home'
226
- };
227
- }
228
-
229
- // If not authenticated, start from Welcome
230
- if (!authState.isAuthenticated) {
231
- return { screen: 'Welcome' };
232
- }
233
-
234
- // If authenticated but no progress, start camera flow
235
- if (progress.completedSteps.length === 0) {
236
- return {
237
- screen: 'Welcome',
238
- params: {
239
- isNewUser: true,
240
- activateCamera: true
241
- }
242
- };
243
- }
244
-
245
- // Resume based on last completed step for users still in onboarding
246
- if (!progress.hasProfilePhoto) {
247
- return {
248
- screen: 'Welcome',
249
- params: {
250
- isNewUser: true,
251
- activateCamera: true
252
- }
253
- };
254
- }
255
-
256
- if (!progress.hasCompletedProfile) {
257
- const profileImage = await AsyncStorage.getItem(STORAGE_KEYS.PROFILE_IMAGE);
258
- return {
259
- screen: 'CreateFreshProfile',
260
- params: {
261
- photo: profileImage,
262
- isReviewerBypass: authState.authMethod === 'onairos'
263
- }
264
- };
265
- }
266
-
267
- if (!progress.hasSelectedIntentions) {
268
- const userProfile = await AsyncStorage.getItem(STORAGE_KEYS.USER_PROFILE);
269
- return {
270
- screen: 'Intention',
271
- params: {
272
- userProfile: userProfile ? JSON.parse(userProfile) : null
273
- }
274
- };
275
- }
276
-
277
- // Default to Results if everything is complete
278
- const userProfile = await AsyncStorage.getItem(STORAGE_KEYS.USER_PROFILE);
279
- return {
280
- screen: 'Results',
281
- params: {
282
- userProfile: userProfile ? JSON.parse(userProfile) : null
283
- }
284
- };
285
-
286
- } catch (error) {
287
- console.error('❌ Error determining resume target:', error);
288
- return { screen: 'Welcome' };
289
- }
290
- };
291
-
292
- /**
293
- * Check if user has completed onboarding flow
294
- */
295
- export const hasCompletedOnboarding = async (): Promise<boolean> => {
296
- try {
297
- const progress = await getUserProgress();
298
- return progress.hasCompletedProfile && progress.hasViewedResults;
299
- } catch (error) {
300
- console.error('❌ Error checking onboarding status:', error);
301
- return false;
302
- }
303
- };
304
-
305
- /**
306
- * Mark user as having reached the event page (completed full onboarding)
307
- * This creates the token that ensures they always return to Results
308
- */
309
- export const markEventPageReached = async (eventData?: {
310
- eventType?: string;
311
- eventCode?: string;
312
- photo?: string;
313
- userProfile?: any;
314
- inferenceData?: any;
315
- }): Promise<void> => {
316
- try {
317
- const progress = await getUserProgress();
318
- const updatedProgress: UserProgress = {
319
- ...progress,
320
- hasReachedEventPage: true,
321
- hasViewedResults: true,
322
- eventData: eventData || progress.eventData,
323
- timestamp: Date.now(),
324
- };
325
-
326
- // Save the updated progress
327
- await saveUserProgress(updatedProgress);
328
-
329
- // Save the onboarding completion token for extra security
330
- await AsyncStorage.setItem(STORAGE_KEYS.ONBOARDING_COMPLETE_TOKEN, 'true');
331
- await AsyncStorage.setItem(STORAGE_KEYS.EVENT_ACCESS_TOKEN, JSON.stringify({
332
- timestamp: Date.now(),
333
- eventData: eventData,
334
- hasAccess: true
335
- }));
336
-
337
- console.log('✅ User marked as having reached event page - will always return to Results');
338
- } catch (error) {
339
- console.error('❌ Error marking event page reached:', error);
340
- }
341
- };
342
-
343
- /**
344
- * Check if user has the event access token (completed onboarding)
345
- */
346
- export const hasEventAccessToken = async (): Promise<boolean> => {
347
- try {
348
- const token = await AsyncStorage.getItem(STORAGE_KEYS.ONBOARDING_COMPLETE_TOKEN);
349
- const progress = await getUserProgress();
350
- return token === 'true' && progress.hasReachedEventPage;
351
- } catch (error) {
352
- console.error('❌ Error checking event access token:', error);
353
- return false;
354
- }
355
- };
356
-
357
- /**
358
- * Mark a step as completed
359
- */
360
- export const markStepCompleted = async (step: string): Promise<void> => {
361
- try {
362
- const progress = await getUserProgress();
363
- if (!progress.completedSteps.includes(step)) {
364
- progress.completedSteps.push(step);
365
- await saveUserProgress(progress);
366
- }
367
- } catch (error) {
368
- console.error('❌ Error marking step completed:', error);
369
- }
370
- };
371
-
372
- /**
373
- * Update user's last screen
374
- */
375
- export const updateLastScreen = async (screen: string, params?: any): Promise<void> => {
376
- try {
377
- await saveUserProgress({
378
- lastScreen: screen,
379
- timestamp: Date.now()
380
- });
381
- } catch (error) {
382
- console.error('❌ Error updating last screen:', error);
383
- }
384
- };
385
-
386
- /**
387
- * Check if this is a returning user with existing progress
388
- */
389
- export const isReturningUser = async (): Promise<boolean> => {
390
- try {
391
- const progress = await getUserProgress();
392
- const authState = await getAuthState();
393
-
394
- return authState.isAuthenticated && progress.completedSteps.length > 0;
395
- } catch (error) {
396
- console.error('❌ Error checking returning user status:', error);
397
- return false;
398
- }
399
- };
400
-
401
- /**
402
- * Mark app as active (call this when app becomes active)
403
- */
404
- export const markAppActive = async (): Promise<void> => {
405
- try {
406
- await saveUserProgress({
407
- timestamp: Date.now()
408
- });
409
- console.log('✅ App marked as active');
410
- } catch (error) {
411
- console.error('❌ Error marking app as active:', error);
412
- }
413
- };
414
-
415
- /**
416
- * Development utility: Get all stored progress data for debugging
417
- */
418
- export const getDebugStorageInfo = async (): Promise<{
419
- progress: UserProgress;
420
- authState: AuthState;
421
- isReturning: boolean;
422
- resumeTarget: { screen: string; params?: any };
423
- }> => {
424
- try {
425
- const progress = await getUserProgress();
426
- const authState = await getAuthState();
427
- const isReturning = await isReturningUser();
428
- const resumeTarget = await getResumeTarget();
429
-
430
- return {
431
- progress,
432
- authState,
433
- isReturning,
434
- resumeTarget
435
- };
436
- } catch (error) {
437
- console.error('❌ Error getting debug storage info:', error);
438
- throw error;
439
- }
440
- };
441
-
442
- /**
443
- * Development utility: Clear all progress (for testing)
444
- */
445
- export const clearAllProgress = async (): Promise<void> => {
446
- try {
447
- await clearUserData();
448
- console.log('✅ All progress data cleared');
449
- } catch (error) {
450
- console.error('❌ Error clearing progress data:', error);
451
- }
1
+ import AsyncStorage from '@react-native-async-storage/async-storage';
2
+ import { clearStoredPin } from './pinStorageUtils';
3
+
4
+ // Storage keys
5
+ export const STORAGE_KEYS = {
6
+ // Authentication
7
+ AUTH_TOKEN: 'auth_token',
8
+ ONAIROS_JWT_TOKEN: 'onairos_jwt_token',
9
+ ENOCH_TOKEN: 'enoch_token',
10
+
11
+ // User data
12
+ USER: 'user',
13
+ USER_PROFILE: 'userProfile',
14
+ USER_PROFILE_FALLBACK: 'userProfileFallback',
15
+
16
+ // App state
17
+ USER_PROGRESS: 'user_progress',
18
+ ONBOARDING_COMPLETED: 'onboardingCompleted',
19
+ IS_FIRST_TIME_USER: 'isFirstTimeUser',
20
+ USER_ATTENDANCE_CONFIRMED: 'userAttendanceConfirmed',
21
+
22
+ // New: Token for completed onboarding with Results access
23
+ ONBOARDING_COMPLETE_TOKEN: 'onboarding_complete_token',
24
+ EVENT_ACCESS_TOKEN: 'event_access_token',
25
+
26
+ // Authentication method tracking
27
+ ONAIROS_USER: 'onairos_user',
28
+ APPLE_USER: 'apple_user',
29
+ AUTH_METHOD: 'auth_method',
30
+
31
+ // Session data
32
+ CURRENT_EVENT_DATA: 'currentEventData',
33
+ CONNECTED_PLATFORMS: 'connectedPlatforms',
34
+ PROFILE_IMAGE: 'profileImage',
35
+
36
+ // Admin status
37
+ USER_ADMIN_STATUS: 'user_admin_status',
38
+ } as const;
39
+
40
+ // User progress tracking
41
+ export interface UserProgress {
42
+ lastScreen: string;
43
+ completedSteps: string[];
44
+ authMethod: 'apple' | 'onairos' | null;
45
+ hasProfilePhoto: boolean;
46
+ hasCompletedProfile: boolean;
47
+ hasSelectedIntentions: boolean;
48
+ hasViewedResults: boolean;
49
+ eventCode?: string;
50
+ hasEnteredEventCode: boolean;
51
+ hasRegisteredForEvent?: boolean;
52
+ // New: Flag to indicate user has completed entire onboarding flow
53
+ hasReachedEventPage: boolean;
54
+ // Store event data for returning users
55
+ eventData?: {
56
+ eventType?: string;
57
+ eventCode?: string;
58
+ photo?: string;
59
+ userProfile?: any;
60
+ inferenceData?: any;
61
+ };
62
+ timestamp: number;
63
+ }
64
+
65
+ // Authentication state
66
+ export interface AuthState {
67
+ isAuthenticated: boolean;
68
+ authMethod: 'apple' | 'onairos' | null;
69
+ hasValidToken: boolean;
70
+ userEmail?: string;
71
+ userName?: string;
72
+ }
73
+
74
+ /**
75
+ * Save user progress to track where they left off
76
+ */
77
+ export const saveUserProgress = async (progress: Partial<UserProgress>): Promise<void> => {
78
+ try {
79
+ const existingProgress = await getUserProgress();
80
+ const updatedProgress: UserProgress = {
81
+ ...existingProgress,
82
+ ...progress,
83
+ timestamp: Date.now(),
84
+ };
85
+
86
+ await AsyncStorage.setItem(STORAGE_KEYS.USER_PROGRESS, JSON.stringify(updatedProgress));
87
+ console.log('✅ User progress saved:', updatedProgress);
88
+ } catch (error) {
89
+ console.error('❌ Error saving user progress:', error);
90
+ }
91
+ };
92
+
93
+ /**
94
+ * Get user progress to determine where to resume
95
+ */
96
+ export const getUserProgress = async (): Promise<UserProgress> => {
97
+ try {
98
+ const progressData = await AsyncStorage.getItem(STORAGE_KEYS.USER_PROGRESS);
99
+ if (progressData) {
100
+ return JSON.parse(progressData);
101
+ }
102
+ } catch (error) {
103
+ console.error('❌ Error getting user progress:', error);
104
+ }
105
+
106
+ // Return default progress
107
+ return {
108
+ lastScreen: 'Welcome',
109
+ completedSteps: [],
110
+ authMethod: null,
111
+ hasProfilePhoto: false,
112
+ hasCompletedProfile: false,
113
+ hasSelectedIntentions: false,
114
+ hasViewedResults: false,
115
+ hasEnteredEventCode: false,
116
+ hasRegisteredForEvent: false,
117
+ hasReachedEventPage: false,
118
+ timestamp: Date.now(),
119
+ };
120
+ };
121
+
122
+ /**
123
+ * Save authentication state
124
+ */
125
+ export const saveAuthState = async (authState: Partial<AuthState>): Promise<void> => {
126
+ try {
127
+ const existingState = await getAuthState();
128
+ const updatedState: AuthState = {
129
+ ...existingState,
130
+ ...authState,
131
+ };
132
+
133
+ // Also save the auth method separately for quick access
134
+ if (authState.authMethod) {
135
+ await AsyncStorage.setItem(STORAGE_KEYS.AUTH_METHOD, authState.authMethod);
136
+ }
137
+
138
+ console.log('✅ Auth state saved:', updatedState);
139
+ } catch (error) {
140
+ console.error('❌ Error saving auth state:', error);
141
+ }
142
+ };
143
+
144
+ /**
145
+ * Get authentication state
146
+ */
147
+ export const getAuthState = async (): Promise<AuthState> => {
148
+ try {
149
+ const authMethod = await AsyncStorage.getItem(STORAGE_KEYS.AUTH_METHOD) as 'apple' | 'onairos' | null;
150
+ const hasToken = !!(await AsyncStorage.getItem(STORAGE_KEYS.AUTH_TOKEN));
151
+
152
+ return {
153
+ isAuthenticated: hasToken,
154
+ authMethod,
155
+ hasValidToken: hasToken,
156
+ };
157
+ } catch (error) {
158
+ console.error('❌ Error getting auth state:', error);
159
+ return {
160
+ isAuthenticated: false,
161
+ authMethod: null,
162
+ hasValidToken: false,
163
+ };
164
+ }
165
+ };
166
+
167
+ /**
168
+ * Clear all user data (for logout)
169
+ */
170
+ export const clearUserData = async (): Promise<void> => {
171
+ try {
172
+ const keysToRemove = [
173
+ STORAGE_KEYS.USER,
174
+ STORAGE_KEYS.USER_PROFILE,
175
+ STORAGE_KEYS.USER_PROFILE_FALLBACK,
176
+ STORAGE_KEYS.USER_PROGRESS,
177
+ STORAGE_KEYS.AUTH_TOKEN,
178
+ STORAGE_KEYS.ONAIROS_JWT_TOKEN,
179
+ STORAGE_KEYS.ENOCH_TOKEN,
180
+ STORAGE_KEYS.ONAIROS_USER,
181
+ STORAGE_KEYS.APPLE_USER,
182
+ STORAGE_KEYS.AUTH_METHOD,
183
+ STORAGE_KEYS.IS_FIRST_TIME_USER,
184
+ STORAGE_KEYS.USER_ATTENDANCE_CONFIRMED,
185
+ STORAGE_KEYS.PROFILE_IMAGE,
186
+ STORAGE_KEYS.ONBOARDING_COMPLETED,
187
+ // Clear the new onboarding completion tokens
188
+ STORAGE_KEYS.ONBOARDING_COMPLETE_TOKEN,
189
+ STORAGE_KEYS.EVENT_ACCESS_TOKEN,
190
+ ];
191
+
192
+ await AsyncStorage.multiRemove(keysToRemove);
193
+
194
+ // Also clear biometrically stored PIN
195
+ try {
196
+ await clearStoredPin();
197
+ console.log('✅ Biometrically stored PIN cleared');
198
+ } catch (error) {
199
+ console.warn('⚠️ Error clearing stored PIN (continuing):', error);
200
+ }
201
+
202
+ console.log('✅ User data cleared including onboarding completion tokens');
203
+ } catch (error) {
204
+ console.error('❌ Error clearing user data:', error);
205
+ }
206
+ };
207
+
208
+ /**
209
+ * Get resume navigation target based on user progress
210
+ */
211
+ export const getResumeTarget = async (): Promise<{ screen: string; params?: any }> => {
212
+ try {
213
+ const progress = await getUserProgress();
214
+ const authState = await getAuthState();
215
+
216
+ // HIGHEST PRIORITY: Check event access token first (regardless of auth state)
217
+ // This ensures release mode reliability when network auth fails
218
+ const hasEventToken = await hasEventAccessToken();
219
+ if (hasEventToken || (progress.hasReachedEventPage && progress.hasViewedResults)) {
220
+ console.log('🎯 User has completed onboarding (verified by token) - returning to Home screen');
221
+
222
+ // After completing first event, users go to Home screen instead of Results
223
+ // This provides a better post-event experience and central hub
224
+ return {
225
+ screen: 'Home'
226
+ };
227
+ }
228
+
229
+ // If not authenticated, start from Welcome
230
+ if (!authState.isAuthenticated) {
231
+ return { screen: 'Welcome' };
232
+ }
233
+
234
+ // If authenticated but no progress, start camera flow
235
+ if (progress.completedSteps.length === 0) {
236
+ return {
237
+ screen: 'Welcome',
238
+ params: {
239
+ isNewUser: true,
240
+ activateCamera: true
241
+ }
242
+ };
243
+ }
244
+
245
+ // Resume based on last completed step for users still in onboarding
246
+ if (!progress.hasProfilePhoto) {
247
+ return {
248
+ screen: 'Welcome',
249
+ params: {
250
+ isNewUser: true,
251
+ activateCamera: true
252
+ }
253
+ };
254
+ }
255
+
256
+ if (!progress.hasCompletedProfile) {
257
+ const profileImage = await AsyncStorage.getItem(STORAGE_KEYS.PROFILE_IMAGE);
258
+ return {
259
+ screen: 'CreateFreshProfile',
260
+ params: {
261
+ photo: profileImage,
262
+ isReviewerBypass: authState.authMethod === 'onairos'
263
+ }
264
+ };
265
+ }
266
+
267
+ if (!progress.hasSelectedIntentions) {
268
+ const userProfile = await AsyncStorage.getItem(STORAGE_KEYS.USER_PROFILE);
269
+ return {
270
+ screen: 'Intention',
271
+ params: {
272
+ userProfile: userProfile ? JSON.parse(userProfile) : null
273
+ }
274
+ };
275
+ }
276
+
277
+ // Default to Results if everything is complete
278
+ const userProfile = await AsyncStorage.getItem(STORAGE_KEYS.USER_PROFILE);
279
+ return {
280
+ screen: 'Results',
281
+ params: {
282
+ userProfile: userProfile ? JSON.parse(userProfile) : null
283
+ }
284
+ };
285
+
286
+ } catch (error) {
287
+ console.error('❌ Error determining resume target:', error);
288
+ return { screen: 'Welcome' };
289
+ }
290
+ };
291
+
292
+ /**
293
+ * Check if user has completed onboarding flow
294
+ */
295
+ export const hasCompletedOnboarding = async (): Promise<boolean> => {
296
+ try {
297
+ const progress = await getUserProgress();
298
+ return progress.hasCompletedProfile && progress.hasViewedResults;
299
+ } catch (error) {
300
+ console.error('❌ Error checking onboarding status:', error);
301
+ return false;
302
+ }
303
+ };
304
+
305
+ /**
306
+ * Mark user as having reached the event page (completed full onboarding)
307
+ * This creates the token that ensures they always return to Results
308
+ */
309
+ export const markEventPageReached = async (eventData?: {
310
+ eventType?: string;
311
+ eventCode?: string;
312
+ photo?: string;
313
+ userProfile?: any;
314
+ inferenceData?: any;
315
+ }): Promise<void> => {
316
+ try {
317
+ const progress = await getUserProgress();
318
+ const updatedProgress: UserProgress = {
319
+ ...progress,
320
+ hasReachedEventPage: true,
321
+ hasViewedResults: true,
322
+ eventData: eventData || progress.eventData,
323
+ timestamp: Date.now(),
324
+ };
325
+
326
+ // Save the updated progress
327
+ await saveUserProgress(updatedProgress);
328
+
329
+ // Save the onboarding completion token for extra security
330
+ await AsyncStorage.setItem(STORAGE_KEYS.ONBOARDING_COMPLETE_TOKEN, 'true');
331
+ await AsyncStorage.setItem(STORAGE_KEYS.EVENT_ACCESS_TOKEN, JSON.stringify({
332
+ timestamp: Date.now(),
333
+ eventData: eventData,
334
+ hasAccess: true
335
+ }));
336
+
337
+ console.log('✅ User marked as having reached event page - will always return to Results');
338
+ } catch (error) {
339
+ console.error('❌ Error marking event page reached:', error);
340
+ }
341
+ };
342
+
343
+ /**
344
+ * Check if user has the event access token (completed onboarding)
345
+ */
346
+ export const hasEventAccessToken = async (): Promise<boolean> => {
347
+ try {
348
+ const token = await AsyncStorage.getItem(STORAGE_KEYS.ONBOARDING_COMPLETE_TOKEN);
349
+ const progress = await getUserProgress();
350
+ return token === 'true' && progress.hasReachedEventPage;
351
+ } catch (error) {
352
+ console.error('❌ Error checking event access token:', error);
353
+ return false;
354
+ }
355
+ };
356
+
357
+ /**
358
+ * Mark a step as completed
359
+ */
360
+ export const markStepCompleted = async (step: string): Promise<void> => {
361
+ try {
362
+ const progress = await getUserProgress();
363
+ if (!progress.completedSteps.includes(step)) {
364
+ progress.completedSteps.push(step);
365
+ await saveUserProgress(progress);
366
+ }
367
+ } catch (error) {
368
+ console.error('❌ Error marking step completed:', error);
369
+ }
370
+ };
371
+
372
+ /**
373
+ * Update user's last screen
374
+ */
375
+ export const updateLastScreen = async (screen: string, params?: any): Promise<void> => {
376
+ try {
377
+ await saveUserProgress({
378
+ lastScreen: screen,
379
+ timestamp: Date.now()
380
+ });
381
+ } catch (error) {
382
+ console.error('❌ Error updating last screen:', error);
383
+ }
384
+ };
385
+
386
+ /**
387
+ * Check if this is a returning user with existing progress
388
+ */
389
+ export const isReturningUser = async (): Promise<boolean> => {
390
+ try {
391
+ const progress = await getUserProgress();
392
+ const authState = await getAuthState();
393
+
394
+ return authState.isAuthenticated && progress.completedSteps.length > 0;
395
+ } catch (error) {
396
+ console.error('❌ Error checking returning user status:', error);
397
+ return false;
398
+ }
399
+ };
400
+
401
+ /**
402
+ * Mark app as active (call this when app becomes active)
403
+ */
404
+ export const markAppActive = async (): Promise<void> => {
405
+ try {
406
+ await saveUserProgress({
407
+ timestamp: Date.now()
408
+ });
409
+ console.log('✅ App marked as active');
410
+ } catch (error) {
411
+ console.error('❌ Error marking app as active:', error);
412
+ }
413
+ };
414
+
415
+ /**
416
+ * Development utility: Get all stored progress data for debugging
417
+ */
418
+ export const getDebugStorageInfo = async (): Promise<{
419
+ progress: UserProgress;
420
+ authState: AuthState;
421
+ isReturning: boolean;
422
+ resumeTarget: { screen: string; params?: any };
423
+ }> => {
424
+ try {
425
+ const progress = await getUserProgress();
426
+ const authState = await getAuthState();
427
+ const isReturning = await isReturningUser();
428
+ const resumeTarget = await getResumeTarget();
429
+
430
+ return {
431
+ progress,
432
+ authState,
433
+ isReturning,
434
+ resumeTarget
435
+ };
436
+ } catch (error) {
437
+ console.error('❌ Error getting debug storage info:', error);
438
+ throw error;
439
+ }
440
+ };
441
+
442
+ /**
443
+ * Development utility: Clear all progress (for testing)
444
+ */
445
+ export const clearAllProgress = async (): Promise<void> => {
446
+ try {
447
+ await clearUserData();
448
+ console.log('✅ All progress data cleared');
449
+ } catch (error) {
450
+ console.error('❌ Error clearing progress data:', error);
451
+ }
452
452
  };