@onairos/react-native 3.1.11 → 3.1.13
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/lib/commonjs/api/index.js +75 -1
- package/lib/commonjs/api/index.js.map +1 -1
- package/lib/commonjs/assets/fonts/EBGaramond-VariableFont_wght.ttf +0 -0
- package/lib/commonjs/assets/fonts/IBMPlexSans-VariableFont_wdth,wght.ttf +0 -0
- package/lib/commonjs/assets/icons/Facebookicon.png +0 -0
- package/lib/commonjs/assets/icons/Gmail.png +0 -0
- package/lib/commonjs/assets/icons/Linkedinicon.png +0 -0
- package/lib/commonjs/assets/icons/Redditicon.png +0 -0
- package/lib/commonjs/assets/icons/YouTubeicon2.png +0 -0
- package/lib/commonjs/assets/icons/YouTubeicon3.png +0 -0
- package/lib/commonjs/assets/icons/farcaster.png +0 -0
- package/lib/commonjs/assets/icons/instagram.png +0 -0
- package/lib/commonjs/assets/icons/pinterest.png +0 -0
- package/lib/commonjs/assets/icons/swerv_logo.png +0 -0
- package/lib/commonjs/assets/icons/twitter.jpg +0 -0
- package/lib/commonjs/assets/images/Checkbox.svg +3 -0
- package/lib/commonjs/assets/images/EnochE.svg +19 -0
- package/lib/commonjs/assets/images/Enochicon1.png +0 -0
- package/lib/commonjs/assets/images/Face_ID_logo.png +0 -0
- package/lib/commonjs/assets/images/Facebookicon.png +0 -0
- package/lib/commonjs/assets/images/Gmail.png +0 -0
- package/lib/commonjs/assets/images/Googlelogo.png +0 -0
- package/lib/commonjs/assets/images/Linkedinicon.png +0 -0
- package/lib/commonjs/assets/images/Onairoslogo.png +0 -0
- package/lib/commonjs/assets/images/Personalityprofile.svg +3 -0
- package/lib/commonjs/assets/images/Personalitytraits.svg +3 -0
- package/lib/commonjs/assets/images/Redditicon.png +0 -0
- package/lib/commonjs/assets/images/Userpreferences.svg +3 -0
- package/lib/commonjs/assets/images/YouTubeicon3.png +0 -0
- package/lib/commonjs/assets/images/arrow.svg +20 -0
- package/lib/commonjs/assets/images/basicproficon.svg +43 -0
- package/lib/commonjs/assets/images/basicprofile.svg +3 -0
- package/lib/commonjs/assets/images/checkmark.svg +4 -0
- package/lib/commonjs/assets/images/contentanalysis.svg +3 -0
- package/lib/commonjs/assets/images/contenticon.svg +23 -0
- package/lib/commonjs/assets/images/persona1.png +0 -0
- package/lib/commonjs/assets/images/persona2.png +0 -0
- package/lib/commonjs/assets/images/persona3.png +0 -0
- package/lib/commonjs/assets/images/persona4.png +0 -0
- package/lib/commonjs/assets/images/persona5.png +0 -0
- package/lib/commonjs/assets/images/personalityicon.svg +18 -0
- package/lib/commonjs/assets/images/x-close.svg +3 -0
- package/lib/commonjs/components/BodyText.js +27 -0
- package/lib/commonjs/components/BodyText.js.map +1 -0
- package/lib/commonjs/components/BrandMark.js +44 -0
- package/lib/commonjs/components/BrandMark.js.map +1 -0
- package/lib/commonjs/components/CodeInput.js +30 -0
- package/lib/commonjs/components/CodeInput.js.map +1 -0
- package/lib/commonjs/components/EmailInput.js +30 -0
- package/lib/commonjs/components/EmailInput.js.map +1 -0
- package/lib/commonjs/components/ExistingUserDataConfirmation.js +474 -0
- package/lib/commonjs/components/ExistingUserDataConfirmation.js.map +1 -0
- package/lib/commonjs/components/GoogleButton.js +55 -0
- package/lib/commonjs/components/GoogleButton.js.map +1 -0
- package/lib/commonjs/components/HeadingGroup.js +43 -0
- package/lib/commonjs/components/HeadingGroup.js.map +1 -0
- package/lib/commonjs/components/ModalHeader.js +99 -0
- package/lib/commonjs/components/ModalHeader.js.map +1 -0
- package/lib/commonjs/components/ModalSheet.js +41 -0
- package/lib/commonjs/components/ModalSheet.js.map +1 -0
- package/lib/commonjs/components/Onairos.js +1 -3
- package/lib/commonjs/components/Onairos.js.map +1 -1
- package/lib/commonjs/components/OnairosButton.js +171 -190
- package/lib/commonjs/components/OnairosButton.js.map +1 -1
- package/lib/commonjs/components/OnairosSignInButton.js +169 -0
- package/lib/commonjs/components/OnairosSignInButton.js.map +1 -0
- package/lib/commonjs/components/Overlay.js +5 -5
- package/lib/commonjs/components/Overlay.js.map +1 -1
- package/lib/commonjs/components/PersonaImage.js +60 -0
- package/lib/commonjs/components/PersonaImage.js.map +1 -0
- package/lib/commonjs/components/PersonaLoadingScreen.js +156 -0
- package/lib/commonjs/components/PersonaLoadingScreen.js.map +1 -0
- package/lib/commonjs/components/PersonalizationConsentScreen.js +316 -0
- package/lib/commonjs/components/PersonalizationConsentScreen.js.map +1 -0
- package/lib/commonjs/components/PinCreationScreen.js +393 -0
- package/lib/commonjs/components/PinCreationScreen.js.map +1 -0
- package/lib/commonjs/components/PinInput.js +282 -120
- package/lib/commonjs/components/PinInput.js.map +1 -1
- package/lib/commonjs/components/PlatformConnectorsStep.js +828 -0
- package/lib/commonjs/components/PlatformConnectorsStep.js.map +1 -0
- package/lib/commonjs/components/PlatformToggle.js +180 -0
- package/lib/commonjs/components/PlatformToggle.js.map +1 -0
- package/lib/commonjs/components/PrimaryButton.js +180 -0
- package/lib/commonjs/components/PrimaryButton.js.map +1 -0
- package/lib/commonjs/components/SignInMatchAnimation.js +197 -0
- package/lib/commonjs/components/SignInMatchAnimation.js.map +1 -0
- package/lib/commonjs/components/SignInStep.js +179 -0
- package/lib/commonjs/components/SignInStep.js.map +1 -0
- package/lib/commonjs/components/TrainingModal.js +808 -563
- package/lib/commonjs/components/TrainingModal.js.map +1 -1
- package/lib/commonjs/components/UniversalOnboarding.js +2304 -1283
- package/lib/commonjs/components/UniversalOnboarding.js.map +1 -1
- package/lib/commonjs/components/VerificationStep.js +154 -0
- package/lib/commonjs/components/VerificationStep.js.map +1 -0
- package/lib/commonjs/components/WelcomeScreen.js +385 -0
- package/lib/commonjs/components/WelcomeScreen.js.map +1 -0
- package/lib/commonjs/components/icons/Basicproficon.js +37 -0
- package/lib/commonjs/components/icons/Basicproficon.js.map +1 -0
- package/lib/commonjs/components/icons/Basicprofile.js +21 -0
- package/lib/commonjs/components/icons/Basicprofile.js.map +1 -0
- package/lib/commonjs/components/icons/Checkbox.js +21 -0
- package/lib/commonjs/components/icons/Checkbox.js.map +1 -0
- package/lib/commonjs/components/icons/Checkmark.js +27 -0
- package/lib/commonjs/components/icons/Checkmark.js.map +1 -0
- package/lib/commonjs/components/icons/Contentanalysis.js +21 -0
- package/lib/commonjs/components/icons/Contentanalysis.js.map +1 -0
- package/lib/commonjs/components/icons/Contenticon.js +39 -0
- package/lib/commonjs/components/icons/Contenticon.js.map +1 -0
- package/lib/commonjs/components/icons/EnochE.js +41 -0
- package/lib/commonjs/components/icons/EnochE.js.map +1 -0
- package/lib/commonjs/components/icons/Personalityicon.js +30 -0
- package/lib/commonjs/components/icons/Personalityicon.js.map +1 -0
- package/lib/commonjs/components/icons/Personalityprofile.js +21 -0
- package/lib/commonjs/components/icons/Personalityprofile.js.map +1 -0
- package/lib/commonjs/components/icons/Personalitytraits.js +21 -0
- package/lib/commonjs/components/icons/Personalitytraits.js.map +1 -0
- package/lib/commonjs/components/icons/Userpreferences.js +21 -0
- package/lib/commonjs/components/icons/Userpreferences.js.map +1 -0
- package/lib/commonjs/components/icons/index.js +84 -0
- package/lib/commonjs/components/icons/index.js.map +1 -0
- package/lib/commonjs/components/onboarding/OAuthWebView.js +134 -743
- package/lib/commonjs/components/onboarding/OAuthWebView.js.map +1 -1
- package/lib/commonjs/config/api.js +34 -0
- package/lib/commonjs/config/api.js.map +1 -0
- package/lib/commonjs/context/AuthContext.js +345 -0
- package/lib/commonjs/context/AuthContext.js.map +1 -0
- package/lib/commonjs/hooks/useConnectedAccounts.js +111 -0
- package/lib/commonjs/hooks/useConnectedAccounts.js.map +1 -0
- package/lib/commonjs/hooks/useConnections.js +120 -125
- package/lib/commonjs/hooks/useConnections.js.map +1 -1
- package/lib/commonjs/hooks/useUserConnections.js +148 -0
- package/lib/commonjs/hooks/useUserConnections.js.map +1 -0
- package/lib/commonjs/index.js +149 -27
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/services/apiClient.js +302 -0
- package/lib/commonjs/services/apiClient.js.map +1 -0
- package/lib/commonjs/services/authService.js +935 -0
- package/lib/commonjs/services/authService.js.map +1 -0
- package/lib/commonjs/services/biometricPinService.js +184 -0
- package/lib/commonjs/services/biometricPinService.js.map +1 -0
- package/lib/commonjs/services/connectedAccountsService.js +268 -0
- package/lib/commonjs/services/connectedAccountsService.js.map +1 -0
- package/lib/commonjs/services/googleAuthService.js +268 -0
- package/lib/commonjs/services/googleAuthService.js.map +1 -0
- package/lib/commonjs/services/imageCompressionService.js +260 -0
- package/lib/commonjs/services/imageCompressionService.js.map +1 -0
- package/lib/commonjs/services/jwtStorageService.js +256 -0
- package/lib/commonjs/services/jwtStorageService.js.map +1 -0
- package/lib/commonjs/services/mobileTrainingService.js +185 -0
- package/lib/commonjs/services/mobileTrainingService.js.map +1 -0
- package/lib/commonjs/services/pinEncryptionService.js +84 -0
- package/lib/commonjs/services/pinEncryptionService.js.map +1 -0
- package/lib/commonjs/services/pinStorageUtils.js +105 -0
- package/lib/commonjs/services/pinStorageUtils.js.map +1 -0
- package/lib/commonjs/services/platformAuthService.js +956 -722
- package/lib/commonjs/services/platformAuthService.js.map +1 -1
- package/lib/commonjs/services/storageService.js +404 -0
- package/lib/commonjs/services/storageService.js.map +1 -0
- package/lib/commonjs/services/trainingApiHelpers.js +73 -0
- package/lib/commonjs/services/trainingApiHelpers.js.map +1 -0
- package/lib/commonjs/services/userConnectionsService.js +486 -0
- package/lib/commonjs/services/userConnectionsService.js.map +1 -0
- package/lib/commonjs/services/youtubeMigrationService.js +415 -0
- package/lib/commonjs/services/youtubeMigrationService.js.map +1 -0
- package/lib/commonjs/theme/index.js +249 -0
- package/lib/commonjs/theme/index.js.map +1 -0
- package/lib/commonjs/utils/eventUtils.js +288 -0
- package/lib/commonjs/utils/eventUtils.js.map +1 -0
- package/lib/commonjs/utils/haptics.js +66 -0
- package/lib/commonjs/utils/haptics.js.map +1 -0
- package/lib/commonjs/utils/imagePreloader.js +6 -0
- package/lib/commonjs/utils/imagePreloader.js.map +1 -0
- package/lib/module/api/index.js +72 -0
- package/lib/module/api/index.js.map +1 -1
- package/lib/module/assets/fonts/EBGaramond-VariableFont_wght.ttf +0 -0
- package/lib/module/assets/fonts/IBMPlexSans-VariableFont_wdth,wght.ttf +0 -0
- package/lib/module/assets/icons/Facebookicon.png +0 -0
- package/lib/module/assets/icons/Gmail.png +0 -0
- package/lib/module/assets/icons/Linkedinicon.png +0 -0
- package/lib/module/assets/icons/Redditicon.png +0 -0
- package/lib/module/assets/icons/YouTubeicon2.png +0 -0
- package/lib/module/assets/icons/YouTubeicon3.png +0 -0
- package/lib/module/assets/icons/farcaster.png +0 -0
- package/lib/module/assets/icons/instagram.png +0 -0
- package/lib/module/assets/icons/pinterest.png +0 -0
- package/lib/module/assets/icons/swerv_logo.png +0 -0
- package/lib/module/assets/icons/twitter.jpg +0 -0
- package/lib/module/assets/images/Checkbox.svg +3 -0
- package/lib/module/assets/images/EnochE.svg +19 -0
- package/lib/module/assets/images/Enochicon1.png +0 -0
- package/lib/module/assets/images/Face_ID_logo.png +0 -0
- package/lib/module/assets/images/Facebookicon.png +0 -0
- package/lib/module/assets/images/Gmail.png +0 -0
- package/lib/module/assets/images/Googlelogo.png +0 -0
- package/lib/module/assets/images/Linkedinicon.png +0 -0
- package/lib/module/assets/images/Onairoslogo.png +0 -0
- package/lib/module/assets/images/Personalityprofile.svg +3 -0
- package/lib/module/assets/images/Personalitytraits.svg +3 -0
- package/lib/module/assets/images/Redditicon.png +0 -0
- package/lib/module/assets/images/Userpreferences.svg +3 -0
- package/lib/module/assets/images/YouTubeicon3.png +0 -0
- package/lib/module/assets/images/arrow.svg +20 -0
- package/lib/module/assets/images/basicproficon.svg +43 -0
- package/lib/module/assets/images/basicprofile.svg +3 -0
- package/lib/module/assets/images/checkmark.svg +4 -0
- package/lib/module/assets/images/contentanalysis.svg +3 -0
- package/lib/module/assets/images/contenticon.svg +23 -0
- package/lib/module/assets/images/persona1.png +0 -0
- package/lib/module/assets/images/persona2.png +0 -0
- package/lib/module/assets/images/persona3.png +0 -0
- package/lib/module/assets/images/persona4.png +0 -0
- package/lib/module/assets/images/persona5.png +0 -0
- package/lib/module/assets/images/personalityicon.svg +18 -0
- package/lib/module/assets/images/x-close.svg +3 -0
- package/lib/module/components/BodyText.js +20 -0
- package/lib/module/components/BodyText.js.map +1 -0
- package/lib/module/components/BrandMark.js +37 -0
- package/lib/module/components/BrandMark.js.map +1 -0
- package/lib/module/components/CodeInput.js +23 -0
- package/lib/module/components/CodeInput.js.map +1 -0
- package/lib/module/components/EmailInput.js +23 -0
- package/lib/module/components/EmailInput.js.map +1 -0
- package/lib/module/components/ExistingUserDataConfirmation.js +465 -0
- package/lib/module/components/ExistingUserDataConfirmation.js.map +1 -0
- package/lib/module/components/GoogleButton.js +48 -0
- package/lib/module/components/GoogleButton.js.map +1 -0
- package/lib/module/components/HeadingGroup.js +36 -0
- package/lib/module/components/HeadingGroup.js.map +1 -0
- package/lib/module/components/ModalHeader.js +92 -0
- package/lib/module/components/ModalHeader.js.map +1 -0
- package/lib/module/components/ModalSheet.js +34 -0
- package/lib/module/components/ModalSheet.js.map +1 -0
- package/lib/module/components/Onairos.js +1 -3
- package/lib/module/components/Onairos.js.map +1 -1
- package/lib/module/components/OnairosButton.js +172 -192
- package/lib/module/components/OnairosButton.js.map +1 -1
- package/lib/module/components/OnairosSignInButton.js +160 -0
- package/lib/module/components/OnairosSignInButton.js.map +1 -0
- package/lib/module/components/Overlay.js +5 -5
- package/lib/module/components/Overlay.js.map +1 -1
- package/lib/module/components/PersonaImage.js +53 -0
- package/lib/module/components/PersonaImage.js.map +1 -0
- package/lib/module/components/PersonaLoadingScreen.js +148 -0
- package/lib/module/components/PersonaLoadingScreen.js.map +1 -0
- package/lib/module/components/PersonalizationConsentScreen.js +309 -0
- package/lib/module/components/PersonalizationConsentScreen.js.map +1 -0
- package/lib/module/components/PinCreationScreen.js +386 -0
- package/lib/module/components/PinCreationScreen.js.map +1 -0
- package/lib/module/components/PinInput.js +283 -120
- package/lib/module/components/PinInput.js.map +1 -1
- package/lib/module/components/PlatformConnectorsStep.js +820 -0
- package/lib/module/components/PlatformConnectorsStep.js.map +1 -0
- package/lib/module/components/PlatformToggle.js +173 -0
- package/lib/module/components/PlatformToggle.js.map +1 -0
- package/lib/module/components/PrimaryButton.js +172 -0
- package/lib/module/components/PrimaryButton.js.map +1 -0
- package/lib/module/components/SignInMatchAnimation.js +189 -0
- package/lib/module/components/SignInMatchAnimation.js.map +1 -0
- package/lib/module/components/SignInStep.js +171 -0
- package/lib/module/components/SignInStep.js.map +1 -0
- package/lib/module/components/TrainingModal.js +809 -565
- package/lib/module/components/TrainingModal.js.map +1 -1
- package/lib/module/components/UniversalOnboarding.js +2307 -1284
- package/lib/module/components/UniversalOnboarding.js.map +1 -1
- package/lib/module/components/VerificationStep.js +146 -0
- package/lib/module/components/VerificationStep.js.map +1 -0
- package/lib/module/components/WelcomeScreen.js +378 -0
- package/lib/module/components/WelcomeScreen.js.map +1 -0
- package/lib/module/components/icons/Basicproficon.js +30 -0
- package/lib/module/components/icons/Basicproficon.js.map +1 -0
- package/lib/module/components/icons/Basicprofile.js +14 -0
- package/lib/module/components/icons/Basicprofile.js.map +1 -0
- package/lib/module/components/icons/Checkbox.js +14 -0
- package/lib/module/components/icons/Checkbox.js.map +1 -0
- package/lib/module/components/icons/Checkmark.js +20 -0
- package/lib/module/components/icons/Checkmark.js.map +1 -0
- package/lib/module/components/icons/Contentanalysis.js +14 -0
- package/lib/module/components/icons/Contentanalysis.js.map +1 -0
- package/lib/module/components/icons/Contenticon.js +32 -0
- package/lib/module/components/icons/Contenticon.js.map +1 -0
- package/lib/module/components/icons/EnochE.js +34 -0
- package/lib/module/components/icons/EnochE.js.map +1 -0
- package/lib/module/components/icons/Personalityicon.js +23 -0
- package/lib/module/components/icons/Personalityicon.js.map +1 -0
- package/lib/module/components/icons/Personalityprofile.js +14 -0
- package/lib/module/components/icons/Personalityprofile.js.map +1 -0
- package/lib/module/components/icons/Personalitytraits.js +14 -0
- package/lib/module/components/icons/Personalitytraits.js.map +1 -0
- package/lib/module/components/icons/Userpreferences.js +14 -0
- package/lib/module/components/icons/Userpreferences.js.map +1 -0
- package/lib/module/components/icons/index.js +13 -0
- package/lib/module/components/icons/index.js.map +1 -0
- package/lib/module/components/onboarding/OAuthWebView.js +136 -744
- package/lib/module/components/onboarding/OAuthWebView.js.map +1 -1
- package/lib/module/config/api.js +26 -0
- package/lib/module/config/api.js.map +1 -0
- package/lib/module/context/AuthContext.js +335 -0
- package/lib/module/context/AuthContext.js.map +1 -0
- package/lib/module/hooks/useConnectedAccounts.js +106 -0
- package/lib/module/hooks/useConnectedAccounts.js.map +1 -0
- package/lib/module/hooks/useConnections.js +119 -125
- package/lib/module/hooks/useConnections.js.map +1 -1
- package/lib/module/hooks/useUserConnections.js +140 -0
- package/lib/module/hooks/useUserConnections.js.map +1 -0
- package/lib/module/index.js +51 -15
- package/lib/module/index.js.map +1 -1
- package/lib/module/services/apiClient.js +298 -0
- package/lib/module/services/apiClient.js.map +1 -0
- package/lib/module/services/authService.js +905 -0
- package/lib/module/services/authService.js.map +1 -0
- package/lib/module/services/biometricPinService.js +173 -0
- package/lib/module/services/biometricPinService.js.map +1 -0
- package/lib/module/services/connectedAccountsService.js +255 -0
- package/lib/module/services/connectedAccountsService.js.map +1 -0
- package/lib/module/services/googleAuthService.js +258 -0
- package/lib/module/services/googleAuthService.js.map +1 -0
- package/lib/module/services/imageCompressionService.js +250 -0
- package/lib/module/services/imageCompressionService.js.map +1 -0
- package/lib/module/services/jwtStorageService.js +239 -0
- package/lib/module/services/jwtStorageService.js.map +1 -0
- package/lib/module/services/mobileTrainingService.js +172 -0
- package/lib/module/services/mobileTrainingService.js.map +1 -0
- package/lib/module/services/pinEncryptionService.js +75 -0
- package/lib/module/services/pinEncryptionService.js.map +1 -0
- package/lib/module/services/pinStorageUtils.js +93 -0
- package/lib/module/services/pinStorageUtils.js.map +1 -0
- package/lib/module/services/platformAuthService.js +943 -704
- package/lib/module/services/platformAuthService.js.map +1 -1
- package/lib/module/services/storageService.js +383 -0
- package/lib/module/services/storageService.js.map +1 -0
- package/lib/module/services/trainingApiHelpers.js +67 -0
- package/lib/module/services/trainingApiHelpers.js.map +1 -0
- package/lib/module/services/userConnectionsService.js +476 -0
- package/lib/module/services/userConnectionsService.js.map +1 -0
- package/lib/module/services/youtubeMigrationService.js +404 -0
- package/lib/module/services/youtubeMigrationService.js.map +1 -0
- package/lib/module/theme/index.js +244 -0
- package/lib/module/theme/index.js.map +1 -0
- package/lib/module/utils/eventUtils.js +270 -0
- package/lib/module/utils/eventUtils.js.map +1 -0
- package/lib/module/utils/haptics.js +59 -0
- package/lib/module/utils/haptics.js.map +1 -0
- package/lib/module/utils/imagePreloader.js +3 -0
- package/lib/module/utils/imagePreloader.js.map +1 -0
- package/lib/typescript/api/index.d.ts +8 -0
- package/lib/typescript/api/index.d.ts.map +1 -1
- package/lib/typescript/components/BodyText.d.ts +10 -0
- package/lib/typescript/components/BodyText.d.ts.map +1 -0
- package/lib/typescript/components/BrandMark.d.ts +11 -0
- package/lib/typescript/components/BrandMark.d.ts.map +1 -0
- package/lib/typescript/components/CodeInput.d.ts +10 -0
- package/lib/typescript/components/CodeInput.d.ts.map +1 -0
- package/lib/typescript/components/EmailInput.d.ts +8 -0
- package/lib/typescript/components/EmailInput.d.ts.map +1 -0
- package/lib/typescript/components/ExistingUserDataConfirmation.d.ts +12 -0
- package/lib/typescript/components/ExistingUserDataConfirmation.d.ts.map +1 -0
- package/lib/typescript/components/GoogleButton.d.ts +11 -0
- package/lib/typescript/components/GoogleButton.d.ts.map +1 -0
- package/lib/typescript/components/HeadingGroup.d.ts +11 -0
- package/lib/typescript/components/HeadingGroup.d.ts.map +1 -0
- package/lib/typescript/components/ModalHeader.d.ts +11 -0
- package/lib/typescript/components/ModalHeader.d.ts.map +1 -0
- package/lib/typescript/components/ModalSheet.d.ts +13 -0
- package/lib/typescript/components/ModalSheet.d.ts.map +1 -0
- package/lib/typescript/components/Onairos.d.ts.map +1 -1
- package/lib/typescript/components/OnairosButton.d.ts +29 -4
- package/lib/typescript/components/OnairosButton.d.ts.map +1 -1
- package/lib/typescript/components/OnairosSignInButton.d.ts +14 -0
- package/lib/typescript/components/OnairosSignInButton.d.ts.map +1 -0
- package/lib/typescript/components/PersonaImage.d.ts +8 -0
- package/lib/typescript/components/PersonaImage.d.ts.map +1 -0
- package/lib/typescript/components/PersonaLoadingScreen.d.ts +10 -0
- package/lib/typescript/components/PersonaLoadingScreen.d.ts.map +1 -0
- package/lib/typescript/components/PersonalizationConsentScreen.d.ts +10 -0
- package/lib/typescript/components/PersonalizationConsentScreen.d.ts.map +1 -0
- package/lib/typescript/components/PinCreationScreen.d.ts +10 -0
- package/lib/typescript/components/PinCreationScreen.d.ts.map +1 -0
- package/lib/typescript/components/PinInput.d.ts +11 -1
- package/lib/typescript/components/PinInput.d.ts.map +1 -1
- package/lib/typescript/components/PlatformConnectorsStep.d.ts +11 -0
- package/lib/typescript/components/PlatformConnectorsStep.d.ts.map +1 -0
- package/lib/typescript/components/PlatformToggle.d.ts +20 -0
- package/lib/typescript/components/PlatformToggle.d.ts.map +1 -0
- package/lib/typescript/components/PrimaryButton.d.ts +22 -0
- package/lib/typescript/components/PrimaryButton.d.ts.map +1 -0
- package/lib/typescript/components/SignInMatchAnimation.d.ts +9 -0
- package/lib/typescript/components/SignInMatchAnimation.d.ts.map +1 -0
- package/lib/typescript/components/SignInStep.d.ts +12 -0
- package/lib/typescript/components/SignInStep.d.ts.map +1 -0
- package/lib/typescript/components/TrainingModal.d.ts +12 -1
- package/lib/typescript/components/TrainingModal.d.ts.map +1 -1
- package/lib/typescript/components/UniversalOnboarding.d.ts +14 -1
- package/lib/typescript/components/UniversalOnboarding.d.ts.map +1 -1
- package/lib/typescript/components/VerificationStep.d.ts +13 -0
- package/lib/typescript/components/VerificationStep.d.ts.map +1 -0
- package/lib/typescript/components/WelcomeScreen.d.ts +9 -0
- package/lib/typescript/components/WelcomeScreen.d.ts.map +1 -0
- package/lib/typescript/components/icons/Basicproficon.d.ts +5 -0
- package/lib/typescript/components/icons/Basicproficon.d.ts.map +1 -0
- package/lib/typescript/components/icons/Basicprofile.d.ts +5 -0
- package/lib/typescript/components/icons/Basicprofile.d.ts.map +1 -0
- package/lib/typescript/components/icons/Checkbox.d.ts +5 -0
- package/lib/typescript/components/icons/Checkbox.d.ts.map +1 -0
- package/lib/typescript/components/icons/Checkmark.d.ts +5 -0
- package/lib/typescript/components/icons/Checkmark.d.ts.map +1 -0
- package/lib/typescript/components/icons/Contentanalysis.d.ts +5 -0
- package/lib/typescript/components/icons/Contentanalysis.d.ts.map +1 -0
- package/lib/typescript/components/icons/Contenticon.d.ts +5 -0
- package/lib/typescript/components/icons/Contenticon.d.ts.map +1 -0
- package/lib/typescript/components/icons/EnochE.d.ts +5 -0
- package/lib/typescript/components/icons/EnochE.d.ts.map +1 -0
- package/lib/typescript/components/icons/Personalityicon.d.ts +5 -0
- package/lib/typescript/components/icons/Personalityicon.d.ts.map +1 -0
- package/lib/typescript/components/icons/Personalityprofile.d.ts +5 -0
- package/lib/typescript/components/icons/Personalityprofile.d.ts.map +1 -0
- package/lib/typescript/components/icons/Personalitytraits.d.ts +5 -0
- package/lib/typescript/components/icons/Personalitytraits.d.ts.map +1 -0
- package/lib/typescript/components/icons/Userpreferences.d.ts +5 -0
- package/lib/typescript/components/icons/Userpreferences.d.ts.map +1 -0
- package/lib/typescript/components/icons/index.d.ts +12 -0
- package/lib/typescript/components/icons/index.d.ts.map +1 -0
- package/lib/typescript/components/onboarding/OAuthWebView.d.ts.map +1 -1
- package/lib/typescript/config/api.d.ts +24 -0
- package/lib/typescript/config/api.d.ts.map +1 -0
- package/lib/typescript/context/AuthContext.d.ts +34 -0
- package/lib/typescript/context/AuthContext.d.ts.map +1 -0
- package/lib/typescript/hooks/useConnectedAccounts.d.ts +11 -0
- package/lib/typescript/hooks/useConnectedAccounts.d.ts.map +1 -0
- package/lib/typescript/hooks/useConnections.d.ts +10 -5
- package/lib/typescript/hooks/useConnections.d.ts.map +1 -1
- package/lib/typescript/hooks/useUserConnections.d.ts +12 -0
- package/lib/typescript/hooks/useUserConnections.d.ts.map +1 -0
- package/lib/typescript/index.d.ts +24 -6
- package/lib/typescript/index.d.ts.map +1 -1
- package/lib/typescript/services/apiClient.d.ts +91 -0
- package/lib/typescript/services/apiClient.d.ts.map +1 -0
- package/lib/typescript/services/authService.d.ts +216 -0
- package/lib/typescript/services/authService.d.ts.map +1 -0
- package/lib/typescript/services/biometricPinService.d.ts +29 -0
- package/lib/typescript/services/biometricPinService.d.ts.map +1 -0
- package/lib/typescript/services/connectedAccountsService.d.ts +56 -0
- package/lib/typescript/services/connectedAccountsService.d.ts.map +1 -0
- package/lib/typescript/services/googleAuthService.d.ts +63 -0
- package/lib/typescript/services/googleAuthService.d.ts.map +1 -0
- package/lib/typescript/services/imageCompressionService.d.ts +37 -0
- package/lib/typescript/services/imageCompressionService.d.ts.map +1 -0
- package/lib/typescript/services/jwtStorageService.d.ts +86 -0
- package/lib/typescript/services/jwtStorageService.d.ts.map +1 -0
- package/lib/typescript/services/mobileTrainingService.d.ts +45 -0
- package/lib/typescript/services/mobileTrainingService.d.ts.map +1 -0
- package/lib/typescript/services/pinEncryptionService.d.ts +17 -0
- package/lib/typescript/services/pinEncryptionService.d.ts.map +1 -0
- package/lib/typescript/services/pinStorageUtils.d.ts +25 -0
- package/lib/typescript/services/pinStorageUtils.d.ts.map +1 -0
- package/lib/typescript/services/platformAuthService.d.ts +34 -109
- package/lib/typescript/services/platformAuthService.d.ts.map +1 -1
- package/lib/typescript/services/storageService.d.ts +128 -0
- package/lib/typescript/services/storageService.d.ts.map +1 -0
- package/lib/typescript/services/trainingApiHelpers.d.ts +38 -0
- package/lib/typescript/services/trainingApiHelpers.d.ts.map +1 -0
- package/lib/typescript/services/userConnectionsService.d.ts +90 -0
- package/lib/typescript/services/userConnectionsService.d.ts.map +1 -0
- package/lib/typescript/services/youtubeMigrationService.d.ts +12 -0
- package/lib/typescript/services/youtubeMigrationService.d.ts.map +1 -0
- package/lib/typescript/theme/index.d.ts +416 -0
- package/lib/typescript/theme/index.d.ts.map +1 -0
- package/lib/typescript/types/index.d.ts +39 -0
- package/lib/typescript/types/index.d.ts.map +1 -1
- package/lib/typescript/utils/eventUtils.d.ts +108 -0
- package/lib/typescript/utils/eventUtils.d.ts.map +1 -0
- package/lib/typescript/utils/haptics.d.ts +11 -0
- package/lib/typescript/utils/haptics.d.ts.map +1 -0
- package/lib/typescript/utils/imagePreloader.d.ts +2 -0
- package/lib/typescript/utils/imagePreloader.d.ts.map +1 -0
- package/package.json +158 -145
- package/src/api/index.ts +41 -0
- package/src/assets/fonts/EBGaramond-VariableFont_wght.ttf +0 -0
- package/src/assets/fonts/IBMPlexSans-VariableFont_wdth,wght.ttf +0 -0
- package/src/assets/icons/Facebookicon.png +0 -0
- package/src/assets/icons/Gmail.png +0 -0
- package/src/assets/icons/Linkedinicon.png +0 -0
- package/src/assets/icons/Redditicon.png +0 -0
- package/src/assets/icons/YouTubeicon2.png +0 -0
- package/src/assets/icons/YouTubeicon3.png +0 -0
- package/src/assets/icons/farcaster.png +0 -0
- package/src/assets/icons/instagram.png +0 -0
- package/src/assets/icons/pinterest.png +0 -0
- package/src/assets/icons/swerv_logo.png +0 -0
- package/src/assets/icons/twitter.jpg +0 -0
- package/src/assets/images/Checkbox.svg +3 -0
- package/src/assets/images/EnochE.svg +19 -0
- package/src/assets/images/Enochicon1.png +0 -0
- package/src/assets/images/Face_ID_logo.png +0 -0
- package/src/assets/images/Facebookicon.png +0 -0
- package/src/assets/images/Gmail.png +0 -0
- package/src/assets/images/Googlelogo.png +0 -0
- package/src/assets/images/Linkedinicon.png +0 -0
- package/src/assets/images/Onairoslogo.png +0 -0
- package/src/assets/images/Personalityprofile.svg +3 -0
- package/src/assets/images/Personalitytraits.svg +3 -0
- package/src/assets/images/Redditicon.png +0 -0
- package/src/assets/images/Userpreferences.svg +3 -0
- package/src/assets/images/YouTubeicon3.png +0 -0
- package/src/assets/images/arrow.svg +20 -0
- package/src/assets/images/basicproficon.svg +43 -0
- package/src/assets/images/basicprofile.svg +3 -0
- package/src/assets/images/checkmark.svg +4 -0
- package/src/assets/images/contentanalysis.svg +3 -0
- package/src/assets/images/contenticon.svg +23 -0
- package/src/assets/images/persona1.png +0 -0
- package/src/assets/images/persona2.png +0 -0
- package/src/assets/images/persona3.png +0 -0
- package/src/assets/images/persona4.png +0 -0
- package/src/assets/images/persona5.png +0 -0
- package/src/assets/images/personalityicon.svg +18 -0
- package/src/assets/images/x-close.svg +3 -0
- package/src/components/BodyText.tsx +33 -0
- package/src/components/BrandMark.tsx +62 -0
- package/src/components/CodeInput.tsx +32 -0
- package/src/components/EmailInput.tsx +31 -0
- package/src/components/ExistingUserDataConfirmation.tsx +507 -0
- package/src/components/GoogleButton.tsx +55 -0
- package/src/components/HeadingGroup.tsx +49 -0
- package/src/components/ModalHeader.tsx +125 -0
- package/src/components/ModalSheet.tsx +57 -0
- package/src/components/Onairos.tsx +422 -424
- package/src/components/OnairosButton.tsx +339 -359
- package/src/components/OnairosSignInButton.tsx +166 -0
- package/src/components/Overlay.tsx +506 -506
- package/src/components/PersonaImage.tsx +79 -0
- package/src/components/PersonaLoadingScreen.tsx +201 -0
- package/src/components/PersonalizationConsentScreen.tsx +410 -0
- package/src/components/PinCreationScreen.tsx +492 -0
- package/src/components/PinInput.tsx +555 -343
- package/src/components/PlatformConnectorsStep.tsx +892 -0
- package/src/components/PlatformToggle.tsx +226 -0
- package/src/components/PrimaryButton.tsx +214 -0
- package/src/components/SignInMatchAnimation.tsx +225 -0
- package/src/components/SignInStep.tsx +217 -0
- package/src/components/TrainingModal.tsx +1047 -737
- package/src/components/UniversalOnboarding.tsx +2888 -1820
- package/src/components/VerificationStep.tsx +198 -0
- package/src/components/WelcomeScreen.tsx +473 -0
- package/src/components/icons/Basicproficon.tsx +30 -0
- package/src/components/icons/Basicprofile.tsx +17 -0
- package/src/components/icons/Checkbox.tsx +17 -0
- package/src/components/icons/Checkmark.tsx +24 -0
- package/src/components/icons/Contentanalysis.tsx +17 -0
- package/src/components/icons/Contenticon.tsx +30 -0
- package/src/components/icons/EnochE.tsx +39 -0
- package/src/components/icons/Personalityicon.tsx +22 -0
- package/src/components/icons/Personalityprofile.tsx +17 -0
- package/src/components/icons/Personalitytraits.tsx +17 -0
- package/src/components/icons/Userpreferences.tsx +17 -0
- package/src/components/icons/index.ts +12 -0
- package/src/components/onboarding/OAuthWebView.tsx +232 -838
- package/src/config/api.ts +25 -0
- package/src/context/AuthContext.tsx +393 -0
- package/src/hooks/useConnectedAccounts.ts +139 -0
- package/src/hooks/useConnections.ts +129 -131
- package/src/hooks/useUserConnections.ts +166 -0
- package/src/index.ts +94 -49
- package/src/services/apiClient.ts +337 -0
- package/src/services/authService.ts +1008 -0
- package/src/services/biometricPinService.ts +193 -0
- package/src/services/connectedAccountsService.ts +290 -0
- package/src/services/googleAuthService.ts +279 -0
- package/src/services/imageCompressionService.ts +303 -0
- package/src/services/jwtStorageService.ts +257 -0
- package/src/services/mobileTrainingService.ts +204 -0
- package/src/services/pinEncryptionService.ts +76 -0
- package/src/services/pinStorageUtils.ts +97 -0
- package/src/services/platformAuthService.ts +1346 -1113
- package/src/services/storageService.ts +452 -0
- package/src/services/trainingApiHelpers.ts +67 -0
- package/src/services/userConnectionsService.ts +557 -0
- package/src/services/youtubeMigrationService.ts +454 -0
- package/src/theme/index.ts +239 -0
- package/src/types/index.ts +265 -238
- package/src/utils/eventUtils.ts +303 -0
- package/src/utils/haptics.ts +59 -0
- package/src/utils/imagePreloader.ts +2 -0
- package/README.md +0 -375
- package/lib/commonjs/assets/images/email.png +0 -0
- package/lib/commonjs/assets/images/linkedin.png +0 -0
- package/lib/commonjs/assets/images/reddit.png +0 -0
- package/lib/commonjs/assets/images/youtube.png +0 -0
- package/lib/commonjs/components/UniversalOnboarding.tsx.new +0 -455
- package/lib/module/assets/images/email.png +0 -0
- package/lib/module/assets/images/linkedin.png +0 -0
- package/lib/module/assets/images/reddit.png +0 -0
- package/lib/module/assets/images/youtube.png +0 -0
- package/lib/module/components/UniversalOnboarding.tsx.new +0 -455
- package/src/assets/images/email.png +0 -0
- package/src/assets/images/linkedin.png +0 -0
- package/src/assets/images/reddit.png +0 -0
- package/src/assets/images/youtube.png +0 -0
- package/src/components/UniversalOnboarding.tsx.new +0 -455
|
@@ -1,1820 +1,2888 @@
|
|
|
1
|
-
import React, { useCallback, useEffect, useState, useRef } from 'react';
|
|
2
|
-
import {
|
|
3
|
-
View,
|
|
4
|
-
Text,
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
ScrollView,
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
import
|
|
24
|
-
|
|
25
|
-
import {
|
|
26
|
-
import { OAuthWebView } from './onboarding/OAuthWebView';
|
|
27
|
-
import { useConnections } from '
|
|
28
|
-
import {
|
|
29
|
-
import { initiateOAuth, initiateNativeAuth, hasNativeSDK, isOAuthCallback
|
|
30
|
-
import
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
const [
|
|
74
|
-
const [
|
|
75
|
-
const [
|
|
76
|
-
const [
|
|
77
|
-
|
|
78
|
-
const [
|
|
79
|
-
const [
|
|
80
|
-
const [
|
|
81
|
-
const [
|
|
82
|
-
const [
|
|
83
|
-
|
|
84
|
-
const [
|
|
85
|
-
|
|
86
|
-
//
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
const
|
|
98
|
-
const
|
|
99
|
-
|
|
100
|
-
//
|
|
101
|
-
const
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
const
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
];
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
const
|
|
114
|
-
const
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
const
|
|
118
|
-
|
|
119
|
-
const
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
const
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
//
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
const
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
console.log(
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
//
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
//
|
|
451
|
-
setConnections(
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
const
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
}
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
}
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
//
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
}
|
|
653
|
-
}
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
//
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
console.log('
|
|
827
|
-
|
|
828
|
-
//
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
const
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
|
|
1582
|
-
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
|
|
1588
|
-
|
|
1589
|
-
|
|
1590
|
-
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
1614
|
-
|
|
1615
|
-
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
|
|
1619
|
-
|
|
1620
|
-
|
|
1621
|
-
|
|
1622
|
-
|
|
1623
|
-
|
|
1624
|
-
|
|
1625
|
-
|
|
1626
|
-
|
|
1627
|
-
|
|
1628
|
-
|
|
1629
|
-
|
|
1630
|
-
|
|
1631
|
-
|
|
1632
|
-
|
|
1633
|
-
|
|
1634
|
-
|
|
1635
|
-
|
|
1636
|
-
|
|
1637
|
-
|
|
1638
|
-
|
|
1639
|
-
|
|
1640
|
-
|
|
1641
|
-
|
|
1642
|
-
|
|
1643
|
-
|
|
1644
|
-
|
|
1645
|
-
|
|
1646
|
-
|
|
1647
|
-
|
|
1648
|
-
|
|
1649
|
-
|
|
1650
|
-
|
|
1651
|
-
|
|
1652
|
-
|
|
1653
|
-
|
|
1654
|
-
|
|
1655
|
-
|
|
1656
|
-
|
|
1657
|
-
|
|
1658
|
-
|
|
1659
|
-
|
|
1660
|
-
|
|
1661
|
-
|
|
1662
|
-
|
|
1663
|
-
|
|
1664
|
-
|
|
1665
|
-
|
|
1666
|
-
|
|
1667
|
-
|
|
1668
|
-
|
|
1669
|
-
|
|
1670
|
-
|
|
1671
|
-
|
|
1672
|
-
|
|
1673
|
-
|
|
1674
|
-
|
|
1675
|
-
|
|
1676
|
-
|
|
1677
|
-
|
|
1678
|
-
|
|
1679
|
-
|
|
1680
|
-
|
|
1681
|
-
|
|
1682
|
-
|
|
1683
|
-
|
|
1684
|
-
|
|
1685
|
-
|
|
1686
|
-
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
|
-
|
|
1690
|
-
|
|
1691
|
-
|
|
1692
|
-
|
|
1693
|
-
|
|
1694
|
-
|
|
1695
|
-
|
|
1696
|
-
|
|
1697
|
-
|
|
1698
|
-
|
|
1699
|
-
|
|
1700
|
-
|
|
1701
|
-
|
|
1702
|
-
|
|
1703
|
-
|
|
1704
|
-
|
|
1705
|
-
|
|
1706
|
-
|
|
1707
|
-
|
|
1708
|
-
|
|
1709
|
-
|
|
1710
|
-
|
|
1711
|
-
|
|
1712
|
-
|
|
1713
|
-
|
|
1714
|
-
|
|
1715
|
-
|
|
1716
|
-
|
|
1717
|
-
|
|
1718
|
-
|
|
1719
|
-
|
|
1720
|
-
|
|
1721
|
-
|
|
1722
|
-
|
|
1723
|
-
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
|
|
1733
|
-
|
|
1734
|
-
|
|
1735
|
-
|
|
1736
|
-
|
|
1737
|
-
|
|
1738
|
-
|
|
1739
|
-
|
|
1740
|
-
|
|
1741
|
-
|
|
1742
|
-
|
|
1743
|
-
|
|
1744
|
-
|
|
1745
|
-
|
|
1746
|
-
|
|
1747
|
-
|
|
1748
|
-
|
|
1749
|
-
|
|
1750
|
-
|
|
1751
|
-
|
|
1752
|
-
|
|
1753
|
-
|
|
1754
|
-
|
|
1755
|
-
|
|
1756
|
-
|
|
1757
|
-
|
|
1758
|
-
|
|
1759
|
-
|
|
1760
|
-
|
|
1761
|
-
|
|
1762
|
-
|
|
1763
|
-
|
|
1764
|
-
|
|
1765
|
-
|
|
1766
|
-
|
|
1767
|
-
|
|
1768
|
-
|
|
1769
|
-
|
|
1770
|
-
|
|
1771
|
-
|
|
1772
|
-
|
|
1773
|
-
|
|
1774
|
-
|
|
1775
|
-
|
|
1776
|
-
|
|
1777
|
-
|
|
1778
|
-
|
|
1779
|
-
|
|
1780
|
-
|
|
1781
|
-
|
|
1782
|
-
|
|
1783
|
-
|
|
1784
|
-
|
|
1785
|
-
|
|
1786
|
-
|
|
1787
|
-
|
|
1788
|
-
|
|
1789
|
-
|
|
1790
|
-
|
|
1791
|
-
|
|
1792
|
-
|
|
1793
|
-
|
|
1794
|
-
|
|
1795
|
-
|
|
1796
|
-
|
|
1797
|
-
|
|
1798
|
-
|
|
1799
|
-
|
|
1800
|
-
|
|
1801
|
-
|
|
1802
|
-
|
|
1803
|
-
|
|
1804
|
-
|
|
1805
|
-
|
|
1806
|
-
|
|
1807
|
-
|
|
1808
|
-
|
|
1809
|
-
|
|
1810
|
-
|
|
1811
|
-
|
|
1812
|
-
|
|
1813
|
-
|
|
1814
|
-
|
|
1815
|
-
|
|
1816
|
-
|
|
1817
|
-
|
|
1818
|
-
|
|
1819
|
-
|
|
1820
|
-
}
|
|
1
|
+
import React, { useCallback, useEffect, useState, useRef } from 'react';
|
|
2
|
+
import {
|
|
3
|
+
View,
|
|
4
|
+
Text,
|
|
5
|
+
Image,
|
|
6
|
+
StyleSheet,
|
|
7
|
+
Dimensions,
|
|
8
|
+
TouchableOpacity,
|
|
9
|
+
ActivityIndicator,
|
|
10
|
+
Platform,
|
|
11
|
+
Modal,
|
|
12
|
+
Animated,
|
|
13
|
+
SafeAreaView,
|
|
14
|
+
ScrollView,
|
|
15
|
+
Switch,
|
|
16
|
+
Linking,
|
|
17
|
+
KeyboardAvoidingView,
|
|
18
|
+
Vibration,
|
|
19
|
+
Easing,
|
|
20
|
+
Alert,
|
|
21
|
+
} from 'react-native';
|
|
22
|
+
// Removed navigation dependencies for SDK compatibility
|
|
23
|
+
import AsyncStorage from '@react-native-async-storage/async-storage';
|
|
24
|
+
// Import components and hooks
|
|
25
|
+
import { PinInput } from './PinInput';
|
|
26
|
+
import { OAuthWebView } from './onboarding/OAuthWebView';
|
|
27
|
+
// import { useConnections } from '../../hooks/useConnections'; // Commented out - file path issue
|
|
28
|
+
// import { useAuth } from '../../context/AuthContext'; // Commented out - file path issue
|
|
29
|
+
import { initiateOAuth, initiateNativeAuth, hasNativeSDK, isOAuthCallback } from '../services/platformAuthService';
|
|
30
|
+
import { triggerHaptic, HapticType } from '../utils/haptics';
|
|
31
|
+
import { getOnairosUsername } from '../services/authService';
|
|
32
|
+
import { io, Socket } from 'socket.io-client';
|
|
33
|
+
import { setTemporaryPin, clearTemporaryPin } from '../services/pinStorageUtils';
|
|
34
|
+
import { getEncryptedPinForAPI } from '../services/pinEncryptionService';
|
|
35
|
+
import { startEnochTrainingWithYouTubeCheck } from '../services/mobileTrainingService';
|
|
36
|
+
|
|
37
|
+
// Import types
|
|
38
|
+
// import type { ConnectionStatus } from '../../hooks/useConnections'; // Commented out - file path issue
|
|
39
|
+
// Removed App-specific navigation types
|
|
40
|
+
|
|
41
|
+
const { height, width } = Dimensions.get('window');
|
|
42
|
+
|
|
43
|
+
export interface UniversalOnboardingProps {
|
|
44
|
+
visible: boolean;
|
|
45
|
+
onClose: () => void;
|
|
46
|
+
AppName: string;
|
|
47
|
+
requestData?: any;
|
|
48
|
+
returnLink?: string;
|
|
49
|
+
onComplete?: (apiUrl: string, token: string, userData: any) => void;
|
|
50
|
+
embedd?: boolean;
|
|
51
|
+
debug?: boolean;
|
|
52
|
+
test?: boolean;
|
|
53
|
+
testMode?: boolean;
|
|
54
|
+
preferredPlatform?: string;
|
|
55
|
+
primaryAuthOnly?: boolean;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// ConnectionStatus interface is now imported from hooks/useConnections
|
|
59
|
+
|
|
60
|
+
export const UniversalOnboarding: React.FC<UniversalOnboardingProps> = ({
|
|
61
|
+
visible,
|
|
62
|
+
onClose,
|
|
63
|
+
AppName,
|
|
64
|
+
requestData,
|
|
65
|
+
returnLink,
|
|
66
|
+
onComplete,
|
|
67
|
+
embedd = false,
|
|
68
|
+
debug = false,
|
|
69
|
+
test = false,
|
|
70
|
+
preferredPlatform,
|
|
71
|
+
primaryAuthOnly = false,
|
|
72
|
+
}) => {
|
|
73
|
+
const [step, setStep] = useState<'connect' | 'pin' | 'persona' | 'oauth' | 'privacy' | 'connections'>(primaryAuthOnly ? 'persona' : 'connect');
|
|
74
|
+
const [connections, setConnections] = useState<any>({});
|
|
75
|
+
const [pin, setPin] = useState<string>('');
|
|
76
|
+
const [selectedTier, setSelectedTier] = useState<'Small' | 'Medium' | 'Large'>('Medium');
|
|
77
|
+
// Training state is now handled by TrainingModal
|
|
78
|
+
const [slideAnim] = useState(new Animated.Value(height * 0.5));
|
|
79
|
+
const [platformToggles, setPlatformToggles] = useState<{[key: string]: boolean}>({});
|
|
80
|
+
const [oauthUrl, setOauthUrl] = useState<string>('');
|
|
81
|
+
const [currentPlatform, setCurrentPlatform] = useState<string>('');
|
|
82
|
+
const [email, setEmail] = useState<string>('');
|
|
83
|
+
const [longPressTimer, setLongPressTimer] = useState<ReturnType<typeof setTimeout> | null>(null);
|
|
84
|
+
const [modalVisible, setModalVisible] = useState(visible);
|
|
85
|
+
|
|
86
|
+
// Debug logging for modal visibility
|
|
87
|
+
useEffect(() => {
|
|
88
|
+
console.log('🔍 UniversalOnboarding: visible prop changed to:', visible);
|
|
89
|
+
console.log('🔍 UniversalOnboarding: modalVisible state is:', modalVisible);
|
|
90
|
+
console.log('🔍 UniversalOnboarding: current step is:', step);
|
|
91
|
+
console.log('🔍 UniversalOnboarding: primaryAuthOnly is:', primaryAuthOnly);
|
|
92
|
+
}, [visible, modalVisible, step, primaryAuthOnly]);
|
|
93
|
+
const isCompletingRef = useRef(false);
|
|
94
|
+
const [connectionsCount, setConnectionsCount] = useState<number>(5); // Simulated connections count
|
|
95
|
+
|
|
96
|
+
// Add state for showing additional platforms
|
|
97
|
+
const [showAdditionalPlatforms, setShowAdditionalPlatforms] = useState<boolean>(false);
|
|
98
|
+
const [additionalPlatformsOpacity] = useState(new Animated.Value(0));
|
|
99
|
+
|
|
100
|
+
// Add ref for ScrollView to control scroll position
|
|
101
|
+
const scrollViewRef = useRef<ScrollView>(null);
|
|
102
|
+
// Get the authenticated user from auth context
|
|
103
|
+
// const { user } = useAuth(); // Hook not available
|
|
104
|
+
const user = null;
|
|
105
|
+
|
|
106
|
+
// State for storing the correct username
|
|
107
|
+
const [username, setUsername] = useState<string>('');
|
|
108
|
+
|
|
109
|
+
// Real training state variables (replacing fake persona state)
|
|
110
|
+
const [personaProgress, setPersonaProgress] = useState(0);
|
|
111
|
+
const [personaStatus, setPersonaStatus] = useState('Initializing...');
|
|
112
|
+
const [isPersonaComplete, setIsPersonaComplete] = useState(false);
|
|
113
|
+
const [socketConnected, setSocketConnected] = useState(false);
|
|
114
|
+
const [hasError, setHasError] = useState(false);
|
|
115
|
+
const [userTraits, setUserTraits] = useState<any>(null);
|
|
116
|
+
const [inferenceResults, setInferenceResults] = useState<any>(null);
|
|
117
|
+
const [userToken, setUserToken] = useState<string | null>(null);
|
|
118
|
+
const [userInfo, setUserInfo] = useState<any>(null);
|
|
119
|
+
const [animatedDots, setAnimatedDots] = useState('');
|
|
120
|
+
const socketRef = useRef<Socket | null>(null);
|
|
121
|
+
const dotsAnimationRef = useRef<ReturnType<typeof setInterval> | null>(null);
|
|
122
|
+
|
|
123
|
+
// Existing user state
|
|
124
|
+
const [isExistingUser, setIsExistingUser] = useState(false);
|
|
125
|
+
const [existingUserToken, setExistingUserToken] = useState<string | null>(null);
|
|
126
|
+
const [existingUserInfo, setExistingUserInfo] = useState<any>(null);
|
|
127
|
+
|
|
128
|
+
// Data scenario states
|
|
129
|
+
const [dataScenario, setDataScenario] = useState<'SUFFICIENT' | 'LIMITED_DATA' | 'NO_DATA' | 'CONNECTIONS_REQUIRED' | null>(null);
|
|
130
|
+
const [dataDetails, setDataDetails] = useState<any>(null);
|
|
131
|
+
const [showDataWarning, setShowDataWarning] = useState(false);
|
|
132
|
+
|
|
133
|
+
// ✅ NEW: Background training state
|
|
134
|
+
const [isBackgroundTrainingStarted, setIsBackgroundTrainingStarted] = useState(false);
|
|
135
|
+
const [backgroundTrainingProgress, setBackgroundTrainingProgress] = useState('');
|
|
136
|
+
const [backgroundSocketId, setBackgroundSocketId] = useState<string | null>(null);
|
|
137
|
+
|
|
138
|
+
// Function to store connected platforms
|
|
139
|
+
const storeConnectedPlatform = async (platformId: string) => {
|
|
140
|
+
try {
|
|
141
|
+
const storedPlatforms = await AsyncStorage.getItem('connectedPlatforms');
|
|
142
|
+
let platforms: string[] = storedPlatforms ? JSON.parse(storedPlatforms) : [];
|
|
143
|
+
|
|
144
|
+
// Add platform if not already in the list
|
|
145
|
+
if (!platforms.includes(platformId)) {
|
|
146
|
+
platforms.push(platformId);
|
|
147
|
+
await AsyncStorage.setItem('connectedPlatforms', JSON.stringify(platforms));
|
|
148
|
+
console.log('📱 Stored connected platform:', platformId, 'Total platforms:', platforms);
|
|
149
|
+
}
|
|
150
|
+
} catch (error) {
|
|
151
|
+
console.error('Error storing connected platform:', error);
|
|
152
|
+
}
|
|
153
|
+
};
|
|
154
|
+
|
|
155
|
+
// Function to remove connected platform from storage
|
|
156
|
+
const removeConnectedPlatform = async (platformId: string) => {
|
|
157
|
+
try {
|
|
158
|
+
const storedPlatforms = await AsyncStorage.getItem('connectedPlatforms');
|
|
159
|
+
let platforms: string[] = storedPlatforms ? JSON.parse(storedPlatforms) : [];
|
|
160
|
+
|
|
161
|
+
// Remove platform from the list
|
|
162
|
+
platforms = platforms.filter(platform => platform !== platformId);
|
|
163
|
+
await AsyncStorage.setItem('connectedPlatforms', JSON.stringify(platforms));
|
|
164
|
+
console.log('📱 Removed connected platform:', platformId, 'Remaining platforms:', platforms);
|
|
165
|
+
} catch (error) {
|
|
166
|
+
console.error('Error removing connected platform:', error);
|
|
167
|
+
}
|
|
168
|
+
};
|
|
169
|
+
|
|
170
|
+
// Function to handle disconnect confirmation
|
|
171
|
+
const handleDisconnectPlatform = (platformId: string, platformName: string) => {
|
|
172
|
+
Alert.alert(
|
|
173
|
+
'Disconnect Platform',
|
|
174
|
+
`Are you sure you want to disconnect ${platformName}?`,
|
|
175
|
+
[
|
|
176
|
+
{
|
|
177
|
+
text: 'No',
|
|
178
|
+
style: 'cancel',
|
|
179
|
+
},
|
|
180
|
+
{
|
|
181
|
+
text: 'Yes',
|
|
182
|
+
style: 'destructive',
|
|
183
|
+
onPress: async () => {
|
|
184
|
+
try {
|
|
185
|
+
// Update local state to show disconnected
|
|
186
|
+
setConnectionStatuses(prev => ({
|
|
187
|
+
...prev,
|
|
188
|
+
[platformId]: 'disconnected'
|
|
189
|
+
}));
|
|
190
|
+
|
|
191
|
+
setConnections(prev => {
|
|
192
|
+
const newConnections = { ...prev };
|
|
193
|
+
delete newConnections[platformId];
|
|
194
|
+
return newConnections;
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
setPlatformToggles(prev => ({
|
|
198
|
+
...prev,
|
|
199
|
+
[platformId]: false
|
|
200
|
+
}));
|
|
201
|
+
|
|
202
|
+
// Remove from storage
|
|
203
|
+
await removeConnectedPlatform(platformId);
|
|
204
|
+
|
|
205
|
+
// Call the disconnect function from the hook
|
|
206
|
+
await disconnectPlatform();
|
|
207
|
+
|
|
208
|
+
console.log('🔌 Disconnected platform:', platformId);
|
|
209
|
+
} catch (error) {
|
|
210
|
+
console.error('Error disconnecting platform:', error);
|
|
211
|
+
}
|
|
212
|
+
},
|
|
213
|
+
},
|
|
214
|
+
]
|
|
215
|
+
);
|
|
216
|
+
};
|
|
217
|
+
|
|
218
|
+
// Function to start animated dots
|
|
219
|
+
const startDotsAnimation = () => {
|
|
220
|
+
if (dotsAnimationRef.current) {
|
|
221
|
+
clearInterval(dotsAnimationRef.current);
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
let dotCount = 0;
|
|
225
|
+
dotsAnimationRef.current = setInterval(() => {
|
|
226
|
+
dotCount = (dotCount + 1) % 4; // 0, 1, 2, 3, then back to 0
|
|
227
|
+
if (dotCount === 0) {
|
|
228
|
+
setAnimatedDots('');
|
|
229
|
+
} else {
|
|
230
|
+
setAnimatedDots('.'.repeat(dotCount));
|
|
231
|
+
}
|
|
232
|
+
}, 500); // Change every 500ms
|
|
233
|
+
};
|
|
234
|
+
|
|
235
|
+
// Function to stop animated dots
|
|
236
|
+
const stopDotsAnimation = () => {
|
|
237
|
+
if (dotsAnimationRef.current) {
|
|
238
|
+
clearInterval(dotsAnimationRef.current);
|
|
239
|
+
dotsAnimationRef.current = null;
|
|
240
|
+
}
|
|
241
|
+
setAnimatedDots('');
|
|
242
|
+
};
|
|
243
|
+
|
|
244
|
+
// Split platforms into main and additional
|
|
245
|
+
const mainPlatforms = [
|
|
246
|
+
{ id: 'pinterest', name: 'Pinterest', color: '#E60023' },
|
|
247
|
+
{ id: 'youtube', name: 'YouTube', color: '#FFFFFF' },
|
|
248
|
+
{ id: 'linkedin', name: 'LinkedIn', color: '#0077B5' },
|
|
249
|
+
];
|
|
250
|
+
|
|
251
|
+
const additionalPlatforms = [
|
|
252
|
+
{ id: 'reddit', name: 'Reddit', color: '#FFFFFF' },
|
|
253
|
+
{ id: 'gmail', name: 'Gmail', color: '#EA4335' },
|
|
254
|
+
];
|
|
255
|
+
|
|
256
|
+
// Keep the original platforms array for compatibility
|
|
257
|
+
const platforms = [...mainPlatforms, ...additionalPlatforms];
|
|
258
|
+
|
|
259
|
+
// const {
|
|
260
|
+
// connectPlatform,
|
|
261
|
+
// disconnectPlatform,
|
|
262
|
+
// getConnectionStatus,
|
|
263
|
+
// isConnecting,
|
|
264
|
+
// } = useConnections(); // Hook not available
|
|
265
|
+
const connectPlatform = async () => {};
|
|
266
|
+
const disconnectPlatform = async () => {};
|
|
267
|
+
const getConnectionStatus = () => 'disconnected';
|
|
268
|
+
const isConnecting = false;
|
|
269
|
+
const isConnected = () => false;
|
|
270
|
+
|
|
271
|
+
// Track connection statuses and currently connecting platform
|
|
272
|
+
const [connectionStatuses, setConnectionStatuses] = useState<Record<string, string>>({});
|
|
273
|
+
const [connectingPlatform, setConnectingPlatform] = useState<string | null>(null);
|
|
274
|
+
|
|
275
|
+
// Function to get the platform icon based on platform ID
|
|
276
|
+
const getPlatformIcon = (platformId: string) => {
|
|
277
|
+
switch (platformId) {
|
|
278
|
+
case 'instagram':
|
|
279
|
+
return require('../assets/icons/instagram.png');
|
|
280
|
+
case 'youtube':
|
|
281
|
+
return require('../assets/icons/YouTubeicon2.png');
|
|
282
|
+
case 'reddit':
|
|
283
|
+
return require('../assets/icons/Redditicon.png');
|
|
284
|
+
case 'pinterest':
|
|
285
|
+
return require('../assets/icons/pinterest.png');
|
|
286
|
+
case 'facebook':
|
|
287
|
+
return require('../assets/icons/Facebookicon.png');
|
|
288
|
+
case 'linkedin':
|
|
289
|
+
return require('../assets/icons/Linkedinicon.png');
|
|
290
|
+
case 'gmail':
|
|
291
|
+
return require('../assets/icons/Gmail.png');
|
|
292
|
+
}
|
|
293
|
+
};
|
|
294
|
+
|
|
295
|
+
// Track if the modal has ever been visible to prevent initial onClose call
|
|
296
|
+
const hasBeenVisibleRef = useRef(false);
|
|
297
|
+
|
|
298
|
+
useEffect(() => {
|
|
299
|
+
if (visible) {
|
|
300
|
+
hasBeenVisibleRef.current = true; // Mark that modal has been visible
|
|
301
|
+
isCompletingRef.current = false; // Reset flag when becoming visible
|
|
302
|
+
setModalVisible(true);
|
|
303
|
+
loadInitialStatus();
|
|
304
|
+
// Animate in
|
|
305
|
+
Animated.spring(slideAnim, {
|
|
306
|
+
toValue: 0,
|
|
307
|
+
friction: 8,
|
|
308
|
+
tension: 40,
|
|
309
|
+
useNativeDriver: true,
|
|
310
|
+
}).start();
|
|
311
|
+
|
|
312
|
+
const subscription = Linking.addEventListener('url', handleUrl);
|
|
313
|
+
return () => {
|
|
314
|
+
subscription.remove();
|
|
315
|
+
};
|
|
316
|
+
} else if (hasBeenVisibleRef.current && !isCompletingRef.current) {
|
|
317
|
+
// Only animate out if NOT completing - prevents flicker during successful completion
|
|
318
|
+
Animated.timing(slideAnim, {
|
|
319
|
+
toValue: height,
|
|
320
|
+
useNativeDriver: true,
|
|
321
|
+
duration: 500, // Longer duration for a more elegant exit
|
|
322
|
+
easing: Easing.bezier(0.16, 1, 0.3, 1), // Custom bezier curve for a luxurious, smooth exit
|
|
323
|
+
}).start(() => {
|
|
324
|
+
// Use a timeout to prevent animation state updates during unmount
|
|
325
|
+
setTimeout(() => {
|
|
326
|
+
setModalVisible(false);
|
|
327
|
+
onClose(); // Call onClose from props
|
|
328
|
+
}, 16);
|
|
329
|
+
});
|
|
330
|
+
} else if (hasBeenVisibleRef.current && isCompletingRef.current) {
|
|
331
|
+
// If completing, hide modal immediately without any animation or delay
|
|
332
|
+
setModalVisible(false);
|
|
333
|
+
// Don't call onClose() when completing - let parent handle the navigation
|
|
334
|
+
isCompletingRef.current = false; // Reset for next time
|
|
335
|
+
}
|
|
336
|
+
}, [visible, onClose]); // Removed isCompleting from dependency array
|
|
337
|
+
|
|
338
|
+
// Cleanup socket connection and dots animation when component unmounts or becomes invisible
|
|
339
|
+
useEffect(() => {
|
|
340
|
+
return () => {
|
|
341
|
+
if (socketRef.current) {
|
|
342
|
+
console.log('🔌 Cleaning up socket connection...');
|
|
343
|
+
socketRef.current.disconnect();
|
|
344
|
+
socketRef.current = null;
|
|
345
|
+
}
|
|
346
|
+
stopDotsAnimation();
|
|
347
|
+
};
|
|
348
|
+
}, [visible]);
|
|
349
|
+
|
|
350
|
+
// Set up deep link listener for OAuth callbacks
|
|
351
|
+
const handleUrl = useCallback(({url}: {url: string}) => {
|
|
352
|
+
if (isOAuthCallback(url)) {
|
|
353
|
+
handleOAuthCallback(url);
|
|
354
|
+
}
|
|
355
|
+
}, []);
|
|
356
|
+
|
|
357
|
+
// Load user data and authentication token when modal becomes visible
|
|
358
|
+
useEffect(() => {
|
|
359
|
+
const loadUserData = async () => {
|
|
360
|
+
try {
|
|
361
|
+
// Check for existing user info first
|
|
362
|
+
const existingToken = await AsyncStorage.getItem('existing_user_token');
|
|
363
|
+
const existingInfo = await AsyncStorage.getItem('existing_user_info');
|
|
364
|
+
|
|
365
|
+
if (existingToken && existingInfo) {
|
|
366
|
+
console.log('🔍 Found existing user info - user wants to add more data');
|
|
367
|
+
setIsExistingUser(true);
|
|
368
|
+
setExistingUserToken(existingToken);
|
|
369
|
+
setExistingUserInfo(JSON.parse(existingInfo));
|
|
370
|
+
|
|
371
|
+
// Clear the temporary storage
|
|
372
|
+
await AsyncStorage.removeItem('existing_user_token');
|
|
373
|
+
await AsyncStorage.removeItem('existing_user_info');
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
const token = await AsyncStorage.getItem('onairos_jwt_token') || await AsyncStorage.getItem('auth_token');
|
|
377
|
+
setUserToken(token);
|
|
378
|
+
|
|
379
|
+
if (token) {
|
|
380
|
+
// Use provided username or get stored username
|
|
381
|
+
const storedUsername = await getOnairosUsername();
|
|
382
|
+
const fallbackUsername = storedUsername || user?.email?.split('@')[0] || user?.name || 'mobile_user';
|
|
383
|
+
|
|
384
|
+
console.log('🔍 Using username for training:', fallbackUsername);
|
|
385
|
+
setUserInfo({
|
|
386
|
+
username: fallbackUsername,
|
|
387
|
+
email: user?.email || null,
|
|
388
|
+
id: null // Will be filled by backend during training
|
|
389
|
+
});
|
|
390
|
+
setUsername(fallbackUsername);
|
|
391
|
+
}
|
|
392
|
+
} catch (error) {
|
|
393
|
+
console.error('Error loading user data:', error);
|
|
394
|
+
// Fallback user info
|
|
395
|
+
const fallbackUsername = user?.email?.split('@')[0] || user?.name || 'mobile_user';
|
|
396
|
+
setUserInfo({
|
|
397
|
+
username: fallbackUsername,
|
|
398
|
+
email: user?.email || null,
|
|
399
|
+
id: null
|
|
400
|
+
});
|
|
401
|
+
setUsername(fallbackUsername);
|
|
402
|
+
}
|
|
403
|
+
};
|
|
404
|
+
|
|
405
|
+
if (visible) {
|
|
406
|
+
loadUserData();
|
|
407
|
+
}
|
|
408
|
+
}, [visible, user]);
|
|
409
|
+
|
|
410
|
+
const loadInitialStatus = async () => {
|
|
411
|
+
try {
|
|
412
|
+
// Get the stored Onairos username first
|
|
413
|
+
const storedUsername = await getOnairosUsername();
|
|
414
|
+
const fallbackUsername = user?.email || user?.name || `user_${Math.floor(Math.random() * 10000)}`;
|
|
415
|
+
const finalUsername = storedUsername || fallbackUsername;
|
|
416
|
+
|
|
417
|
+
console.log('🔍 Loading username for data connections:', {
|
|
418
|
+
storedUsername,
|
|
419
|
+
fallbackUsername,
|
|
420
|
+
finalUsername
|
|
421
|
+
});
|
|
422
|
+
|
|
423
|
+
setUsername(finalUsername);
|
|
424
|
+
|
|
425
|
+
// Initialize connection statuses
|
|
426
|
+
const connectionStatus = await getConnectionStatus();
|
|
427
|
+
console.log('Initial connection status:', connectionStatus);
|
|
428
|
+
|
|
429
|
+
// Update the main connections state
|
|
430
|
+
setConnections(connectionStatus);
|
|
431
|
+
|
|
432
|
+
// Convert connections object to status strings
|
|
433
|
+
const statuses: Record<string, string> = {};
|
|
434
|
+
Object.keys(connectionStatus).forEach(platform => {
|
|
435
|
+
statuses[platform] = connectionStatus[platform]?.connected ? 'connected' : 'disconnected';
|
|
436
|
+
});
|
|
437
|
+
setConnectionStatuses(statuses);
|
|
438
|
+
|
|
439
|
+
// Initialize platform toggles based on connection statuses
|
|
440
|
+
const toggles: {[key: string]: boolean} = {};
|
|
441
|
+
Object.keys(connectionStatus).forEach(platform => {
|
|
442
|
+
toggles[platform] = connectionStatus[platform]?.connected || false;
|
|
443
|
+
});
|
|
444
|
+
setPlatformToggles(toggles);
|
|
445
|
+
|
|
446
|
+
console.log('Connection statuses set:', statuses);
|
|
447
|
+
console.log('Platform toggles set:', toggles);
|
|
448
|
+
} catch (error) {
|
|
449
|
+
console.error('Error loading initial connection status:', error);
|
|
450
|
+
// Set empty objects as fallback
|
|
451
|
+
setConnections({});
|
|
452
|
+
setConnectionStatuses({});
|
|
453
|
+
setPlatformToggles({});
|
|
454
|
+
|
|
455
|
+
// Still set a fallback username even if other loading fails
|
|
456
|
+
const fallbackUsername = user?.email || user?.name || `user_${Math.floor(Math.random() * 10000)}`;
|
|
457
|
+
setUsername(fallbackUsername);
|
|
458
|
+
}
|
|
459
|
+
};
|
|
460
|
+
|
|
461
|
+
const handleClose = () => {
|
|
462
|
+
const currentlyCompleting = isCompletingRef.current; // Capture ref's current value
|
|
463
|
+
|
|
464
|
+
// Animate out with a luxurious, smooth motion
|
|
465
|
+
Animated.timing(slideAnim, {
|
|
466
|
+
toValue: height, // Full slide down
|
|
467
|
+
useNativeDriver: true,
|
|
468
|
+
duration: 500, // Longer duration for a more elegant exit
|
|
469
|
+
easing: Easing.bezier(0.16, 1, 0.3, 1), // Custom bezier curve for a luxurious, smooth exit
|
|
470
|
+
}).start(() => {
|
|
471
|
+
// Small delay before closing modal to ensure animation completes fully
|
|
472
|
+
setTimeout(() => {
|
|
473
|
+
setModalVisible(false);
|
|
474
|
+
if (!currentlyCompleting) { // Use the captured value
|
|
475
|
+
onClose();
|
|
476
|
+
}
|
|
477
|
+
// Do NOT reset isCompletingRef.current here. The useEffect watching props.visible is responsible for that.
|
|
478
|
+
}, 100);
|
|
479
|
+
});
|
|
480
|
+
};
|
|
481
|
+
|
|
482
|
+
const handleConnectPlatform = async (platformId: string) => {
|
|
483
|
+
// Trigger haptic feedback when connect button is pressed
|
|
484
|
+
triggerHaptic(HapticType.BUTTON_PRESS);
|
|
485
|
+
|
|
486
|
+
setConnectingPlatform(platformId);
|
|
487
|
+
|
|
488
|
+
try {
|
|
489
|
+
// Check if the platform has a native SDK
|
|
490
|
+
if (hasNativeSDK(platformId)) {
|
|
491
|
+
// Use native SDK authentication
|
|
492
|
+
setCurrentPlatform(platformId);
|
|
493
|
+
const success = await initiateNativeAuth(platformId, username);
|
|
494
|
+
|
|
495
|
+
if (success) {
|
|
496
|
+
// Update connections state
|
|
497
|
+
setConnections(prev => ({
|
|
498
|
+
...prev,
|
|
499
|
+
[platformId]: { userName: username, connected: true }
|
|
500
|
+
}));
|
|
501
|
+
|
|
502
|
+
// Update platform toggles
|
|
503
|
+
setPlatformToggles(prev => ({
|
|
504
|
+
...prev,
|
|
505
|
+
[platformId]: true
|
|
506
|
+
}));
|
|
507
|
+
|
|
508
|
+
// Update connection statuses
|
|
509
|
+
setConnectionStatuses(prev => ({
|
|
510
|
+
...prev,
|
|
511
|
+
[platformId]: 'connected'
|
|
512
|
+
}));
|
|
513
|
+
|
|
514
|
+
// Store the connected platform
|
|
515
|
+
await storeConnectedPlatform(platformId);
|
|
516
|
+
}
|
|
517
|
+
} else {
|
|
518
|
+
// For other platforms, use the web OAuth flow
|
|
519
|
+
setCurrentPlatform(platformId);
|
|
520
|
+
const oauthUrl = await initiateOAuth(platformId, username);
|
|
521
|
+
|
|
522
|
+
if (oauthUrl) {
|
|
523
|
+
setOauthUrl(oauthUrl);
|
|
524
|
+
setStep('oauth');
|
|
525
|
+
}
|
|
526
|
+
}
|
|
527
|
+
} catch (error) {
|
|
528
|
+
console.error(`Error connecting to ${platformId}:`, error);
|
|
529
|
+
} finally {
|
|
530
|
+
setConnectingPlatform(null);
|
|
531
|
+
}
|
|
532
|
+
};
|
|
533
|
+
|
|
534
|
+
const togglePlatform = useCallback(async (platformId: string) => {
|
|
535
|
+
// If toggling on, initiate the OAuth flow for the platform
|
|
536
|
+
if (!platformToggles[platformId]) {
|
|
537
|
+
try {
|
|
538
|
+
// Special case for Instagram which uses the existing flow
|
|
539
|
+
if (platformId === 'instagram') {
|
|
540
|
+
setPlatformToggles(prev => ({
|
|
541
|
+
...prev,
|
|
542
|
+
[platformId]: !prev[platformId]
|
|
543
|
+
}));
|
|
544
|
+
setConnections(prev => ({
|
|
545
|
+
...prev,
|
|
546
|
+
[platformId]: { userName: `${platformId}_user`, connected: true }
|
|
547
|
+
}));
|
|
548
|
+
// Store the connected platform
|
|
549
|
+
await storeConnectedPlatform(platformId);
|
|
550
|
+
return;
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
// Check if the platform has a native SDK
|
|
554
|
+
if (hasNativeSDK(platformId)) {
|
|
555
|
+
// Use native SDK authentication
|
|
556
|
+
setCurrentPlatform(platformId);
|
|
557
|
+
const success = await initiateNativeAuth(platformId, username);
|
|
558
|
+
|
|
559
|
+
if (success) {
|
|
560
|
+
// Update connections state
|
|
561
|
+
setConnections(prev => ({
|
|
562
|
+
...prev,
|
|
563
|
+
[platformId]: { userName: username, connected: true }
|
|
564
|
+
}));
|
|
565
|
+
|
|
566
|
+
// Update platform toggles
|
|
567
|
+
setPlatformToggles(prev => ({
|
|
568
|
+
...prev,
|
|
569
|
+
[platformId]: true
|
|
570
|
+
}));
|
|
571
|
+
|
|
572
|
+
// Store the connected platform
|
|
573
|
+
await storeConnectedPlatform(platformId);
|
|
574
|
+
}
|
|
575
|
+
return;
|
|
576
|
+
}
|
|
577
|
+
|
|
578
|
+
// For other platforms, use the web OAuth flow
|
|
579
|
+
setCurrentPlatform(platformId);
|
|
580
|
+
const oauthUrl = await initiateOAuth(platformId, username);
|
|
581
|
+
|
|
582
|
+
// If oauthUrl is null, it means we should use native SDK (which should have been caught above)
|
|
583
|
+
if (oauthUrl) {
|
|
584
|
+
setOauthUrl(oauthUrl);
|
|
585
|
+
setStep('oauth');
|
|
586
|
+
}
|
|
587
|
+
} catch (error) {
|
|
588
|
+
console.error(`Error initiating OAuth for ${platformId}:`, error);
|
|
589
|
+
// If there's an error, don't toggle the platform
|
|
590
|
+
return;
|
|
591
|
+
}
|
|
592
|
+
} else {
|
|
593
|
+
// If toggling off, just update the state
|
|
594
|
+
setPlatformToggles(prev => ({
|
|
595
|
+
...prev,
|
|
596
|
+
[platformId]: !prev[platformId]
|
|
597
|
+
}));
|
|
598
|
+
|
|
599
|
+
// Remove connection
|
|
600
|
+
setConnections(prev => {
|
|
601
|
+
const newConnections = { ...prev };
|
|
602
|
+
delete newConnections[platformId];
|
|
603
|
+
return newConnections;
|
|
604
|
+
});
|
|
605
|
+
}
|
|
606
|
+
}, [platformToggles, username]);
|
|
607
|
+
|
|
608
|
+
/**
|
|
609
|
+
* Handles OAuth callback URLs
|
|
610
|
+
*/
|
|
611
|
+
const handleOAuthCallback = useCallback((url: string) => {
|
|
612
|
+
try {
|
|
613
|
+
// Extract the authorization code from the URL
|
|
614
|
+
const parsedUrl = new URL(url);
|
|
615
|
+
const code = parsedUrl.searchParams.get('code');
|
|
616
|
+
const platform = parsedUrl.searchParams.get('platform') || currentPlatform;
|
|
617
|
+
|
|
618
|
+
if (code && platform) {
|
|
619
|
+
// Update connections state
|
|
620
|
+
setConnections(prev => ({
|
|
621
|
+
...prev,
|
|
622
|
+
[platform]: { userName: username, connected: true }
|
|
623
|
+
}));
|
|
624
|
+
|
|
625
|
+
// Update platform toggles
|
|
626
|
+
setPlatformToggles(prev => ({
|
|
627
|
+
...prev,
|
|
628
|
+
[platform]: true
|
|
629
|
+
}));
|
|
630
|
+
|
|
631
|
+
// Return to the connect step
|
|
632
|
+
setStep('connect');
|
|
633
|
+
}
|
|
634
|
+
} catch (error) {
|
|
635
|
+
console.error('Error handling OAuth callback:', error);
|
|
636
|
+
}
|
|
637
|
+
}, [currentPlatform, username]);
|
|
638
|
+
|
|
639
|
+
/**
|
|
640
|
+
* Handles successful OAuth authentication from the OAuthWebView
|
|
641
|
+
*/
|
|
642
|
+
const handleOAuthSuccess = useCallback(async (code: string) => {
|
|
643
|
+
console.log(`🎉 OAuth success for ${currentPlatform} - backend callback completed`);
|
|
644
|
+
console.log(`📝 Received result:`, code);
|
|
645
|
+
|
|
646
|
+
if (currentPlatform) {
|
|
647
|
+
console.log(`✅ Updating connection state for ${currentPlatform}`);
|
|
648
|
+
|
|
649
|
+
// Update connections state
|
|
650
|
+
setConnections(prev => ({
|
|
651
|
+
...prev,
|
|
652
|
+
[currentPlatform]: { userName: username, connected: true }
|
|
653
|
+
}));
|
|
654
|
+
|
|
655
|
+
// Update platform toggles
|
|
656
|
+
setPlatformToggles(prev => ({
|
|
657
|
+
...prev,
|
|
658
|
+
[currentPlatform]: true
|
|
659
|
+
}));
|
|
660
|
+
|
|
661
|
+
// Update connection statuses
|
|
662
|
+
setConnectionStatuses(prev => ({
|
|
663
|
+
...prev,
|
|
664
|
+
[currentPlatform]: 'connected'
|
|
665
|
+
}));
|
|
666
|
+
|
|
667
|
+
// Store the connected platform
|
|
668
|
+
await storeConnectedPlatform(currentPlatform);
|
|
669
|
+
|
|
670
|
+
console.log(`💾 ${currentPlatform} connection stored successfully`);
|
|
671
|
+
}
|
|
672
|
+
|
|
673
|
+
// Close the OAuth window by returning to the connect step
|
|
674
|
+
console.log('🔄 Returning to connect step');
|
|
675
|
+
setOauthUrl('');
|
|
676
|
+
setStep('connect');
|
|
677
|
+
}, [currentPlatform, username, storeConnectedPlatform]);
|
|
678
|
+
|
|
679
|
+
const handlePinSubmit = useCallback(async (userPin: string) => {
|
|
680
|
+
setPin(userPin);
|
|
681
|
+
|
|
682
|
+
// Store PIN temporarily for training component access
|
|
683
|
+
setTemporaryPin(userPin);
|
|
684
|
+
|
|
685
|
+
console.log('🔐 [PIN SUBMIT] PIN submitted, checking for background training...');
|
|
686
|
+
|
|
687
|
+
// ✅ NEW: Check if background training is already running
|
|
688
|
+
if (isBackgroundTrainingStarted && backgroundSocketId) {
|
|
689
|
+
console.log('✅ [PIN SUBMIT] Background training detected, continuing with PIN validation...');
|
|
690
|
+
|
|
691
|
+
// Continue with existing training by sending PIN validation
|
|
692
|
+
try {
|
|
693
|
+
await continueBackgroundTrainingWithPin(userPin);
|
|
694
|
+
setStep('persona'); // Move to persona step to show training progress
|
|
695
|
+
} catch (error) {
|
|
696
|
+
console.error('❌ [PIN SUBMIT] Failed to continue background training:', error);
|
|
697
|
+
// ❌ DISABLED: Don't start new training when PIN is submitted
|
|
698
|
+
// Just show persona step with error state
|
|
699
|
+
setStep('persona');
|
|
700
|
+
setPersonaStatus('Error: Failed to continue training');
|
|
701
|
+
setHasError(true);
|
|
702
|
+
}
|
|
703
|
+
} else {
|
|
704
|
+
console.log('ℹ️ [PIN SUBMIT] No background training detected');
|
|
705
|
+
// ❌ DISABLED: Don't start training when PIN is submitted
|
|
706
|
+
// Training should only start during connector→PIN transition
|
|
707
|
+
setStep('persona');
|
|
708
|
+
setPersonaStatus('No training in progress. Please restart the flow.');
|
|
709
|
+
setHasError(true);
|
|
710
|
+
}
|
|
711
|
+
|
|
712
|
+
console.log('🔐 [PIN SUBMIT] PIN stored securely, moved to persona step');
|
|
713
|
+
}, [isBackgroundTrainingStarted, backgroundSocketId]);
|
|
714
|
+
|
|
715
|
+
// Start real Enoch training via API (restored for backwards compatibility)
|
|
716
|
+
const startEnochTraining = async (socketId: string, authToken?: string) => {
|
|
717
|
+
try {
|
|
718
|
+
setPersonaStatus('Starting training...');
|
|
719
|
+
setPersonaProgress(15);
|
|
720
|
+
|
|
721
|
+
// Use provided token or get from AsyncStorage to avoid state timing issues
|
|
722
|
+
const token = authToken || await AsyncStorage.getItem('onairos_jwt_token') || await AsyncStorage.getItem('auth_token');
|
|
723
|
+
|
|
724
|
+
if (!token) {
|
|
725
|
+
console.error('❌ No authentication token available');
|
|
726
|
+
throw new Error('No authentication token available');
|
|
727
|
+
}
|
|
728
|
+
|
|
729
|
+
console.log('🚀 Starting Enoch training with socketId:', socketId);
|
|
730
|
+
console.log('🔑 Using auth token:', token ? `${token.substring(0, 20)}...` : 'None');
|
|
731
|
+
|
|
732
|
+
// Get stored Onairos username for API calls
|
|
733
|
+
const storedUsername = await getOnairosUsername();
|
|
734
|
+
const finalUsername = storedUsername || userInfo?.username || userInfo?.name || username || 'mobile_user';
|
|
735
|
+
|
|
736
|
+
// Get connected platforms information
|
|
737
|
+
const connectedPlatforms = await AsyncStorage.getItem('connectedPlatforms');
|
|
738
|
+
const platformsList = connectedPlatforms ? JSON.parse(connectedPlatforms) : [];
|
|
739
|
+
|
|
740
|
+
console.log('📱 Connected platforms for training:', platformsList);
|
|
741
|
+
|
|
742
|
+
// Get encrypted PIN for training (if available)
|
|
743
|
+
const encryptedPin = await getEncryptedPinForAPI().catch(error => {
|
|
744
|
+
console.warn('⚠️ Could not get encrypted PIN for training:', error);
|
|
745
|
+
return null;
|
|
746
|
+
});
|
|
747
|
+
|
|
748
|
+
// Prepare user data for training - match backend expected format
|
|
749
|
+
const trainingData = {
|
|
750
|
+
socketId,
|
|
751
|
+
username: finalUsername,
|
|
752
|
+
email: userInfo?.email || null,
|
|
753
|
+
modelKey: null,
|
|
754
|
+
connectedPlatforms: platformsList,
|
|
755
|
+
platformConnections: connections,
|
|
756
|
+
...(encryptedPin && {
|
|
757
|
+
encryptedPin: encryptedPin,
|
|
758
|
+
hasPinData: true
|
|
759
|
+
})
|
|
760
|
+
};
|
|
761
|
+
|
|
762
|
+
console.log('📤 Sending training data to /mobile-training/enoch:', trainingData);
|
|
763
|
+
|
|
764
|
+
// Use the new training function that includes YouTube migration check
|
|
765
|
+
const result = await startEnochTrainingWithYouTubeCheck(trainingData);
|
|
766
|
+
console.log('📡 Training API response:', result);
|
|
767
|
+
|
|
768
|
+
// Handle CONNECTIONS_REQUIRED scenario (pre-training validation)
|
|
769
|
+
if (result.requiresConnections || result.code === 'CONNECTIONS_REQUIRED') {
|
|
770
|
+
console.log('🔗 Connections required detected from HTTP response');
|
|
771
|
+
setDataScenario('CONNECTIONS_REQUIRED');
|
|
772
|
+
setDataDetails(result);
|
|
773
|
+
setShowDataWarning(true);
|
|
774
|
+
setPersonaStatus('Connections required');
|
|
775
|
+
setHasError(true);
|
|
776
|
+
stopDotsAnimation();
|
|
777
|
+
return;
|
|
778
|
+
}
|
|
779
|
+
|
|
780
|
+
if (result.success) {
|
|
781
|
+
console.log('🚀 Training Started:', result.message);
|
|
782
|
+
console.log('🎯 Training Features:', result.features);
|
|
783
|
+
|
|
784
|
+
// Log the new features from the spec
|
|
785
|
+
if (result.features) {
|
|
786
|
+
console.log('✅ Inference enabled:', result.features.inference);
|
|
787
|
+
console.log('💾 Storage method:', result.features.storage);
|
|
788
|
+
console.log('🔒 Compression enabled:', result.features.compression);
|
|
789
|
+
console.log('🔐 Encryption enabled:', result.features.encryption);
|
|
790
|
+
console.log('📊 Training type:', result.features.type);
|
|
791
|
+
console.log('🗄️ Databases:', result.features.databases);
|
|
792
|
+
console.log('📈 Query scores enabled:', result.features.queryScores);
|
|
793
|
+
}
|
|
794
|
+
|
|
795
|
+
setPersonaStatus('Training model...');
|
|
796
|
+
setPersonaProgress(25);
|
|
797
|
+
} else {
|
|
798
|
+
console.error('❌ Training start failed:', result.error);
|
|
799
|
+
setPersonaStatus(`Error: ${result.error || 'Training failed to start'}`);
|
|
800
|
+
setHasError(true);
|
|
801
|
+
stopDotsAnimation();
|
|
802
|
+
}
|
|
803
|
+
} catch (error) {
|
|
804
|
+
console.error('❌ Training start error:', error);
|
|
805
|
+
setPersonaStatus(`Error: ${error instanceof Error ? error.message : 'Unknown error'}`);
|
|
806
|
+
setHasError(true);
|
|
807
|
+
stopDotsAnimation();
|
|
808
|
+
}
|
|
809
|
+
};
|
|
810
|
+
|
|
811
|
+
// ✅ NEW: Continue background training with PIN validation
|
|
812
|
+
const continueBackgroundTrainingWithPin = async (userPin: string) => {
|
|
813
|
+
try {
|
|
814
|
+
console.log('🔐 [BACKGROUND] Continuing existing background training with PIN validation');
|
|
815
|
+
console.log('🔑 Using auth token:', `${userToken?.substring(0, 20)}...`);
|
|
816
|
+
|
|
817
|
+
// Check if we have a valid socket ID
|
|
818
|
+
if (!backgroundSocketId) {
|
|
819
|
+
throw new Error('No background socket ID available');
|
|
820
|
+
}
|
|
821
|
+
|
|
822
|
+
// ❌ REMOVED: Don't send new training signal - training already started!
|
|
823
|
+
// We should just validate the PIN with the existing training, not start new training
|
|
824
|
+
|
|
825
|
+
console.log('🔐 [BACKGROUND] PIN validation - continuing with existing training session');
|
|
826
|
+
console.log('🔌 [BACKGROUND] Using existing socket ID:', backgroundSocketId);
|
|
827
|
+
|
|
828
|
+
// Just log that we're continuing - the existing training should handle PIN internally
|
|
829
|
+
console.log('✅ [BACKGROUND] PIN submitted for existing training session');
|
|
830
|
+
|
|
831
|
+
} catch (error) {
|
|
832
|
+
console.error('❌ [BACKGROUND] Failed to continue background training:', error);
|
|
833
|
+
throw error;
|
|
834
|
+
}
|
|
835
|
+
};
|
|
836
|
+
|
|
837
|
+
// Replace fake persona creation with real training setup
|
|
838
|
+
const startPersonaCreation = async () => {
|
|
839
|
+
setPersonaProgress(0);
|
|
840
|
+
setPersonaStatus('Initializing');
|
|
841
|
+
setIsPersonaComplete(false);
|
|
842
|
+
setHasError(false);
|
|
843
|
+
|
|
844
|
+
// Start the dots animation
|
|
845
|
+
startDotsAnimation();
|
|
846
|
+
|
|
847
|
+
try {
|
|
848
|
+
console.log('🚀 Starting persona creation...');
|
|
849
|
+
|
|
850
|
+
// Ensure we have a valid authentication token before starting
|
|
851
|
+
console.log('🔐 Step 1: Ensuring authentication token...');
|
|
852
|
+
const authToken = await ensureAuthToken();
|
|
853
|
+
|
|
854
|
+
if (!authToken) {
|
|
855
|
+
throw new Error('Failed to create or retrieve authentication token');
|
|
856
|
+
}
|
|
857
|
+
|
|
858
|
+
// Set the token in state
|
|
859
|
+
setUserToken(authToken);
|
|
860
|
+
console.log('✅ Authentication token set in state:', `${authToken.substring(0, 20)}...`);
|
|
861
|
+
console.log('🔍 Token length:', authToken.length);
|
|
862
|
+
|
|
863
|
+
// Also verify it was stored properly
|
|
864
|
+
const storedToken = await AsyncStorage.getItem('onairos_jwt_token');
|
|
865
|
+
console.log('🔑 Token stored verification:', storedToken ? `${storedToken.substring(0, 20)}...` : 'Not stored');
|
|
866
|
+
|
|
867
|
+
// If userInfo is not set, try to reload it
|
|
868
|
+
if (!userInfo) {
|
|
869
|
+
console.log('🔄 UserInfo not available, attempting to reload...');
|
|
870
|
+
const storedUsername = await getOnairosUsername();
|
|
871
|
+
const fallbackUsername = storedUsername || user?.email?.split('@')[0] || user?.name || 'mobile_user';
|
|
872
|
+
|
|
873
|
+
const newUserInfo = {
|
|
874
|
+
username: fallbackUsername,
|
|
875
|
+
email: user?.email || null,
|
|
876
|
+
id: null
|
|
877
|
+
};
|
|
878
|
+
|
|
879
|
+
setUserInfo(newUserInfo);
|
|
880
|
+
setUsername(fallbackUsername);
|
|
881
|
+
|
|
882
|
+
console.log('🧑💻 Set user info:', newUserInfo);
|
|
883
|
+
|
|
884
|
+
// Give a moment for state to update
|
|
885
|
+
await new Promise<void>(resolve => setTimeout(() => resolve(), 200));
|
|
886
|
+
}
|
|
887
|
+
|
|
888
|
+
// Check again after potential reload
|
|
889
|
+
const currentUserInfo = userInfo || {
|
|
890
|
+
username: username || user?.email?.split('@')[0] || user?.name || 'mobile_user',
|
|
891
|
+
email: user?.email || null,
|
|
892
|
+
id: null
|
|
893
|
+
};
|
|
894
|
+
|
|
895
|
+
if (!authToken) {
|
|
896
|
+
console.error('❌ No authentication token available after ensureAuthToken');
|
|
897
|
+
throw new Error('No authentication token available');
|
|
898
|
+
}
|
|
899
|
+
|
|
900
|
+
console.log('🔧 Setting up socket connection for real training...');
|
|
901
|
+
console.log('🧑💻 User info available:', currentUserInfo);
|
|
902
|
+
console.log('🔑 Token available:', !!authToken);
|
|
903
|
+
console.log('🌐 Attempting to connect to: https://api2.onairos.uk');
|
|
904
|
+
console.log('📱 Device platform:', Platform.OS);
|
|
905
|
+
console.log('🔗 Network connectivity check starting...');
|
|
906
|
+
|
|
907
|
+
setPersonaStatus('Connecting');
|
|
908
|
+
setPersonaProgress(5);
|
|
909
|
+
|
|
910
|
+
// Initialize socket connection with enhanced configuration
|
|
911
|
+
socketRef.current = io('https://api2.onairos.uk', {
|
|
912
|
+
transports: ['websocket', 'polling'], // Add polling as fallback
|
|
913
|
+
autoConnect: false,
|
|
914
|
+
timeout: 15000, // Increase timeout to 15 seconds
|
|
915
|
+
reconnection: true, // Enable reconnection with limits
|
|
916
|
+
reconnectionAttempts: 3,
|
|
917
|
+
reconnectionDelay: 1000,
|
|
918
|
+
forceNew: true // Force a new connection
|
|
919
|
+
});
|
|
920
|
+
|
|
921
|
+
console.log('🔌 Socket instance created:', {
|
|
922
|
+
connected: socketRef.current.connected,
|
|
923
|
+
id: socketRef.current.id,
|
|
924
|
+
disconnected: socketRef.current.disconnected
|
|
925
|
+
});
|
|
926
|
+
|
|
927
|
+
// Socket event listeners with enhanced error handling
|
|
928
|
+
socketRef.current.on('connect', () => {
|
|
929
|
+
console.log('✅ Socket connected for training');
|
|
930
|
+
console.log('🔌 Socket connection details:', {
|
|
931
|
+
id: socketRef.current?.id,
|
|
932
|
+
connected: socketRef.current?.connected,
|
|
933
|
+
transport: socketRef.current?.io?.engine?.transport?.name
|
|
934
|
+
});
|
|
935
|
+
|
|
936
|
+
setSocketConnected(true);
|
|
937
|
+
setPersonaStatus('Starting training');
|
|
938
|
+
setPersonaProgress(10);
|
|
939
|
+
|
|
940
|
+
const socketId = socketRef.current?.id;
|
|
941
|
+
console.log('🔌 Socket ID for training:', socketId);
|
|
942
|
+
|
|
943
|
+
if (socketId) {
|
|
944
|
+
// Add a small delay to ensure socket is fully ready and registered on backend
|
|
945
|
+
console.log('🔄 Socket ready for persona display with token:', authToken ? `${authToken.substring(0, 20)}...` : 'None');
|
|
946
|
+
console.log('⏰ Socket registered but training will not start from persona screen...');
|
|
947
|
+
// ❌ DISABLED: Don't start training from persona screen
|
|
948
|
+
// Training should only start during connector→PIN transition
|
|
949
|
+
// setTimeout(() => {
|
|
950
|
+
// console.log('🚀 Now starting training with socket ID:', socketId);
|
|
951
|
+
// startEnochTraining(socketId, authToken);
|
|
952
|
+
// }, 2000);
|
|
953
|
+
|
|
954
|
+
// Just show the persona screen without starting training
|
|
955
|
+
setPersonaStatus('Waiting for training to start from connector→PIN transition');
|
|
956
|
+
} else {
|
|
957
|
+
console.error('❌ No socket ID available after connection');
|
|
958
|
+
setPersonaStatus('Connection error. Please try again.');
|
|
959
|
+
setHasError(true);
|
|
960
|
+
stopDotsAnimation();
|
|
961
|
+
}
|
|
962
|
+
});
|
|
963
|
+
|
|
964
|
+
socketRef.current.on('disconnect', (reason) => {
|
|
965
|
+
console.log('❌ Socket disconnected, reason:', reason);
|
|
966
|
+
console.log('🔍 Disconnect details:', {
|
|
967
|
+
reason: reason,
|
|
968
|
+
wasConnected: socketConnected,
|
|
969
|
+
socketId: socketRef.current?.id
|
|
970
|
+
});
|
|
971
|
+
setSocketConnected(false);
|
|
972
|
+
});
|
|
973
|
+
|
|
974
|
+
socketRef.current.on('reconnect', (attemptNumber) => {
|
|
975
|
+
console.log('🔄 Socket reconnected after', attemptNumber, 'attempts');
|
|
976
|
+
setSocketConnected(true);
|
|
977
|
+
});
|
|
978
|
+
|
|
979
|
+
socketRef.current.on('reconnect_attempt', (attemptNumber) => {
|
|
980
|
+
console.log('🔄 Socket reconnection attempt:', attemptNumber);
|
|
981
|
+
setPersonaStatus(`Reconnecting... (${attemptNumber}/3)`);
|
|
982
|
+
});
|
|
983
|
+
|
|
984
|
+
socketRef.current.on('reconnect_error', (error) => {
|
|
985
|
+
console.error('❌ Socket reconnection error:', error);
|
|
986
|
+
});
|
|
987
|
+
|
|
988
|
+
socketRef.current.on('reconnect_failed', () => {
|
|
989
|
+
console.error('❌ Socket reconnection failed after all attempts');
|
|
990
|
+
setPersonaStatus('Connection failed. Please try again.');
|
|
991
|
+
setHasError(true);
|
|
992
|
+
stopDotsAnimation();
|
|
993
|
+
});
|
|
994
|
+
|
|
995
|
+
socketRef.current.on('connect_error', (error) => {
|
|
996
|
+
console.error('❌ Socket connection error:', error);
|
|
997
|
+
console.error('❌ Socket error details:', {
|
|
998
|
+
message: error.message,
|
|
999
|
+
name: error.name,
|
|
1000
|
+
stack: error.stack,
|
|
1001
|
+
errorObject: error
|
|
1002
|
+
});
|
|
1003
|
+
setPersonaStatus('Connection error. Please try again.');
|
|
1004
|
+
setHasError(true);
|
|
1005
|
+
stopDotsAnimation();
|
|
1006
|
+
});
|
|
1007
|
+
|
|
1008
|
+
socketRef.current.on('trainingCompleted', (data) => {
|
|
1009
|
+
console.log('✅ Training Complete:', data);
|
|
1010
|
+
setPersonaStatus('Running test inference');
|
|
1011
|
+
setPersonaProgress(60);
|
|
1012
|
+
});
|
|
1013
|
+
|
|
1014
|
+
socketRef.current.on('inferenceCompleted', (data) => {
|
|
1015
|
+
console.log('🧠 Inference Complete:', data);
|
|
1016
|
+
setPersonaStatus('Uploading to S3');
|
|
1017
|
+
setPersonaProgress(80);
|
|
1018
|
+
setUserTraits(data.traits);
|
|
1019
|
+
setInferenceResults(data.inferenceResults);
|
|
1020
|
+
});
|
|
1021
|
+
|
|
1022
|
+
socketRef.current.on('modelStandby', (data) => {
|
|
1023
|
+
console.log('🎉 All Complete:', data);
|
|
1024
|
+
|
|
1025
|
+
// Log completion details based on new spec
|
|
1026
|
+
if (data.completed) {
|
|
1027
|
+
console.log('✅ Training completed:', data.message);
|
|
1028
|
+
console.log('💾 Storage method:', data.storage);
|
|
1029
|
+
console.log('🔐 Encryption enabled:', data.encryption);
|
|
1030
|
+
console.log('🧠 Inference enabled:', data.inference);
|
|
1031
|
+
|
|
1032
|
+
// Log database info for Enoch mode
|
|
1033
|
+
if (data.databases && Array.isArray(data.databases)) {
|
|
1034
|
+
console.log('🗄️ Databases used:', data.databases.join(', '));
|
|
1035
|
+
}
|
|
1036
|
+
|
|
1037
|
+
// Log testing mode
|
|
1038
|
+
if (data.testing) {
|
|
1039
|
+
console.log('🧪 Testing mode enabled');
|
|
1040
|
+
}
|
|
1041
|
+
}
|
|
1042
|
+
|
|
1043
|
+
setIsPersonaComplete(true);
|
|
1044
|
+
setPersonaStatus('Complete!');
|
|
1045
|
+
setPersonaProgress(100);
|
|
1046
|
+
stopDotsAnimation();
|
|
1047
|
+
});
|
|
1048
|
+
|
|
1049
|
+
socketRef.current.on('trainingUpdate', (data) => {
|
|
1050
|
+
console.log('📊 Training update:', data);
|
|
1051
|
+
|
|
1052
|
+
// Handle YouTube token expiry
|
|
1053
|
+
if (data.error && data.error.includes('YouTube access token has expired')) {
|
|
1054
|
+
console.log('🔄 YouTube token expired, triggering reconnection...');
|
|
1055
|
+
setDataScenario(null);
|
|
1056
|
+
setShowDataWarning(false);
|
|
1057
|
+
setPersonaStatus('YouTube token expired - reconnecting...');
|
|
1058
|
+
|
|
1059
|
+
// Try to refresh tokens first before full reconnection
|
|
1060
|
+
setTimeout(async () => {
|
|
1061
|
+
try {
|
|
1062
|
+
// Import the refresh function
|
|
1063
|
+
const { refreshYouTubeTokens } = await import('../services/platformAuthService');
|
|
1064
|
+
|
|
1065
|
+
console.log('🔄 Attempting to refresh YouTube tokens...');
|
|
1066
|
+
const refreshSuccess = await refreshYouTubeTokens();
|
|
1067
|
+
|
|
1068
|
+
if (refreshSuccess) {
|
|
1069
|
+
console.log('✅ YouTube tokens refreshed, but training restart disabled');
|
|
1070
|
+
setPersonaStatus('YouTube tokens refreshed - but training only starts from connector→PIN');
|
|
1071
|
+
|
|
1072
|
+
// ❌ DISABLED: Don't restart training from persona screen
|
|
1073
|
+
// Training should only start during connector→PIN transition
|
|
1074
|
+
// if (socketRef.current?.id) {
|
|
1075
|
+
// startEnochTraining(socketRef.current.id, userToken ?? undefined);
|
|
1076
|
+
// }
|
|
1077
|
+
|
|
1078
|
+
setHasError(true); // Show error so user can restart flow properly
|
|
1079
|
+
} else {
|
|
1080
|
+
console.log('❌ Token refresh failed, attempting full reconnection...');
|
|
1081
|
+
setPersonaStatus('Token refresh failed - please restart from connector screen');
|
|
1082
|
+
|
|
1083
|
+
// ❌ DISABLED: Don't restart training from persona screen
|
|
1084
|
+
// Fall back to full reconnection
|
|
1085
|
+
try {
|
|
1086
|
+
await handleConnectPlatform('youtube');
|
|
1087
|
+
console.log('✅ YouTube reconnected, but training restart disabled');
|
|
1088
|
+
setPersonaStatus('YouTube reconnected - please restart from connector screen');
|
|
1089
|
+
|
|
1090
|
+
// ❌ DISABLED: Don't restart training from persona screen
|
|
1091
|
+
// Training should only start during connector→PIN transition
|
|
1092
|
+
// if (socketRef.current?.id) {
|
|
1093
|
+
// startEnochTraining(socketRef.current.id, userToken ?? undefined);
|
|
1094
|
+
// }
|
|
1095
|
+
|
|
1096
|
+
setHasError(true); // Show error so user can restart flow properly
|
|
1097
|
+
} catch (reconnectError) {
|
|
1098
|
+
console.error('❌ YouTube reconnection failed:', reconnectError);
|
|
1099
|
+
setPersonaStatus('YouTube reconnection failed. Please restart from connector screen.');
|
|
1100
|
+
setHasError(true);
|
|
1101
|
+
stopDotsAnimation();
|
|
1102
|
+
}
|
|
1103
|
+
}
|
|
1104
|
+
} catch (error) {
|
|
1105
|
+
console.error('❌ YouTube token refresh/reconnection error:', error);
|
|
1106
|
+
setPersonaStatus('YouTube connection failed. Please try again.');
|
|
1107
|
+
setHasError(true);
|
|
1108
|
+
stopDotsAnimation();
|
|
1109
|
+
}
|
|
1110
|
+
}, 1000);
|
|
1111
|
+
return;
|
|
1112
|
+
}
|
|
1113
|
+
|
|
1114
|
+
// Handle connections required scenario (pre-training validation)
|
|
1115
|
+
if (data.requiresConnections || data.code === 'CONNECTIONS_REQUIRED') {
|
|
1116
|
+
console.log('🔗 Connections required detected from socket');
|
|
1117
|
+
setDataScenario('CONNECTIONS_REQUIRED');
|
|
1118
|
+
setDataDetails(data);
|
|
1119
|
+
setShowDataWarning(true);
|
|
1120
|
+
setPersonaStatus('Connections required');
|
|
1121
|
+
setHasError(true);
|
|
1122
|
+
stopDotsAnimation();
|
|
1123
|
+
return;
|
|
1124
|
+
}
|
|
1125
|
+
|
|
1126
|
+
// Handle data scenario responses
|
|
1127
|
+
if (data.code === 'NO_DATA') {
|
|
1128
|
+
console.log('🚫 No data scenario detected');
|
|
1129
|
+
setDataScenario('NO_DATA');
|
|
1130
|
+
setDataDetails(data.details);
|
|
1131
|
+
setShowDataWarning(true);
|
|
1132
|
+
setPersonaStatus('No interaction data found');
|
|
1133
|
+
setHasError(true);
|
|
1134
|
+
stopDotsAnimation();
|
|
1135
|
+
return;
|
|
1136
|
+
}
|
|
1137
|
+
|
|
1138
|
+
if (data.code === 'LIMITED_DATA') {
|
|
1139
|
+
console.log('ℹ️ Limited data scenario detected');
|
|
1140
|
+
setDataScenario('LIMITED_DATA');
|
|
1141
|
+
setDataDetails(data.details);
|
|
1142
|
+
setShowDataWarning(true);
|
|
1143
|
+
setPersonaStatus('Creating your persona with available data');
|
|
1144
|
+
// Don't set hasError - training continues
|
|
1145
|
+
return;
|
|
1146
|
+
}
|
|
1147
|
+
|
|
1148
|
+
// Handle regular training updates
|
|
1149
|
+
if (data.error) {
|
|
1150
|
+
console.error('❌ Training update error:', data.error);
|
|
1151
|
+
setPersonaStatus(`Error: ${data.error}`);
|
|
1152
|
+
setHasError(true);
|
|
1153
|
+
stopDotsAnimation();
|
|
1154
|
+
} else if (data.progress) {
|
|
1155
|
+
setPersonaProgress(data.progress);
|
|
1156
|
+
setPersonaStatus(data.status || 'Training in progress');
|
|
1157
|
+
// Clear data warning if training progresses normally
|
|
1158
|
+
if (showDataWarning && data.progress > 30) {
|
|
1159
|
+
setShowDataWarning(false);
|
|
1160
|
+
}
|
|
1161
|
+
}
|
|
1162
|
+
});
|
|
1163
|
+
|
|
1164
|
+
// Connect to socket with timeout
|
|
1165
|
+
console.log('🔌 Attempting to connect to socket...');
|
|
1166
|
+
console.log('🔌 Socket config:', {
|
|
1167
|
+
url: 'https://api2.onairos.uk',
|
|
1168
|
+
transports: ['websocket'],
|
|
1169
|
+
autoConnect: false,
|
|
1170
|
+
timeout: 10000,
|
|
1171
|
+
reconnection: false
|
|
1172
|
+
});
|
|
1173
|
+
socketRef.current.connect();
|
|
1174
|
+
console.log('🔌 Socket connect() called - waiting for connection...');
|
|
1175
|
+
|
|
1176
|
+
// Add immediate state check
|
|
1177
|
+
setTimeout(() => {
|
|
1178
|
+
console.log('🔍 Socket state after 1 second:', {
|
|
1179
|
+
connected: socketRef.current?.connected,
|
|
1180
|
+
disconnected: socketRef.current?.disconnected,
|
|
1181
|
+
id: socketRef.current?.id,
|
|
1182
|
+
engineConnected: socketRef.current?.io?.engine?.readyState
|
|
1183
|
+
});
|
|
1184
|
+
}, 1000);
|
|
1185
|
+
|
|
1186
|
+
setTimeout(() => {
|
|
1187
|
+
console.log('🔍 Socket state after 5 seconds:', {
|
|
1188
|
+
connected: socketRef.current?.connected,
|
|
1189
|
+
disconnected: socketRef.current?.disconnected,
|
|
1190
|
+
id: socketRef.current?.id,
|
|
1191
|
+
engineConnected: socketRef.current?.io?.engine?.readyState
|
|
1192
|
+
});
|
|
1193
|
+
}, 5000);
|
|
1194
|
+
|
|
1195
|
+
// Set a timeout for socket connection with enhanced fallback
|
|
1196
|
+
setTimeout(() => {
|
|
1197
|
+
if (!socketConnected && socketRef.current && !socketRef.current.connected) {
|
|
1198
|
+
console.error('❌ Socket connection timeout after 20 seconds');
|
|
1199
|
+
console.error('🔍 Socket state:', {
|
|
1200
|
+
connected: socketRef.current.connected,
|
|
1201
|
+
disconnected: socketRef.current.disconnected,
|
|
1202
|
+
id: socketRef.current.id
|
|
1203
|
+
});
|
|
1204
|
+
|
|
1205
|
+
setPersonaStatus('Connection timeout. Please check your internet and try again.');
|
|
1206
|
+
setHasError(true);
|
|
1207
|
+
stopDotsAnimation();
|
|
1208
|
+
|
|
1209
|
+
// Cleanup socket
|
|
1210
|
+
if (socketRef.current) {
|
|
1211
|
+
socketRef.current.disconnect();
|
|
1212
|
+
socketRef.current = null;
|
|
1213
|
+
}
|
|
1214
|
+
}
|
|
1215
|
+
}, 20000); // Increased timeout to 20 seconds
|
|
1216
|
+
|
|
1217
|
+
} catch (error) {
|
|
1218
|
+
console.error('❌ Error in startPersonaCreation:', error);
|
|
1219
|
+
setPersonaStatus('Failed to initialize training. Please try again.');
|
|
1220
|
+
setHasError(true);
|
|
1221
|
+
stopDotsAnimation();
|
|
1222
|
+
}
|
|
1223
|
+
};
|
|
1224
|
+
|
|
1225
|
+
// Get user-friendly status message based on progress (updated for real training)
|
|
1226
|
+
const getPersonaStatusMessage = (progress: number) => {
|
|
1227
|
+
if (hasError) return 'Something went wrong. Please try again.';
|
|
1228
|
+
if (isPersonaComplete) return 'Your persona is ready! 🎉';
|
|
1229
|
+
|
|
1230
|
+
let baseMessage = '';
|
|
1231
|
+
if (progress < 20) {
|
|
1232
|
+
baseMessage = 'Keeping your data private';
|
|
1233
|
+
} else if (progress < 40) {
|
|
1234
|
+
baseMessage = 'Trying to understand your mind';
|
|
1235
|
+
} else if (progress < 60) {
|
|
1236
|
+
baseMessage = 'You\'re more interesting than I expected';
|
|
1237
|
+
} else if (progress < 80) {
|
|
1238
|
+
baseMessage = 'Finalizing your unique persona';
|
|
1239
|
+
} else if (progress < 95) {
|
|
1240
|
+
baseMessage = 'Almost done';
|
|
1241
|
+
} else {
|
|
1242
|
+
baseMessage = 'Just a few more seconds';
|
|
1243
|
+
}
|
|
1244
|
+
|
|
1245
|
+
return baseMessage + animatedDots;
|
|
1246
|
+
};
|
|
1247
|
+
|
|
1248
|
+
// Handle persona completion - now continues the onboarding flow instead of going to separate training
|
|
1249
|
+
const handlePersonaComplete = async () => {
|
|
1250
|
+
console.log('🎉 Real persona creation completed successfully');
|
|
1251
|
+
// Cleanup socket connection
|
|
1252
|
+
if (socketRef.current) {
|
|
1253
|
+
console.log('🔌 Disconnecting training socket...');
|
|
1254
|
+
socketRef.current.disconnect();
|
|
1255
|
+
socketRef.current = null;
|
|
1256
|
+
}
|
|
1257
|
+
// Clear temporary PIN since training is complete
|
|
1258
|
+
clearTemporaryPin();
|
|
1259
|
+
// Set the completion flag BEFORE calling onComplete
|
|
1260
|
+
isCompletingRef.current = true;
|
|
1261
|
+
|
|
1262
|
+
// Get the real authentication token instead of using placeholder
|
|
1263
|
+
try {
|
|
1264
|
+
const realToken = await AsyncStorage.getItem('onairos_jwt_token') ||
|
|
1265
|
+
await AsyncStorage.getItem('enoch_token') ||
|
|
1266
|
+
await AsyncStorage.getItem('auth_token');
|
|
1267
|
+
|
|
1268
|
+
if (realToken) {
|
|
1269
|
+
console.log('✅ Using real authentication token for onComplete:', `${realToken.substring(0, 30)}...`);
|
|
1270
|
+
// Call onComplete with the REAL token that was created during ensureAuthToken
|
|
1271
|
+
onComplete?.('https://api2.onairos.uk', realToken, { email: userInfo?.email || '', ...userInfo });
|
|
1272
|
+
} else {
|
|
1273
|
+
console.error('❌ No real authentication token found after training completion');
|
|
1274
|
+
// Fallback to placeholder token if no real token exists
|
|
1275
|
+
onComplete?.('https://api2.onairos.uk', 'training-complete-token', { email: userInfo?.email || '', ...userInfo });
|
|
1276
|
+
}
|
|
1277
|
+
} catch (error) {
|
|
1278
|
+
console.error('❌ Error retrieving real token for onComplete:', error);
|
|
1279
|
+
// Fallback to placeholder token on error
|
|
1280
|
+
onComplete?.('https://api2.onairos.uk', 'training-complete-token', { email: userInfo?.email || '', ...userInfo });
|
|
1281
|
+
}
|
|
1282
|
+
};
|
|
1283
|
+
|
|
1284
|
+
// Ensure authentication token exists before training
|
|
1285
|
+
const ensureAuthToken = async () => {
|
|
1286
|
+
try {
|
|
1287
|
+
// Check if we already have an authentication token (prioritize Enoch-specific tokens)
|
|
1288
|
+
let existingToken = await AsyncStorage.getItem('onairos_jwt_token') ||
|
|
1289
|
+
await AsyncStorage.getItem('enoch_token') ||
|
|
1290
|
+
await AsyncStorage.getItem('auth_token');
|
|
1291
|
+
|
|
1292
|
+
if (existingToken && existingToken.trim().length > 20) {
|
|
1293
|
+
console.log('✅ Authentication token already exists:', `${existingToken.substring(0, 20)}...`);
|
|
1294
|
+
console.log('🔍 Token length:', existingToken.length);
|
|
1295
|
+
console.log('🔍 Token format check:', existingToken.includes('.') ? 'Looks like JWT' : 'Not JWT format');
|
|
1296
|
+
return existingToken;
|
|
1297
|
+
}
|
|
1298
|
+
|
|
1299
|
+
console.log('🔐 Creating Enoch authentication token for universal onboarding...');
|
|
1300
|
+
|
|
1301
|
+
// Create user accounts and get proper Enoch token
|
|
1302
|
+
const fallbackEmail = user?.email || `${username || 'user'}@onairos.temp`;
|
|
1303
|
+
const fallbackUsername = username || user?.name?.split('@')[0] || 'mobile_user';
|
|
1304
|
+
|
|
1305
|
+
console.log('🔐 Using credentials:', { email: fallbackEmail, username: fallbackUsername });
|
|
1306
|
+
|
|
1307
|
+
// Step 1: Create Enoch user first
|
|
1308
|
+
console.log('🔐 Step 1: Creating Enoch user...');
|
|
1309
|
+
try {
|
|
1310
|
+
const enochRegisterResponse = await fetch('https://api2.onairos.uk/enoch/users/register', {
|
|
1311
|
+
method: 'POST',
|
|
1312
|
+
headers: {
|
|
1313
|
+
'Content-Type': 'application/json'
|
|
1314
|
+
},
|
|
1315
|
+
body: JSON.stringify({
|
|
1316
|
+
email: fallbackEmail,
|
|
1317
|
+
name: fallbackUsername,
|
|
1318
|
+
photoUrl: ''
|
|
1319
|
+
})
|
|
1320
|
+
});
|
|
1321
|
+
|
|
1322
|
+
console.log('📡 Enoch register response status:', enochRegisterResponse.status);
|
|
1323
|
+
const enochResponseData = await enochRegisterResponse.json();
|
|
1324
|
+
console.log('🔗 Enoch user creation response:', enochResponseData);
|
|
1325
|
+
} catch (enochError) {
|
|
1326
|
+
console.warn('⚠️ Enoch user creation failed (continuing):', enochError);
|
|
1327
|
+
}
|
|
1328
|
+
|
|
1329
|
+
// Step 2: Create Onairos account to get JWT token (this is the critical step)
|
|
1330
|
+
console.log('🔐 Step 2: Creating Onairos account...');
|
|
1331
|
+
const onairosSignupResponse = await fetch('https://api2.onairos.uk/register/enoch', {
|
|
1332
|
+
method: 'POST',
|
|
1333
|
+
headers: {
|
|
1334
|
+
'Content-Type': 'application/json'
|
|
1335
|
+
},
|
|
1336
|
+
body: JSON.stringify({
|
|
1337
|
+
email: fallbackEmail,
|
|
1338
|
+
username: fallbackUsername,
|
|
1339
|
+
name: fallbackUsername
|
|
1340
|
+
})
|
|
1341
|
+
});
|
|
1342
|
+
|
|
1343
|
+
console.log('📡 Onairos register response status:', onairosSignupResponse.status);
|
|
1344
|
+
|
|
1345
|
+
if (!onairosSignupResponse.ok) {
|
|
1346
|
+
const errorText = await onairosSignupResponse.text();
|
|
1347
|
+
console.error('❌ Onairos signup failed:', errorText);
|
|
1348
|
+
throw new Error(`Onairos signup failed: ${onairosSignupResponse.status} ${errorText}`);
|
|
1349
|
+
}
|
|
1350
|
+
|
|
1351
|
+
const onairosResponseData = await onairosSignupResponse.json();
|
|
1352
|
+
console.log('🔗 Onairos account creation response:', onairosResponseData);
|
|
1353
|
+
|
|
1354
|
+
// Extract the token from the response
|
|
1355
|
+
let authToken = null;
|
|
1356
|
+
if (onairosResponseData.token) {
|
|
1357
|
+
authToken = onairosResponseData.token;
|
|
1358
|
+
} else if (onairosResponseData.data?.token) {
|
|
1359
|
+
authToken = onairosResponseData.data.token;
|
|
1360
|
+
} else if (onairosResponseData.jwt) {
|
|
1361
|
+
authToken = onairosResponseData.jwt;
|
|
1362
|
+
}
|
|
1363
|
+
|
|
1364
|
+
if (!authToken) {
|
|
1365
|
+
console.error('❌ No token found in response:', onairosResponseData);
|
|
1366
|
+
throw new Error('No authentication token returned from server');
|
|
1367
|
+
}
|
|
1368
|
+
|
|
1369
|
+
// Validate the token format
|
|
1370
|
+
if (typeof authToken !== 'string' || authToken.length < 20) {
|
|
1371
|
+
console.error('❌ Invalid token format:', authToken);
|
|
1372
|
+
throw new Error('Invalid token format received');
|
|
1373
|
+
}
|
|
1374
|
+
|
|
1375
|
+
// Check if it looks like a JWT
|
|
1376
|
+
const jwtParts = authToken.split('.');
|
|
1377
|
+
if (jwtParts.length !== 3) {
|
|
1378
|
+
console.warn('⚠️ Token does not appear to be a valid JWT:', `${authToken.substring(0, 20)}...`);
|
|
1379
|
+
} else {
|
|
1380
|
+
console.log('✅ Token appears to be a valid JWT format');
|
|
1381
|
+
}
|
|
1382
|
+
|
|
1383
|
+
// Store the token in multiple locations for maximum compatibility
|
|
1384
|
+
await AsyncStorage.setItem('onairos_jwt_token', authToken);
|
|
1385
|
+
await AsyncStorage.setItem('auth_token', authToken);
|
|
1386
|
+
await AsyncStorage.setItem('enoch_token', authToken);
|
|
1387
|
+
await AsyncStorage.setItem('onairos_username', onairosResponseData.username || fallbackUsername);
|
|
1388
|
+
|
|
1389
|
+
console.log('✅ Successfully stored authentication tokens');
|
|
1390
|
+
console.log('🔑 Token preview:', `${authToken.substring(0, 20)}...`);
|
|
1391
|
+
console.log('🔑 Token length:', authToken.length);
|
|
1392
|
+
console.log('👤 Username stored:', onairosResponseData.username || fallbackUsername);
|
|
1393
|
+
|
|
1394
|
+
return authToken;
|
|
1395
|
+
|
|
1396
|
+
} catch (error) {
|
|
1397
|
+
console.error('❌ Error ensuring authentication token:', error);
|
|
1398
|
+
throw error;
|
|
1399
|
+
}
|
|
1400
|
+
};
|
|
1401
|
+
|
|
1402
|
+
const canProceed = Object.values(platformToggles).some(value => value);
|
|
1403
|
+
|
|
1404
|
+
const handleProceed = () => {
|
|
1405
|
+
if (canProceed) {
|
|
1406
|
+
// Trigger haptic feedback when continue button is pressed
|
|
1407
|
+
triggerHaptic(HapticType.BUTTON_PRESS);
|
|
1408
|
+
|
|
1409
|
+
// ✅ NEW: Start background training when transitioning from connectors to PIN screen
|
|
1410
|
+
console.log('🚀 [TRANSITION] Starting background training during connect → pin transition');
|
|
1411
|
+
startBackgroundTraining().catch(error => {
|
|
1412
|
+
console.error('❌ [TRANSITION] Background training failed during transition:', error);
|
|
1413
|
+
// Continue to PIN screen even if training fails
|
|
1414
|
+
});
|
|
1415
|
+
|
|
1416
|
+
setStep('pin');
|
|
1417
|
+
}
|
|
1418
|
+
};
|
|
1419
|
+
|
|
1420
|
+
const handleReviewerBypass = () => {
|
|
1421
|
+
console.log('Reviewer bypass activated');
|
|
1422
|
+
|
|
1423
|
+
// Set the completion flag BEFORE calling onComplete
|
|
1424
|
+
isCompletingRef.current = true;
|
|
1425
|
+
|
|
1426
|
+
// Call onComplete with a special reviewer token that the parent can recognize
|
|
1427
|
+
onComplete?.('https://api2.onairos.uk', 'reviewer-bypass-token', { email: 'reviewer@apple.com' });
|
|
1428
|
+
};
|
|
1429
|
+
|
|
1430
|
+
// Removed navigation dependency for SDK compatibility
|
|
1431
|
+
|
|
1432
|
+
// Training is now handled by the TrainingModal component
|
|
1433
|
+
|
|
1434
|
+
// ✅ NEW: Background training function - starts when PIN screen appears
|
|
1435
|
+
const startBackgroundTraining = useCallback(async (): Promise<void> => {
|
|
1436
|
+
try {
|
|
1437
|
+
console.log('🚀 [BACKGROUND] Starting background training optimization...');
|
|
1438
|
+
setBackgroundTrainingProgress('Connecting...');
|
|
1439
|
+
|
|
1440
|
+
// Step 1: Ensure authentication token exists
|
|
1441
|
+
const authToken = await ensureAuthToken();
|
|
1442
|
+
if (!authToken) {
|
|
1443
|
+
throw new Error('Failed to create authentication token for background training');
|
|
1444
|
+
}
|
|
1445
|
+
|
|
1446
|
+
console.log('✅ [BACKGROUND] Auth token ready:', `${authToken.substring(0, 20)}...`);
|
|
1447
|
+
setUserToken(authToken);
|
|
1448
|
+
|
|
1449
|
+
// Step 2: Set up user info if not available
|
|
1450
|
+
if (!userInfo) {
|
|
1451
|
+
const storedUsername = await getOnairosUsername();
|
|
1452
|
+
const fallbackUsername = storedUsername || user?.email?.split('@')[0] || user?.name || 'mobile_user';
|
|
1453
|
+
|
|
1454
|
+
const newUserInfo = {
|
|
1455
|
+
username: fallbackUsername,
|
|
1456
|
+
email: user?.email || null,
|
|
1457
|
+
id: null
|
|
1458
|
+
};
|
|
1459
|
+
|
|
1460
|
+
setUserInfo(newUserInfo);
|
|
1461
|
+
setUsername(fallbackUsername);
|
|
1462
|
+
console.log('🧑💻 [BACKGROUND] User info set:', newUserInfo);
|
|
1463
|
+
}
|
|
1464
|
+
|
|
1465
|
+
// Step 3: Initialize socket connection for background training
|
|
1466
|
+
console.log('🔌 [BACKGROUND] Setting up socket for background training...');
|
|
1467
|
+
setBackgroundTrainingProgress('Initializing data collection...');
|
|
1468
|
+
|
|
1469
|
+
const backgroundSocket = io('https://api2.onairos.uk', {
|
|
1470
|
+
transports: ['websocket', 'polling'],
|
|
1471
|
+
autoConnect: false,
|
|
1472
|
+
timeout: 15000,
|
|
1473
|
+
reconnection: true,
|
|
1474
|
+
reconnectionAttempts: 3,
|
|
1475
|
+
reconnectionDelay: 1000,
|
|
1476
|
+
forceNew: true
|
|
1477
|
+
});
|
|
1478
|
+
|
|
1479
|
+
// Set up socket event listeners for background training
|
|
1480
|
+
backgroundSocket.on('connect', async () => {
|
|
1481
|
+
console.log('✅ [BACKGROUND] Socket connected, starting background data collection...');
|
|
1482
|
+
const socketId = backgroundSocket.id;
|
|
1483
|
+
setBackgroundSocketId(socketId || null);
|
|
1484
|
+
setBackgroundTrainingProgress('Collecting your data...');
|
|
1485
|
+
|
|
1486
|
+
if (socketId) {
|
|
1487
|
+
// Step 4: Start background training WITHOUT PIN (per backend instructions)
|
|
1488
|
+
await startBackgroundEnochTraining(socketId, authToken);
|
|
1489
|
+
}
|
|
1490
|
+
});
|
|
1491
|
+
|
|
1492
|
+
backgroundSocket.on('trainingUpdate', (data) => {
|
|
1493
|
+
if (data.progress) {
|
|
1494
|
+
setBackgroundTrainingProgress(data.status || 'Processing...');
|
|
1495
|
+
console.log('📊 [BACKGROUND] Training progress:', data.progress, '%');
|
|
1496
|
+
}
|
|
1497
|
+
});
|
|
1498
|
+
|
|
1499
|
+
backgroundSocket.on('disconnect', () => {
|
|
1500
|
+
console.log('❌ [BACKGROUND] Socket disconnected');
|
|
1501
|
+
});
|
|
1502
|
+
|
|
1503
|
+
// Store socket reference for later use
|
|
1504
|
+
socketRef.current = backgroundSocket;
|
|
1505
|
+
|
|
1506
|
+
// Connect the socket to start background training
|
|
1507
|
+
backgroundSocket.connect();
|
|
1508
|
+
|
|
1509
|
+
console.log('✅ [BACKGROUND] Background training initiated successfully');
|
|
1510
|
+
|
|
1511
|
+
} catch (error) {
|
|
1512
|
+
console.error('❌ [BACKGROUND] Background training failed:', error);
|
|
1513
|
+
setBackgroundTrainingProgress('');
|
|
1514
|
+
throw error;
|
|
1515
|
+
}
|
|
1516
|
+
}, [userInfo, username, user]);
|
|
1517
|
+
|
|
1518
|
+
// ✅ NEW: Background training API call - starts data collection without PIN
|
|
1519
|
+
const startBackgroundEnochTraining = async (socketId: string, authToken: string) => {
|
|
1520
|
+
try {
|
|
1521
|
+
console.log('🚀 [BACKGROUND] Starting background training with socketId:', socketId);
|
|
1522
|
+
console.log('🔑 Using auth token:', `${authToken.substring(0, 20)}...`);
|
|
1523
|
+
|
|
1524
|
+
// Prepare background training data
|
|
1525
|
+
const backgroundData = {
|
|
1526
|
+
socketId,
|
|
1527
|
+
username: userInfo?.username || userInfo?.name || username || 'mobile_user',
|
|
1528
|
+
email: userInfo?.email || null,
|
|
1529
|
+
modelKey: null,
|
|
1530
|
+
connectedPlatforms: [], // No connected platforms for background training
|
|
1531
|
+
platformConnections: {}, // No platform connections for background training
|
|
1532
|
+
// No encrypted PIN for background training
|
|
1533
|
+
};
|
|
1534
|
+
|
|
1535
|
+
console.log('📤 Sending background training data to /mobile-training/enoch:', backgroundData);
|
|
1536
|
+
|
|
1537
|
+
// Use the new training function that includes YouTube migration check
|
|
1538
|
+
const backgroundResult = await startEnochTrainingWithYouTubeCheck(backgroundData);
|
|
1539
|
+
console.log('📡 Background training API response:', backgroundResult);
|
|
1540
|
+
|
|
1541
|
+
// Handle CONNECTIONS_REQUIRED scenario (pre-training validation)
|
|
1542
|
+
if (backgroundResult.requiresConnections || backgroundResult.code === 'CONNECTIONS_REQUIRED') {
|
|
1543
|
+
console.log('🔗 Connections required detected from background training');
|
|
1544
|
+
setDataScenario('CONNECTIONS_REQUIRED');
|
|
1545
|
+
setDataDetails(backgroundResult);
|
|
1546
|
+
setShowDataWarning(true);
|
|
1547
|
+
setPersonaStatus('Connections required');
|
|
1548
|
+
setHasError(true);
|
|
1549
|
+
stopDotsAnimation();
|
|
1550
|
+
return;
|
|
1551
|
+
}
|
|
1552
|
+
|
|
1553
|
+
if (backgroundResult.success) {
|
|
1554
|
+
console.log('🚀 Background training started:', backgroundResult.message);
|
|
1555
|
+
console.log('🎯 Background training Features:', backgroundResult.features);
|
|
1556
|
+
|
|
1557
|
+
// ✅ CRITICAL: Set background training started flag
|
|
1558
|
+
setIsBackgroundTrainingStarted(true);
|
|
1559
|
+
|
|
1560
|
+
// Log the new features from the spec
|
|
1561
|
+
if (backgroundResult.features) {
|
|
1562
|
+
console.log('✅ Inference enabled:', backgroundResult.features.inference);
|
|
1563
|
+
console.log('💾 Storage method:', backgroundResult.features.storage);
|
|
1564
|
+
console.log('🔒 Compression enabled:', backgroundResult.features.compression);
|
|
1565
|
+
console.log('🔐 Encryption enabled:', backgroundResult.features.encryption);
|
|
1566
|
+
console.log('📊 Training type:', backgroundResult.features.type);
|
|
1567
|
+
console.log('🗄️ Databases:', backgroundResult.features.databases);
|
|
1568
|
+
console.log('📈 Query scores enabled:', backgroundResult.features.queryScores);
|
|
1569
|
+
}
|
|
1570
|
+
|
|
1571
|
+
setPersonaStatus('Background training model...');
|
|
1572
|
+
setPersonaProgress(25);
|
|
1573
|
+
} else {
|
|
1574
|
+
console.error('❌ Background training start failed:', backgroundResult.error);
|
|
1575
|
+
setPersonaStatus(`Error: ${backgroundResult.error || 'Background training failed to start'}`);
|
|
1576
|
+
setHasError(true);
|
|
1577
|
+
stopDotsAnimation();
|
|
1578
|
+
}
|
|
1579
|
+
} catch (error) {
|
|
1580
|
+
console.error('❌ Background training start error:', error);
|
|
1581
|
+
setPersonaStatus(`Error: ${error instanceof Error ? error.message : 'Unknown error'}`);
|
|
1582
|
+
setHasError(true);
|
|
1583
|
+
stopDotsAnimation();
|
|
1584
|
+
}
|
|
1585
|
+
};
|
|
1586
|
+
|
|
1587
|
+
return (
|
|
1588
|
+
<Modal
|
|
1589
|
+
transparent={true}
|
|
1590
|
+
visible={modalVisible}
|
|
1591
|
+
animationType="none"
|
|
1592
|
+
onRequestClose={handleClose}
|
|
1593
|
+
>
|
|
1594
|
+
<View style={styles.modalOverlay}>
|
|
1595
|
+
<Animated.View
|
|
1596
|
+
style={[
|
|
1597
|
+
styles.bottomSheet,
|
|
1598
|
+
{ transform: [{ translateY: slideAnim }] },
|
|
1599
|
+
]}
|
|
1600
|
+
>
|
|
1601
|
+
<SafeAreaView style={styles.container}>
|
|
1602
|
+
<View style={styles.handleContainer}>
|
|
1603
|
+
<TouchableOpacity onPress={handleClose} style={styles.handleButton}>
|
|
1604
|
+
<View style={styles.handle} />
|
|
1605
|
+
</TouchableOpacity>
|
|
1606
|
+
</View>
|
|
1607
|
+
|
|
1608
|
+
{step === 'connect' && (
|
|
1609
|
+
<View style={styles.connectContainer}>
|
|
1610
|
+
<View style={styles.header}>
|
|
1611
|
+
<View style={styles.headerContent}>
|
|
1612
|
+
<View style={styles.appIcon}>
|
|
1613
|
+
<Text style={styles.appIconText}>O</Text>
|
|
1614
|
+
</View>
|
|
1615
|
+
<Text style={styles.arrow}>→</Text>
|
|
1616
|
+
<View style={styles.onairosIcon}>
|
|
1617
|
+
<Image
|
|
1618
|
+
source={require('../assets/images/Enochicon1.png')}
|
|
1619
|
+
style={styles.onairosIconImage}
|
|
1620
|
+
resizeMode="contain"
|
|
1621
|
+
/>
|
|
1622
|
+
</View>
|
|
1623
|
+
</View>
|
|
1624
|
+
<View style={styles.titleContainer}>
|
|
1625
|
+
<Text style={styles.mainTitle}>
|
|
1626
|
+
{isExistingUser ? 'Add More Data to Enoch' : 'Connect your platforms to Enoch via Onairos'}
|
|
1627
|
+
</Text>
|
|
1628
|
+
<Text style={styles.privacyMessage}>
|
|
1629
|
+
{isExistingUser
|
|
1630
|
+
? 'Connect additional accounts to enhance your digital personality. Your privacy is ensured.'
|
|
1631
|
+
: 'Connect one account to get started. Each additional connection improves your match quality. Your privacy is ensured.'
|
|
1632
|
+
}{' '}
|
|
1633
|
+
<Text
|
|
1634
|
+
style={styles.privacyLink}
|
|
1635
|
+
onPress={() => setStep('privacy')}
|
|
1636
|
+
>
|
|
1637
|
+
How it's used →
|
|
1638
|
+
</Text>
|
|
1639
|
+
</Text>
|
|
1640
|
+
|
|
1641
|
+
{/* Existing User Info Banner */}
|
|
1642
|
+
{isExistingUser && existingUserInfo && (
|
|
1643
|
+
<View style={styles.existingUserBanner}>
|
|
1644
|
+
<Text style={styles.existingUserText}>
|
|
1645
|
+
✅ You already have {existingUserInfo.existingUserData?.summary?.connectionsCount || 0} connections
|
|
1646
|
+
</Text>
|
|
1647
|
+
<Text style={styles.existingUserSubtext}>
|
|
1648
|
+
Add more platforms to get even better insights
|
|
1649
|
+
</Text>
|
|
1650
|
+
</View>
|
|
1651
|
+
)}
|
|
1652
|
+
{connectionStatuses['linkedin'] === 'connected' &&
|
|
1653
|
+
Object.values(connectionStatuses).filter(status => status === 'connected').length === 1 && (
|
|
1654
|
+
<View style={styles.linkedinRequirementContainer}>
|
|
1655
|
+
<Text style={styles.linkedinRequirementText}>
|
|
1656
|
+
<Text style={styles.linkedinRequirementAsterisk}>*</Text>
|
|
1657
|
+
<Text style={styles.linkedinRequirementMessage}> LinkedIn requires pairing with an additional platform for optimal results</Text>
|
|
1658
|
+
</Text>
|
|
1659
|
+
</View>
|
|
1660
|
+
)}
|
|
1661
|
+
</View>
|
|
1662
|
+
</View>
|
|
1663
|
+
|
|
1664
|
+
<View
|
|
1665
|
+
style={{
|
|
1666
|
+
height: 1,
|
|
1667
|
+
backgroundColor: '#CCCCCC',
|
|
1668
|
+
width: '100%',
|
|
1669
|
+
marginVertical: 0,
|
|
1670
|
+
}}
|
|
1671
|
+
/>
|
|
1672
|
+
|
|
1673
|
+
<ScrollView
|
|
1674
|
+
ref={scrollViewRef}
|
|
1675
|
+
style={styles.platformsScrollView}
|
|
1676
|
+
contentContainerStyle={styles.platformsScrollContent}
|
|
1677
|
+
showsVerticalScrollIndicator={true}
|
|
1678
|
+
bounces={true}
|
|
1679
|
+
alwaysBounceVertical={true}
|
|
1680
|
+
indicatorStyle="black"
|
|
1681
|
+
scrollEventThrottle={16}
|
|
1682
|
+
directionalLockEnabled={true}
|
|
1683
|
+
keyboardShouldPersistTaps="handled"
|
|
1684
|
+
decelerationRate="normal"
|
|
1685
|
+
contentOffset={{ x: 0, y: 60 }}
|
|
1686
|
+
>
|
|
1687
|
+
<View style={styles.platformsContainer}>
|
|
1688
|
+
{primaryAuthOnly ? (
|
|
1689
|
+
// Only show email option when primaryAuthOnly is true
|
|
1690
|
+
<View style={styles.platformItem}>
|
|
1691
|
+
<View style={styles.platformInfo}>
|
|
1692
|
+
<View style={[styles.platformIcon, { backgroundColor: '#4285F4' }]}>
|
|
1693
|
+
<Text style={styles.platformIconText}>@</Text>
|
|
1694
|
+
</View>
|
|
1695
|
+
<Text style={styles.platformName}>Email</Text>
|
|
1696
|
+
</View>
|
|
1697
|
+
|
|
1698
|
+
<TouchableOpacity
|
|
1699
|
+
onPress={async () => {
|
|
1700
|
+
// Trigger haptic feedback when sign in button is pressed
|
|
1701
|
+
triggerHaptic(HapticType.BUTTON_PRESS);
|
|
1702
|
+
|
|
1703
|
+
// Mark email as connected for primaryAuth flow
|
|
1704
|
+
setConnections(prev => ({
|
|
1705
|
+
...prev,
|
|
1706
|
+
email: { userName: email || 'user@example.com', connected: true }
|
|
1707
|
+
}));
|
|
1708
|
+
setConnectionStatuses(prev => ({
|
|
1709
|
+
...prev,
|
|
1710
|
+
email: 'connected'
|
|
1711
|
+
}));
|
|
1712
|
+
setPlatformToggles(prev => ({
|
|
1713
|
+
...prev,
|
|
1714
|
+
email: true
|
|
1715
|
+
}));
|
|
1716
|
+
|
|
1717
|
+
// Store the connected platform
|
|
1718
|
+
await storeConnectedPlatform('email');
|
|
1719
|
+
|
|
1720
|
+
setStep('connections');
|
|
1721
|
+
}}
|
|
1722
|
+
style={[
|
|
1723
|
+
styles.footerButtonConfirm,
|
|
1724
|
+
{ paddingVertical: 8, paddingHorizontal: 16 }
|
|
1725
|
+
]}
|
|
1726
|
+
>
|
|
1727
|
+
<Text style={styles.footerButtonTextConfirm}>
|
|
1728
|
+
Sign in
|
|
1729
|
+
</Text>
|
|
1730
|
+
</TouchableOpacity>
|
|
1731
|
+
</View>
|
|
1732
|
+
) : (
|
|
1733
|
+
// Show main platforms first
|
|
1734
|
+
<>
|
|
1735
|
+
{mainPlatforms.map(platform => {
|
|
1736
|
+
const isConnected = connectionStatuses[platform.id] === 'connected';
|
|
1737
|
+
const isPlatformConnecting = connectingPlatform === platform.id;
|
|
1738
|
+
|
|
1739
|
+
return (
|
|
1740
|
+
<View key={platform.id} style={styles.platformItem}>
|
|
1741
|
+
<View style={styles.platformInfo}>
|
|
1742
|
+
{platform.id === 'linkedin' ? (
|
|
1743
|
+
// Use square container for LinkedIn
|
|
1744
|
+
<View style={[styles.linkedinPlatformIcon, { backgroundColor: platform.color }]}>
|
|
1745
|
+
<Image
|
|
1746
|
+
source={getPlatformIcon(platform.id)}
|
|
1747
|
+
style={styles.platformIconImage}
|
|
1748
|
+
resizeMode="contain"
|
|
1749
|
+
/>
|
|
1750
|
+
</View>
|
|
1751
|
+
) : platform.id === 'pinterest' ? (
|
|
1752
|
+
// Use smaller circular container for Pinterest
|
|
1753
|
+
<View style={[styles.pinterestPlatformIcon, { backgroundColor: platform.color }]}>
|
|
1754
|
+
<Image
|
|
1755
|
+
source={getPlatformIcon(platform.id)}
|
|
1756
|
+
style={styles.pinterestIconImage}
|
|
1757
|
+
resizeMode="contain"
|
|
1758
|
+
/>
|
|
1759
|
+
</View>
|
|
1760
|
+
) : (
|
|
1761
|
+
<View style={[styles.platformIcon, { backgroundColor: platform.color }]}>
|
|
1762
|
+
<Image
|
|
1763
|
+
source={getPlatformIcon(platform.id)}
|
|
1764
|
+
style={
|
|
1765
|
+
platform.id === 'youtube' ? styles.youtubeIconImage :
|
|
1766
|
+
styles.platformIconImage
|
|
1767
|
+
}
|
|
1768
|
+
resizeMode="contain"
|
|
1769
|
+
/>
|
|
1770
|
+
</View>
|
|
1771
|
+
)}
|
|
1772
|
+
<Text style={styles.platformName}>
|
|
1773
|
+
{platform.name}
|
|
1774
|
+
{platform.id === 'linkedin' && connectionStatuses['linkedin'] === 'connected' &&
|
|
1775
|
+
Object.values(connectionStatuses).filter(status => status === 'connected').length === 1 && <Text style={styles.asterisk}>*</Text>}
|
|
1776
|
+
</Text>
|
|
1777
|
+
</View>
|
|
1778
|
+
|
|
1779
|
+
<TouchableOpacity
|
|
1780
|
+
onPress={() => {
|
|
1781
|
+
if (isConnected) {
|
|
1782
|
+
// Handle disconnect
|
|
1783
|
+
handleDisconnectPlatform(platform.id, platform.name);
|
|
1784
|
+
} else {
|
|
1785
|
+
// Handle connect
|
|
1786
|
+
handleConnectPlatform(platform.id);
|
|
1787
|
+
}
|
|
1788
|
+
}}
|
|
1789
|
+
onLongPress={platform.id === 'youtube' ? () => {
|
|
1790
|
+
// Start a timer for haptic feedback at 2 seconds
|
|
1791
|
+
const hapticTimer = setTimeout(() => {
|
|
1792
|
+
// Provide haptic feedback
|
|
1793
|
+
Vibration.vibrate(100);
|
|
1794
|
+
}, 2000);
|
|
1795
|
+
|
|
1796
|
+
// Start a timer for 4 seconds for the bypass
|
|
1797
|
+
const bypassTimer = setTimeout(() => {
|
|
1798
|
+
handleReviewerBypass();
|
|
1799
|
+
}, 4000);
|
|
1800
|
+
|
|
1801
|
+
// Store the timer
|
|
1802
|
+
setLongPressTimer(bypassTimer);
|
|
1803
|
+
} : undefined}
|
|
1804
|
+
onPressOut={platform.id === 'youtube' ? () => {
|
|
1805
|
+
// Clear the timer if the press is released before 4 seconds
|
|
1806
|
+
if (longPressTimer) {
|
|
1807
|
+
clearTimeout(longPressTimer);
|
|
1808
|
+
setLongPressTimer(null);
|
|
1809
|
+
}
|
|
1810
|
+
} : undefined}
|
|
1811
|
+
style={[
|
|
1812
|
+
isConnected ? styles.footerButtonConnected : styles.footerButtonConfirm,
|
|
1813
|
+
{ paddingVertical: 8, paddingHorizontal: 16 }
|
|
1814
|
+
]}
|
|
1815
|
+
disabled={isPlatformConnecting}
|
|
1816
|
+
>
|
|
1817
|
+
{isPlatformConnecting ? (
|
|
1818
|
+
<ActivityIndicator size="small" color="#fff" />
|
|
1819
|
+
) : (
|
|
1820
|
+
<Text style={isConnected ? styles.footerButtonTextConnected : styles.footerButtonTextConfirm}>
|
|
1821
|
+
{isConnected ? 'Connected' : 'Connect'}
|
|
1822
|
+
</Text>
|
|
1823
|
+
)}
|
|
1824
|
+
</TouchableOpacity>
|
|
1825
|
+
</View>
|
|
1826
|
+
);
|
|
1827
|
+
})}
|
|
1828
|
+
|
|
1829
|
+
{/* Add additional platforms toggle button */}
|
|
1830
|
+
<TouchableOpacity
|
|
1831
|
+
style={styles.additionalPlatformsToggle}
|
|
1832
|
+
onPress={() => {
|
|
1833
|
+
triggerHaptic(HapticType.BUTTON_PRESS);
|
|
1834
|
+
const newShowState = !showAdditionalPlatforms;
|
|
1835
|
+
|
|
1836
|
+
if (newShowState) {
|
|
1837
|
+
// Expanding - show platforms first, then animate in and scroll
|
|
1838
|
+
setShowAdditionalPlatforms(true);
|
|
1839
|
+
Animated.timing(additionalPlatformsOpacity, {
|
|
1840
|
+
toValue: 1,
|
|
1841
|
+
duration: 300,
|
|
1842
|
+
useNativeDriver: true,
|
|
1843
|
+
}).start();
|
|
1844
|
+
|
|
1845
|
+
// Auto-scroll to reveal additional platforms when expanding
|
|
1846
|
+
setTimeout(() => {
|
|
1847
|
+
scrollViewRef.current?.scrollTo({
|
|
1848
|
+
y: 220, // Scroll down to reveal additional platforms and hint at Gmail
|
|
1849
|
+
animated: true,
|
|
1850
|
+
});
|
|
1851
|
+
}, 100);
|
|
1852
|
+
} else {
|
|
1853
|
+
// Collapsing - animate out first, then hide platforms and scroll back up
|
|
1854
|
+
Animated.timing(additionalPlatformsOpacity, {
|
|
1855
|
+
toValue: 0,
|
|
1856
|
+
duration: 300,
|
|
1857
|
+
useNativeDriver: true,
|
|
1858
|
+
}).start(() => {
|
|
1859
|
+
setShowAdditionalPlatforms(false);
|
|
1860
|
+
});
|
|
1861
|
+
|
|
1862
|
+
// Scroll back up smoothly when collapsing
|
|
1863
|
+
setTimeout(() => {
|
|
1864
|
+
scrollViewRef.current?.scrollTo({
|
|
1865
|
+
y: 0, // Scroll back to top
|
|
1866
|
+
animated: true,
|
|
1867
|
+
});
|
|
1868
|
+
}, 100);
|
|
1869
|
+
}
|
|
1870
|
+
}}
|
|
1871
|
+
>
|
|
1872
|
+
<Text style={styles.additionalPlatformsText}>
|
|
1873
|
+
{showAdditionalPlatforms ? '− Hide additional platforms' : '+ Add additional platforms'}
|
|
1874
|
+
</Text>
|
|
1875
|
+
</TouchableOpacity>
|
|
1876
|
+
|
|
1877
|
+
{/* Show additional platforms when expanded */}
|
|
1878
|
+
{showAdditionalPlatforms && (
|
|
1879
|
+
<Animated.View style={{ opacity: additionalPlatformsOpacity }}>
|
|
1880
|
+
{additionalPlatforms.map(platform => {
|
|
1881
|
+
const isConnected = connectionStatuses[platform.id] === 'connected';
|
|
1882
|
+
const isPlatformConnecting = connectingPlatform === platform.id;
|
|
1883
|
+
|
|
1884
|
+
return (
|
|
1885
|
+
<View key={platform.id} style={styles.platformItem}>
|
|
1886
|
+
<View style={styles.platformInfo}>
|
|
1887
|
+
{platform.id === 'gmail' ? (
|
|
1888
|
+
// Use the same wrapper for size/centering, but transparent background
|
|
1889
|
+
<View style={[styles.platformIcon, { backgroundColor: 'transparent' }]}>
|
|
1890
|
+
<Image
|
|
1891
|
+
source={getPlatformIcon(platform.id)}
|
|
1892
|
+
style={styles.gmailIconImage}
|
|
1893
|
+
resizeMode="contain"
|
|
1894
|
+
/>
|
|
1895
|
+
</View>
|
|
1896
|
+
) : (
|
|
1897
|
+
<View style={[styles.platformIcon, { backgroundColor: platform.color }]}>
|
|
1898
|
+
<Image
|
|
1899
|
+
source={getPlatformIcon(platform.id)}
|
|
1900
|
+
style={
|
|
1901
|
+
platform.id === 'reddit' ? styles.redditIconImage :
|
|
1902
|
+
styles.platformIconImage
|
|
1903
|
+
}
|
|
1904
|
+
resizeMode="contain"
|
|
1905
|
+
/>
|
|
1906
|
+
</View>
|
|
1907
|
+
)}
|
|
1908
|
+
<Text style={styles.platformName}>{platform.name}</Text>
|
|
1909
|
+
</View>
|
|
1910
|
+
|
|
1911
|
+
<TouchableOpacity
|
|
1912
|
+
onPress={() => {
|
|
1913
|
+
if (isConnected) {
|
|
1914
|
+
// Handle disconnect
|
|
1915
|
+
handleDisconnectPlatform(platform.id, platform.name);
|
|
1916
|
+
} else {
|
|
1917
|
+
// Handle connect
|
|
1918
|
+
handleConnectPlatform(platform.id);
|
|
1919
|
+
}
|
|
1920
|
+
}}
|
|
1921
|
+
style={[
|
|
1922
|
+
isConnected ? styles.footerButtonConnected : styles.footerButtonConfirm,
|
|
1923
|
+
{ paddingVertical: 8, paddingHorizontal: 16 }
|
|
1924
|
+
]}
|
|
1925
|
+
disabled={isPlatformConnecting}
|
|
1926
|
+
>
|
|
1927
|
+
{isPlatformConnecting ? (
|
|
1928
|
+
<ActivityIndicator size="small" color="#fff" />
|
|
1929
|
+
) : (
|
|
1930
|
+
<Text style={isConnected ? styles.footerButtonTextConnected : styles.footerButtonTextConfirm}>
|
|
1931
|
+
{isConnected ? 'Connected' : 'Connect'}
|
|
1932
|
+
</Text>
|
|
1933
|
+
)}
|
|
1934
|
+
</TouchableOpacity>
|
|
1935
|
+
</View>
|
|
1936
|
+
);
|
|
1937
|
+
})}
|
|
1938
|
+
</Animated.View>
|
|
1939
|
+
)}
|
|
1940
|
+
</>
|
|
1941
|
+
)}
|
|
1942
|
+
</View>
|
|
1943
|
+
</ScrollView>
|
|
1944
|
+
|
|
1945
|
+
<View style={styles.footer}>
|
|
1946
|
+
<TouchableOpacity
|
|
1947
|
+
style={styles.footerButtonCancel}
|
|
1948
|
+
onPress={handleClose}
|
|
1949
|
+
>
|
|
1950
|
+
<Text style={styles.footerButtonText}>Cancel</Text>
|
|
1951
|
+
</TouchableOpacity>
|
|
1952
|
+
|
|
1953
|
+
<TouchableOpacity
|
|
1954
|
+
style={[
|
|
1955
|
+
styles.footerButtonConfirm,
|
|
1956
|
+
!canProceed && styles.footerButtonDisabled,
|
|
1957
|
+
]}
|
|
1958
|
+
onPress={handleProceed}
|
|
1959
|
+
disabled={!canProceed}
|
|
1960
|
+
>
|
|
1961
|
+
<Text style={styles.footerButtonTextConfirm}>Continue</Text>
|
|
1962
|
+
</TouchableOpacity>
|
|
1963
|
+
</View>
|
|
1964
|
+
</View>
|
|
1965
|
+
)}
|
|
1966
|
+
|
|
1967
|
+
{step === 'pin' && (
|
|
1968
|
+
<PinInput
|
|
1969
|
+
onSubmit={handlePinSubmit}
|
|
1970
|
+
minLength={8}
|
|
1971
|
+
requireSpecialChar
|
|
1972
|
+
requireNumber
|
|
1973
|
+
onBack={() => setStep('connect')}
|
|
1974
|
+
enableBiometricStorage={true}
|
|
1975
|
+
// ✅ REMOVED: Background training now starts during transition, not on component mount
|
|
1976
|
+
// onBackgroundTrainingStart={startBackgroundTraining}
|
|
1977
|
+
showBackgroundProgress={true}
|
|
1978
|
+
backgroundProgressText={backgroundTrainingProgress || "Training is starting in the background..."}
|
|
1979
|
+
/>
|
|
1980
|
+
)}
|
|
1981
|
+
|
|
1982
|
+
{step === 'persona' && (
|
|
1983
|
+
<View style={styles.personaContainer}>
|
|
1984
|
+
<View style={styles.personaHeaderWithBack}>
|
|
1985
|
+
<TouchableOpacity
|
|
1986
|
+
style={[
|
|
1987
|
+
styles.personaBackButton,
|
|
1988
|
+
// Highlight the back button when there's insufficient data
|
|
1989
|
+
(dataScenario === 'NO_DATA' || dataScenario === 'CONNECTIONS_REQUIRED') && styles.highlightedBackButton
|
|
1990
|
+
]}
|
|
1991
|
+
onPress={() => setStep('connect')} // Changed from 'pin' to 'connect' to go back to platform connections
|
|
1992
|
+
>
|
|
1993
|
+
<Text style={[
|
|
1994
|
+
{ fontSize: 24 },
|
|
1995
|
+
// Make the arrow more prominent when insufficient data
|
|
1996
|
+
(dataScenario === 'NO_DATA' || dataScenario === 'CONNECTIONS_REQUIRED') && styles.highlightedBackArrow
|
|
1997
|
+
]}>←</Text>
|
|
1998
|
+
</TouchableOpacity>
|
|
1999
|
+
<Text style={styles.personaTitle}>
|
|
2000
|
+
{isPersonaComplete ? 'Your persona is ready! 🎉' : 'Creating your persona'}
|
|
2001
|
+
</Text>
|
|
2002
|
+
</View>
|
|
2003
|
+
<Text style={styles.personaSubtitle}>
|
|
2004
|
+
{isPersonaComplete
|
|
2005
|
+
? 'We\'ve created a personalized experience just for you.'
|
|
2006
|
+
: 'This will only take a moment. We\'re personalizing your experience.'
|
|
2007
|
+
}
|
|
2008
|
+
</Text>
|
|
2009
|
+
|
|
2010
|
+
<View style={styles.personaProgressContainer}>
|
|
2011
|
+
<View style={styles.personaProgressBar}>
|
|
2012
|
+
<View
|
|
2013
|
+
style={[
|
|
2014
|
+
styles.personaProgressFill,
|
|
2015
|
+
{ width: `${personaProgress}%` },
|
|
2016
|
+
hasError && styles.progressError
|
|
2017
|
+
]}
|
|
2018
|
+
/>
|
|
2019
|
+
</View>
|
|
2020
|
+
<Text style={styles.personaProgressText}>{Math.round(personaProgress)}%</Text>
|
|
2021
|
+
{!isPersonaComplete && (
|
|
2022
|
+
<Text style={styles.personaStatusText}>{getPersonaStatusMessage(personaProgress)}</Text>
|
|
2023
|
+
)}
|
|
2024
|
+
</View>
|
|
2025
|
+
|
|
2026
|
+
{/* Data Warning Component */}
|
|
2027
|
+
{showDataWarning && dataScenario && (
|
|
2028
|
+
<View style={[
|
|
2029
|
+
styles.dataWarningContainer,
|
|
2030
|
+
(dataScenario === 'NO_DATA' || dataScenario === 'CONNECTIONS_REQUIRED') ? styles.dataConnectionsRequired : styles.dataInfoContainer
|
|
2031
|
+
]}>
|
|
2032
|
+
<View style={styles.dataWarningHeader}>
|
|
2033
|
+
<Text style={styles.dataWarningIcon}>
|
|
2034
|
+
{(dataScenario === 'NO_DATA' || dataScenario === 'CONNECTIONS_REQUIRED') ? '‼️' : 'ℹ️'}
|
|
2035
|
+
</Text>
|
|
2036
|
+
<Text style={[
|
|
2037
|
+
styles.dataWarningTitle,
|
|
2038
|
+
{ color: (dataScenario === 'NO_DATA' || dataScenario === 'CONNECTIONS_REQUIRED') ? '#000000' : '#0369A1' }
|
|
2039
|
+
]}>
|
|
2040
|
+
{dataScenario === 'CONNECTIONS_REQUIRED'
|
|
2041
|
+
? 'Not enough data to personalize your experience'
|
|
2042
|
+
: dataScenario === 'NO_DATA'
|
|
2043
|
+
? 'Not enough data to personalize your experience'
|
|
2044
|
+
: 'Working with your available data'
|
|
2045
|
+
}
|
|
2046
|
+
</Text>
|
|
2047
|
+
</View>
|
|
2048
|
+
|
|
2049
|
+
<Text style={[
|
|
2050
|
+
styles.dataWarningMessage,
|
|
2051
|
+
{ color: (dataScenario === 'NO_DATA' || dataScenario === 'CONNECTIONS_REQUIRED') ? '#374151' : '#0C4A6E' }
|
|
2052
|
+
]}>
|
|
2053
|
+
{dataScenario === 'CONNECTIONS_REQUIRED'
|
|
2054
|
+
? 'To provide the best experience possible, please go back and add an additional platform.'
|
|
2055
|
+
: dataScenario === 'NO_DATA'
|
|
2056
|
+
? 'To provide the best experience possible, please go back and add an additional platform.'
|
|
2057
|
+
: 'We\'re building your persona with the information currently available.'
|
|
2058
|
+
}
|
|
2059
|
+
</Text>
|
|
2060
|
+
|
|
2061
|
+
{/* Add back button call-to-action for NO_DATA and CONNECTIONS_REQUIRED scenarios */}
|
|
2062
|
+
{(dataScenario === 'NO_DATA' || dataScenario === 'CONNECTIONS_REQUIRED') && (
|
|
2063
|
+
<TouchableOpacity
|
|
2064
|
+
style={styles.goBackButton}
|
|
2065
|
+
onPress={() => setStep('connect')}
|
|
2066
|
+
activeOpacity={0.8}
|
|
2067
|
+
>
|
|
2068
|
+
<Text style={styles.goBackButtonText}>← Add another platform</Text>
|
|
2069
|
+
</TouchableOpacity>
|
|
2070
|
+
)}
|
|
2071
|
+
|
|
2072
|
+
{dataDetails?.suggestions && dataScenario !== 'NO_DATA' && (
|
|
2073
|
+
<View style={[
|
|
2074
|
+
styles.dataWarningSuggestions,
|
|
2075
|
+
{ borderTopColor: 'rgba(3, 105, 161, 0.2)' }
|
|
2076
|
+
]}>
|
|
2077
|
+
<Text style={[
|
|
2078
|
+
styles.dataWarningSuggestionsTitle,
|
|
2079
|
+
{ color: '#0369A1' }
|
|
2080
|
+
]}>
|
|
2081
|
+
For higher model quality:
|
|
2082
|
+
</Text>
|
|
2083
|
+
{dataDetails.suggestions.slice(0, 2).map((suggestion: string, index: number) => {
|
|
2084
|
+
// Override specific suggestions with new text
|
|
2085
|
+
let displayText = suggestion;
|
|
2086
|
+
if (suggestion.toLowerCase().includes('better model quality') ||
|
|
2087
|
+
suggestion.toLowerCase().includes('interact with more content')) {
|
|
2088
|
+
displayText = 'Connect additional platforms';
|
|
2089
|
+
} else if (suggestion.toLowerCase().includes('like/dislike more videos') ||
|
|
2090
|
+
suggestion.toLowerCase().includes('posts, or content')) {
|
|
2091
|
+
displayText = 'Interact and generate more content (like/dislike more videos, etc.)';
|
|
2092
|
+
}
|
|
2093
|
+
|
|
2094
|
+
return (
|
|
2095
|
+
<Text key={index} style={[
|
|
2096
|
+
styles.dataWarningSuggestionItem,
|
|
2097
|
+
{ color: '#0C4A6E' }
|
|
2098
|
+
]}>
|
|
2099
|
+
• {displayText}
|
|
2100
|
+
</Text>
|
|
2101
|
+
);
|
|
2102
|
+
})}
|
|
2103
|
+
</View>
|
|
2104
|
+
)}
|
|
2105
|
+
|
|
2106
|
+
{dataScenario === 'LIMITED_DATA' && (
|
|
2107
|
+
<Text style={[
|
|
2108
|
+
styles.dataWarningContinueNote,
|
|
2109
|
+
{ color: '#0369A1' }
|
|
2110
|
+
]}>
|
|
2111
|
+
|
|
2112
|
+
</Text>
|
|
2113
|
+
)}
|
|
2114
|
+
</View>
|
|
2115
|
+
)}
|
|
2116
|
+
|
|
2117
|
+
{/* YouTube Reconnection Indicator */}
|
|
2118
|
+
{personaStatus.includes('YouTube token expired') && (
|
|
2119
|
+
<View style={[styles.dataWarningContainer, styles.dataInfoContainer]}>
|
|
2120
|
+
<View style={styles.dataWarningHeader}>
|
|
2121
|
+
<Text style={styles.dataWarningIcon}>🔄</Text>
|
|
2122
|
+
<Text style={[styles.dataWarningTitle, { color: '#0369A1' }]}>
|
|
2123
|
+
Refreshing YouTube connection
|
|
2124
|
+
</Text>
|
|
2125
|
+
</View>
|
|
2126
|
+
<Text style={[styles.dataWarningMessage, { color: '#0C4A6E' }]}>
|
|
2127
|
+
Your YouTube access expired. We're automatically reconnecting...
|
|
2128
|
+
</Text>
|
|
2129
|
+
</View>
|
|
2130
|
+
)}
|
|
2131
|
+
|
|
2132
|
+
{isPersonaComplete && (
|
|
2133
|
+
<View style={styles.personaCompleteContainer}>
|
|
2134
|
+
<TouchableOpacity
|
|
2135
|
+
style={styles.personaContinueButton}
|
|
2136
|
+
onPress={() => {
|
|
2137
|
+
console.log('🎯 Continue button pressed - completing onboarding');
|
|
2138
|
+
handlePersonaComplete();
|
|
2139
|
+
}}
|
|
2140
|
+
activeOpacity={0.8}
|
|
2141
|
+
>
|
|
2142
|
+
<Text style={styles.personaContinueButtonText}>Continue</Text>
|
|
2143
|
+
</TouchableOpacity>
|
|
2144
|
+
</View>
|
|
2145
|
+
)}
|
|
2146
|
+
|
|
2147
|
+
{hasError && !isPersonaComplete && !showDataWarning && (
|
|
2148
|
+
<View style={styles.personaCompleteContainer}>
|
|
2149
|
+
<Text style={styles.personaCompleteTitle}>Something went wrong</Text>
|
|
2150
|
+
<Text style={styles.personaCompleteSubtitle}>
|
|
2151
|
+
Please try again or contact support if the issue persists.
|
|
2152
|
+
</Text>
|
|
2153
|
+
<TouchableOpacity
|
|
2154
|
+
style={[styles.personaContinueButton, { backgroundColor: '#FF3B30' }]}
|
|
2155
|
+
onPress={() => {
|
|
2156
|
+
console.log('🔄 Retry button pressed - redirecting to connector screen');
|
|
2157
|
+
setHasError(false);
|
|
2158
|
+
// ❌ DISABLED: Don't start new training on retry
|
|
2159
|
+
// Training should only start during connector→PIN transition
|
|
2160
|
+
// startPersonaCreation();
|
|
2161
|
+
|
|
2162
|
+
// Instead, go back to connector screen so user can restart proper flow
|
|
2163
|
+
setStep('connect');
|
|
2164
|
+
setPersonaStatus('Initializing');
|
|
2165
|
+
setPersonaProgress(0);
|
|
2166
|
+
}}
|
|
2167
|
+
activeOpacity={0.8}
|
|
2168
|
+
>
|
|
2169
|
+
<Text style={styles.personaContinueButtonText}>Restart</Text>
|
|
2170
|
+
</TouchableOpacity>
|
|
2171
|
+
</View>
|
|
2172
|
+
)}
|
|
2173
|
+
</View>
|
|
2174
|
+
)}
|
|
2175
|
+
|
|
2176
|
+
|
|
2177
|
+
|
|
2178
|
+
{step === 'oauth' && oauthUrl && (
|
|
2179
|
+
<View style={{ marginTop: -17 }}>
|
|
2180
|
+
<OAuthWebView
|
|
2181
|
+
url={oauthUrl}
|
|
2182
|
+
platform={currentPlatform}
|
|
2183
|
+
onClose={() => {
|
|
2184
|
+
setStep('connect');
|
|
2185
|
+
setOauthUrl('');
|
|
2186
|
+
}}
|
|
2187
|
+
onSuccess={handleOAuthSuccess}
|
|
2188
|
+
onComplete={() => setStep('connect')}
|
|
2189
|
+
/>
|
|
2190
|
+
</View>
|
|
2191
|
+
)}
|
|
2192
|
+
|
|
2193
|
+
{step === 'privacy' && (
|
|
2194
|
+
<View style={styles.modalContent}>
|
|
2195
|
+
<View style={styles.privacyHeader}>
|
|
2196
|
+
<TouchableOpacity
|
|
2197
|
+
style={styles.backButton}
|
|
2198
|
+
onPress={() => setStep('connect')}
|
|
2199
|
+
>
|
|
2200
|
+
<Text style={styles.backButtonText}>←</Text>
|
|
2201
|
+
</TouchableOpacity>
|
|
2202
|
+
<Text style={styles.headerTitle}>How Enoch uses personal data</Text>
|
|
2203
|
+
<View style={styles.backButtonSpacer} />
|
|
2204
|
+
</View>
|
|
2205
|
+
|
|
2206
|
+
<View style={styles.privacyDetailsContainer}>
|
|
2207
|
+
<Text style={styles.privacyDetailsTitle}></Text>
|
|
2208
|
+
|
|
2209
|
+
<View style={styles.privacyBulletPoint}>
|
|
2210
|
+
<Text style={styles.bulletPoint}>•</Text>
|
|
2211
|
+
<Text style={styles.privacyBulletText}>
|
|
2212
|
+
Enoch legally accesses your platform data with explicit permission for this event only - never stored post-session and auto-deleted.
|
|
2213
|
+
</Text>
|
|
2214
|
+
</View>
|
|
2215
|
+
|
|
2216
|
+
<View style={styles.privacyBulletPoint}>
|
|
2217
|
+
<Text style={styles.bulletPoint}>•</Text>
|
|
2218
|
+
<Text style={styles.privacyBulletText}>
|
|
2219
|
+
Enoch NEVER sells your data. You are a user, not a commodity.
|
|
2220
|
+
</Text>
|
|
2221
|
+
</View>
|
|
2222
|
+
|
|
2223
|
+
<View style={styles.privacyBulletPoint}>
|
|
2224
|
+
<Text style={styles.bulletPoint}>•</Text>
|
|
2225
|
+
<Text style={styles.privacyBulletText}>
|
|
2226
|
+
Data collected builds your Onairos persona, enabling personalized experiences across future products while prioritizing your data sovereignty.
|
|
2227
|
+
</Text>
|
|
2228
|
+
</View>
|
|
2229
|
+
</View>
|
|
2230
|
+
|
|
2231
|
+
<TouchableOpacity
|
|
2232
|
+
style={styles.footerButtonConfirm}
|
|
2233
|
+
onPress={() => {
|
|
2234
|
+
triggerHaptic(HapticType.BUTTON_PRESS);
|
|
2235
|
+
setStep('connect');
|
|
2236
|
+
}}
|
|
2237
|
+
>
|
|
2238
|
+
<Text style={styles.footerButtonTextConfirm}>Got it</Text>
|
|
2239
|
+
</TouchableOpacity>
|
|
2240
|
+
</View>
|
|
2241
|
+
)}
|
|
2242
|
+
|
|
2243
|
+
{step === 'connections' && (
|
|
2244
|
+
<View style={styles.modalContent}>
|
|
2245
|
+
<View style={styles.privacyHeader}>
|
|
2246
|
+
<TouchableOpacity
|
|
2247
|
+
style={styles.backButton}
|
|
2248
|
+
onPress={() => setStep(primaryAuthOnly ? 'connections' : 'connect')}
|
|
2249
|
+
>
|
|
2250
|
+
<Text style={styles.backButtonText}>←</Text>
|
|
2251
|
+
</TouchableOpacity>
|
|
2252
|
+
<Text style={styles.headerTitle}>Connections Found</Text>
|
|
2253
|
+
<View style={styles.backButtonSpacer} />
|
|
2254
|
+
</View>
|
|
2255
|
+
|
|
2256
|
+
<View style={styles.privacyDetailsContainer}>
|
|
2257
|
+
<Text style={styles.connectionsCountText}>
|
|
2258
|
+
We found {connectionsCount} potential connections for you!
|
|
2259
|
+
</Text>
|
|
2260
|
+
|
|
2261
|
+
<View style={styles.privacyBulletPoint}>
|
|
2262
|
+
<Text style={styles.bulletPoint}>•</Text>
|
|
2263
|
+
<Text style={styles.privacyBulletText}>
|
|
2264
|
+
Continue to see your personalized matches
|
|
2265
|
+
</Text>
|
|
2266
|
+
</View>
|
|
2267
|
+
|
|
2268
|
+
<View style={styles.privacyBulletPoint}>
|
|
2269
|
+
<Text style={styles.bulletPoint}>•</Text>
|
|
2270
|
+
<Text style={styles.privacyBulletText}>
|
|
2271
|
+
Your privacy is protected - we only show compatible profiles
|
|
2272
|
+
</Text>
|
|
2273
|
+
</View>
|
|
2274
|
+
|
|
2275
|
+
<View style={styles.privacyBulletPoint}>
|
|
2276
|
+
<Text style={styles.bulletPoint}>•</Text>
|
|
2277
|
+
<Text style={styles.privacyBulletText}>
|
|
2278
|
+
Ready to start building meaningful connections?
|
|
2279
|
+
</Text>
|
|
2280
|
+
</View>
|
|
2281
|
+
</View>
|
|
2282
|
+
|
|
2283
|
+
<TouchableOpacity
|
|
2284
|
+
style={styles.footerButtonConfirm}
|
|
2285
|
+
onPress={async () => {
|
|
2286
|
+
triggerHaptic(HapticType.BUTTON_PRESS);
|
|
2287
|
+
// Complete the onboarding flow
|
|
2288
|
+
isCompletingRef.current = true;
|
|
2289
|
+
|
|
2290
|
+
// Check if this is an existing user adding more data
|
|
2291
|
+
if (isExistingUser && existingUserToken) {
|
|
2292
|
+
console.log('🔑 EXISTING USER: UniversalOnboarding complete, returning existing user token:', `${existingUserToken.substring(0, 20)}...`);
|
|
2293
|
+
onComplete?.('https://api2.onairos.uk', existingUserToken, { email: userInfo?.email || '', ...userInfo });
|
|
2294
|
+
} else {
|
|
2295
|
+
// For new users, retrieve the stored JWT token from TrainingModal
|
|
2296
|
+
const storedToken = await AsyncStorage.getItem('onairos_jwt_token') ||
|
|
2297
|
+
await AsyncStorage.getItem('auth_token') ||
|
|
2298
|
+
await AsyncStorage.getItem('enoch_token');
|
|
2299
|
+
|
|
2300
|
+
const storedEmail = await AsyncStorage.getItem('user_email');
|
|
2301
|
+
|
|
2302
|
+
if (storedToken) {
|
|
2303
|
+
console.log('🔑 NEW USER: UniversalOnboarding complete, returning stored JWT token:', `${storedToken.substring(0, 20)}...`);
|
|
2304
|
+
onComplete?.('https://api2.onairos.uk', storedToken, { email: storedEmail || userInfo?.email || '', ...userInfo });
|
|
2305
|
+
} else {
|
|
2306
|
+
console.warn('⚠️ NEW USER: No stored JWT token found, using fallback');
|
|
2307
|
+
onComplete?.('https://api2.onairos.uk', 'connections-complete-token', { email: userInfo?.email || '', ...userInfo });
|
|
2308
|
+
}
|
|
2309
|
+
}
|
|
2310
|
+
}}
|
|
2311
|
+
>
|
|
2312
|
+
<Text style={styles.footerButtonTextConfirm}>Continue to Setup</Text>
|
|
2313
|
+
</TouchableOpacity>
|
|
2314
|
+
</View>
|
|
2315
|
+
)}
|
|
2316
|
+
</SafeAreaView>
|
|
2317
|
+
</Animated.View>
|
|
2318
|
+
</View>
|
|
2319
|
+
</Modal>
|
|
2320
|
+
);
|
|
2321
|
+
};
|
|
2322
|
+
|
|
2323
|
+
const styles = StyleSheet.create({
|
|
2324
|
+
modalOverlay: {
|
|
2325
|
+
flex: 1,
|
|
2326
|
+
justifyContent: 'flex-end',
|
|
2327
|
+
backgroundColor: 'rgba(0, 0, 0, 0.5)',
|
|
2328
|
+
},
|
|
2329
|
+
bottomSheet: {
|
|
2330
|
+
backgroundColor: '#FFFFFF',
|
|
2331
|
+
borderTopLeftRadius: 20,
|
|
2332
|
+
borderTopRightRadius: 20,
|
|
2333
|
+
paddingTop: 8,
|
|
2334
|
+
paddingBottom: Platform.OS === 'ios' ? 20 : 0,
|
|
2335
|
+
minHeight: height * .86,
|
|
2336
|
+
width: '100%',
|
|
2337
|
+
},
|
|
2338
|
+
container: {
|
|
2339
|
+
flex: 1,
|
|
2340
|
+
},
|
|
2341
|
+
handleContainer: {
|
|
2342
|
+
alignItems: 'center',
|
|
2343
|
+
paddingVertical: 8,
|
|
2344
|
+
},
|
|
2345
|
+
handleButton: {
|
|
2346
|
+
padding: 10,
|
|
2347
|
+
width: 60,
|
|
2348
|
+
},
|
|
2349
|
+
handle: {
|
|
2350
|
+
width: 40,
|
|
2351
|
+
height: 5,
|
|
2352
|
+
borderRadius: 3,
|
|
2353
|
+
backgroundColor: '#E0E0E0',
|
|
2354
|
+
},
|
|
2355
|
+
header: {
|
|
2356
|
+
alignItems: 'center',
|
|
2357
|
+
marginBottom: 20,
|
|
2358
|
+
paddingHorizontal: 24,
|
|
2359
|
+
},
|
|
2360
|
+
headerContent: {
|
|
2361
|
+
flexDirection: 'row',
|
|
2362
|
+
alignItems: 'center',
|
|
2363
|
+
justifyContent: 'center',
|
|
2364
|
+
marginBottom: 24,
|
|
2365
|
+
},
|
|
2366
|
+
appIcon: {
|
|
2367
|
+
width: 48,
|
|
2368
|
+
height: 48,
|
|
2369
|
+
borderRadius: 24,
|
|
2370
|
+
backgroundColor: '#F5F5F5',
|
|
2371
|
+
alignItems: 'center',
|
|
2372
|
+
justifyContent: 'center',
|
|
2373
|
+
},
|
|
2374
|
+
appIconText: {
|
|
2375
|
+
fontSize: 24,
|
|
2376
|
+
fontWeight: 'bold',
|
|
2377
|
+
color: '#333',
|
|
2378
|
+
},
|
|
2379
|
+
arrow: {
|
|
2380
|
+
marginHorizontal: 16,
|
|
2381
|
+
fontSize: 24,
|
|
2382
|
+
color: '#666',
|
|
2383
|
+
},
|
|
2384
|
+
onairosIcon: {
|
|
2385
|
+
width: 54,
|
|
2386
|
+
height: 54,
|
|
2387
|
+
borderRadius: 32,
|
|
2388
|
+
backgroundColor: 'transparent',
|
|
2389
|
+
alignItems: 'center',
|
|
2390
|
+
justifyContent: 'center',
|
|
2391
|
+
},
|
|
2392
|
+
onairosIconText: {
|
|
2393
|
+
fontSize: 24,
|
|
2394
|
+
fontWeight: 'bold',
|
|
2395
|
+
color: '#fff',
|
|
2396
|
+
},
|
|
2397
|
+
onairosIconImage: {
|
|
2398
|
+
width: 54,
|
|
2399
|
+
height: 54,
|
|
2400
|
+
},
|
|
2401
|
+
titleContainer: {
|
|
2402
|
+
alignItems: 'center',
|
|
2403
|
+
},
|
|
2404
|
+
mainTitle: {
|
|
2405
|
+
fontSize: 24,
|
|
2406
|
+
fontWeight: '600',
|
|
2407
|
+
color: '#333',
|
|
2408
|
+
textAlign: 'center',
|
|
2409
|
+
marginBottom: 12,
|
|
2410
|
+
},
|
|
2411
|
+
privacyMessage: {
|
|
2412
|
+
fontSize: 14,
|
|
2413
|
+
color: '#666',
|
|
2414
|
+
textAlign: 'center',
|
|
2415
|
+
marginBottom: 20,
|
|
2416
|
+
},
|
|
2417
|
+
privacyLink: {
|
|
2418
|
+
color: '#000000',
|
|
2419
|
+
fontWeight: '600',
|
|
2420
|
+
textDecorationLine: 'underline',
|
|
2421
|
+
},
|
|
2422
|
+
boldText: {
|
|
2423
|
+
fontWeight: 'bold',
|
|
2424
|
+
},
|
|
2425
|
+
content: {
|
|
2426
|
+
flex: 1,
|
|
2427
|
+
paddingHorizontal: 24,
|
|
2428
|
+
},
|
|
2429
|
+
platformsScrollView: {
|
|
2430
|
+
flex: 1,
|
|
2431
|
+
width: '100%',
|
|
2432
|
+
},
|
|
2433
|
+
platformsScrollContent: {
|
|
2434
|
+
paddingBottom: 0,
|
|
2435
|
+
paddingHorizontal: 24,
|
|
2436
|
+
},
|
|
2437
|
+
platformsContainer: {
|
|
2438
|
+
marginTop: 16,
|
|
2439
|
+
},
|
|
2440
|
+
platformItem: {
|
|
2441
|
+
flexDirection: 'row',
|
|
2442
|
+
alignItems: 'center',
|
|
2443
|
+
justifyContent: 'space-between',
|
|
2444
|
+
paddingVertical: 16,
|
|
2445
|
+
paddingHorizontal: 8,
|
|
2446
|
+
borderBottomWidth: 1,
|
|
2447
|
+
borderBottomColor: '#E5E5E5',
|
|
2448
|
+
},
|
|
2449
|
+
platformInfo: {
|
|
2450
|
+
flexDirection: 'row',
|
|
2451
|
+
alignItems: 'center',
|
|
2452
|
+
},
|
|
2453
|
+
platformIcon: {
|
|
2454
|
+
width: 40,
|
|
2455
|
+
height: 40,
|
|
2456
|
+
borderRadius: 20,
|
|
2457
|
+
backgroundColor: '#F5F5F5',
|
|
2458
|
+
alignItems: 'center',
|
|
2459
|
+
justifyContent: 'center',
|
|
2460
|
+
marginRight: 16,
|
|
2461
|
+
},
|
|
2462
|
+
platformIconText: {
|
|
2463
|
+
fontSize: 18,
|
|
2464
|
+
fontWeight: 'bold',
|
|
2465
|
+
color: '#333',
|
|
2466
|
+
textAlign: 'center',
|
|
2467
|
+
textAlignVertical: 'center',
|
|
2468
|
+
},
|
|
2469
|
+
platformIconImage: {
|
|
2470
|
+
width: 24,
|
|
2471
|
+
height: 24,
|
|
2472
|
+
},
|
|
2473
|
+
youtubeIconImage: {
|
|
2474
|
+
width: 58,
|
|
2475
|
+
height: 58,
|
|
2476
|
+
},
|
|
2477
|
+
redditIconImage: {
|
|
2478
|
+
width: 34,
|
|
2479
|
+
height: 34,
|
|
2480
|
+
},
|
|
2481
|
+
pinterestIconImage: {
|
|
2482
|
+
width: 48,
|
|
2483
|
+
height: 48,
|
|
2484
|
+
},
|
|
2485
|
+
gmailIconImage: {
|
|
2486
|
+
width: 32,
|
|
2487
|
+
height: 32,
|
|
2488
|
+
},
|
|
2489
|
+
linkedinPlatformIcon: {
|
|
2490
|
+
width: 40,
|
|
2491
|
+
height: 40,
|
|
2492
|
+
borderRadius: 8,
|
|
2493
|
+
backgroundColor: '#F5F5F5',
|
|
2494
|
+
alignItems: 'center',
|
|
2495
|
+
justifyContent: 'center',
|
|
2496
|
+
marginRight: 16,
|
|
2497
|
+
},
|
|
2498
|
+
pinterestPlatformIcon: {
|
|
2499
|
+
width: 34,
|
|
2500
|
+
height: 34,
|
|
2501
|
+
borderRadius: 17,
|
|
2502
|
+
backgroundColor: '#F5F5F5',
|
|
2503
|
+
alignItems: 'center',
|
|
2504
|
+
justifyContent: 'center',
|
|
2505
|
+
marginRight: 16,
|
|
2506
|
+
},
|
|
2507
|
+
platformName: {
|
|
2508
|
+
fontSize: 16,
|
|
2509
|
+
color: '#333',
|
|
2510
|
+
textAlignVertical: 'center',
|
|
2511
|
+
},
|
|
2512
|
+
footer: {
|
|
2513
|
+
flexDirection: 'row',
|
|
2514
|
+
alignItems: 'center',
|
|
2515
|
+
justifyContent: 'space-between',
|
|
2516
|
+
padding: 24,
|
|
2517
|
+
borderTopWidth: 1,
|
|
2518
|
+
borderTopColor: '#E5E5E5',
|
|
2519
|
+
},
|
|
2520
|
+
footerButtonCancel: {
|
|
2521
|
+
paddingVertical: 12,
|
|
2522
|
+
paddingHorizontal: 16,
|
|
2523
|
+
},
|
|
2524
|
+
footerButtonText: {
|
|
2525
|
+
color: '#666',
|
|
2526
|
+
fontSize: 16,
|
|
2527
|
+
},
|
|
2528
|
+
footerButtonConfirm: {
|
|
2529
|
+
paddingVertical: 12,
|
|
2530
|
+
paddingHorizontal: 24,
|
|
2531
|
+
backgroundColor: '#000000',
|
|
2532
|
+
borderRadius: 8,
|
|
2533
|
+
marginTop: 20,
|
|
2534
|
+
},
|
|
2535
|
+
footerButtonConnected: {
|
|
2536
|
+
paddingVertical: 12,
|
|
2537
|
+
paddingHorizontal: 24,
|
|
2538
|
+
backgroundColor: '#E9C46A',
|
|
2539
|
+
borderRadius: 8,
|
|
2540
|
+
},
|
|
2541
|
+
footerButtonDisabled: {
|
|
2542
|
+
backgroundColor: '#E5E5E5',
|
|
2543
|
+
},
|
|
2544
|
+
footerButtonTextConfirm: {
|
|
2545
|
+
color: '#fff',
|
|
2546
|
+
fontSize: 16,
|
|
2547
|
+
fontWeight: '600',
|
|
2548
|
+
},
|
|
2549
|
+
footerButtonTextConnected: {
|
|
2550
|
+
color: '#000',
|
|
2551
|
+
fontSize: 16,
|
|
2552
|
+
fontWeight: '600',
|
|
2553
|
+
},
|
|
2554
|
+
connectContainer: {
|
|
2555
|
+
flex: 1,
|
|
2556
|
+
},
|
|
2557
|
+
modalContent: {
|
|
2558
|
+
flex: 1,
|
|
2559
|
+
backgroundColor: '#FFFFFF',
|
|
2560
|
+
borderTopLeftRadius: 20,
|
|
2561
|
+
borderTopRightRadius: 20,
|
|
2562
|
+
padding: 24,
|
|
2563
|
+
},
|
|
2564
|
+
backButton: {
|
|
2565
|
+
padding: 8,
|
|
2566
|
+
width: 40,
|
|
2567
|
+
},
|
|
2568
|
+
backButtonText: {
|
|
2569
|
+
fontSize: 24,
|
|
2570
|
+
color: '#000000',
|
|
2571
|
+
},
|
|
2572
|
+
backButtonSpacer: {
|
|
2573
|
+
width: 40,
|
|
2574
|
+
},
|
|
2575
|
+
headerTitle: {
|
|
2576
|
+
fontSize: 18,
|
|
2577
|
+
fontWeight: '600',
|
|
2578
|
+
color: '#333',
|
|
2579
|
+
textAlign: 'center',
|
|
2580
|
+
},
|
|
2581
|
+
privacyHeader: {
|
|
2582
|
+
flexDirection: 'row',
|
|
2583
|
+
alignItems: 'center',
|
|
2584
|
+
justifyContent: 'space-between',
|
|
2585
|
+
paddingHorizontal: 16,
|
|
2586
|
+
paddingVertical: 20,
|
|
2587
|
+
backgroundColor: '#FFFFFF',
|
|
2588
|
+
borderBottomWidth: 1,
|
|
2589
|
+
borderBottomColor: '#F0F0F0',
|
|
2590
|
+
},
|
|
2591
|
+
privacyDetailsContainer: {
|
|
2592
|
+
paddingHorizontal: 24,
|
|
2593
|
+
paddingVertical: 8,
|
|
2594
|
+
flex: 1,
|
|
2595
|
+
marginTop: 20,
|
|
2596
|
+
},
|
|
2597
|
+
privacyDetailsTitle: {
|
|
2598
|
+
fontSize: 20,
|
|
2599
|
+
fontWeight: '600',
|
|
2600
|
+
color: '#333',
|
|
2601
|
+
marginBottom: 0,
|
|
2602
|
+
},
|
|
2603
|
+
privacyBulletPoint: {
|
|
2604
|
+
flexDirection: 'row',
|
|
2605
|
+
marginBottom: 16,
|
|
2606
|
+
alignItems: 'flex-start',
|
|
2607
|
+
},
|
|
2608
|
+
bulletPoint: {
|
|
2609
|
+
fontSize: 18,
|
|
2610
|
+
marginRight: 8,
|
|
2611
|
+
color: '#333',
|
|
2612
|
+
},
|
|
2613
|
+
privacyBulletText: {
|
|
2614
|
+
fontSize: 16,
|
|
2615
|
+
color: '#333',
|
|
2616
|
+
flex: 1,
|
|
2617
|
+
lineHeight: 24,
|
|
2618
|
+
},
|
|
2619
|
+
connectionsCountText: {
|
|
2620
|
+
fontSize: 18,
|
|
2621
|
+
fontWeight: '600',
|
|
2622
|
+
color: '#333',
|
|
2623
|
+
marginBottom: 24,
|
|
2624
|
+
},
|
|
2625
|
+
personaContainer: {
|
|
2626
|
+
flex: 1,
|
|
2627
|
+
padding: 16,
|
|
2628
|
+
backgroundColor: '#fff',
|
|
2629
|
+
justifyContent: 'flex-start',
|
|
2630
|
+
},
|
|
2631
|
+
personaHeaderWithBack: {
|
|
2632
|
+
flexDirection: 'row',
|
|
2633
|
+
alignItems: 'center',
|
|
2634
|
+
justifyContent: 'space-between',
|
|
2635
|
+
marginBottom: 16,
|
|
2636
|
+
paddingVertical: 8,
|
|
2637
|
+
},
|
|
2638
|
+
personaBackButton: {
|
|
2639
|
+
padding: 8,
|
|
2640
|
+
},
|
|
2641
|
+
personaHeader: {
|
|
2642
|
+
alignItems: 'center',
|
|
2643
|
+
marginBottom: 32,
|
|
2644
|
+
paddingHorizontal: 24,
|
|
2645
|
+
},
|
|
2646
|
+
personaTitle: {
|
|
2647
|
+
fontSize: 20,
|
|
2648
|
+
fontWeight: '600',
|
|
2649
|
+
color: '#333',
|
|
2650
|
+
textAlign: 'center',
|
|
2651
|
+
flex: 1,
|
|
2652
|
+
marginBottom: 8,
|
|
2653
|
+
},
|
|
2654
|
+
personaSubtitle: {
|
|
2655
|
+
fontSize: 14,
|
|
2656
|
+
color: '#666',
|
|
2657
|
+
marginBottom: 24,
|
|
2658
|
+
textAlign: 'center',
|
|
2659
|
+
},
|
|
2660
|
+
personaProgressContainer: {
|
|
2661
|
+
marginBottom: 24,
|
|
2662
|
+
paddingHorizontal: 0,
|
|
2663
|
+
},
|
|
2664
|
+
personaProgressBar: {
|
|
2665
|
+
height: 8,
|
|
2666
|
+
backgroundColor: '#F5F5F5',
|
|
2667
|
+
borderRadius: 4,
|
|
2668
|
+
overflow: 'hidden',
|
|
2669
|
+
marginBottom: 12,
|
|
2670
|
+
},
|
|
2671
|
+
personaProgressFill: {
|
|
2672
|
+
height: '100%',
|
|
2673
|
+
backgroundColor: '#1BA9D4',
|
|
2674
|
+
borderRadius: 4,
|
|
2675
|
+
},
|
|
2676
|
+
personaProgressText: {
|
|
2677
|
+
fontSize: 16,
|
|
2678
|
+
fontWeight: '600',
|
|
2679
|
+
color: '#333',
|
|
2680
|
+
textAlign: 'center',
|
|
2681
|
+
marginBottom: 8,
|
|
2682
|
+
},
|
|
2683
|
+
personaStatusText: {
|
|
2684
|
+
fontSize: 14,
|
|
2685
|
+
color: '#666',
|
|
2686
|
+
textAlign: 'center',
|
|
2687
|
+
},
|
|
2688
|
+
personaCompleteContainer: {
|
|
2689
|
+
alignItems: 'center',
|
|
2690
|
+
paddingHorizontal: 0,
|
|
2691
|
+
},
|
|
2692
|
+
personaCompleteTitle: {
|
|
2693
|
+
fontSize: 20,
|
|
2694
|
+
fontWeight: '600',
|
|
2695
|
+
color: '#333',
|
|
2696
|
+
marginBottom: 8,
|
|
2697
|
+
textAlign: 'center',
|
|
2698
|
+
},
|
|
2699
|
+
personaCompleteSubtitle: {
|
|
2700
|
+
fontSize: 14,
|
|
2701
|
+
color: '#666',
|
|
2702
|
+
textAlign: 'center',
|
|
2703
|
+
marginBottom: 40,
|
|
2704
|
+
},
|
|
2705
|
+
personaContinueButton: {
|
|
2706
|
+
backgroundColor: '#000000',
|
|
2707
|
+
paddingVertical: 16,
|
|
2708
|
+
paddingHorizontal: 48,
|
|
2709
|
+
borderRadius: 16,
|
|
2710
|
+
alignItems: 'center',
|
|
2711
|
+
width: '100%',
|
|
2712
|
+
marginTop: 32,
|
|
2713
|
+
shadowColor: '#000',
|
|
2714
|
+
shadowOffset: { width: 0, height: 2 },
|
|
2715
|
+
shadowOpacity: 0.1,
|
|
2716
|
+
shadowRadius: 4,
|
|
2717
|
+
elevation: 3,
|
|
2718
|
+
},
|
|
2719
|
+
personaContinueButtonText: {
|
|
2720
|
+
color: '#fff',
|
|
2721
|
+
fontSize: 16,
|
|
2722
|
+
fontWeight: '600',
|
|
2723
|
+
},
|
|
2724
|
+
progressError: {
|
|
2725
|
+
backgroundColor: '#FF3B30',
|
|
2726
|
+
},
|
|
2727
|
+
dataWarningContainer: {
|
|
2728
|
+
padding: 16,
|
|
2729
|
+
borderRadius: 12,
|
|
2730
|
+
marginTop: 16,
|
|
2731
|
+
borderWidth: 1,
|
|
2732
|
+
shadowColor: '#000',
|
|
2733
|
+
shadowOffset: { width: 0, height: 2 },
|
|
2734
|
+
shadowOpacity: 0.1,
|
|
2735
|
+
shadowRadius: 4,
|
|
2736
|
+
elevation: 3,
|
|
2737
|
+
},
|
|
2738
|
+
dataWarningHeader: {
|
|
2739
|
+
flexDirection: 'row',
|
|
2740
|
+
alignItems: 'center',
|
|
2741
|
+
marginBottom: 8,
|
|
2742
|
+
},
|
|
2743
|
+
dataWarningIcon: {
|
|
2744
|
+
fontSize: 20,
|
|
2745
|
+
marginRight: 8,
|
|
2746
|
+
},
|
|
2747
|
+
dataWarningTitle: {
|
|
2748
|
+
fontSize: 16,
|
|
2749
|
+
fontWeight: '600',
|
|
2750
|
+
flex: 1,
|
|
2751
|
+
},
|
|
2752
|
+
dataWarningMessage: {
|
|
2753
|
+
fontSize: 14,
|
|
2754
|
+
marginBottom: 0,
|
|
2755
|
+
lineHeight: 20,
|
|
2756
|
+
},
|
|
2757
|
+
dataWarningSuggestions: {
|
|
2758
|
+
marginTop: 12,
|
|
2759
|
+
paddingTop: 12,
|
|
2760
|
+
borderTopWidth: 1,
|
|
2761
|
+
},
|
|
2762
|
+
dataWarningSuggestionsTitle: {
|
|
2763
|
+
fontSize: 14,
|
|
2764
|
+
fontWeight: '600',
|
|
2765
|
+
marginBottom: 6,
|
|
2766
|
+
},
|
|
2767
|
+
dataWarningSuggestionItem: {
|
|
2768
|
+
fontSize: 13,
|
|
2769
|
+
marginBottom: 4,
|
|
2770
|
+
lineHeight: 18,
|
|
2771
|
+
},
|
|
2772
|
+
dataWarningContinueNote: {
|
|
2773
|
+
fontSize: 13,
|
|
2774
|
+
fontWeight: '500',
|
|
2775
|
+
marginTop: 12,
|
|
2776
|
+
fontStyle: 'italic',
|
|
2777
|
+
},
|
|
2778
|
+
dataWarningError: {
|
|
2779
|
+
backgroundColor: '#FFF5F5',
|
|
2780
|
+
borderColor: '#FEB2B2',
|
|
2781
|
+
},
|
|
2782
|
+
dataInfoContainer: {
|
|
2783
|
+
backgroundColor: '#F0F9FF',
|
|
2784
|
+
borderColor: '#BAE6FD',
|
|
2785
|
+
},
|
|
2786
|
+
dataConnectionsRequired: {
|
|
2787
|
+
backgroundColor: '#F5F5F5',
|
|
2788
|
+
borderColor: '#D1D5DB',
|
|
2789
|
+
shadowColor: '#6B7280',
|
|
2790
|
+
shadowOffset: { width: 0, height: 0 },
|
|
2791
|
+
shadowOpacity: 0.15,
|
|
2792
|
+
shadowRadius: 8,
|
|
2793
|
+
},
|
|
2794
|
+
highlightedBackButton: {
|
|
2795
|
+
backgroundColor: '#F5F5F5',
|
|
2796
|
+
borderRadius: 20,
|
|
2797
|
+
borderWidth: 2,
|
|
2798
|
+
borderColor: '#000000',
|
|
2799
|
+
shadowColor: '#000000',
|
|
2800
|
+
shadowOffset: { width: 0, height: 0 },
|
|
2801
|
+
shadowOpacity: 0.3,
|
|
2802
|
+
shadowRadius: 8,
|
|
2803
|
+
elevation: 5,
|
|
2804
|
+
},
|
|
2805
|
+
highlightedBackArrow: {
|
|
2806
|
+
color: '#000000',
|
|
2807
|
+
fontWeight: 'bold',
|
|
2808
|
+
},
|
|
2809
|
+
goBackButton: {
|
|
2810
|
+
backgroundColor: '#000000',
|
|
2811
|
+
paddingVertical: 12,
|
|
2812
|
+
paddingHorizontal: 16,
|
|
2813
|
+
borderRadius: 8,
|
|
2814
|
+
marginTop: 12,
|
|
2815
|
+
alignItems: 'center',
|
|
2816
|
+
shadowColor: '#000000',
|
|
2817
|
+
shadowOffset: { width: 0, height: 0 },
|
|
2818
|
+
shadowOpacity: 0.3,
|
|
2819
|
+
shadowRadius: 6,
|
|
2820
|
+
elevation: 3,
|
|
2821
|
+
},
|
|
2822
|
+
goBackButtonText: {
|
|
2823
|
+
color: '#FFFFFF',
|
|
2824
|
+
fontSize: 14,
|
|
2825
|
+
fontWeight: '600',
|
|
2826
|
+
},
|
|
2827
|
+
additionalPlatformsToggle: {
|
|
2828
|
+
paddingVertical: 16,
|
|
2829
|
+
paddingHorizontal: 8,
|
|
2830
|
+
alignItems: 'center',
|
|
2831
|
+
borderBottomWidth: 1,
|
|
2832
|
+
borderBottomColor: '#E5E5E5',
|
|
2833
|
+
},
|
|
2834
|
+
additionalPlatformsText: {
|
|
2835
|
+
fontSize: 14,
|
|
2836
|
+
color: '#666',
|
|
2837
|
+
fontWeight: '500',
|
|
2838
|
+
},
|
|
2839
|
+
asterisk: {
|
|
2840
|
+
color: '#FF6B6B',
|
|
2841
|
+
fontSize: 16,
|
|
2842
|
+
fontWeight: 'bold',
|
|
2843
|
+
marginLeft: 2,
|
|
2844
|
+
},
|
|
2845
|
+
|
|
2846
|
+
linkedinRequirementContainer: {
|
|
2847
|
+
backgroundColor: '#F8F9FA',
|
|
2848
|
+
borderWidth: 1,
|
|
2849
|
+
borderColor: '#E5E7EB',
|
|
2850
|
+
borderRadius: 8,
|
|
2851
|
+
paddingHorizontal: 12,
|
|
2852
|
+
paddingVertical: 8,
|
|
2853
|
+
marginTop: 8,
|
|
2854
|
+
marginHorizontal: 4,
|
|
2855
|
+
},
|
|
2856
|
+
linkedinRequirementText: {
|
|
2857
|
+
fontSize: 12,
|
|
2858
|
+
fontStyle: 'italic',
|
|
2859
|
+
textAlign: 'center',
|
|
2860
|
+
},
|
|
2861
|
+
linkedinRequirementAsterisk: {
|
|
2862
|
+
color: '#FF6B6B',
|
|
2863
|
+
fontWeight: 'bold',
|
|
2864
|
+
},
|
|
2865
|
+
linkedinRequirementMessage: {
|
|
2866
|
+
color: '#6B7280',
|
|
2867
|
+
},
|
|
2868
|
+
existingUserBanner: {
|
|
2869
|
+
backgroundColor: '#F0F9FF',
|
|
2870
|
+
borderWidth: 1,
|
|
2871
|
+
borderColor: '#0EA5E9',
|
|
2872
|
+
borderRadius: 12,
|
|
2873
|
+
paddingHorizontal: 16,
|
|
2874
|
+
paddingVertical: 12,
|
|
2875
|
+
marginTop: 12,
|
|
2876
|
+
},
|
|
2877
|
+
existingUserText: {
|
|
2878
|
+
fontSize: 14,
|
|
2879
|
+
fontWeight: '600',
|
|
2880
|
+
color: '#0369A1',
|
|
2881
|
+
marginBottom: 4,
|
|
2882
|
+
},
|
|
2883
|
+
existingUserSubtext: {
|
|
2884
|
+
fontSize: 12,
|
|
2885
|
+
color: '#0C4A6E',
|
|
2886
|
+
lineHeight: 16,
|
|
2887
|
+
},
|
|
2888
|
+
});
|