@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,393 +1,393 @@
1
- import React, { createContext, useState, useEffect, useContext } from 'react';
2
- import AsyncStorage from '@react-native-async-storage/async-storage';
3
- import { User } from '../types/index';
4
- import {
5
- saveAuthToken,
6
- getAuthToken,
7
- removeAuthToken,
8
- verifyToken,
9
- getUserProfile,
10
- authenticateWithApple,
11
- authenticateWithOnairos,
12
- authenticateWithOnairosSignIn,
13
- updateUserOnboardedStatus
14
- } from '../services/authService';
15
- import {
16
- saveUserProgress,
17
- saveAuthState,
18
- getAuthState,
19
- clearUserData,
20
- getResumeTarget,
21
- markStepCompleted,
22
- updateLastScreen,
23
- isReturningUser,
24
- markEventPageReached,
25
- hasEventAccessToken,
26
- STORAGE_KEYS
27
- } from '../services/storageService';
28
-
29
- interface AuthContextType {
30
- user: User | null;
31
- isLoading: boolean;
32
- hasCompletedOnboarding: boolean;
33
- login: (userData: User) => void;
34
- logout: () => void;
35
- deleteAccount: () => Promise<void>;
36
- completeOnboarding: (userData: Partial<User>) => void;
37
- updateUser: (userData: Partial<User>) => void;
38
- appleSignIn: (appleAuthData: any) => Promise<User>;
39
- onairosSignIn: (onairosAuthData: { token: string; email: string }) => Promise<User>;
40
- isAuthenticated: boolean;
41
- updateOnboardedStatus: () => Promise<void>;
42
- // New methods for progress tracking
43
- getResumeTarget: () => Promise<{ screen: string; params?: any }>;
44
- markStepCompleted: (step: string) => Promise<void>;
45
- updateLastScreen: (screen: string, params?: any) => Promise<void>;
46
- isReturningUser: () => Promise<boolean>;
47
- // New methods for event access token
48
- markEventPageReached: (eventData?: any) => Promise<void>;
49
- hasEventAccessToken: () => Promise<boolean>;
50
- }
51
-
52
- const AuthContext = createContext<AuthContextType | undefined>(undefined);
53
-
54
- export const AuthProvider: React.FC<{ children: React.ReactNode }> = ({ children }) => {
55
- const [user, setUser] = useState<User | null>(null);
56
- const [isLoading, setIsLoading] = useState(true);
57
- const [hasCompletedOnboarding, setHasCompletedOnboarding] = useState(false);
58
- const [isAuthenticated, setIsAuthenticated] = useState(false);
59
-
60
- useEffect(() => {
61
- // Check if user is already logged in
62
- const loadStoredUser = async () => {
63
- try {
64
- // PRIORITY 1: Check if user has completed onboarding (for release mode reliability)
65
- const hasEventToken = await hasEventAccessToken();
66
- const storedUser = await AsyncStorage.getItem('user');
67
-
68
- if (hasEventToken && storedUser) {
69
- console.log('🎯 Found event access token - user has completed onboarding, authentication confirmed');
70
- setUser(JSON.parse(storedUser));
71
- setIsAuthenticated(true);
72
- setHasCompletedOnboarding(true);
73
- setIsLoading(false);
74
- return; // Skip network verification for completed users
75
- }
76
-
77
- // PRIORITY 2: Check if we have a JWT token for users still in onboarding
78
- const token = await getAuthToken();
79
-
80
- if (token) {
81
- // For users with tokens but no completion token, try network verification
82
- // but don't fail if network is unreachable (important for release mode)
83
- let isValid = false;
84
- try {
85
- isValid = await verifyToken();
86
- } catch (networkError) {
87
- console.warn('🌐 Network verification failed, using local token validation:', networkError);
88
- // In release mode, network might be slow/unreliable
89
- // If we have a token and stored user, trust the local state
90
- if (storedUser) {
91
- console.log('💾 Network unreachable, trusting local authentication state');
92
- isValid = true; // Trust local state when network fails
93
- }
94
- }
95
-
96
- if (isValid) {
97
- // Token is valid (or we're trusting local state), get user data
98
- if (storedUser) {
99
- setUser(JSON.parse(storedUser));
100
- setIsAuthenticated(true);
101
- } else {
102
- // If user data is not in AsyncStorage, try to fetch it
103
- try {
104
- const userData = await getUserProfile();
105
- await AsyncStorage.setItem('user', JSON.stringify(userData));
106
- setUser(userData);
107
- setIsAuthenticated(true);
108
- } catch (profileError) {
109
- console.error('Failed to fetch user profile:', profileError);
110
- // Only remove token if we're sure it's invalid (not just network issues)
111
- const errorMessage = profileError instanceof Error ? profileError.message : String(profileError);
112
- if (errorMessage.includes('401') || errorMessage.includes('403')) {
113
- await removeAuthToken();
114
- } else {
115
- console.log('🌐 Profile fetch failed (likely network), keeping authentication state');
116
- // Create fallback user for offline scenarios
117
- if (token) {
118
- const fallbackUser = {
119
- id: 'offline_user',
120
- name: 'Onairos User',
121
- email: 'user@onairos.com',
122
- onboarded: false
123
- };
124
- await AsyncStorage.setItem('user', JSON.stringify(fallbackUser));
125
- setUser(fallbackUser);
126
- setIsAuthenticated(true);
127
- }
128
- }
129
- }
130
- }
131
- } else {
132
- // Token verification definitely failed - remove it
133
- await removeAuthToken();
134
- }
135
- }
136
-
137
- const onboardingCompleted = await AsyncStorage.getItem('onboardingCompleted');
138
- if (onboardingCompleted === 'true') {
139
- setHasCompletedOnboarding(true);
140
- }
141
- } catch (error) {
142
- console.error('Failed to load authentication state:', error);
143
- } finally {
144
- setIsLoading(false);
145
- }
146
- };
147
-
148
- loadStoredUser();
149
- }, []);
150
-
151
- const login = async (userData: User) => {
152
- try {
153
- // Ensure onboarded is set to false for new users
154
- const userWithOnboarded = {
155
- ...userData,
156
- onboarded: false // Always force camera flow for new logins
157
- };
158
-
159
- await AsyncStorage.setItem('user', JSON.stringify(userWithOnboarded));
160
- setUser(userWithOnboarded);
161
- setIsAuthenticated(true);
162
-
163
- // Save auth state and mark authentication step as completed
164
- await saveAuthState({
165
- isAuthenticated: true,
166
- authMethod: userData.email?.includes('apple') ? 'apple' : 'onairos',
167
- hasValidToken: true,
168
- userEmail: userData.email,
169
- userName: userData.name
170
- });
171
-
172
- await markStepCompleted('authentication');
173
-
174
- console.log('User logged in with onboarded=false:', userWithOnboarded);
175
- } catch (error) {
176
- console.error('Failed to save user data:', error);
177
- }
178
- };
179
-
180
- // Handle Apple Sign-In
181
- const appleSignIn = async (appleAuthData: any): Promise<User> => {
182
- try {
183
- setIsLoading(true);
184
-
185
- // Call the API to authenticate with Apple
186
- const authResponse = await authenticateWithApple(appleAuthData);
187
-
188
- // Save the JWT token
189
- await saveAuthToken(authResponse.token);
190
-
191
- // CRITICAL: Save auth method as 'apple' for proper button logic
192
- await AsyncStorage.setItem('auth_method', 'apple');
193
-
194
- // Save Onairos connection status from backend response
195
- if (authResponse.onairos) {
196
- await AsyncStorage.setItem('hasConnectedOnairos', authResponse.onairos.hasConnectedOnairos.toString());
197
- if (authResponse.onairos.onairosUserId) {
198
- await AsyncStorage.setItem('onairosUserId', authResponse.onairos.onairosUserId);
199
- }
200
- if (authResponse.onairos.lastConnectedAt) {
201
- await AsyncStorage.setItem('lastConnectedAt', authResponse.onairos.lastConnectedAt);
202
- }
203
- console.log('🔗 Stored Onairos connection status:', authResponse.onairos.hasConnectedOnairos);
204
- } else {
205
- // Default to false if no Onairos info provided
206
- await AsyncStorage.setItem('hasConnectedOnairos', 'false');
207
- console.log('🔗 No Onairos connection info from backend, defaulting to false');
208
- }
209
-
210
- // Create user object from response
211
- const userData: User = {
212
- id: authResponse.user.id,
213
- name: authResponse.user.name || 'Onairos User',
214
- email: authResponse.user.email,
215
- profilePicture: authResponse.user.profilePicture,
216
- onboarded: false // Default to false for new Apple sign-ins
217
- };
218
-
219
- // Save user data to AsyncStorage and update state
220
- await AsyncStorage.setItem('user', JSON.stringify(userData));
221
- setUser(userData);
222
- setIsAuthenticated(true);
223
-
224
- console.log('🍎 Apple sign-in completed - auth_method set to "apple"');
225
-
226
- return userData;
227
- } catch (error) {
228
- console.error('Apple sign-in failed:', error);
229
- throw error;
230
- } finally {
231
- setIsLoading(false);
232
- }
233
- };
234
-
235
- // Handle Onairos Sign-In (similar to Apple)
236
- const onairosSignIn = async (onairosAuthData: { token: string; email: string }): Promise<User> => {
237
- try {
238
- setIsLoading(true);
239
-
240
- // Call the API to authenticate with Onairos
241
- const authResponse = await authenticateWithOnairos(onairosAuthData);
242
-
243
- // Save the JWT token
244
- await saveAuthToken(authResponse.token);
245
-
246
- // CRITICAL: Save auth method as 'onairos' for proper button logic
247
- await AsyncStorage.setItem('auth_method', 'onairos');
248
-
249
- // Create user object from response
250
- const userData: User = {
251
- id: authResponse.user.id,
252
- name: authResponse.user.name || 'Onairos User',
253
- email: authResponse.user.email,
254
- profilePicture: authResponse.user.profilePicture,
255
- onboarded: false // Default to false for new Onairos sign-ins
256
- };
257
-
258
- // Save user data to AsyncStorage and update state
259
- await AsyncStorage.setItem('user', JSON.stringify(userData));
260
- setUser(userData);
261
- setIsAuthenticated(true);
262
-
263
- console.log('🔑 Onairos sign-in completed - auth_method set to "onairos"');
264
-
265
- return userData;
266
- } catch (error) {
267
- console.error('Onairos sign-in failed:', error);
268
- throw error;
269
- } finally {
270
- setIsLoading(false);
271
- }
272
- };
273
-
274
- const logout = async () => {
275
- try {
276
- // Clear all user data using the new storage service
277
- await clearUserData();
278
- setUser(null);
279
- setIsAuthenticated(false);
280
- } catch (error) {
281
- console.error('Failed to remove user data:', error);
282
- }
283
- };
284
-
285
- const completeOnboarding = async (userData: Partial<User>) => {
286
- try {
287
- // Update user data
288
- const updatedUser = { ...user, ...userData };
289
- await AsyncStorage.setItem('user', JSON.stringify(updatedUser));
290
- setUser(updatedUser as User);
291
-
292
- // Update onboarded status on backend
293
- await updateOnboardedStatus();
294
- } catch (error) {
295
- console.error('Failed to complete onboarding:', error);
296
- throw error;
297
- }
298
- };
299
-
300
- const updateUser = async (userData: Partial<User>) => {
301
- try {
302
- if (!user) return;
303
- const updatedUser = { ...user, ...userData };
304
- await AsyncStorage.setItem('user', JSON.stringify(updatedUser));
305
- setUser(updatedUser);
306
- } catch (error) {
307
- console.error('Failed to update user data:', error);
308
- }
309
- };
310
-
311
- // Update user onboarded status
312
- const updateOnboardedStatus = async (): Promise<void> => {
313
- try {
314
- setIsLoading(true);
315
-
316
- // Call the API to update onboarded status
317
- await updateUserOnboardedStatus();
318
-
319
- // Update local user data
320
- if (user) {
321
- const updatedUser = { ...user, onboarded: true };
322
- await AsyncStorage.setItem('user', JSON.stringify(updatedUser));
323
- setUser(updatedUser);
324
- }
325
- } catch (error) {
326
- console.error('Failed to update onboarded status:', error);
327
- throw error;
328
- } finally {
329
- setIsLoading(false);
330
- }
331
- };
332
-
333
- const deleteAccount = async () => {
334
- try {
335
- // In a real app, you would make an API call to delete the user account on the server
336
- // For example: await api.deleteUser(user.id);
337
-
338
- // Remove user data from AsyncStorage
339
- await AsyncStorage.removeItem('user');
340
-
341
- // Remove JWT token
342
- await removeAuthToken();
343
-
344
- // Clear any other user-related data from AsyncStorage
345
- await AsyncStorage.removeItem('onboardingCompleted');
346
-
347
- // Update state
348
- setUser(null);
349
- setIsAuthenticated(false);
350
- setHasCompletedOnboarding(false);
351
-
352
- console.log('Account deleted successfully');
353
- } catch (error) {
354
- console.error('Failed to delete account:', error);
355
- throw error;
356
- }
357
- };
358
-
359
- return (
360
- <AuthContext.Provider value={{
361
- user,
362
- isLoading,
363
- hasCompletedOnboarding,
364
- login,
365
- logout,
366
- deleteAccount,
367
- completeOnboarding,
368
- updateUser,
369
- appleSignIn,
370
- onairosSignIn,
371
- isAuthenticated,
372
- updateOnboardedStatus,
373
- // Progress tracking methods
374
- getResumeTarget,
375
- markStepCompleted,
376
- updateLastScreen,
377
- isReturningUser,
378
- // Event access token methods
379
- markEventPageReached,
380
- hasEventAccessToken
381
- }}>
382
- {children}
383
- </AuthContext.Provider>
384
- );
385
- };
386
-
387
- export const useAuth = (): AuthContextType => {
388
- const context = useContext(AuthContext);
389
- if (context === undefined) {
390
- throw new Error('useAuth must be used within an AuthProvider');
391
- }
392
- return context;
393
- };
1
+ import React, { createContext, useState, useEffect, useContext } from 'react';
2
+ import AsyncStorage from '@react-native-async-storage/async-storage';
3
+ import { User } from '../types/index';
4
+ import {
5
+ saveAuthToken,
6
+ getAuthToken,
7
+ removeAuthToken,
8
+ verifyToken,
9
+ getUserProfile,
10
+ authenticateWithApple,
11
+ authenticateWithOnairos,
12
+ authenticateWithOnairosSignIn,
13
+ updateUserOnboardedStatus
14
+ } from '../services/authService';
15
+ import {
16
+ saveUserProgress,
17
+ saveAuthState,
18
+ getAuthState,
19
+ clearUserData,
20
+ getResumeTarget,
21
+ markStepCompleted,
22
+ updateLastScreen,
23
+ isReturningUser,
24
+ markEventPageReached,
25
+ hasEventAccessToken,
26
+ STORAGE_KEYS
27
+ } from '../services/storageService';
28
+
29
+ interface AuthContextType {
30
+ user: User | null;
31
+ isLoading: boolean;
32
+ hasCompletedOnboarding: boolean;
33
+ login: (userData: User) => void;
34
+ logout: () => void;
35
+ deleteAccount: () => Promise<void>;
36
+ completeOnboarding: (userData: Partial<User>) => void;
37
+ updateUser: (userData: Partial<User>) => void;
38
+ appleSignIn: (appleAuthData: any) => Promise<User>;
39
+ onairosSignIn: (onairosAuthData: { token: string; email: string }) => Promise<User>;
40
+ isAuthenticated: boolean;
41
+ updateOnboardedStatus: () => Promise<void>;
42
+ // New methods for progress tracking
43
+ getResumeTarget: () => Promise<{ screen: string; params?: any }>;
44
+ markStepCompleted: (step: string) => Promise<void>;
45
+ updateLastScreen: (screen: string, params?: any) => Promise<void>;
46
+ isReturningUser: () => Promise<boolean>;
47
+ // New methods for event access token
48
+ markEventPageReached: (eventData?: any) => Promise<void>;
49
+ hasEventAccessToken: () => Promise<boolean>;
50
+ }
51
+
52
+ const AuthContext = createContext<AuthContextType | undefined>(undefined);
53
+
54
+ export const AuthProvider: React.FC<{ children: React.ReactNode }> = ({ children }) => {
55
+ const [user, setUser] = useState<User | null>(null);
56
+ const [isLoading, setIsLoading] = useState(true);
57
+ const [hasCompletedOnboarding, setHasCompletedOnboarding] = useState(false);
58
+ const [isAuthenticated, setIsAuthenticated] = useState(false);
59
+
60
+ useEffect(() => {
61
+ // Check if user is already logged in
62
+ const loadStoredUser = async () => {
63
+ try {
64
+ // PRIORITY 1: Check if user has completed onboarding (for release mode reliability)
65
+ const hasEventToken = await hasEventAccessToken();
66
+ const storedUser = await AsyncStorage.getItem('user');
67
+
68
+ if (hasEventToken && storedUser) {
69
+ console.log('🎯 Found event access token - user has completed onboarding, authentication confirmed');
70
+ setUser(JSON.parse(storedUser));
71
+ setIsAuthenticated(true);
72
+ setHasCompletedOnboarding(true);
73
+ setIsLoading(false);
74
+ return; // Skip network verification for completed users
75
+ }
76
+
77
+ // PRIORITY 2: Check if we have a JWT token for users still in onboarding
78
+ const token = await getAuthToken();
79
+
80
+ if (token) {
81
+ // For users with tokens but no completion token, try network verification
82
+ // but don't fail if network is unreachable (important for release mode)
83
+ let isValid = false;
84
+ try {
85
+ isValid = await verifyToken();
86
+ } catch (networkError) {
87
+ console.warn('🌐 Network verification failed, using local token validation:', networkError);
88
+ // In release mode, network might be slow/unreliable
89
+ // If we have a token and stored user, trust the local state
90
+ if (storedUser) {
91
+ console.log('💾 Network unreachable, trusting local authentication state');
92
+ isValid = true; // Trust local state when network fails
93
+ }
94
+ }
95
+
96
+ if (isValid) {
97
+ // Token is valid (or we're trusting local state), get user data
98
+ if (storedUser) {
99
+ setUser(JSON.parse(storedUser));
100
+ setIsAuthenticated(true);
101
+ } else {
102
+ // If user data is not in AsyncStorage, try to fetch it
103
+ try {
104
+ const userData = await getUserProfile();
105
+ await AsyncStorage.setItem('user', JSON.stringify(userData));
106
+ setUser(userData);
107
+ setIsAuthenticated(true);
108
+ } catch (profileError) {
109
+ console.error('Failed to fetch user profile:', profileError);
110
+ // Only remove token if we're sure it's invalid (not just network issues)
111
+ const errorMessage = profileError instanceof Error ? profileError.message : String(profileError);
112
+ if (errorMessage.includes('401') || errorMessage.includes('403')) {
113
+ await removeAuthToken();
114
+ } else {
115
+ console.log('🌐 Profile fetch failed (likely network), keeping authentication state');
116
+ // Create fallback user for offline scenarios
117
+ if (token) {
118
+ const fallbackUser = {
119
+ id: 'offline_user',
120
+ name: 'Onairos User',
121
+ email: 'user@onairos.com',
122
+ onboarded: false
123
+ };
124
+ await AsyncStorage.setItem('user', JSON.stringify(fallbackUser));
125
+ setUser(fallbackUser);
126
+ setIsAuthenticated(true);
127
+ }
128
+ }
129
+ }
130
+ }
131
+ } else {
132
+ // Token verification definitely failed - remove it
133
+ await removeAuthToken();
134
+ }
135
+ }
136
+
137
+ const onboardingCompleted = await AsyncStorage.getItem('onboardingCompleted');
138
+ if (onboardingCompleted === 'true') {
139
+ setHasCompletedOnboarding(true);
140
+ }
141
+ } catch (error) {
142
+ console.error('Failed to load authentication state:', error);
143
+ } finally {
144
+ setIsLoading(false);
145
+ }
146
+ };
147
+
148
+ loadStoredUser();
149
+ }, []);
150
+
151
+ const login = async (userData: User) => {
152
+ try {
153
+ // Ensure onboarded is set to false for new users
154
+ const userWithOnboarded = {
155
+ ...userData,
156
+ onboarded: false // Always force camera flow for new logins
157
+ };
158
+
159
+ await AsyncStorage.setItem('user', JSON.stringify(userWithOnboarded));
160
+ setUser(userWithOnboarded);
161
+ setIsAuthenticated(true);
162
+
163
+ // Save auth state and mark authentication step as completed
164
+ await saveAuthState({
165
+ isAuthenticated: true,
166
+ authMethod: userData.email?.includes('apple') ? 'apple' : 'onairos',
167
+ hasValidToken: true,
168
+ userEmail: userData.email,
169
+ userName: userData.name
170
+ });
171
+
172
+ await markStepCompleted('authentication');
173
+
174
+ console.log('User logged in with onboarded=false:', userWithOnboarded);
175
+ } catch (error) {
176
+ console.error('Failed to save user data:', error);
177
+ }
178
+ };
179
+
180
+ // Handle Apple Sign-In
181
+ const appleSignIn = async (appleAuthData: any): Promise<User> => {
182
+ try {
183
+ setIsLoading(true);
184
+
185
+ // Call the API to authenticate with Apple
186
+ const authResponse = await authenticateWithApple(appleAuthData);
187
+
188
+ // Save the JWT token
189
+ await saveAuthToken(authResponse.token);
190
+
191
+ // CRITICAL: Save auth method as 'apple' for proper button logic
192
+ await AsyncStorage.setItem('auth_method', 'apple');
193
+
194
+ // Save Onairos connection status from backend response
195
+ if (authResponse.onairos) {
196
+ await AsyncStorage.setItem('hasConnectedOnairos', authResponse.onairos.hasConnectedOnairos.toString());
197
+ if (authResponse.onairos.onairosUserId) {
198
+ await AsyncStorage.setItem('onairosUserId', authResponse.onairos.onairosUserId);
199
+ }
200
+ if (authResponse.onairos.lastConnectedAt) {
201
+ await AsyncStorage.setItem('lastConnectedAt', authResponse.onairos.lastConnectedAt);
202
+ }
203
+ console.log('🔗 Stored Onairos connection status:', authResponse.onairos.hasConnectedOnairos);
204
+ } else {
205
+ // Default to false if no Onairos info provided
206
+ await AsyncStorage.setItem('hasConnectedOnairos', 'false');
207
+ console.log('🔗 No Onairos connection info from backend, defaulting to false');
208
+ }
209
+
210
+ // Create user object from response
211
+ const userData: User = {
212
+ id: authResponse.user.id,
213
+ name: authResponse.user.name || 'Onairos User',
214
+ email: authResponse.user.email,
215
+ profilePicture: authResponse.user.profilePicture,
216
+ onboarded: false // Default to false for new Apple sign-ins
217
+ };
218
+
219
+ // Save user data to AsyncStorage and update state
220
+ await AsyncStorage.setItem('user', JSON.stringify(userData));
221
+ setUser(userData);
222
+ setIsAuthenticated(true);
223
+
224
+ console.log('🍎 Apple sign-in completed - auth_method set to "apple"');
225
+
226
+ return userData;
227
+ } catch (error) {
228
+ console.error('Apple sign-in failed:', error);
229
+ throw error;
230
+ } finally {
231
+ setIsLoading(false);
232
+ }
233
+ };
234
+
235
+ // Handle Onairos Sign-In (similar to Apple)
236
+ const onairosSignIn = async (onairosAuthData: { token: string; email: string }): Promise<User> => {
237
+ try {
238
+ setIsLoading(true);
239
+
240
+ // Call the API to authenticate with Onairos
241
+ const authResponse = await authenticateWithOnairos(onairosAuthData);
242
+
243
+ // Save the JWT token
244
+ await saveAuthToken(authResponse.token);
245
+
246
+ // CRITICAL: Save auth method as 'onairos' for proper button logic
247
+ await AsyncStorage.setItem('auth_method', 'onairos');
248
+
249
+ // Create user object from response
250
+ const userData: User = {
251
+ id: authResponse.user.id,
252
+ name: authResponse.user.name || 'Onairos User',
253
+ email: authResponse.user.email,
254
+ profilePicture: authResponse.user.profilePicture,
255
+ onboarded: false // Default to false for new Onairos sign-ins
256
+ };
257
+
258
+ // Save user data to AsyncStorage and update state
259
+ await AsyncStorage.setItem('user', JSON.stringify(userData));
260
+ setUser(userData);
261
+ setIsAuthenticated(true);
262
+
263
+ console.log('🔑 Onairos sign-in completed - auth_method set to "onairos"');
264
+
265
+ return userData;
266
+ } catch (error) {
267
+ console.error('Onairos sign-in failed:', error);
268
+ throw error;
269
+ } finally {
270
+ setIsLoading(false);
271
+ }
272
+ };
273
+
274
+ const logout = async () => {
275
+ try {
276
+ // Clear all user data using the new storage service
277
+ await clearUserData();
278
+ setUser(null);
279
+ setIsAuthenticated(false);
280
+ } catch (error) {
281
+ console.error('Failed to remove user data:', error);
282
+ }
283
+ };
284
+
285
+ const completeOnboarding = async (userData: Partial<User>) => {
286
+ try {
287
+ // Update user data
288
+ const updatedUser = { ...user, ...userData };
289
+ await AsyncStorage.setItem('user', JSON.stringify(updatedUser));
290
+ setUser(updatedUser as User);
291
+
292
+ // Update onboarded status on backend
293
+ await updateOnboardedStatus();
294
+ } catch (error) {
295
+ console.error('Failed to complete onboarding:', error);
296
+ throw error;
297
+ }
298
+ };
299
+
300
+ const updateUser = async (userData: Partial<User>) => {
301
+ try {
302
+ if (!user) return;
303
+ const updatedUser = { ...user, ...userData };
304
+ await AsyncStorage.setItem('user', JSON.stringify(updatedUser));
305
+ setUser(updatedUser);
306
+ } catch (error) {
307
+ console.error('Failed to update user data:', error);
308
+ }
309
+ };
310
+
311
+ // Update user onboarded status
312
+ const updateOnboardedStatus = async (): Promise<void> => {
313
+ try {
314
+ setIsLoading(true);
315
+
316
+ // Call the API to update onboarded status
317
+ await updateUserOnboardedStatus();
318
+
319
+ // Update local user data
320
+ if (user) {
321
+ const updatedUser = { ...user, onboarded: true };
322
+ await AsyncStorage.setItem('user', JSON.stringify(updatedUser));
323
+ setUser(updatedUser);
324
+ }
325
+ } catch (error) {
326
+ console.error('Failed to update onboarded status:', error);
327
+ throw error;
328
+ } finally {
329
+ setIsLoading(false);
330
+ }
331
+ };
332
+
333
+ const deleteAccount = async () => {
334
+ try {
335
+ // In a real app, you would make an API call to delete the user account on the server
336
+ // For example: await api.deleteUser(user.id);
337
+
338
+ // Remove user data from AsyncStorage
339
+ await AsyncStorage.removeItem('user');
340
+
341
+ // Remove JWT token
342
+ await removeAuthToken();
343
+
344
+ // Clear any other user-related data from AsyncStorage
345
+ await AsyncStorage.removeItem('onboardingCompleted');
346
+
347
+ // Update state
348
+ setUser(null);
349
+ setIsAuthenticated(false);
350
+ setHasCompletedOnboarding(false);
351
+
352
+ console.log('Account deleted successfully');
353
+ } catch (error) {
354
+ console.error('Failed to delete account:', error);
355
+ throw error;
356
+ }
357
+ };
358
+
359
+ return (
360
+ <AuthContext.Provider value={{
361
+ user,
362
+ isLoading,
363
+ hasCompletedOnboarding,
364
+ login,
365
+ logout,
366
+ deleteAccount,
367
+ completeOnboarding,
368
+ updateUser,
369
+ appleSignIn,
370
+ onairosSignIn,
371
+ isAuthenticated,
372
+ updateOnboardedStatus,
373
+ // Progress tracking methods
374
+ getResumeTarget,
375
+ markStepCompleted,
376
+ updateLastScreen,
377
+ isReturningUser,
378
+ // Event access token methods
379
+ markEventPageReached,
380
+ hasEventAccessToken
381
+ }}>
382
+ {children}
383
+ </AuthContext.Provider>
384
+ );
385
+ };
386
+
387
+ export const useAuth = (): AuthContextType => {
388
+ const context = useContext(AuthContext);
389
+ if (context === undefined) {
390
+ throw new Error('useAuth must be used within an AuthProvider');
391
+ }
392
+ return context;
393
+ };