@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.
- package/README.md +404 -0
- package/lib/commonjs/assets/images/Checkbox.svg +3 -3
- package/lib/commonjs/assets/images/EnochE.svg +19 -19
- package/lib/commonjs/assets/images/Personalityprofile.svg +3 -3
- package/lib/commonjs/assets/images/Personalitytraits.svg +3 -3
- package/lib/commonjs/assets/images/Userpreferences.svg +3 -3
- package/lib/commonjs/assets/images/arrow.svg +20 -20
- package/lib/commonjs/assets/images/basicproficon.svg +43 -43
- package/lib/commonjs/assets/images/basicprofile.svg +3 -3
- package/lib/commonjs/assets/images/checkmark.svg +4 -4
- package/lib/commonjs/assets/images/contentanalysis.svg +3 -3
- package/lib/commonjs/assets/images/contenticon.svg +23 -23
- package/lib/commonjs/assets/images/personalityicon.svg +18 -18
- package/lib/commonjs/assets/images/x-close.svg +3 -3
- package/lib/commonjs/components/OnairosButton.js +290 -0
- package/lib/commonjs/components/OnairosButton.js.map +1 -0
- package/lib/commonjs/components/OnairosSignInButton.js +30 -8
- package/lib/commonjs/components/OnairosSignInButton.js.map +1 -1
- package/lib/commonjs/components/UniversalOnboarding.js +4 -4
- package/lib/commonjs/config/api.js +2 -2
- package/lib/commonjs/hooks/useConnections.js +6 -6
- package/lib/commonjs/hooks/useUserConnections.js +10 -10
- package/lib/commonjs/index.js +9 -10
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/services/apiClient.js +35 -35
- package/lib/commonjs/services/apiKeyService.js +99 -99
- package/lib/commonjs/services/authService.js +82 -82
- package/lib/commonjs/services/biometricPinService.js +10 -10
- package/lib/commonjs/services/connectedAccountsService.js +32 -32
- package/lib/commonjs/services/googleAuthService.js +15 -15
- package/lib/commonjs/services/imageCompressionService.js +15 -15
- package/lib/commonjs/services/jwtStorageService.js +59 -59
- package/lib/commonjs/services/mobileTrainingService.js +14 -14
- package/lib/commonjs/services/pinEncryptionService.js +10 -10
- package/lib/commonjs/services/pinStorageUtils.js +15 -15
- package/lib/commonjs/services/platformAuthService.js +47 -47
- package/lib/commonjs/services/storageService.js +31 -31
- package/lib/commonjs/services/trainingApiHelpers.js +33 -33
- package/lib/commonjs/services/userConnectionsService.js +24 -24
- package/lib/commonjs/utils/Portal.js +4 -4
- package/lib/commonjs/utils/api.js +24 -24
- package/lib/commonjs/utils/auth.js +18 -18
- package/lib/commonjs/utils/crypto.js +13 -13
- package/lib/commonjs/utils/encryption.js +12 -12
- package/lib/commonjs/utils/eventUtils.js +52 -52
- package/lib/commonjs/utils/programmaticFlow.js +16 -16
- package/lib/commonjs/utils/retryHelper.js +27 -27
- package/lib/module/assets/images/Checkbox.svg +3 -3
- package/lib/module/assets/images/EnochE.svg +19 -19
- package/lib/module/assets/images/Personalityprofile.svg +3 -3
- package/lib/module/assets/images/Personalitytraits.svg +3 -3
- package/lib/module/assets/images/Userpreferences.svg +3 -3
- package/lib/module/assets/images/arrow.svg +20 -20
- package/lib/module/assets/images/basicproficon.svg +43 -43
- package/lib/module/assets/images/basicprofile.svg +3 -3
- package/lib/module/assets/images/checkmark.svg +4 -4
- package/lib/module/assets/images/contentanalysis.svg +3 -3
- package/lib/module/assets/images/contenticon.svg +23 -23
- package/lib/module/assets/images/personalityicon.svg +18 -18
- package/lib/module/assets/images/x-close.svg +3 -3
- package/lib/module/components/OnairosButton.js +282 -0
- package/lib/module/components/OnairosButton.js.map +1 -0
- package/lib/module/components/OnairosSignInButton.js +30 -8
- package/lib/module/components/OnairosSignInButton.js.map +1 -1
- package/lib/module/components/UniversalOnboarding.js +4 -4
- package/lib/module/config/api.js +2 -2
- package/lib/module/hooks/useConnections.js +6 -6
- package/lib/module/hooks/useUserConnections.js +10 -10
- package/lib/module/index.js +8 -10
- package/lib/module/index.js.map +1 -1
- package/lib/module/services/apiClient.js +35 -35
- package/lib/module/services/apiKeyService.js +99 -99
- package/lib/module/services/authService.js +82 -82
- package/lib/module/services/biometricPinService.js +10 -10
- package/lib/module/services/connectedAccountsService.js +32 -32
- package/lib/module/services/googleAuthService.js +15 -15
- package/lib/module/services/imageCompressionService.js +15 -15
- package/lib/module/services/jwtStorageService.js +59 -59
- package/lib/module/services/mobileTrainingService.js +14 -14
- package/lib/module/services/pinEncryptionService.js +10 -10
- package/lib/module/services/pinStorageUtils.js +15 -15
- package/lib/module/services/platformAuthService.js +47 -47
- package/lib/module/services/storageService.js +31 -31
- package/lib/module/services/trainingApiHelpers.js +33 -33
- package/lib/module/services/userConnectionsService.js +24 -24
- package/lib/module/utils/Portal.js +4 -4
- package/lib/module/utils/api.js +24 -24
- package/lib/module/utils/auth.js +18 -18
- package/lib/module/utils/crypto.js +13 -13
- package/lib/module/utils/encryption.js +12 -12
- package/lib/module/utils/eventUtils.js +52 -52
- package/lib/module/utils/programmaticFlow.js +16 -16
- package/lib/module/utils/retryHelper.js +27 -27
- package/lib/typescript/components/OnairosButton.d.ts +37 -0
- package/lib/typescript/components/OnairosButton.d.ts.map +1 -0
- package/lib/typescript/components/OnairosSignInButton.d.ts +2 -1
- package/lib/typescript/components/OnairosSignInButton.d.ts.map +1 -1
- package/lib/typescript/index.d.ts +3 -4
- package/lib/typescript/index.d.ts.map +1 -1
- package/package.json +163 -163
- package/src/api/index.ts +151 -151
- package/src/assets/images/Checkbox.svg +3 -3
- package/src/assets/images/EnochE.svg +19 -19
- package/src/assets/images/Personalityprofile.svg +3 -3
- package/src/assets/images/Personalitytraits.svg +3 -3
- package/src/assets/images/Userpreferences.svg +3 -3
- package/src/assets/images/arrow.svg +20 -20
- package/src/assets/images/basicproficon.svg +43 -43
- package/src/assets/images/basicprofile.svg +3 -3
- package/src/assets/images/checkmark.svg +4 -4
- package/src/assets/images/contentanalysis.svg +3 -3
- package/src/assets/images/contenticon.svg +23 -23
- package/src/assets/images/personalityicon.svg +18 -18
- package/src/assets/images/x-close.svg +3 -3
- package/src/components/BodyText.tsx +33 -33
- package/src/components/BrandMark.tsx +62 -62
- package/src/components/CodeInput.tsx +32 -32
- package/src/components/DataRequestScreen.tsx +355 -355
- package/src/components/EmailInput.tsx +31 -31
- package/src/components/EmailVerificationModal.tsx +363 -363
- package/src/components/ExistingUserDataConfirmation.tsx +506 -506
- package/src/components/GoogleButton.tsx +55 -55
- package/src/components/HeadingGroup.tsx +49 -49
- package/src/components/ModalHeader.tsx +125 -125
- package/src/components/ModalSheet.tsx +57 -57
- package/src/components/Onairos.tsx +422 -422
- package/src/components/OnairosButton.tsx +339 -0
- package/src/components/OnairosSignInButton.tsx +30 -10
- package/src/components/Overlay.tsx +506 -506
- package/src/components/PersonaImage.tsx +79 -79
- package/src/components/PersonaLoadingScreen.tsx +201 -201
- package/src/components/PersonalizationConsentScreen.tsx +410 -410
- package/src/components/PinCreationScreen.tsx +492 -492
- package/src/components/PinInput.tsx +555 -555
- package/src/components/PlatformConnectorsStep.tsx +891 -891
- package/src/components/PlatformList.tsx +144 -144
- package/src/components/PlatformToggle.tsx +226 -226
- package/src/components/PrimaryButton.tsx +213 -213
- package/src/components/SignInMatchAnimation.tsx +225 -225
- package/src/components/SignInStep.tsx +217 -217
- package/src/components/TrainingModal.tsx +1047 -1047
- package/src/components/UniversalOnboarding.tsx +2887 -2887
- package/src/components/VerificationStep.tsx +198 -198
- package/src/components/WelcomeScreen.tsx +473 -473
- package/src/components/icons/Basicproficon.tsx +30 -30
- package/src/components/icons/Basicprofile.tsx +17 -17
- package/src/components/icons/Checkbox.tsx +17 -17
- package/src/components/icons/Checkmark.tsx +24 -24
- package/src/components/icons/Contentanalysis.tsx +17 -17
- package/src/components/icons/Contenticon.tsx +30 -30
- package/src/components/icons/EnochE.tsx +39 -39
- package/src/components/icons/Personalityicon.tsx +22 -22
- package/src/components/icons/Personalityprofile.tsx +17 -17
- package/src/components/icons/Personalitytraits.tsx +17 -17
- package/src/components/icons/Userpreferences.tsx +17 -17
- package/src/components/icons/index.ts +12 -12
- package/src/components/onboarding/OAuthWebView.tsx +232 -232
- package/src/config/api.ts +25 -25
- package/src/context/AuthContext.tsx +393 -393
- package/src/hooks/useConnectedAccounts.ts +138 -138
- package/src/hooks/useConnections.ts +161 -161
- package/src/hooks/useCredentials.ts +174 -174
- package/src/hooks/useUserConnections.ts +165 -165
- package/src/index.js +14 -0
- package/src/index.ts +94 -96
- package/src/services/apiClient.ts +336 -336
- package/src/services/apiKeyService.ts +919 -919
- package/src/services/authService.ts +1008 -1008
- package/src/services/biometricPinService.ts +192 -192
- package/src/services/connectedAccountsService.ts +289 -289
- package/src/services/googleAuthService.ts +279 -279
- package/src/services/imageCompressionService.ts +302 -302
- package/src/services/jwtStorageService.ts +256 -256
- package/src/services/mobileTrainingService.ts +203 -203
- package/src/services/pinEncryptionService.ts +75 -75
- package/src/services/pinStorageUtils.ts +96 -96
- package/src/services/platformAuthService.ts +1346 -1346
- package/src/services/storageService.ts +451 -451
- package/src/services/trainingApiHelpers.ts +66 -66
- package/src/services/userConnectionsService.ts +556 -556
- package/src/services/youtubeMigrationService.ts +453 -453
- package/src/theme/index.ts +239 -239
- package/src/types/ambient.d.ts +28 -28
- package/src/types/index.ts +265 -265
- package/src/types/node-fix.d.ts +18 -18
- package/src/types/node-override.d.ts +23 -23
- package/src/types/opacity.d.ts +15 -15
- package/src/types/types.d.ts +17 -17
- package/src/utils/Portal.tsx +82 -82
- package/src/utils/api.js +111 -111
- package/src/utils/auth.js +103 -103
- package/src/utils/crypto.js +59 -59
- package/src/utils/encryption.ts +68 -68
- package/src/utils/eventUtils.ts +302 -302
- package/src/utils/haptics.ts +58 -58
- package/src/utils/imagePreloader.ts +2 -2
- package/src/utils/programmaticFlow.ts +112 -112
- 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
|
};
|