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