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