@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,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
  };