@oxyhq/services 5.11.11 → 5.12.0

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 (327) hide show
  1. package/README.md +48 -7
  2. package/lib/commonjs/core/OxyServices.js +162 -12
  3. package/lib/commonjs/core/OxyServices.js.map +1 -1
  4. package/lib/commonjs/i18n/index.js +40 -0
  5. package/lib/commonjs/i18n/index.js.map +1 -0
  6. package/lib/commonjs/i18n/locales/en-US.json +681 -0
  7. package/lib/commonjs/i18n/locales/es-ES.json +689 -0
  8. package/lib/commonjs/ui/components/FollowButton.js +1 -1
  9. package/lib/commonjs/ui/components/FollowButton.js.map +1 -1
  10. package/lib/commonjs/ui/components/GroupedItem.js +2 -1
  11. package/lib/commonjs/ui/components/GroupedItem.js.map +1 -1
  12. package/lib/commonjs/ui/components/Header.js +4 -3
  13. package/lib/commonjs/ui/components/Header.js.map +1 -1
  14. package/lib/commonjs/ui/components/OxyProvider.js +112 -105
  15. package/lib/commonjs/ui/components/OxyProvider.js.map +1 -1
  16. package/lib/commonjs/ui/components/ProfileCard.js +5 -1
  17. package/lib/commonjs/ui/components/ProfileCard.js.map +1 -1
  18. package/lib/commonjs/ui/components/Section.js +1 -1
  19. package/lib/commonjs/ui/components/StepBasedScreen.js +17 -17
  20. package/lib/commonjs/ui/components/StepBasedScreen.js.map +1 -1
  21. package/lib/commonjs/ui/components/internal/GroupedPillButtons.js +15 -3
  22. package/lib/commonjs/ui/components/internal/GroupedPillButtons.js.map +1 -1
  23. package/lib/commonjs/ui/components/internal/PinInput.js +10 -4
  24. package/lib/commonjs/ui/components/internal/PinInput.js.map +1 -1
  25. package/lib/commonjs/ui/context/OxyContext.js +128 -12
  26. package/lib/commonjs/ui/context/OxyContext.js.map +1 -1
  27. package/lib/commonjs/ui/hooks/useI18n.js +22 -0
  28. package/lib/commonjs/ui/hooks/useI18n.js.map +1 -0
  29. package/lib/commonjs/ui/navigation/OxyRouter.js +11 -131
  30. package/lib/commonjs/ui/navigation/OxyRouter.js.map +1 -1
  31. package/lib/commonjs/ui/navigation/routes.js +127 -0
  32. package/lib/commonjs/ui/navigation/routes.js.map +1 -0
  33. package/lib/commonjs/ui/navigation/types.js +7 -0
  34. package/lib/commonjs/ui/navigation/types.js.map +1 -1
  35. package/lib/commonjs/ui/screens/AccountCenterScreen.js +55 -47
  36. package/lib/commonjs/ui/screens/AccountCenterScreen.js.map +1 -1
  37. package/lib/commonjs/ui/screens/AccountOverviewScreen.js +69 -61
  38. package/lib/commonjs/ui/screens/AccountOverviewScreen.js.map +1 -1
  39. package/lib/commonjs/ui/screens/AccountSettingsScreen.js +378 -37
  40. package/lib/commonjs/ui/screens/AccountSettingsScreen.js.map +1 -1
  41. package/lib/commonjs/ui/screens/AccountSwitcherScreen.js +52 -34
  42. package/lib/commonjs/ui/screens/AccountSwitcherScreen.js.map +1 -1
  43. package/lib/commonjs/ui/screens/FeedbackScreen.js +40 -36
  44. package/lib/commonjs/ui/screens/FeedbackScreen.js.map +1 -1
  45. package/lib/commonjs/ui/screens/LanguageSelectorScreen.js +105 -78
  46. package/lib/commonjs/ui/screens/LanguageSelectorScreen.js.map +1 -1
  47. package/lib/commonjs/ui/screens/PaymentGatewayScreen.js +2 -2
  48. package/lib/commonjs/ui/screens/PaymentGatewayScreen.js.map +1 -1
  49. package/lib/commonjs/ui/screens/PremiumSubscriptionScreen.js +92 -60
  50. package/lib/commonjs/ui/screens/PremiumSubscriptionScreen.js.map +1 -1
  51. package/lib/commonjs/ui/screens/ProfileScreen.js +21 -11
  52. package/lib/commonjs/ui/screens/ProfileScreen.js.map +1 -1
  53. package/lib/commonjs/ui/screens/RecoverAccountScreen.js +30 -8
  54. package/lib/commonjs/ui/screens/RecoverAccountScreen.js.map +1 -1
  55. package/lib/commonjs/ui/screens/SignInScreen.js +47 -26
  56. package/lib/commonjs/ui/screens/SignInScreen.js.map +1 -1
  57. package/lib/commonjs/ui/screens/WelcomeNewUserScreen.js +31 -24
  58. package/lib/commonjs/ui/screens/WelcomeNewUserScreen.js.map +1 -1
  59. package/lib/commonjs/ui/screens/internal/SignInPasswordStep.js +11 -7
  60. package/lib/commonjs/ui/screens/internal/SignInPasswordStep.js.map +1 -1
  61. package/lib/commonjs/ui/screens/internal/SignInUsernameStep.js +12 -6
  62. package/lib/commonjs/ui/screens/internal/SignInUsernameStep.js.map +1 -1
  63. package/lib/commonjs/ui/screens/karma/KarmaAboutScreen.js +11 -7
  64. package/lib/commonjs/ui/screens/karma/KarmaAboutScreen.js.map +1 -1
  65. package/lib/commonjs/ui/screens/karma/KarmaCenterScreen.js +15 -11
  66. package/lib/commonjs/ui/screens/karma/KarmaCenterScreen.js.map +1 -1
  67. package/lib/commonjs/ui/screens/karma/KarmaFAQScreen.js +19 -27
  68. package/lib/commonjs/ui/screens/karma/KarmaFAQScreen.js.map +1 -1
  69. package/lib/commonjs/ui/screens/karma/KarmaLeaderboardScreen.js +8 -4
  70. package/lib/commonjs/ui/screens/karma/KarmaLeaderboardScreen.js.map +1 -1
  71. package/lib/commonjs/ui/screens/karma/KarmaRewardsScreen.js +14 -10
  72. package/lib/commonjs/ui/screens/karma/KarmaRewardsScreen.js.map +1 -1
  73. package/lib/commonjs/ui/screens/karma/KarmaRulesScreen.js +7 -3
  74. package/lib/commonjs/ui/screens/karma/KarmaRulesScreen.js.map +1 -1
  75. package/lib/commonjs/ui/screens/steps/RecoverRequestStep.js +19 -14
  76. package/lib/commonjs/ui/screens/steps/RecoverRequestStep.js.map +1 -1
  77. package/lib/commonjs/ui/screens/steps/RecoverResetPasswordStep.js +130 -0
  78. package/lib/commonjs/ui/screens/steps/RecoverResetPasswordStep.js.map +1 -0
  79. package/lib/commonjs/ui/screens/steps/RecoverSuccessStep.js +13 -13
  80. package/lib/commonjs/ui/screens/steps/RecoverSuccessStep.js.map +1 -1
  81. package/lib/commonjs/ui/screens/steps/RecoverVerifyStep.js +14 -20
  82. package/lib/commonjs/ui/screens/steps/RecoverVerifyStep.js.map +1 -1
  83. package/lib/commonjs/ui/screens/steps/SignInPasswordStep.js +22 -8
  84. package/lib/commonjs/ui/screens/steps/SignInPasswordStep.js.map +1 -1
  85. package/lib/commonjs/ui/screens/steps/SignInTotpStep.js +161 -0
  86. package/lib/commonjs/ui/screens/steps/SignInTotpStep.js.map +1 -0
  87. package/lib/commonjs/ui/screens/steps/SignInUsernameStep.js +12 -6
  88. package/lib/commonjs/ui/screens/steps/SignInUsernameStep.js.map +1 -1
  89. package/lib/commonjs/ui/screens/steps/SignUpIdentityStep.js +10 -6
  90. package/lib/commonjs/ui/screens/steps/SignUpIdentityStep.js.map +1 -1
  91. package/lib/commonjs/ui/screens/steps/SignUpSecurityStep.js +10 -6
  92. package/lib/commonjs/ui/screens/steps/SignUpSecurityStep.js.map +1 -1
  93. package/lib/commonjs/ui/screens/steps/SignUpSummaryStep.js +34 -4
  94. package/lib/commonjs/ui/screens/steps/SignUpSummaryStep.js.map +1 -1
  95. package/lib/commonjs/ui/screens/steps/SignUpWelcomeStep.js +9 -10
  96. package/lib/commonjs/ui/screens/steps/SignUpWelcomeStep.js.map +1 -1
  97. package/lib/commonjs/ui/styles/authStyles.js +1 -2
  98. package/lib/commonjs/ui/styles/authStyles.js.map +1 -1
  99. package/lib/commonjs/utils/deviceManager.js +1 -1
  100. package/lib/commonjs/utils/deviceManager.js.map +1 -1
  101. package/lib/commonjs/utils/validationUtils.js +4 -2
  102. package/lib/commonjs/utils/validationUtils.js.map +1 -1
  103. package/lib/module/core/OxyServices.js +162 -12
  104. package/lib/module/core/OxyServices.js.map +1 -1
  105. package/lib/module/i18n/index.js +35 -0
  106. package/lib/module/i18n/index.js.map +1 -0
  107. package/lib/module/i18n/locales/en-US.json +681 -0
  108. package/lib/module/i18n/locales/es-ES.json +689 -0
  109. package/lib/module/ui/components/FollowButton.js +1 -1
  110. package/lib/module/ui/components/FollowButton.js.map +1 -1
  111. package/lib/module/ui/components/GroupedItem.js +2 -1
  112. package/lib/module/ui/components/GroupedItem.js.map +1 -1
  113. package/lib/module/ui/components/Header.js +4 -3
  114. package/lib/module/ui/components/Header.js.map +1 -1
  115. package/lib/module/ui/components/OxyProvider.js +111 -105
  116. package/lib/module/ui/components/OxyProvider.js.map +1 -1
  117. package/lib/module/ui/components/ProfileCard.js +5 -1
  118. package/lib/module/ui/components/ProfileCard.js.map +1 -1
  119. package/lib/module/ui/components/Section.js +1 -1
  120. package/lib/module/ui/components/StepBasedScreen.js +17 -17
  121. package/lib/module/ui/components/StepBasedScreen.js.map +1 -1
  122. package/lib/module/ui/components/internal/GroupedPillButtons.js +15 -3
  123. package/lib/module/ui/components/internal/GroupedPillButtons.js.map +1 -1
  124. package/lib/module/ui/components/internal/PinInput.js +9 -4
  125. package/lib/module/ui/components/internal/PinInput.js.map +1 -1
  126. package/lib/module/ui/context/OxyContext.js +128 -12
  127. package/lib/module/ui/context/OxyContext.js.map +1 -1
  128. package/lib/module/ui/hooks/useI18n.js +18 -0
  129. package/lib/module/ui/hooks/useI18n.js.map +1 -0
  130. package/lib/module/ui/navigation/OxyRouter.js +7 -124
  131. package/lib/module/ui/navigation/OxyRouter.js.map +1 -1
  132. package/lib/module/ui/navigation/routes.js +122 -0
  133. package/lib/module/ui/navigation/routes.js.map +1 -0
  134. package/lib/module/ui/navigation/types.js +19 -1
  135. package/lib/module/ui/navigation/types.js.map +1 -1
  136. package/lib/module/ui/screens/AccountCenterScreen.js +55 -47
  137. package/lib/module/ui/screens/AccountCenterScreen.js.map +1 -1
  138. package/lib/module/ui/screens/AccountOverviewScreen.js +69 -61
  139. package/lib/module/ui/screens/AccountOverviewScreen.js.map +1 -1
  140. package/lib/module/ui/screens/AccountSettingsScreen.js +378 -37
  141. package/lib/module/ui/screens/AccountSettingsScreen.js.map +1 -1
  142. package/lib/module/ui/screens/AccountSwitcherScreen.js +52 -34
  143. package/lib/module/ui/screens/AccountSwitcherScreen.js.map +1 -1
  144. package/lib/module/ui/screens/FeedbackScreen.js +40 -36
  145. package/lib/module/ui/screens/FeedbackScreen.js.map +1 -1
  146. package/lib/module/ui/screens/LanguageSelectorScreen.js +107 -80
  147. package/lib/module/ui/screens/LanguageSelectorScreen.js.map +1 -1
  148. package/lib/module/ui/screens/PaymentGatewayScreen.js +2 -2
  149. package/lib/module/ui/screens/PaymentGatewayScreen.js.map +1 -1
  150. package/lib/module/ui/screens/PremiumSubscriptionScreen.js +92 -60
  151. package/lib/module/ui/screens/PremiumSubscriptionScreen.js.map +1 -1
  152. package/lib/module/ui/screens/ProfileScreen.js +21 -11
  153. package/lib/module/ui/screens/ProfileScreen.js.map +1 -1
  154. package/lib/module/ui/screens/RecoverAccountScreen.js +30 -8
  155. package/lib/module/ui/screens/RecoverAccountScreen.js.map +1 -1
  156. package/lib/module/ui/screens/SignInScreen.js +47 -26
  157. package/lib/module/ui/screens/SignInScreen.js.map +1 -1
  158. package/lib/module/ui/screens/WelcomeNewUserScreen.js +31 -24
  159. package/lib/module/ui/screens/WelcomeNewUserScreen.js.map +1 -1
  160. package/lib/module/ui/screens/internal/SignInPasswordStep.js +11 -7
  161. package/lib/module/ui/screens/internal/SignInPasswordStep.js.map +1 -1
  162. package/lib/module/ui/screens/internal/SignInUsernameStep.js +12 -6
  163. package/lib/module/ui/screens/internal/SignInUsernameStep.js.map +1 -1
  164. package/lib/module/ui/screens/karma/KarmaAboutScreen.js +11 -7
  165. package/lib/module/ui/screens/karma/KarmaAboutScreen.js.map +1 -1
  166. package/lib/module/ui/screens/karma/KarmaCenterScreen.js +15 -11
  167. package/lib/module/ui/screens/karma/KarmaCenterScreen.js.map +1 -1
  168. package/lib/module/ui/screens/karma/KarmaFAQScreen.js +19 -27
  169. package/lib/module/ui/screens/karma/KarmaFAQScreen.js.map +1 -1
  170. package/lib/module/ui/screens/karma/KarmaLeaderboardScreen.js +8 -4
  171. package/lib/module/ui/screens/karma/KarmaLeaderboardScreen.js.map +1 -1
  172. package/lib/module/ui/screens/karma/KarmaRewardsScreen.js +14 -10
  173. package/lib/module/ui/screens/karma/KarmaRewardsScreen.js.map +1 -1
  174. package/lib/module/ui/screens/karma/KarmaRulesScreen.js +7 -3
  175. package/lib/module/ui/screens/karma/KarmaRulesScreen.js.map +1 -1
  176. package/lib/module/ui/screens/steps/RecoverRequestStep.js +19 -14
  177. package/lib/module/ui/screens/steps/RecoverRequestStep.js.map +1 -1
  178. package/lib/module/ui/screens/steps/RecoverResetPasswordStep.js +125 -0
  179. package/lib/module/ui/screens/steps/RecoverResetPasswordStep.js.map +1 -0
  180. package/lib/module/ui/screens/steps/RecoverSuccessStep.js +13 -13
  181. package/lib/module/ui/screens/steps/RecoverSuccessStep.js.map +1 -1
  182. package/lib/module/ui/screens/steps/RecoverVerifyStep.js +14 -20
  183. package/lib/module/ui/screens/steps/RecoverVerifyStep.js.map +1 -1
  184. package/lib/module/ui/screens/steps/SignInPasswordStep.js +22 -8
  185. package/lib/module/ui/screens/steps/SignInPasswordStep.js.map +1 -1
  186. package/lib/module/ui/screens/steps/SignInTotpStep.js +156 -0
  187. package/lib/module/ui/screens/steps/SignInTotpStep.js.map +1 -0
  188. package/lib/module/ui/screens/steps/SignInUsernameStep.js +12 -6
  189. package/lib/module/ui/screens/steps/SignInUsernameStep.js.map +1 -1
  190. package/lib/module/ui/screens/steps/SignUpIdentityStep.js +10 -6
  191. package/lib/module/ui/screens/steps/SignUpIdentityStep.js.map +1 -1
  192. package/lib/module/ui/screens/steps/SignUpSecurityStep.js +10 -6
  193. package/lib/module/ui/screens/steps/SignUpSecurityStep.js.map +1 -1
  194. package/lib/module/ui/screens/steps/SignUpSummaryStep.js +34 -4
  195. package/lib/module/ui/screens/steps/SignUpSummaryStep.js.map +1 -1
  196. package/lib/module/ui/screens/steps/SignUpWelcomeStep.js +9 -10
  197. package/lib/module/ui/screens/steps/SignUpWelcomeStep.js.map +1 -1
  198. package/lib/module/ui/styles/authStyles.js +1 -2
  199. package/lib/module/ui/styles/authStyles.js.map +1 -1
  200. package/lib/module/utils/deviceManager.js +1 -1
  201. package/lib/module/utils/deviceManager.js.map +1 -1
  202. package/lib/module/utils/validationUtils.js +4 -2
  203. package/lib/module/utils/validationUtils.js.map +1 -1
  204. package/lib/typescript/core/OxyServices.d.ts +57 -3
  205. package/lib/typescript/core/OxyServices.d.ts.map +1 -1
  206. package/lib/typescript/i18n/index.d.ts +4 -0
  207. package/lib/typescript/i18n/index.d.ts.map +1 -0
  208. package/lib/typescript/models/interfaces.d.ts +4 -0
  209. package/lib/typescript/models/interfaces.d.ts.map +1 -1
  210. package/lib/typescript/ui/components/GroupedItem.d.ts.map +1 -1
  211. package/lib/typescript/ui/components/Header.d.ts.map +1 -1
  212. package/lib/typescript/ui/components/OxyProvider.d.ts +1 -1
  213. package/lib/typescript/ui/components/OxyProvider.d.ts.map +1 -1
  214. package/lib/typescript/ui/components/ProfileCard.d.ts.map +1 -1
  215. package/lib/typescript/ui/components/StepBasedScreen.d.ts +2 -1
  216. package/lib/typescript/ui/components/StepBasedScreen.d.ts.map +1 -1
  217. package/lib/typescript/ui/components/internal/GroupedPillButtons.d.ts.map +1 -1
  218. package/lib/typescript/ui/components/internal/PinInput.d.ts +6 -3
  219. package/lib/typescript/ui/components/internal/PinInput.d.ts.map +1 -1
  220. package/lib/typescript/ui/context/OxyContext.d.ts +7 -4
  221. package/lib/typescript/ui/context/OxyContext.d.ts.map +1 -1
  222. package/lib/typescript/ui/hooks/useI18n.d.ts +5 -0
  223. package/lib/typescript/ui/hooks/useI18n.d.ts.map +1 -0
  224. package/lib/typescript/ui/navigation/OxyRouter.d.ts.map +1 -1
  225. package/lib/typescript/ui/navigation/routes.d.ts +9 -0
  226. package/lib/typescript/ui/navigation/routes.d.ts.map +1 -0
  227. package/lib/typescript/ui/navigation/types.d.ts +24 -10
  228. package/lib/typescript/ui/navigation/types.d.ts.map +1 -1
  229. package/lib/typescript/ui/screens/AccountCenterScreen.d.ts.map +1 -1
  230. package/lib/typescript/ui/screens/AccountOverviewScreen.d.ts.map +1 -1
  231. package/lib/typescript/ui/screens/AccountSettingsScreen.d.ts.map +1 -1
  232. package/lib/typescript/ui/screens/AccountSwitcherScreen.d.ts.map +1 -1
  233. package/lib/typescript/ui/screens/FeedbackScreen.d.ts.map +1 -1
  234. package/lib/typescript/ui/screens/LanguageSelectorScreen.d.ts.map +1 -1
  235. package/lib/typescript/ui/screens/PremiumSubscriptionScreen.d.ts.map +1 -1
  236. package/lib/typescript/ui/screens/ProfileScreen.d.ts.map +1 -1
  237. package/lib/typescript/ui/screens/RecoverAccountScreen.d.ts.map +1 -1
  238. package/lib/typescript/ui/screens/SignInScreen.d.ts.map +1 -1
  239. package/lib/typescript/ui/screens/WelcomeNewUserScreen.d.ts.map +1 -1
  240. package/lib/typescript/ui/screens/internal/SignInPasswordStep.d.ts +2 -1
  241. package/lib/typescript/ui/screens/internal/SignInPasswordStep.d.ts.map +1 -1
  242. package/lib/typescript/ui/screens/internal/SignInUsernameStep.d.ts.map +1 -1
  243. package/lib/typescript/ui/screens/karma/KarmaAboutScreen.d.ts.map +1 -1
  244. package/lib/typescript/ui/screens/karma/KarmaCenterScreen.d.ts.map +1 -1
  245. package/lib/typescript/ui/screens/karma/KarmaFAQScreen.d.ts.map +1 -1
  246. package/lib/typescript/ui/screens/karma/KarmaLeaderboardScreen.d.ts.map +1 -1
  247. package/lib/typescript/ui/screens/karma/KarmaRewardsScreen.d.ts.map +1 -1
  248. package/lib/typescript/ui/screens/karma/KarmaRulesScreen.d.ts.map +1 -1
  249. package/lib/typescript/ui/screens/steps/RecoverRequestStep.d.ts +4 -1
  250. package/lib/typescript/ui/screens/steps/RecoverRequestStep.d.ts.map +1 -1
  251. package/lib/typescript/ui/screens/steps/RecoverResetPasswordStep.d.ts +24 -0
  252. package/lib/typescript/ui/screens/steps/RecoverResetPasswordStep.d.ts.map +1 -0
  253. package/lib/typescript/ui/screens/steps/RecoverSuccessStep.d.ts +2 -1
  254. package/lib/typescript/ui/screens/steps/RecoverSuccessStep.d.ts.map +1 -1
  255. package/lib/typescript/ui/screens/steps/RecoverVerifyStep.d.ts +3 -1
  256. package/lib/typescript/ui/screens/steps/RecoverVerifyStep.d.ts.map +1 -1
  257. package/lib/typescript/ui/screens/steps/SignInPasswordStep.d.ts +1 -0
  258. package/lib/typescript/ui/screens/steps/SignInPasswordStep.d.ts.map +1 -1
  259. package/lib/typescript/ui/screens/steps/SignInTotpStep.d.ts +19 -0
  260. package/lib/typescript/ui/screens/steps/SignInTotpStep.d.ts.map +1 -0
  261. package/lib/typescript/ui/screens/steps/SignInUsernameStep.d.ts +2 -1
  262. package/lib/typescript/ui/screens/steps/SignInUsernameStep.d.ts.map +1 -1
  263. package/lib/typescript/ui/screens/steps/SignUpIdentityStep.d.ts +2 -1
  264. package/lib/typescript/ui/screens/steps/SignUpIdentityStep.d.ts.map +1 -1
  265. package/lib/typescript/ui/screens/steps/SignUpSecurityStep.d.ts +2 -1
  266. package/lib/typescript/ui/screens/steps/SignUpSecurityStep.d.ts.map +1 -1
  267. package/lib/typescript/ui/screens/steps/SignUpSummaryStep.d.ts +2 -1
  268. package/lib/typescript/ui/screens/steps/SignUpSummaryStep.d.ts.map +1 -1
  269. package/lib/typescript/ui/screens/steps/SignUpWelcomeStep.d.ts +2 -1
  270. package/lib/typescript/ui/screens/steps/SignUpWelcomeStep.d.ts.map +1 -1
  271. package/lib/typescript/ui/styles/authStyles.d.ts +0 -1
  272. package/lib/typescript/ui/styles/authStyles.d.ts.map +1 -1
  273. package/lib/typescript/utils/validationUtils.d.ts.map +1 -1
  274. package/package.json +49 -15
  275. package/src/core/OxyServices.ts +138 -19
  276. package/src/i18n/index.ts +39 -0
  277. package/src/i18n/locales/en-US.json +681 -0
  278. package/src/i18n/locales/es-ES.json +689 -0
  279. package/src/models/interfaces.ts +6 -1
  280. package/src/ui/components/FollowButton.tsx +2 -2
  281. package/src/ui/components/GroupedItem.tsx +2 -1
  282. package/src/ui/components/Header.tsx +4 -3
  283. package/src/ui/components/OxyProvider.tsx +107 -114
  284. package/src/ui/components/ProfileCard.tsx +5 -1
  285. package/src/ui/components/Section.tsx +1 -1
  286. package/src/ui/components/StepBasedScreen.tsx +17 -14
  287. package/src/ui/components/internal/GroupedPillButtons.tsx +10 -6
  288. package/src/ui/components/internal/PinInput.tsx +15 -6
  289. package/src/ui/context/OxyContext.tsx +123 -20
  290. package/src/ui/hooks/useI18n.ts +12 -0
  291. package/src/ui/navigation/OxyRouter.tsx +15 -134
  292. package/src/ui/navigation/routes.ts +153 -0
  293. package/src/ui/navigation/types.ts +28 -10
  294. package/src/ui/screens/AccountCenterScreen.tsx +47 -45
  295. package/src/ui/screens/AccountOverviewScreen.tsx +68 -70
  296. package/src/ui/screens/AccountSettingsScreen.tsx +265 -41
  297. package/src/ui/screens/AccountSwitcherScreen.tsx +35 -33
  298. package/src/ui/screens/FeedbackScreen.tsx +39 -37
  299. package/src/ui/screens/LanguageSelectorScreen.tsx +99 -70
  300. package/src/ui/screens/PaymentGatewayScreen.tsx +6 -6
  301. package/src/ui/screens/PremiumSubscriptionScreen.tsx +56 -54
  302. package/src/ui/screens/ProfileScreen.tsx +14 -8
  303. package/src/ui/screens/RecoverAccountScreen.tsx +29 -8
  304. package/src/ui/screens/SignInScreen.tsx +39 -30
  305. package/src/ui/screens/WelcomeNewUserScreen.tsx +31 -17
  306. package/src/ui/screens/internal/SignInPasswordStep.tsx +11 -8
  307. package/src/ui/screens/internal/SignInUsernameStep.tsx +10 -8
  308. package/src/ui/screens/karma/KarmaAboutScreen.tsx +23 -11
  309. package/src/ui/screens/karma/KarmaCenterScreen.tsx +21 -11
  310. package/src/ui/screens/karma/KarmaFAQScreen.tsx +15 -33
  311. package/src/ui/screens/karma/KarmaLeaderboardScreen.tsx +6 -4
  312. package/src/ui/screens/karma/KarmaRewardsScreen.tsx +28 -10
  313. package/src/ui/screens/karma/KarmaRulesScreen.tsx +5 -3
  314. package/src/ui/screens/steps/RecoverRequestStep.tsx +20 -17
  315. package/src/ui/screens/steps/RecoverResetPasswordStep.tsx +133 -0
  316. package/src/ui/screens/steps/RecoverSuccessStep.tsx +12 -19
  317. package/src/ui/screens/steps/RecoverVerifyStep.tsx +15 -24
  318. package/src/ui/screens/steps/SignInPasswordStep.tsx +19 -6
  319. package/src/ui/screens/steps/SignInTotpStep.tsx +129 -0
  320. package/src/ui/screens/steps/SignInUsernameStep.tsx +11 -10
  321. package/src/ui/screens/steps/SignUpIdentityStep.tsx +10 -11
  322. package/src/ui/screens/steps/SignUpSecurityStep.tsx +10 -11
  323. package/src/ui/screens/steps/SignUpSummaryStep.tsx +24 -9
  324. package/src/ui/screens/steps/SignUpWelcomeStep.tsx +8 -14
  325. package/src/ui/styles/authStyles.ts +0 -1
  326. package/src/utils/deviceManager.ts +1 -1
  327. package/src/utils/validationUtils.ts +5 -3
@@ -8,6 +8,11 @@ export interface User {
8
8
  email?: string;
9
9
  // Avatar file id (asset id)
10
10
  avatar?: string;
11
+ // Privacy and security settings
12
+ privacySettings?: {
13
+ twoFactorEnabled?: boolean;
14
+ [key: string]: unknown;
15
+ };
11
16
  name?: {
12
17
  first?: string;
13
18
  last?: string;
@@ -330,4 +335,4 @@ export interface DeviceSessionLogoutResponse {
330
335
  export interface UpdateDeviceNameResponse {
331
336
  message: string;
332
337
  deviceName: string;
333
- }
338
+ }
@@ -76,7 +76,7 @@ const FollowButton: React.FC<FollowButtonProps> = ({
76
76
  event.stopPropagation?.();
77
77
  }
78
78
  if (disabled || isLoading) return;
79
-
79
+
80
80
  // Press animation
81
81
  scale.value = withTiming(0.95, { duration: 100 }, (finished) => {
82
82
  if (finished) {
@@ -112,7 +112,7 @@ const FollowButton: React.FC<FollowButtonProps> = ({
112
112
  // Animate button on follow/unfollow
113
113
  useEffect(() => {
114
114
  animationProgress.value = withTiming(isFollowing ? 1 : 0, { duration: 300, easing: Easing.inOut(Easing.ease) });
115
- }, [isFollowing, animationProgress]);
115
+ }, [isFollowing]);
116
116
 
117
117
  // Animated styles for better performance
118
118
  const animatedButtonStyle = useAnimatedStyle(() => {
@@ -131,7 +131,8 @@ const styles = StyleSheet.create({
131
131
  groupedItemContent: {
132
132
  flexDirection: 'row',
133
133
  alignItems: 'center',
134
- padding: 16,
134
+ paddingVertical: 12,
135
+ paddingHorizontal: 12,
135
136
  width: '100%',
136
137
  },
137
138
  groupedItemContentDense: {
@@ -276,16 +276,17 @@ const styles = StyleSheet.create({
276
276
  container: {
277
277
  paddingTop: Platform.OS === 'ios' ? 50 : 16,
278
278
  paddingBottom: 12,
279
- position: 'absolute',
280
279
  top: 0,
281
280
  left: 0,
282
281
  right: 0,
283
282
  zIndex: 1000,
284
283
  ...Platform.select({
285
284
  web: {
286
- position: 'absolute' as const,
285
+ position: 'sticky' as any,
286
+ },
287
+ default: {
288
+ position: 'absolute',
287
289
  },
288
- default: {},
289
290
  }),
290
291
  },
291
292
  content: {
@@ -1,9 +1,8 @@
1
- import type React from 'react';
2
- import { useCallback, useRef, useState, useEffect, useMemo } from 'react';
3
- import { View, Text, StyleSheet, Dimensions, Platform, Animated, StatusBar, Keyboard, KeyboardEvent, AppState } from 'react-native';
1
+ import React, { useCallback, useRef, useState, useEffect, useMemo, forwardRef, useImperativeHandle } from 'react';
2
+ import { View, Text, StyleSheet, Platform, Animated, StatusBar, Keyboard, KeyboardEvent, AppState } from 'react-native';
4
3
  import { SafeAreaProvider, useSafeAreaInsets } from 'react-native-safe-area-context';
5
4
  import { GestureHandlerRootView } from 'react-native-gesture-handler';
6
- import type { OxyProviderProps } from '../navigation/types';
5
+ import type { OxyProviderProps, BottomSheetController } from '../navigation/types';
7
6
  import { OxyContextProvider, useOxy } from '../context/OxyContext';
8
7
  import OxyRouter from '../navigation/OxyRouter';
9
8
  import { FontLoader, setupFonts } from './FontLoader';
@@ -36,8 +35,8 @@ const OxyProvider: React.FC<OxyProviderProps> = (props) => {
36
35
  ...bottomSheetProps
37
36
  } = props;
38
37
 
39
- // Create internal bottom sheet ref
40
- const internalBottomSheetRef = useRef<BottomSheetModalRef>(null);
38
+ // Create typed internal bottom sheet controller ref
39
+ const internalBottomSheetRef = useRef<BottomSheetController>(null);
41
40
 
42
41
  // Initialize React Query Client (use provided client or create a default one once)
43
42
  const queryClientRef = useRef<QueryClient | null>(null);
@@ -68,6 +67,14 @@ const OxyProvider: React.FC<OxyProviderProps> = (props) => {
68
67
  };
69
68
  }, []);
70
69
 
70
+ // Mirror internal controller to external ref if provided (back-compat)
71
+ useEffect(() => {
72
+ if (props.bottomSheetRef) {
73
+ props.bottomSheetRef.current = internalBottomSheetRef.current;
74
+ }
75
+ // eslint-disable-next-line react-hooks/exhaustive-deps
76
+ }, [props.bottomSheetRef]);
77
+
71
78
  // If contextOnly is true, we just provide the context without the bottom sheet UI
72
79
  if (contextOnly) {
73
80
  return (
@@ -99,7 +106,7 @@ const OxyProvider: React.FC<OxyProviderProps> = (props) => {
99
106
  <BottomSheetModalProvider>
100
107
  <StatusBar translucent backgroundColor="transparent" />
101
108
  <SafeAreaProvider>
102
- <OxyBottomSheet {...bottomSheetProps} bottomSheetRef={internalBottomSheetRef} oxyServices={oxyServices} />
109
+ <OxyBottomSheet {...bottomSheetProps} ref={internalBottomSheetRef} oxyServices={oxyServices} />
103
110
  {children}
104
111
  </SafeAreaProvider>
105
112
  </BottomSheetModalProvider>
@@ -122,17 +129,19 @@ const OxyProvider: React.FC<OxyProviderProps> = (props) => {
122
129
  * This is the original OxyProvider UI functionality, now extracted into its own component
123
130
  * and reimplemented using BottomSheetModal for better Android compatibility
124
131
  */
125
- const OxyBottomSheet: React.FC<OxyProviderProps> = ({
132
+ type OxyBottomSheetProps = Omit<OxyProviderProps, 'children' | 'contextOnly' | 'queryClient' | 'bottomSheetRef'>;
133
+
134
+ const OxyBottomSheet = forwardRef<BottomSheetController, OxyBottomSheetProps>(({
126
135
  oxyServices: providedOxyServices,
127
136
  initialScreen = 'SignIn',
128
137
  onClose,
129
138
  onAuthenticated,
130
139
  theme = 'light',
131
140
  customStyles = {},
132
- bottomSheetRef,
133
141
  autoPresent = false,
134
142
  showInternalToaster = true,
135
- }) => {
143
+ appInsets,
144
+ }, ref) => {
136
145
  // Helper function to determine if native driver should be used
137
146
  const shouldUseNativeDriver = () => {
138
147
  return Platform.OS === 'ios';
@@ -142,96 +151,87 @@ const OxyBottomSheet: React.FC<OxyProviderProps> = ({
142
151
  const oxyServices = providedOxyServices || contextOxy?.oxyServices;
143
152
  // Use the internal ref (which is passed as a prop from OxyProvider)
144
153
  const modalRef = useRef<BottomSheetModalRef>(null);
145
- const navigationRef = useRef<((screen: string, props?: Record<string, unknown>) => void) | null>(null);
154
+ const isOpenRef = useRef(false);
155
+ const navigationRef = useRef<((screen: any, props?: Record<string, unknown>) => void) | null>(null);
146
156
  // Remove contentHeight, containerWidth, and snap point state/logic
147
157
  // Animation values - keep for content fade/slide
148
158
  const fadeAnim = useRef(new Animated.Value(Platform.OS === 'android' ? 1 : 0)).current;
149
159
  const slideAnim = useRef(new Animated.Value(Platform.OS === 'android' ? 0 : 50)).current;
150
- useEffect(() => {
151
- if (bottomSheetRef && modalRef.current) {
152
- const methodsToExpose = ['snapToIndex', 'snapToPosition', 'close', 'expand', 'collapse', 'present', 'dismiss'];
153
- methodsToExpose.forEach((method) => {
154
- if (modalRef.current && typeof modalRef.current[method as keyof typeof modalRef.current] === 'function') {
155
- // @ts-ignore
156
- bottomSheetRef.current = bottomSheetRef.current || {};
157
- // @ts-ignore
158
- bottomSheetRef.current[method] = (...args: any[]) => {
159
- // @ts-ignore
160
- return modalRef.current?.[method]?.(...args);
161
- };
162
- }
163
- });
164
-
165
- // Add a method to navigate between screens
166
- // @ts-ignore
167
- bottomSheetRef.current._navigateToScreen = (screenName: string, props?: Record<string, any>) => {
168
- console.log('_navigateToScreen called with:', screenName, props);
169
- if (navigationRef.current) {
170
- console.log('Using navigationRef.current');
171
- navigationRef.current(screenName, props);
172
- return;
173
- }
174
- console.log('navigationRef.current not available, using event system');
175
- if (typeof document !== 'undefined') {
176
- const event = new CustomEvent('oxy:navigate', { detail: { screen: screenName, props } });
177
- document.dispatchEvent(event);
178
- } else {
179
- (globalThis as any).oxyNavigateEvent = { screen: screenName, props };
180
- }
181
- };
182
-
183
- if (bottomSheetRef.current && typeof bottomSheetRef.current === 'object') {
184
- console.log('Bottom sheet ref methods exposed:', Object.keys(bottomSheetRef.current));
160
+ // Expose a clean, typed imperative API
161
+ useImperativeHandle(ref, () => ({
162
+ present: () => {
163
+ if (!isOpenRef.current) modalRef.current?.present?.();
164
+ },
165
+ dismiss: () => modalRef.current?.dismiss?.(),
166
+ expand: () => {
167
+ // Ensure presented, then animate content in
168
+ if (!isOpenRef.current) modalRef.current?.present?.();
169
+ Animated.parallel([
170
+ Animated.timing(fadeAnim, {
171
+ toValue: 1,
172
+ duration: 300,
173
+ useNativeDriver: shouldUseNativeDriver(),
174
+ }),
175
+ Animated.spring(slideAnim, {
176
+ toValue: 0,
177
+ friction: 8,
178
+ tension: 40,
179
+ useNativeDriver: shouldUseNativeDriver(),
180
+ }),
181
+ ]).start();
182
+ },
183
+ collapse: () => modalRef.current?.collapse?.(),
184
+ snapToIndex: (index: number) => modalRef.current?.snapToIndex?.(index),
185
+ snapToPosition: (position: number | string) => modalRef.current?.snapToPosition?.(position as any),
186
+ navigate: (screen: any, props?: Record<string, any>) => {
187
+ if (navigationRef.current) {
188
+ navigationRef.current(screen, props);
189
+ return;
190
+ }
191
+ if (typeof document !== 'undefined') {
192
+ const event = new CustomEvent('oxy:navigate', { detail: { screen, props } });
193
+ document.dispatchEvent(event);
194
+ } else {
195
+ (globalThis as any).oxyNavigateEvent = { screen, props };
185
196
  }
186
197
  }
187
- }, [bottomSheetRef, modalRef]);
198
+ }), [fadeAnim, slideAnim]);
188
199
  // Keyboard handling (unchanged)
189
200
  const [keyboardVisible, setKeyboardVisible] = useState(false);
201
+ const [keyboardHeight, setKeyboardHeight] = useState(0);
190
202
  const insets = useSafeAreaInsets();
191
203
  useEffect(() => {
192
- const keyboardWillShowListener = Keyboard.addListener(
193
- Platform.OS === 'ios' ? 'keyboardWillShow' : 'keyboardDidShow',
194
- () => {
195
- setKeyboardVisible(true);
196
- if (modalRef.current) {
197
- requestAnimationFrame(() => {
198
- modalRef.current?.expand?.();
199
- });
200
- }
201
- }
202
- );
203
- const keyboardWillHideListener = Keyboard.addListener(
204
- Platform.OS === 'ios' ? 'keyboardWillHide' : 'keyboardDidHide',
205
- () => {
206
- setKeyboardVisible(false);
207
- }
208
- );
204
+ // Use 'did' events on iOS to avoid multiple intermediate willShow updates
205
+ const showEvent = Platform.OS === 'ios' ? 'keyboardDidShow' : 'keyboardDidShow';
206
+ const hideEvent = Platform.OS === 'ios' ? 'keyboardDidHide' : 'keyboardDidHide';
207
+ let lastH = 0;
208
+ let lastTs = 0;
209
+ const MIN_DELTA = 8;
210
+ const MIN_INTERVAL = 80; // ms
211
+ const onShow = (e: KeyboardEvent) => {
212
+ const h = e?.endCoordinates?.height ?? 0;
213
+ const now = Date.now();
214
+ if (Math.abs(h - lastH) < MIN_DELTA && now - lastTs < MIN_INTERVAL) return;
215
+ lastH = h;
216
+ lastTs = now;
217
+ setKeyboardVisible(true);
218
+ setKeyboardHeight(h);
219
+ };
220
+ const onHide = () => {
221
+ lastH = 0;
222
+ lastTs = Date.now();
223
+ setKeyboardVisible(false);
224
+ setKeyboardHeight(0);
225
+ };
226
+ const showSub = Keyboard.addListener(showEvent as any, onShow as any);
227
+ const hideSub = Keyboard.addListener(hideEvent as any, onHide as any);
209
228
  return () => {
210
- keyboardWillShowListener.remove();
211
- keyboardWillHideListener.remove();
229
+ showSub.remove();
230
+ hideSub.remove();
212
231
  };
213
232
  }, []);
214
233
  // Present the modal when component mounts, but only if autoPresent is true
215
234
  useEffect(() => {
216
- if (bottomSheetRef && modalRef.current) {
217
- // @ts-ignore
218
- bottomSheetRef.current.expand = () => {
219
- modalRef.current?.present();
220
- Animated.parallel([
221
- Animated.timing(fadeAnim, {
222
- toValue: 1,
223
- duration: 300,
224
- useNativeDriver: shouldUseNativeDriver(),
225
- }),
226
- Animated.spring(slideAnim, {
227
- toValue: 0,
228
- friction: 8,
229
- tension: 40,
230
- useNativeDriver: shouldUseNativeDriver(),
231
- }),
232
- ]).start();
233
- };
234
- }
235
235
  if (autoPresent && modalRef.current) {
236
236
  const timer = setTimeout(() => {
237
237
  modalRef.current?.present();
@@ -251,7 +251,7 @@ const OxyBottomSheet: React.FC<OxyProviderProps> = ({
251
251
  }, 100);
252
252
  return () => clearTimeout(timer);
253
253
  }
254
- }, [bottomSheetRef, modalRef, fadeAnim, slideAnim, autoPresent]);
254
+ }, [modalRef, autoPresent]);
255
255
  // Close the bottom sheet with animation (unchanged)
256
256
  const handleClose = useCallback(() => {
257
257
  Animated.timing(fadeAnim, {
@@ -266,7 +266,7 @@ const OxyBottomSheet: React.FC<OxyProviderProps> = ({
266
266
  }, Platform.OS === 'android' ? 150 : 100);
267
267
  }
268
268
  });
269
- }, [onClose, fadeAnim]);
269
+ }, [onClose]);
270
270
  // Handle authentication success (unchanged)
271
271
  const handleAuthenticated = useCallback((user: any) => {
272
272
  fadeAnim.stopAnimation();
@@ -280,7 +280,7 @@ const OxyBottomSheet: React.FC<OxyProviderProps> = ({
280
280
  onClose();
281
281
  }, 100);
282
282
  }
283
- }, [onAuthenticated, onClose, fadeAnim, slideAnim]);
283
+ }, [onAuthenticated, onClose]);
284
284
  // Backdrop rendering (unchanged)
285
285
  const renderBackdrop = useCallback(
286
286
  (props: BottomSheetBackdropProps) => (
@@ -293,19 +293,6 @@ const OxyBottomSheet: React.FC<OxyProviderProps> = ({
293
293
  ),
294
294
  []
295
295
  );
296
- // Memoize background style
297
- const backgroundStyle = useMemo(() => {
298
- const baseColor = customStyles.backgroundColor || (theme === 'light' ? '#FFFFFF' : '#121212');
299
- return {
300
- backgroundColor: baseColor,
301
- opacity: 1,
302
- ...Platform.select({
303
- android: { elevation: 24 },
304
- })
305
- };
306
- }, [customStyles.backgroundColor, theme]);
307
- // Handle sheet index changes (unchanged)
308
- const handleSheetChanges = useCallback((index: number) => { }, []);
309
296
  // Modernized BottomSheetModal usage
310
297
  return (
311
298
  <BottomSheetModal
@@ -315,8 +302,9 @@ const OxyBottomSheet: React.FC<OxyProviderProps> = ({
315
302
  enablePanDownToClose
316
303
  backdropComponent={renderBackdrop}
317
304
  backgroundStyle={[
318
- backgroundStyle,
319
305
  {
306
+ borderBottomLeftRadius: 0,
307
+ borderBottomRightRadius: 0,
320
308
  borderTopLeftRadius: 35,
321
309
  borderTopRightRadius: 35,
322
310
  }
@@ -326,27 +314,31 @@ const OxyBottomSheet: React.FC<OxyProviderProps> = ({
326
314
  width: 40,
327
315
  height: 4,
328
316
  }}
329
- onChange={handleSheetChanges}
317
+ handleStyle={{
318
+ position: 'absolute',
319
+ top: 0,
320
+ left: 0,
321
+ right: 0,
322
+ }}
330
323
  style={styles.bottomSheetContainer}
331
324
  keyboardBehavior="interactive"
332
325
  keyboardBlurBehavior="restore"
333
- android_keyboardInputMode="adjustResize"
326
+ android_keyboardInputMode="adjustPan"
334
327
  enableOverDrag={false}
335
328
  enableContentPanningGesture={true}
336
329
  enableHandlePanningGesture={true}
337
330
  overDragResistanceFactor={2.5}
338
331
  enableBlurKeyboardOnGesture={true}
339
332
  detached
340
- // Uncomment below to use a sticky footer
341
- // footerComponent={<YourFooterComponent />}
342
- onAnimate={(fromIndex: number, toIndex: number) => {
343
- console.log(`Animating from index ${fromIndex} to ${toIndex}`);
344
- }}
333
+ topInset={(insets?.top ?? 0) + (appInsets?.top ?? 0)}
334
+ bottomInset={((Platform.OS === 'android' ? (keyboardVisible ? keyboardHeight : 0) : 0)) + (appInsets?.bottom ?? 0)}
335
+ onChange={(index) => { isOpenRef.current = index !== -1; }}
336
+ onDismiss={() => { isOpenRef.current = false; }}
345
337
  >
346
338
  <BottomSheetScrollView
347
- style={[
348
- styles.contentContainer,
349
- ]}
339
+ style={[styles.contentContainer]}
340
+ keyboardShouldPersistTaps="handled"
341
+ contentContainerStyle={{ paddingBottom: (insets?.bottom ?? 0) + (appInsets?.bottom ?? 0) }}
350
342
  >
351
343
  <View style={styles.centeredContentWrapper}>
352
344
  <Animated.View
@@ -382,12 +374,13 @@ const OxyBottomSheet: React.FC<OxyProviderProps> = ({
382
374
  )}
383
375
  </BottomSheetModal>
384
376
  );
385
- };
377
+ });
386
378
 
387
379
  const styles = StyleSheet.create({
388
380
  bottomSheetContainer: {
389
381
  maxWidth: 800,
390
382
  width: '100%',
383
+ alignSelf: 'center',
391
384
  marginHorizontal: 'auto',
392
385
  },
393
386
  contentContainer: {
@@ -397,7 +390,7 @@ const styles = StyleSheet.create({
397
390
  },
398
391
  centeredContentWrapper: {
399
392
  width: '100%',
400
- marginHorizontal: 'auto',
393
+ alignSelf: 'center',
401
394
  },
402
395
  animatedContent: {
403
396
  width: '100%',
@@ -1,6 +1,7 @@
1
1
  import type React from 'react';
2
2
  import { View, Text, TouchableOpacity, StyleSheet } from 'react-native';
3
3
  import { Ionicons } from '@expo/vector-icons';
4
+ import { useI18n } from '../hooks/useI18n';
4
5
  import Avatar from './Avatar';
5
6
  import { useOxy } from '../context/OxyContext';
6
7
  import { fontFamilies } from '../styles/fonts';
@@ -27,6 +28,7 @@ const ProfileCard: React.FC<ProfileCardProps> = ({
27
28
  }) => {
28
29
  const isDarkTheme = theme === 'dark';
29
30
  const { oxyServices } = useOxy();
31
+ const { t } = useI18n();
30
32
  const textColor = isDarkTheme ? '#FFFFFF' : '#000000';
31
33
  const secondaryBackgroundColor = isDarkTheme ? '#222222' : '#FFFFFF';
32
34
  const primaryColor = '#0066CC';
@@ -58,7 +60,9 @@ const ProfileCard: React.FC<ProfileCardProps> = ({
58
60
  style={styles.editProfileButton}
59
61
  onPress={onEditPress}
60
62
  >
61
- <Text style={[styles.editProfileText, { color: primaryColor }]}>Edit Profile</Text>
63
+ <Text style={[styles.editProfileText, { color: primaryColor }]}>
64
+ {t('editProfile.title') || 'Edit Profile'}
65
+ </Text>
62
66
  </TouchableOpacity>
63
67
  )}
64
68
  </View>
@@ -27,7 +27,7 @@ const Section: React.FC<SectionProps> = ({
27
27
 
28
28
  const styles = StyleSheet.create({
29
29
  section: {
30
- marginBottom: 24,
30
+ marginBottom: 10,
31
31
  },
32
32
  firstSection: {
33
33
  marginTop: 8,
@@ -21,6 +21,7 @@ import Animated, {
21
21
  } from 'react-native-reanimated';
22
22
  import { useThemeColors, createAuthStyles } from '../styles';
23
23
  import type { BaseScreenProps } from '../navigation/types';
24
+ import type { RouteName } from '../navigation/routes';
24
25
 
25
26
  export interface StepConfig {
26
27
  id: string;
@@ -39,7 +40,7 @@ export interface StepBasedScreenProps extends Omit<BaseScreenProps, 'navigate'>
39
40
  onStepChange?: (currentStep: number, totalSteps: number) => void;
40
41
  onComplete?: (stepData: any[]) => void;
41
42
  stepData?: any[];
42
- navigate: (screen: string, props?: Record<string, any>) => void;
43
+ navigate: (screen: RouteName, props?: Record<string, any>) => void;
43
44
  oxyServices: any; // Required services for step components
44
45
  }
45
46
 
@@ -128,7 +129,6 @@ const StepBasedScreen: React.FC<StepBasedScreenProps> = ({
128
129
  lineHeight: 50.4, // 42 * 1.2
129
130
  marginBottom: 12,
130
131
  textAlign: 'left' as const,
131
- letterSpacing: -0.5,
132
132
  },
133
133
  modernSubtitle: {
134
134
  fontSize: 18,
@@ -138,7 +138,6 @@ const StepBasedScreen: React.FC<StepBasedScreenProps> = ({
138
138
  },
139
139
  modernInputContainer: {
140
140
  width: '100%',
141
- marginBottom: 24,
142
141
  },
143
142
  button: {
144
143
  flexDirection: 'row' as const,
@@ -237,18 +236,22 @@ const StepBasedScreen: React.FC<StepBasedScreenProps> = ({
237
236
  withTiming(0.95, { duration: 50 })
238
237
  );
239
238
 
239
+ // Define a JS function for runOnJS to avoid inline closures
240
+ const applyStepChange = (targetStep: number, totalSteps: number) => {
241
+ setState(prev => ({
242
+ ...prev,
243
+ currentStep: targetStep,
244
+ isTransitioning: false,
245
+ }));
246
+ onStepChangeRef.current?.(targetStep, totalSteps);
247
+ };
248
+
240
249
  fadeAnim.value = withSequence(
241
250
  withTiming(0, { duration: 200 }),
242
251
  withTiming(0, { duration: 50 }, (finished) => {
243
252
  if (finished) {
244
- runOnJS(() => {
245
- setState(prev => ({
246
- ...prev,
247
- currentStep: nextStep,
248
- isTransitioning: false
249
- }));
250
- onStepChangeRef.current?.(nextStep, steps.length);
251
- })();
253
+ // Call back to JS thread correctly
254
+ runOnJS(applyStepChange)(nextStep, steps.length);
252
255
 
253
256
  // Reset animations with proper timing
254
257
  slideAnim.value = withDelay(16, withTiming(-50, { duration: 0 }));
@@ -267,7 +270,7 @@ const StepBasedScreen: React.FC<StepBasedScreenProps> = ({
267
270
  }
268
271
  })
269
272
  );
270
- }, [fadeAnim, slideAnim, scaleAnim, enableAnimations, steps.length]);
273
+ }, [enableAnimations, steps.length]);
271
274
 
272
275
  // Navigation functions
273
276
  const nextStep = useCallback(() => {
@@ -372,8 +375,8 @@ const StepBasedScreen: React.FC<StepBasedScreenProps> = ({
372
375
 
373
376
  return (
374
377
  <KeyboardAvoidingView
375
- style={[styles.container, { backgroundColor: colors.background }]}
376
- behavior={Platform.OS === 'ios' ? 'padding' : 'height'}
378
+ style={[styles.container]}
379
+ behavior={undefined}
377
380
  >
378
381
  <StatusBar
379
382
  barStyle={theme === 'dark' ? 'light-content' : 'dark-content'}
@@ -32,6 +32,7 @@ const GroupedPillButtons: React.FC<GroupedPillButtonsProps> = ({
32
32
  gap: 6,
33
33
  minWidth: 70,
34
34
  borderWidth: 1,
35
+ flexShrink: 0,
35
36
  ...Platform.select({
36
37
  web: {
37
38
  boxShadow: '0 2px 4px rgba(0,0,0,0.1)',
@@ -122,7 +123,8 @@ const GroupedPillButtons: React.FC<GroupedPillButtonsProps> = ({
122
123
  const baseTextStyle = {
123
124
  fontSize: 15,
124
125
  fontWeight: '600' as const,
125
- flex: 1,
126
+ // Avoid stretching that can cause wraps on native
127
+ flexShrink: 1,
126
128
  };
127
129
 
128
130
  let textColor = colors.text;
@@ -140,6 +142,7 @@ const GroupedPillButtons: React.FC<GroupedPillButtonsProps> = ({
140
142
  return {
141
143
  ...baseTextStyle,
142
144
  color: textColor,
145
+ ...(Platform.OS === 'web' ? { whiteSpace: 'nowrap' as any } : null),
143
146
  };
144
147
  };
145
148
 
@@ -155,7 +158,8 @@ const GroupedPillButtons: React.FC<GroupedPillButtonsProps> = ({
155
158
  };
156
159
 
157
160
  const isBackButton = (button: ButtonConfig) => {
158
- return button.text.toLowerCase().includes('back') ||
161
+ const text = typeof button.text === 'string' ? button.text.toLowerCase() : '';
162
+ return text.includes('back') ||
159
163
  button.icon === 'arrow-back' ||
160
164
  button.icon === 'chevron-back';
161
165
  };
@@ -180,7 +184,7 @@ const GroupedPillButtons: React.FC<GroupedPillButtonsProps> = ({
180
184
  // Single button: icon on right
181
185
  return (
182
186
  <>
183
- <Text style={getTextStyle(button, colors)}>
187
+ <Text style={getTextStyle(button, colors)} numberOfLines={1} ellipsizeMode="tail">
184
188
  {button.text}
185
189
  </Text>
186
190
  {button.icon && (
@@ -203,7 +207,7 @@ const GroupedPillButtons: React.FC<GroupedPillButtonsProps> = ({
203
207
  color={iconColor}
204
208
  />
205
209
  )}
206
- <Text style={getTextStyle(button, colors)}>
210
+ <Text style={getTextStyle(button, colors)} numberOfLines={1} ellipsizeMode="tail">
207
211
  {button.text}
208
212
  </Text>
209
213
  </>
@@ -212,7 +216,7 @@ const GroupedPillButtons: React.FC<GroupedPillButtonsProps> = ({
212
216
  // Second button or forward/action button: text on left, icon on right
213
217
  return (
214
218
  <>
215
- <Text style={getTextStyle(button, colors)}>
219
+ <Text style={getTextStyle(button, colors)} numberOfLines={1} ellipsizeMode="tail">
216
220
  {button.text}
217
221
  </Text>
218
222
  {button.icon && (
@@ -254,4 +258,4 @@ const styles = StyleSheet.create({
254
258
  },
255
259
  });
256
260
 
257
- export default GroupedPillButtons;
261
+ export default GroupedPillButtons;
@@ -1,5 +1,4 @@
1
- import type React from 'react';
2
- import { useRef } from 'react';
1
+ import React, { useRef, forwardRef, useImperativeHandle } from 'react';
3
2
  import { View, TextInput, StyleSheet, Platform, type NativeSyntheticEvent, type TextInputKeyPressEventData } from 'react-native';
4
3
 
5
4
  interface PinInputColors {
@@ -11,7 +10,7 @@ interface PinInputColors {
11
10
  border: string;
12
11
  }
13
12
 
14
- interface PinInputProps {
13
+ export interface PinInputProps {
15
14
  value: string;
16
15
  onChange: (val: string) => void;
17
16
  length?: number;
@@ -20,9 +19,19 @@ interface PinInputProps {
20
19
  colors: PinInputColors;
21
20
  }
22
21
 
23
- const PinInput: React.FC<PinInputProps> = ({ value, onChange, length = 6, disabled, autoFocus, colors }) => {
22
+ export interface PinInputHandle {
23
+ focus: () => void;
24
+ }
25
+
26
+ const PinInput = forwardRef<PinInputHandle, PinInputProps>(({ value, onChange, length = 6, disabled, autoFocus, colors }, ref) => {
24
27
  const inputs = useRef<Array<TextInput | null>>([]);
25
28
 
29
+ useImperativeHandle(ref, () => ({
30
+ focus: () => {
31
+ inputs.current[0]?.focus();
32
+ }
33
+ }), []);
34
+
26
35
  const handleChange = (text: string, idx: number) => {
27
36
  if (!/^[0-9]*$/.test(text)) return;
28
37
  let newValue = value.split('');
@@ -74,7 +83,7 @@ const PinInput: React.FC<PinInputProps> = ({ value, onChange, length = 6, disabl
74
83
  ))}
75
84
  </View>
76
85
  );
77
- };
86
+ });
78
87
 
79
88
  const styles = StyleSheet.create({
80
89
  pinContainer: {
@@ -109,4 +118,4 @@ const styles = StyleSheet.create({
109
118
  },
110
119
  });
111
120
 
112
- export default PinInput;
121
+ export default PinInput;