@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
@@ -7,6 +7,7 @@ import { toast } from '../../lib/sonner';
7
7
  import StepBasedScreen, { type StepConfig } from '../components/StepBasedScreen';
8
8
  import SignInUsernameStep from './steps/SignInUsernameStep';
9
9
  import SignInPasswordStep from './steps/SignInPasswordStep';
10
+ import SignInTotpStep from './steps/SignInTotpStep';
10
11
 
11
12
  const SignInScreen: React.FC<BaseScreenProps> = ({
12
13
  navigate,
@@ -29,15 +30,10 @@ const SignInScreen: React.FC<BaseScreenProps> = ({
29
30
  initialUserProfile ? 'valid' : 'idle'
30
31
  );
31
32
 
32
- // Monitor username state changes
33
- useEffect(() => {
34
- console.log('👀 SignInScreen username state changed:', username);
35
- }, [username]);
36
-
37
33
  // Cache for validation results to prevent repeated API calls
38
34
  const validationCache = useRef<Map<string, { profile: any }>>(new Map());
39
35
 
40
- const { login, isLoading, user, isAuthenticated, sessions, oxyServices } = useOxy();
36
+ const { login, completeMfaLogin, isLoading, user, isAuthenticated, sessions, oxyServices } = useOxy();
41
37
 
42
38
  // Only log props in development mode to reduce console noise
43
39
  if (__DEV__) {
@@ -55,10 +51,10 @@ const SignInScreen: React.FC<BaseScreenProps> = ({
55
51
 
56
52
  // Username validation using core services with caching
57
53
  const validateUsername = useCallback(async (usernameToValidate: string) => {
58
- console.log('🔍 Validating username:', usernameToValidate);
54
+ if (__DEV__) console.log('🔍 Validating username:', usernameToValidate);
59
55
 
60
56
  if (!usernameToValidate || usernameToValidate.length < 3) {
61
- console.log('❌ Username too short');
57
+ if (__DEV__) console.log('❌ Username too short');
62
58
  setValidationStatus('invalid');
63
59
  setErrorMessage('Username must be at least 3 characters.');
64
60
  return false;
@@ -75,21 +71,21 @@ const SignInScreen: React.FC<BaseScreenProps> = ({
75
71
  // Check cache first
76
72
  const cached = validationCache.current.get(usernameToValidate);
77
73
  if (cached) {
78
- console.log('✅ Username found in cache:', cached.profile);
74
+ if (__DEV__) console.log('✅ Username found in cache:', cached.profile);
79
75
  setUserProfile(cached.profile);
80
76
  setValidationStatus('valid');
81
77
  setErrorMessage('');
82
78
  return true;
83
79
  }
84
80
 
85
- console.log('🔄 Validating username with API...');
81
+ if (__DEV__) console.log('🔄 Validating username with API...');
86
82
  setIsValidating(true);
87
83
  setValidationStatus('validating');
88
84
 
89
85
  try {
90
86
  // Check if username exists
91
87
  const profile = await oxyServices.getProfileByUsername(usernameToValidate);
92
- console.log('📋 Profile response:', profile);
88
+ if (__DEV__) console.log('📋 Profile response:', profile);
93
89
 
94
90
  if (profile && profile.username) {
95
91
  const profileData = {
@@ -99,7 +95,7 @@ const SignInScreen: React.FC<BaseScreenProps> = ({
99
95
  id: profile.id
100
96
  };
101
97
 
102
- console.log('✅ Username is valid:', profileData);
98
+ if (__DEV__) console.log('✅ Username is valid:', profileData);
103
99
  setUserProfile(profileData);
104
100
  setValidationStatus('valid');
105
101
  setErrorMessage('');
@@ -111,13 +107,13 @@ const SignInScreen: React.FC<BaseScreenProps> = ({
111
107
 
112
108
  return true;
113
109
  } else {
114
- console.log('❌ Username not found');
110
+ if (__DEV__) console.log('❌ Username not found');
115
111
  setValidationStatus('invalid');
116
112
  setErrorMessage('Username not found.');
117
113
  return false;
118
114
  }
119
115
  } catch (error: any) {
120
- console.log('🚨 Validation error:', error);
116
+ if (__DEV__) console.log('🚨 Validation error:', error);
121
117
 
122
118
  // If user not found (404), username doesn't exist
123
119
  if (error.status === 404 || error.code === 'USER_NOT_FOUND') {
@@ -129,7 +125,7 @@ const SignInScreen: React.FC<BaseScreenProps> = ({
129
125
 
130
126
  // For development/testing: if API fails, allow any 3+ character username
131
127
  if (__DEV__) {
132
- console.log('⚠️ Development mode: allowing username due to API error');
128
+ if (__DEV__) console.log('⚠️ Development mode: allowing username due to API error');
133
129
  setValidationStatus('valid');
134
130
  setErrorMessage('');
135
131
  return true;
@@ -179,6 +175,8 @@ const SignInScreen: React.FC<BaseScreenProps> = ({
179
175
  return valid;
180
176
  }, [username, validateUsername]);
181
177
 
178
+ const [mfaToken, setMfaToken] = useState<string | null>(null);
179
+
182
180
  const handleSignIn = useCallback(async () => {
183
181
  if (!password) {
184
182
  setErrorMessage('Please enter your password.');
@@ -195,6 +193,10 @@ const SignInScreen: React.FC<BaseScreenProps> = ({
195
193
  onAuthenticated(user);
196
194
  }
197
195
  } catch (error: any) {
196
+ if (error?.code === 'MFA_REQUIRED' && error?.mfaToken) {
197
+ setMfaToken(error.mfaToken);
198
+ return; // Password step will auto-advance when MFA token is set
199
+ }
198
200
  setErrorMessage(error.message || 'Login failed');
199
201
  }
200
202
  }, [username, password, login, onAuthenticated, userProfile]);
@@ -207,24 +209,22 @@ const SignInScreen: React.FC<BaseScreenProps> = ({
207
209
  }, []);
208
210
 
209
211
  // Step configurations
210
- const steps: StepConfig[] = useMemo(() => [
211
- {
212
- id: 'username',
213
- component: SignInUsernameStep,
214
- canProceed: () => true, // Let the component handle validation internally
215
- },
216
- {
217
- id: 'password',
218
- component: SignInPasswordStep,
219
- canProceed: () => true, // Let the component handle validation internally
220
- },
221
- ], [username, password, validationStatus, validateUsername, handleSignIn]);
212
+ const steps: StepConfig[] = useMemo(() => {
213
+ const base: StepConfig[] = [
214
+ { id: 'username', component: SignInUsernameStep, canProceed: () => true },
215
+ { id: 'password', component: SignInPasswordStep, canProceed: () => true },
216
+ ];
217
+ if (mfaToken) {
218
+ base.push({ id: 'totp', component: SignInTotpStep, canProceed: () => true });
219
+ }
220
+ return base;
221
+ }, [mfaToken, username, password, validationStatus, validateUsername, handleSignIn]);
222
222
 
223
223
  // Handle step completion (final step)
224
224
  const handleComplete = useCallback(async (stepData: any[]) => {
225
225
  // The sign-in is handled by the password step component
226
226
  // This callback is here for interface compatibility
227
- console.log('Sign-in flow completed');
227
+ if (__DEV__) console.log('Sign-in flow completed');
228
228
  }, []);
229
229
 
230
230
  // Step data for the reusable component
@@ -258,12 +258,21 @@ const SignInScreen: React.FC<BaseScreenProps> = ({
258
258
  handleInputFocus,
259
259
  handleInputBlur,
260
260
  handleSignIn, // Add sign-in function for password step
261
+ mfaToken,
261
262
  },
263
+ ...(mfaToken ? [{
264
+ username,
265
+ mfaToken,
266
+ completeMfaLogin,
267
+ errorMessage,
268
+ setErrorMessage,
269
+ isLoading,
270
+ }] : []),
262
271
  ], [
263
- username, password, errorMessage, validationStatus, userProfile,
272
+ username, password, errorMessage, validationStatus, userProfile, mfaToken,
264
273
  isValidating, isInputFocused, isAddAccountMode, user, showPassword,
265
274
  isLoading, handleUsernameChange, handlePasswordChange, handleInputFocus, handleInputBlur,
266
- validateUsername, handleSignIn
275
+ validateUsername, handleSignIn, completeMfaLogin
267
276
  ]);
268
277
 
269
278
  return (
@@ -8,6 +8,7 @@ import { toast } from '../../lib/sonner';
8
8
  import { useAuthStore } from '../stores/authStore';
9
9
  import { useThemeColors } from '../styles';
10
10
  import GroupedPillButtons from '../components/internal/GroupedPillButtons';
11
+ import { useI18n } from '../hooks/useI18n';
11
12
 
12
13
  /**
13
14
  * Post-signup welcome & onboarding screen.
@@ -22,6 +23,7 @@ const WelcomeNewUserScreen: React.FC<BaseScreenProps & { newUser?: any }> = ({
22
23
  newUser,
23
24
  }) => {
24
25
  const { user, oxyServices } = useOxy();
26
+ const { t } = useI18n();
25
27
  const updateUser = useAuthStore(s => s.updateUser);
26
28
  const currentUser = user || newUser; // fallback
27
29
  const colors = useThemeColors(theme);
@@ -35,13 +37,25 @@ const WelcomeNewUserScreen: React.FC<BaseScreenProps & { newUser?: any }> = ({
35
37
  const avatarUri = currentUser?.avatar ? oxyServices.getFileDownloadUrl(currentUser.avatar as string, 'thumb') : undefined;
36
38
 
37
39
  // Steps content
40
+ const welcomeTitle = currentUser?.username
41
+ ? (t('welcomeNew.welcome.titleWithName', { username: currentUser.username }) || `Welcome, ${currentUser.username} 👋`)
42
+ : (t('welcomeNew.welcome.title') || 'Welcome 👋');
38
43
  const steps: Array<{ key: string; title: string; bullets?: string[]; body?: string; showAvatar?: boolean; }> = [
39
- { key: 'welcome', title: `Welcome${currentUser?.username ? `, ${currentUser.username}` : ''} 👋`, body: 'You just created an account in a calm, ethical space. A few quick things — then you\'re in.' },
40
- { key: 'account', title: 'One Account. Simple.', bullets: ['One identity across everything', 'No re‑signing in all the time', 'Your preferences stay with you'] },
41
- { key: 'principles', title: 'What We Stand For', bullets: ['Privacy by default', 'No manipulative feeds', 'You decide what to share', 'No selling your data'] },
42
- { key: 'karma', title: 'Karma = Trust & Growth', body: 'Oxy Karma is a points system that reacts to what you do. Helpful, respectful, constructive actions earn it. Harmful or loweffort stuff chips it away. More karma can unlock benefits; low karma can limit features. It keeps things fair and rewards real contribution.' },
43
- { key: 'avatar', title: 'Make It Yours', body: 'Add an avatar so people recognize you. It will show anywhere you show up here. Skip if you want — you can add it later.', showAvatar: true },
44
- { key: 'ready', title: 'You\'re Ready', body: 'Explore. Contribute. Earn karma. Stay in control.' }
44
+ { key: 'welcome', title: welcomeTitle, body: t('welcomeNew.welcome.body') || "You just created an account in a calm, ethical space. A few quick things — then you're in." },
45
+ { key: 'account', title: t('welcomeNew.account.title') || 'One Account. Simple.', bullets: [
46
+ t('welcomeNew.account.bullets.0') || 'One identity across everything',
47
+ t('welcomeNew.account.bullets.1') || 'No resigning in all the time',
48
+ t('welcomeNew.account.bullets.2') || 'Your preferences stay with you',
49
+ ] },
50
+ { key: 'principles', title: t('welcomeNew.principles.title') || 'What We Stand For', bullets: [
51
+ t('welcomeNew.principles.bullets.0') || 'Privacy by default',
52
+ t('welcomeNew.principles.bullets.1') || 'No manipulative feeds',
53
+ t('welcomeNew.principles.bullets.2') || 'You decide what to share',
54
+ t('welcomeNew.principles.bullets.3') || 'No selling your data',
55
+ ] },
56
+ { key: 'karma', title: t('welcomeNew.karma.title') || 'Karma = Trust & Growth', body: t('welcomeNew.karma.body') || 'Oxy Karma is a points system that reacts to what you do. Helpful, respectful, constructive actions earn it. Harmful or low‑effort stuff chips it away. More karma can unlock benefits; low karma can limit features. It keeps things fair and rewards real contribution.' },
57
+ { key: 'avatar', title: t('welcomeNew.avatar.title') || 'Make It Yours', body: t('welcomeNew.avatar.body') || 'Add an avatar so people recognize you. It will show anywhere you show up here. Skip if you want — you can add it later.', showAvatar: true },
58
+ { key: 'ready', title: t('welcomeNew.ready.title') || "You're Ready", body: t('welcomeNew.ready.body') || 'Explore. Contribute. Earn karma. Stay in control.' }
45
59
  ];
46
60
  const totalSteps = steps.length;
47
61
  const avatarStepIndex = steps.findIndex(s => s.showAvatar);
@@ -68,8 +82,8 @@ const WelcomeNewUserScreen: React.FC<BaseScreenProps & { newUser?: any }> = ({
68
82
  disabledMimeTypes: ['video/', 'audio/', 'application/pdf'],
69
83
  afterSelect: 'back',
70
84
  onSelect: async (file: any) => {
71
- if (!file.contentType.startsWith('image/')) { toast.error('Please select an image file'); return; }
72
- try { await updateUser({ avatar: file.id }, oxyServices); toast.success('Avatar updated'); } catch (e: any) { toast.error(e.message || 'Failed to update avatar'); }
85
+ if (!file.contentType.startsWith('image/')) { toast.error(t('editProfile.toasts.selectImage') || 'Please select an image file'); return; }
86
+ try { await updateUser({ avatar: file.id }, oxyServices); toast.success(t('editProfile.toasts.avatarUpdated') || 'Avatar updated'); } catch (e: any) { toast.error(e.message || t('editProfile.toasts.updateAvatarFailed') || 'Failed to update avatar'); }
73
87
  }
74
88
  });
75
89
  }, [navigate, updateUser, oxyServices]);
@@ -78,25 +92,25 @@ const WelcomeNewUserScreen: React.FC<BaseScreenProps & { newUser?: any }> = ({
78
92
  const pillButtons = useMemo(() => {
79
93
  if (currentStep === totalSteps - 1) {
80
94
  return [
81
- { text: 'Back', onPress: prevStep, icon: 'arrow-back', variant: 'transparent' },
82
- { text: 'Enter', onPress: finish, icon: 'log-in-outline', variant: 'primary' },
95
+ { text: t('welcomeNew.actions.back') || 'Back', onPress: prevStep, icon: 'arrow-back', variant: 'transparent' },
96
+ { text: t('welcomeNew.actions.enter') || 'Enter', onPress: finish, icon: 'log-in-outline', variant: 'primary' },
83
97
  ];
84
98
  }
85
99
  if (currentStep === 0) {
86
100
  const arr: any[] = [];
87
- if (avatarStepIndex > 0) arr.push({ text: 'Skip', onPress: skipToAvatar, icon: 'play-skip-forward', variant: 'transparent' });
88
- arr.push({ text: 'Next', onPress: nextStep, icon: 'arrow-forward', variant: 'primary' });
101
+ if (avatarStepIndex > 0) arr.push({ text: t('welcomeNew.actions.skip') || 'Skip', onPress: skipToAvatar, icon: 'play-skip-forward', variant: 'transparent' });
102
+ arr.push({ text: t('welcomeNew.actions.next') || 'Next', onPress: nextStep, icon: 'arrow-forward', variant: 'primary' });
89
103
  return arr;
90
104
  }
91
105
  if (step.showAvatar) {
92
106
  return [
93
- { text: 'Back', onPress: prevStep, icon: 'arrow-back', variant: 'transparent' },
94
- { text: avatarUri ? 'Continue' : 'Skip', onPress: nextStep, icon: 'arrow-forward', variant: 'primary' },
107
+ { text: t('welcomeNew.actions.back') || 'Back', onPress: prevStep, icon: 'arrow-back', variant: 'transparent' },
108
+ { text: avatarUri ? (t('welcomeNew.actions.continue') || 'Continue') : (t('welcomeNew.actions.skip') || 'Skip'), onPress: nextStep, icon: 'arrow-forward', variant: 'primary' },
95
109
  ];
96
110
  }
97
111
  return [
98
- { text: 'Back', onPress: prevStep, icon: 'arrow-back', variant: 'transparent' },
99
- { text: 'Next', onPress: nextStep, icon: 'arrow-forward', variant: 'primary' },
112
+ { text: t('welcomeNew.actions.back') || 'Back', onPress: prevStep, icon: 'arrow-back', variant: 'transparent' },
113
+ { text: t('welcomeNew.actions.next') || 'Next', onPress: nextStep, icon: 'arrow-forward', variant: 'primary' },
100
114
  ];
101
115
  }, [currentStep, totalSteps, prevStep, nextStep, finish, skipToAvatar, avatarStepIndex, step.showAvatar, avatarUri]);
102
116
 
@@ -126,7 +140,7 @@ const WelcomeNewUserScreen: React.FC<BaseScreenProps & { newUser?: any }> = ({
126
140
  <Avatar size={120} name={currentUser?.username} uri={avatarUri} theme={theme} style={styles.avatar} />
127
141
  <TouchableOpacity style={styles.changeAvatarButton} onPress={openAvatarPicker}>
128
142
  <Ionicons name="image-outline" size={18} color="#FFFFFF" />
129
- <Text style={styles.changeAvatarText}>{avatarUri ? 'Change Avatar' : 'Add Avatar'}</Text>
143
+ <Text style={styles.changeAvatarText}>{avatarUri ? (t('welcomeNew.avatar.change') || 'Change Avatar') : (t('welcomeNew.avatar.add') || 'Add Avatar')}</Text>
130
144
  </TouchableOpacity>
131
145
  </View>
132
146
  )}
@@ -1,4 +1,5 @@
1
1
  import type React from 'react';
2
+ import type { RouteName } from '../../navigation/routes';
2
3
  import { useRef, useCallback, useEffect } from 'react';
3
4
  import { View, Text, TouchableOpacity, type TextInput, StatusBar } from 'react-native';
4
5
  import Animated, {
@@ -7,6 +8,7 @@ import Animated, {
7
8
  } from 'react-native-reanimated';
8
9
  import { Ionicons } from '@expo/vector-icons';
9
10
  import Avatar from '../../components/Avatar';
11
+ import { useI18n } from '../../hooks/useI18n';
10
12
  import GroupedPillButtons from '../../components/internal/GroupedPillButtons';
11
13
  import TextField from '../../components/internal/TextField';
12
14
 
@@ -30,7 +32,7 @@ interface SignInPasswordStepProps {
30
32
  handleSignIn: () => void;
31
33
  isLoading: boolean;
32
34
  prevStep: () => void;
33
- navigate: (screen: string, props?: Record<string, any>) => void;
35
+ navigate: (screen: RouteName, props?: Record<string, any>) => void;
34
36
  }
35
37
 
36
38
  const SignInPasswordStep: React.FC<SignInPasswordStepProps> = ({
@@ -56,6 +58,7 @@ const SignInPasswordStep: React.FC<SignInPasswordStepProps> = ({
56
58
  navigate,
57
59
  }) => {
58
60
  const inputRef = useRef<TextInput>(null);
61
+ const { t } = useI18n();
59
62
 
60
63
  // Animated styles - properly memoized to prevent re-renders
61
64
  const containerAnimatedStyle = useAnimatedStyle(() => {
@@ -121,7 +124,7 @@ const SignInPasswordStep: React.FC<SignInPasswordStepProps> = ({
121
124
  <View style={styles.modernInputContainer}>
122
125
  <TextField
123
126
  ref={inputRef}
124
- label="Password"
127
+ label={t('common.labels.password')}
125
128
  leading={<Ionicons name="lock-closed-outline" size={24} color={colors.secondaryText} />}
126
129
  value={password}
127
130
  onChangeText={handlePasswordChange}
@@ -137,26 +140,26 @@ const SignInPasswordStep: React.FC<SignInPasswordStepProps> = ({
137
140
  autoFocus
138
141
  />
139
142
  <View style={{ flexDirection: 'row', alignItems: 'center', marginBottom: 16 }}>
140
- <Text style={[styles.footerText, { color: colors.text }]}>Forgot your password? </Text>
143
+ <Text style={[styles.footerText, { color: colors.text }]}>{t('signin.forgotPrompt') || 'Forgot your password?'} </Text>
141
144
  <TouchableOpacity onPress={() => navigate('RecoverAccount', {
142
145
  returnTo: 'SignIn',
143
146
  returnStep: 1,
144
147
  returnData: { username, userProfile }
145
148
  })}>
146
- <Text style={[styles.modernLinkText, { color: colors.primary }]}>Recover your account</Text>
149
+ <Text style={[styles.modernLinkText, { color: colors.primary }]}>{t('common.links.recoverAccount')}</Text>
147
150
  </TouchableOpacity>
148
151
  </View>
149
152
  </View>
150
153
  <GroupedPillButtons
151
154
  buttons={[
152
155
  {
153
- text: 'Back',
156
+ text: t('common.actions.back'),
154
157
  onPress: prevStep,
155
158
  icon: 'arrow-back',
156
159
  variant: 'transparent',
157
160
  },
158
161
  {
159
- text: 'Sign In',
162
+ text: t('common.actions.signIn'),
160
163
  onPress: handleSignIn,
161
164
  icon: 'log-in',
162
165
  variant: 'primary',
@@ -169,7 +172,7 @@ const SignInPasswordStep: React.FC<SignInPasswordStepProps> = ({
169
172
  <View style={styles.securityNotice}>
170
173
  <Ionicons name="shield-checkmark" size={14} color={colors.secondaryText} />
171
174
  <Text style={[styles.securityText, { color: colors.secondaryText }]}>
172
- Your data is encrypted and secure
175
+ {t('signin.security.dataSecure') || 'Your data is encrypted and secure'}
173
176
  </Text>
174
177
  </View>
175
178
  <StatusBar
@@ -180,4 +183,4 @@ const SignInPasswordStep: React.FC<SignInPasswordStepProps> = ({
180
183
  );
181
184
  };
182
185
 
183
- export default SignInPasswordStep;
186
+ export default SignInPasswordStep;
@@ -6,6 +6,7 @@ import Animated, {
6
6
  SharedValue,
7
7
  } from 'react-native-reanimated';
8
8
  import { Ionicons } from '@expo/vector-icons';
9
+ import { useI18n } from '../../hooks/useI18n';
9
10
  import HighFive from '../../../assets/illustrations/HighFive';
10
11
  import GroupedPillButtons from '../../components/internal/GroupedPillButtons';
11
12
  import TextField from '../../components/internal/TextField';
@@ -52,6 +53,7 @@ const SignInUsernameStep: React.FC<SignInUsernameStepProps> = ({
52
53
  navigate,
53
54
  }) => {
54
55
  const inputRef = useRef<TextInput>(null);
56
+ const { t } = useI18n();
55
57
 
56
58
  // Animated styles - properly memoized to prevent re-renders
57
59
  const animatedStyle = useAnimatedStyle(() => {
@@ -80,12 +82,12 @@ const SignInUsernameStep: React.FC<SignInUsernameStepProps> = ({
80
82
  <HighFive width={100} height={100} />
81
83
  <View style={styles.modernHeader}>
82
84
  <Text style={[styles.modernTitle, { color: colors.text }]}>
83
- {isAddAccountMode ? 'Add Another Account' : 'Sign In'}
85
+ {isAddAccountMode ? (t('signin.addAccountTitle') || 'Add Another Account') : (t('signin.title') || 'Sign In')}
84
86
  </Text>
85
87
  <Text style={[styles.modernSubtitle, { color: colors.secondaryText }]}>
86
88
  {isAddAccountMode
87
- ? 'Sign in with another account'
88
- : 'Sign in to continue your journey'
89
+ ? (t('signin.addAccountSubtitle') || 'Sign in with another account')
90
+ : (t('signin.subtitle') || 'Sign in to continue your journey')
89
91
  }
90
92
  </Text>
91
93
  </View>
@@ -93,14 +95,14 @@ const SignInUsernameStep: React.FC<SignInUsernameStepProps> = ({
93
95
  <View style={[styles.modernInfoCard, { backgroundColor: colors.inputBackground }]}>
94
96
  <Ionicons name="information-circle" size={20} color={colors.primary} />
95
97
  <Text style={[styles.modernInfoText, { color: colors.text }]}>
96
- Currently signed in as <Text style={{ fontWeight: 'bold' }}>{user?.username}</Text>
98
+ {t('signin.currentlySignedInAs', { username: user?.username }) || 'Currently signed in as '}<Text style={{ fontWeight: 'bold' }}>{user?.username}</Text>
97
99
  </Text>
98
100
  </View>
99
101
  )}
100
102
  <View style={styles.modernInputContainer}>
101
103
  <TextField
102
104
  ref={inputRef}
103
- label="Username"
105
+ label={t('common.labels.username')}
104
106
  leading={<Ionicons name="person-outline" size={24} color={colors.secondaryText} />}
105
107
  value={username}
106
108
  onChangeText={handleUsernameChange}
@@ -120,13 +122,13 @@ const SignInUsernameStep: React.FC<SignInUsernameStepProps> = ({
120
122
  <GroupedPillButtons
121
123
  buttons={[
122
124
  {
123
- text: 'Sign Up',
125
+ text: t('common.links.signUp') || 'Sign Up',
124
126
  onPress: () => navigate('SignUp'),
125
127
  icon: 'person-add',
126
128
  variant: 'transparent',
127
129
  },
128
130
  {
129
- text: 'Continue',
131
+ text: t('common.actions.continue'),
130
132
  onPress: handleUsernameContinue,
131
133
  icon: 'arrow-forward',
132
134
  variant: 'primary',
@@ -140,4 +142,4 @@ const SignInUsernameStep: React.FC<SignInUsernameStepProps> = ({
140
142
  );
141
143
  };
142
144
 
143
- export default SignInUsernameStep;
145
+ export default SignInUsernameStep;
@@ -2,8 +2,10 @@ import type React from 'react';
2
2
  import { View, Text, StyleSheet, ScrollView, Platform } from 'react-native';
3
3
  import type { BaseScreenProps } from '../../navigation/types';
4
4
  import { Header } from '../../components';
5
+ import { useI18n } from '../../hooks/useI18n';
5
6
 
6
7
  const KarmaAboutScreen: React.FC<BaseScreenProps> = ({ goBack, theme }) => {
8
+ const { t } = useI18n();
7
9
  const isDarkTheme = theme === 'dark';
8
10
  const backgroundColor = isDarkTheme ? '#121212' : '#FFFFFF';
9
11
  const textColor = isDarkTheme ? '#FFFFFF' : '#000000';
@@ -12,22 +14,32 @@ const KarmaAboutScreen: React.FC<BaseScreenProps> = ({ goBack, theme }) => {
12
14
  return (
13
15
  <View style={[styles.container, { backgroundColor }]}>
14
16
  <Header
15
- title="About Karma"
16
- subtitle="Learn about the karma system"
17
+ title={t('karma.about.title') || 'About Karma'}
18
+ subtitle={t('karma.about.subtitle') || 'Learn about the karma system'}
17
19
  theme={theme}
18
20
  onBack={goBack}
19
21
  elevation="subtle"
20
22
  />
21
23
  <ScrollView contentContainerStyle={styles.contentContainer}>
22
- <Text style={[styles.paragraph, { color: textColor }]}>Karma is a recognition of your positive actions in the Oxy Ecosystem. It cannot be sent or received directly, only earned by contributing to the community.</Text>
23
- <Text style={[styles.section, { color: primaryColor }]}>How to Earn Karma</Text>
24
- <Text style={[styles.paragraph, { color: textColor }]}>• Helping other users{'\n'}
25
- Reporting bugs{'\n'}
26
- Contributing content{'\n'}
27
- • Participating in events{'\n'}
28
- Other positive actions</Text>
29
- <Text style={[styles.section, { color: primaryColor }]}>Why Karma?</Text>
30
- <Text style={[styles.paragraph, { color: textColor }]}>Karma unlocks special features and recognition in the Oxy Ecosystem. The more you contribute, the more you earn!</Text>
24
+ <Text style={[styles.paragraph, { color: textColor }]}>
25
+ {t('karma.about.intro') || 'Karma is a recognition of your positive actions in the Oxy Ecosystem. It cannot be sent or received directly, only earned by contributing to the community.'}
26
+ </Text>
27
+ <Text style={[styles.section, { color: primaryColor }]}>
28
+ {t('karma.about.how.title') || 'How to Earn Karma'}
29
+ </Text>
30
+ <Text style={[styles.paragraph, { color: textColor }]}>
31
+ {t('karma.about.how.help') || 'Helping other users'}{'\n'}
32
+ {t('karma.about.how.report') || 'Reporting bugs'}{'\n'}
33
+ • {t('karma.about.how.contribute') || 'Contributing content'}{'\n'}
34
+ • {t('karma.about.how.participate') || 'Participating in events'}{'\n'}
35
+ • {t('karma.about.how.other') || 'Other positive actions'}
36
+ </Text>
37
+ <Text style={[styles.section, { color: primaryColor }]}>
38
+ {t('karma.about.why.title') || 'Why Karma?'}
39
+ </Text>
40
+ <Text style={[styles.paragraph, { color: textColor }]}>
41
+ {t('karma.about.why.text') || 'Karma unlocks special features and recognition in the Oxy Ecosystem. The more you contribute, the more you earn!'}
42
+ </Text>
31
43
  </ScrollView>
32
44
  </View>
33
45
  );
@@ -15,6 +15,7 @@ import { useOxy } from '../../context/OxyContext';
15
15
  import { fontFamilies } from '../../styles/fonts';
16
16
  import Avatar from '../../components/Avatar';
17
17
  import { Ionicons } from '@expo/vector-icons';
18
+ import { useI18n } from '../../hooks/useI18n';
18
19
 
19
20
  const KarmaCenterScreen: React.FC<BaseScreenProps> = ({
20
21
  theme,
@@ -22,6 +23,7 @@ const KarmaCenterScreen: React.FC<BaseScreenProps> = ({
22
23
  goBack,
23
24
  }) => {
24
25
  const { user, oxyServices, isAuthenticated } = useOxy();
26
+ const { t } = useI18n();
25
27
  const [karmaTotal, setKarmaTotal] = useState<number | null>(null);
26
28
  const [karmaHistory, setKarmaHistory] = useState<any[]>([]);
27
29
  const [isLoading, setIsLoading] = useState(true);
@@ -55,7 +57,7 @@ const KarmaCenterScreen: React.FC<BaseScreenProps> = ({
55
57
  if (!isAuthenticated) {
56
58
  return (
57
59
  <View style={[styles.container, { backgroundColor }]}>
58
- <Text style={[styles.message, { color: textColor }]}>Not signed in</Text>
60
+ <Text style={[styles.message, { color: textColor }]}>{t('common.status.notSignedIn') || 'Not signed in'}</Text>
59
61
  </View>
60
62
  );
61
63
  }
@@ -79,46 +81,54 @@ const KarmaCenterScreen: React.FC<BaseScreenProps> = ({
79
81
  theme={theme}
80
82
  style={styles.avatar}
81
83
  />
82
- <Text style={[styles.karmaLabel, { color: isDarkTheme ? '#BBBBBB' : '#888888' }]}>Karma Balance</Text>
84
+ <Text style={[styles.karmaLabel, { color: isDarkTheme ? '#BBBBBB' : '#888888' }]}>
85
+ {t('karma.center.balance') || 'Karma Balance'}
86
+ </Text>
83
87
  <Text style={[styles.karmaAmount, { color: primaryColor }]}>{karmaTotal ?? 0}</Text>
84
88
  <View style={styles.actionRow}>
85
89
  <TouchableOpacity style={styles.actionIconWrapper} onPress={() => navigate && navigate('KarmaLeaderboard')}>
86
90
  <View style={[styles.actionIcon, { backgroundColor: '#E0E0E0' }]}>
87
91
  <Ionicons name="trophy-outline" size={28} color="#888" />
88
92
  </View>
89
- <Text style={styles.actionLabel}>Leaderboard</Text>
93
+ <Text style={styles.actionLabel}>{t('karma.center.actions.leaderboard') || 'Leaderboard'}</Text>
90
94
  </TouchableOpacity>
91
95
  <TouchableOpacity style={styles.actionIconWrapper} onPress={() => navigate && navigate('KarmaRules')}>
92
96
  <View style={[styles.actionIcon, { backgroundColor: '#E0E0E0' }]}>
93
97
  <Ionicons name="document-text-outline" size={28} color="#888" />
94
98
  </View>
95
- <Text style={styles.actionLabel}>Rules</Text>
99
+ <Text style={styles.actionLabel}>{t('karma.center.actions.rules') || 'Rules'}</Text>
96
100
  </TouchableOpacity>
97
101
  <TouchableOpacity style={styles.actionIconWrapper} onPress={() => navigate && navigate('AboutKarma')}>
98
102
  <View style={[styles.actionIcon, { backgroundColor: '#E0E0E0' }]}>
99
103
  <Ionicons name="star-outline" size={28} color="#888" />
100
104
  </View>
101
- <Text style={styles.actionLabel}>About</Text>
105
+ <Text style={styles.actionLabel}>{t('karma.center.actions.about') || 'About'}</Text>
102
106
  </TouchableOpacity>
103
107
  <TouchableOpacity style={styles.actionIconWrapper} onPress={() => navigate && navigate('KarmaRewards')}>
104
108
  <View style={[styles.actionIcon, { backgroundColor: '#E0E0E0' }]}>
105
109
  <Ionicons name="gift-outline" size={28} color="#888" />
106
110
  </View>
107
- <Text style={styles.actionLabel}>Rewards</Text>
111
+ <Text style={styles.actionLabel}>{t('karma.center.actions.rewards') || 'Rewards'}</Text>
108
112
  </TouchableOpacity>
109
113
  <TouchableOpacity style={styles.actionIconWrapper} onPress={() => navigate && navigate('KarmaFAQ')}>
110
114
  <View style={[styles.actionIcon, { backgroundColor: '#E0E0E0' }]}>
111
115
  <Ionicons name="help-circle-outline" size={28} color="#888" />
112
116
  </View>
113
- <Text style={styles.actionLabel}>FAQ</Text>
117
+ <Text style={styles.actionLabel}>{t('karma.center.actions.faq') || 'FAQ'}</Text>
114
118
  </TouchableOpacity>
115
119
  </View>
116
- <Text style={styles.infoText}>Karma can only be earned by positive actions in the Oxy Ecosystem. It cannot be sent or received directly.</Text>
120
+ <Text style={styles.infoText}>
121
+ {t('karma.center.info') || 'Karma can only be earned by positive actions in the Oxy Ecosystem. It cannot be sent or received directly.'}
122
+ </Text>
117
123
  </View>
118
- <Text style={[styles.sectionTitle, { color: textColor }]}>Karma History</Text>
124
+ <Text style={[styles.sectionTitle, { color: textColor }]}>
125
+ {t('karma.center.history') || 'Karma History'}
126
+ </Text>
119
127
  <View style={styles.historyContainer}>
120
128
  {karmaHistory.length === 0 ? (
121
- <Text style={{ color: textColor, textAlign: 'center', marginTop: 16 }}>No karma history yet.</Text>
129
+ <Text style={{ color: textColor, textAlign: 'center', marginTop: 16 }}>
130
+ {t('karma.center.noHistory') || 'No karma history yet.'}
131
+ </Text>
122
132
  ) : (
123
133
  karmaHistory.map((entry: any) => (
124
134
  <View key={entry.id} style={[styles.historyItem, { borderColor }]}>
@@ -126,7 +136,7 @@ const KarmaCenterScreen: React.FC<BaseScreenProps> = ({
126
136
  {entry.points > 0 ? '+' : ''}{entry.points}
127
137
  </Text>
128
138
  <Text style={[styles.historyDesc, { color: textColor }]}>
129
- {entry.reason || 'No description'}
139
+ {entry.reason || (t('karma.center.noDescription') || 'No description')}
130
140
  </Text>
131
141
  <Text style={[styles.historyDate, { color: isDarkTheme ? '#BBBBBB' : '#888888' }]}>
132
142
  {entry.createdAt ? new Date(entry.createdAt).toLocaleString() : ''}