@onairos/react-native 3.1.16 → 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 (198) 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/OnairosButton.js +290 -0
  16. package/lib/commonjs/components/OnairosButton.js.map +1 -0
  17. package/lib/commonjs/components/OnairosSignInButton.js +30 -8
  18. package/lib/commonjs/components/OnairosSignInButton.js.map +1 -1
  19. package/lib/commonjs/components/UniversalOnboarding.js +4 -4
  20. package/lib/commonjs/config/api.js +2 -2
  21. package/lib/commonjs/hooks/useConnections.js +6 -6
  22. package/lib/commonjs/hooks/useUserConnections.js +10 -10
  23. package/lib/commonjs/index.js +9 -10
  24. package/lib/commonjs/index.js.map +1 -1
  25. package/lib/commonjs/services/apiClient.js +35 -35
  26. package/lib/commonjs/services/apiKeyService.js +99 -99
  27. package/lib/commonjs/services/authService.js +82 -82
  28. package/lib/commonjs/services/biometricPinService.js +10 -10
  29. package/lib/commonjs/services/connectedAccountsService.js +32 -32
  30. package/lib/commonjs/services/googleAuthService.js +15 -15
  31. package/lib/commonjs/services/imageCompressionService.js +15 -15
  32. package/lib/commonjs/services/jwtStorageService.js +59 -59
  33. package/lib/commonjs/services/mobileTrainingService.js +14 -14
  34. package/lib/commonjs/services/pinEncryptionService.js +10 -10
  35. package/lib/commonjs/services/pinStorageUtils.js +15 -15
  36. package/lib/commonjs/services/platformAuthService.js +47 -47
  37. package/lib/commonjs/services/storageService.js +31 -31
  38. package/lib/commonjs/services/trainingApiHelpers.js +33 -33
  39. package/lib/commonjs/services/userConnectionsService.js +24 -24
  40. package/lib/commonjs/utils/Portal.js +4 -4
  41. package/lib/commonjs/utils/api.js +24 -24
  42. package/lib/commonjs/utils/auth.js +18 -18
  43. package/lib/commonjs/utils/crypto.js +13 -13
  44. package/lib/commonjs/utils/encryption.js +12 -12
  45. package/lib/commonjs/utils/eventUtils.js +52 -52
  46. package/lib/commonjs/utils/programmaticFlow.js +16 -16
  47. package/lib/commonjs/utils/retryHelper.js +27 -27
  48. package/lib/module/assets/images/Checkbox.svg +3 -3
  49. package/lib/module/assets/images/EnochE.svg +19 -19
  50. package/lib/module/assets/images/Personalityprofile.svg +3 -3
  51. package/lib/module/assets/images/Personalitytraits.svg +3 -3
  52. package/lib/module/assets/images/Userpreferences.svg +3 -3
  53. package/lib/module/assets/images/arrow.svg +20 -20
  54. package/lib/module/assets/images/basicproficon.svg +43 -43
  55. package/lib/module/assets/images/basicprofile.svg +3 -3
  56. package/lib/module/assets/images/checkmark.svg +4 -4
  57. package/lib/module/assets/images/contentanalysis.svg +3 -3
  58. package/lib/module/assets/images/contenticon.svg +23 -23
  59. package/lib/module/assets/images/personalityicon.svg +18 -18
  60. package/lib/module/assets/images/x-close.svg +3 -3
  61. package/lib/module/components/OnairosButton.js +282 -0
  62. package/lib/module/components/OnairosButton.js.map +1 -0
  63. package/lib/module/components/OnairosSignInButton.js +30 -8
  64. package/lib/module/components/OnairosSignInButton.js.map +1 -1
  65. package/lib/module/components/UniversalOnboarding.js +4 -4
  66. package/lib/module/config/api.js +2 -2
  67. package/lib/module/hooks/useConnections.js +6 -6
  68. package/lib/module/hooks/useUserConnections.js +10 -10
  69. package/lib/module/index.js +8 -10
  70. package/lib/module/index.js.map +1 -1
  71. package/lib/module/services/apiClient.js +35 -35
  72. package/lib/module/services/apiKeyService.js +99 -99
  73. package/lib/module/services/authService.js +82 -82
  74. package/lib/module/services/biometricPinService.js +10 -10
  75. package/lib/module/services/connectedAccountsService.js +32 -32
  76. package/lib/module/services/googleAuthService.js +15 -15
  77. package/lib/module/services/imageCompressionService.js +15 -15
  78. package/lib/module/services/jwtStorageService.js +59 -59
  79. package/lib/module/services/mobileTrainingService.js +14 -14
  80. package/lib/module/services/pinEncryptionService.js +10 -10
  81. package/lib/module/services/pinStorageUtils.js +15 -15
  82. package/lib/module/services/platformAuthService.js +47 -47
  83. package/lib/module/services/storageService.js +31 -31
  84. package/lib/module/services/trainingApiHelpers.js +33 -33
  85. package/lib/module/services/userConnectionsService.js +24 -24
  86. package/lib/module/utils/Portal.js +4 -4
  87. package/lib/module/utils/api.js +24 -24
  88. package/lib/module/utils/auth.js +18 -18
  89. package/lib/module/utils/crypto.js +13 -13
  90. package/lib/module/utils/encryption.js +12 -12
  91. package/lib/module/utils/eventUtils.js +52 -52
  92. package/lib/module/utils/programmaticFlow.js +16 -16
  93. package/lib/module/utils/retryHelper.js +27 -27
  94. package/lib/typescript/components/OnairosButton.d.ts +37 -0
  95. package/lib/typescript/components/OnairosButton.d.ts.map +1 -0
  96. package/lib/typescript/components/OnairosSignInButton.d.ts +2 -1
  97. package/lib/typescript/components/OnairosSignInButton.d.ts.map +1 -1
  98. package/lib/typescript/index.d.ts +3 -4
  99. package/lib/typescript/index.d.ts.map +1 -1
  100. package/package.json +163 -163
  101. package/src/api/index.ts +151 -151
  102. package/src/assets/images/Checkbox.svg +3 -3
  103. package/src/assets/images/EnochE.svg +19 -19
  104. package/src/assets/images/Personalityprofile.svg +3 -3
  105. package/src/assets/images/Personalitytraits.svg +3 -3
  106. package/src/assets/images/Userpreferences.svg +3 -3
  107. package/src/assets/images/arrow.svg +20 -20
  108. package/src/assets/images/basicproficon.svg +43 -43
  109. package/src/assets/images/basicprofile.svg +3 -3
  110. package/src/assets/images/checkmark.svg +4 -4
  111. package/src/assets/images/contentanalysis.svg +3 -3
  112. package/src/assets/images/contenticon.svg +23 -23
  113. package/src/assets/images/personalityicon.svg +18 -18
  114. package/src/assets/images/x-close.svg +3 -3
  115. package/src/components/BodyText.tsx +33 -33
  116. package/src/components/BrandMark.tsx +62 -62
  117. package/src/components/CodeInput.tsx +32 -32
  118. package/src/components/DataRequestScreen.tsx +355 -355
  119. package/src/components/EmailInput.tsx +31 -31
  120. package/src/components/EmailVerificationModal.tsx +363 -363
  121. package/src/components/ExistingUserDataConfirmation.tsx +506 -506
  122. package/src/components/GoogleButton.tsx +55 -55
  123. package/src/components/HeadingGroup.tsx +49 -49
  124. package/src/components/ModalHeader.tsx +125 -125
  125. package/src/components/ModalSheet.tsx +57 -57
  126. package/src/components/Onairos.tsx +422 -422
  127. package/src/components/OnairosButton.tsx +339 -0
  128. package/src/components/OnairosSignInButton.tsx +30 -10
  129. package/src/components/Overlay.tsx +506 -506
  130. package/src/components/PersonaImage.tsx +79 -79
  131. package/src/components/PersonaLoadingScreen.tsx +201 -201
  132. package/src/components/PersonalizationConsentScreen.tsx +410 -410
  133. package/src/components/PinCreationScreen.tsx +492 -492
  134. package/src/components/PinInput.tsx +555 -555
  135. package/src/components/PlatformConnectorsStep.tsx +891 -891
  136. package/src/components/PlatformList.tsx +144 -144
  137. package/src/components/PlatformToggle.tsx +226 -226
  138. package/src/components/PrimaryButton.tsx +213 -213
  139. package/src/components/SignInMatchAnimation.tsx +225 -225
  140. package/src/components/SignInStep.tsx +217 -217
  141. package/src/components/TrainingModal.tsx +1047 -1047
  142. package/src/components/UniversalOnboarding.tsx +2887 -2887
  143. package/src/components/VerificationStep.tsx +198 -198
  144. package/src/components/WelcomeScreen.tsx +473 -473
  145. package/src/components/icons/Basicproficon.tsx +30 -30
  146. package/src/components/icons/Basicprofile.tsx +17 -17
  147. package/src/components/icons/Checkbox.tsx +17 -17
  148. package/src/components/icons/Checkmark.tsx +24 -24
  149. package/src/components/icons/Contentanalysis.tsx +17 -17
  150. package/src/components/icons/Contenticon.tsx +30 -30
  151. package/src/components/icons/EnochE.tsx +39 -39
  152. package/src/components/icons/Personalityicon.tsx +22 -22
  153. package/src/components/icons/Personalityprofile.tsx +17 -17
  154. package/src/components/icons/Personalitytraits.tsx +17 -17
  155. package/src/components/icons/Userpreferences.tsx +17 -17
  156. package/src/components/icons/index.ts +12 -12
  157. package/src/components/onboarding/OAuthWebView.tsx +232 -232
  158. package/src/config/api.ts +25 -25
  159. package/src/context/AuthContext.tsx +393 -393
  160. package/src/hooks/useConnectedAccounts.ts +138 -138
  161. package/src/hooks/useConnections.ts +161 -161
  162. package/src/hooks/useCredentials.ts +174 -174
  163. package/src/hooks/useUserConnections.ts +165 -165
  164. package/src/index.js +14 -0
  165. package/src/index.ts +94 -96
  166. package/src/services/apiClient.ts +336 -336
  167. package/src/services/apiKeyService.ts +919 -919
  168. package/src/services/authService.ts +1008 -1008
  169. package/src/services/biometricPinService.ts +192 -192
  170. package/src/services/connectedAccountsService.ts +289 -289
  171. package/src/services/googleAuthService.ts +279 -279
  172. package/src/services/imageCompressionService.ts +302 -302
  173. package/src/services/jwtStorageService.ts +256 -256
  174. package/src/services/mobileTrainingService.ts +203 -203
  175. package/src/services/pinEncryptionService.ts +75 -75
  176. package/src/services/pinStorageUtils.ts +96 -96
  177. package/src/services/platformAuthService.ts +1346 -1346
  178. package/src/services/storageService.ts +451 -451
  179. package/src/services/trainingApiHelpers.ts +66 -66
  180. package/src/services/userConnectionsService.ts +556 -556
  181. package/src/services/youtubeMigrationService.ts +453 -453
  182. package/src/theme/index.ts +239 -239
  183. package/src/types/ambient.d.ts +28 -28
  184. package/src/types/index.ts +265 -265
  185. package/src/types/node-fix.d.ts +18 -18
  186. package/src/types/node-override.d.ts +23 -23
  187. package/src/types/opacity.d.ts +15 -15
  188. package/src/types/types.d.ts +17 -17
  189. package/src/utils/Portal.tsx +82 -82
  190. package/src/utils/api.js +111 -111
  191. package/src/utils/auth.js +103 -103
  192. package/src/utils/crypto.js +59 -59
  193. package/src/utils/encryption.ts +68 -68
  194. package/src/utils/eventUtils.ts +302 -302
  195. package/src/utils/haptics.ts +58 -58
  196. package/src/utils/imagePreloader.ts +2 -2
  197. package/src/utils/programmaticFlow.ts +112 -112
  198. 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
  };