@oxyhq/services 5.13.0 → 5.13.2

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 (353) hide show
  1. package/README.md +71 -0
  2. package/lib/commonjs/core/HttpClient.js +238 -0
  3. package/lib/commonjs/core/HttpClient.js.map +1 -0
  4. package/lib/commonjs/core/OxyServices.js +530 -332
  5. package/lib/commonjs/core/OxyServices.js.map +1 -1
  6. package/lib/commonjs/core/RequestManager.js +199 -0
  7. package/lib/commonjs/core/RequestManager.js.map +1 -0
  8. package/lib/commonjs/core/index.js +38 -1
  9. package/lib/commonjs/core/index.js.map +1 -1
  10. package/lib/commonjs/i18n/index.js +37 -1
  11. package/lib/commonjs/i18n/index.js.map +1 -1
  12. package/lib/commonjs/i18n/locales/ar-SA.json +128 -0
  13. package/lib/commonjs/i18n/locales/ca-ES.json +128 -0
  14. package/lib/commonjs/i18n/locales/de-DE.json +128 -0
  15. package/lib/commonjs/i18n/locales/en-US.json +85 -12
  16. package/lib/commonjs/i18n/locales/es-ES.json +58 -6
  17. package/lib/commonjs/i18n/locales/fr-FR.json +128 -0
  18. package/lib/commonjs/i18n/locales/it-IT.json +128 -0
  19. package/lib/commonjs/i18n/locales/ja-JP.json +127 -0
  20. package/lib/commonjs/i18n/locales/ko-KR.json +128 -0
  21. package/lib/commonjs/i18n/locales/pt-PT.json +128 -0
  22. package/lib/commonjs/i18n/locales/zh-CN.json +128 -0
  23. package/lib/commonjs/index.js +36 -0
  24. package/lib/commonjs/index.js.map +1 -1
  25. package/lib/commonjs/ui/components/Avatar.js +94 -27
  26. package/lib/commonjs/ui/components/Avatar.js.map +1 -1
  27. package/lib/commonjs/ui/components/FollowButton.js +1 -0
  28. package/lib/commonjs/ui/components/FollowButton.js.map +1 -1
  29. package/lib/commonjs/ui/components/FontLoader.js +22 -42
  30. package/lib/commonjs/ui/components/FontLoader.js.map +1 -1
  31. package/lib/commonjs/ui/components/OxyProvider.js +5 -8
  32. package/lib/commonjs/ui/components/OxyProvider.js.map +1 -1
  33. package/lib/commonjs/ui/components/StepBasedScreen.js +64 -44
  34. package/lib/commonjs/ui/components/StepBasedScreen.js.map +1 -1
  35. package/lib/commonjs/ui/components/internal/GroupedPillButtons.js +14 -35
  36. package/lib/commonjs/ui/components/internal/GroupedPillButtons.js.map +1 -1
  37. package/lib/commonjs/ui/components/internal/PinInput.js +2 -2
  38. package/lib/commonjs/ui/components/internal/PinInput.js.map +1 -1
  39. package/lib/commonjs/ui/components/internal/TextField.js +13 -8
  40. package/lib/commonjs/ui/components/internal/TextField.js.map +1 -1
  41. package/lib/commonjs/ui/context/OxyContext.js +443 -371
  42. package/lib/commonjs/ui/context/OxyContext.js.map +1 -1
  43. package/lib/commonjs/ui/hooks/useSessionSocket.js +80 -22
  44. package/lib/commonjs/ui/hooks/useSessionSocket.js.map +1 -1
  45. package/lib/commonjs/ui/index.js +4 -1
  46. package/lib/commonjs/ui/index.js.map +1 -1
  47. package/lib/commonjs/ui/screens/AccountSettingsScreen.js +32 -2
  48. package/lib/commonjs/ui/screens/AccountSettingsScreen.js.map +1 -1
  49. package/lib/commonjs/ui/screens/AccountSwitcherScreen.js +101 -59
  50. package/lib/commonjs/ui/screens/AccountSwitcherScreen.js.map +1 -1
  51. package/lib/commonjs/ui/screens/FileManagementScreen.js +3 -2
  52. package/lib/commonjs/ui/screens/FileManagementScreen.js.map +1 -1
  53. package/lib/commonjs/ui/screens/LanguageSelectorScreen.js +75 -117
  54. package/lib/commonjs/ui/screens/LanguageSelectorScreen.js.map +1 -1
  55. package/lib/commonjs/ui/screens/SignInScreen.js +43 -50
  56. package/lib/commonjs/ui/screens/SignInScreen.js.map +1 -1
  57. package/lib/commonjs/ui/screens/SignUpScreen.js +14 -16
  58. package/lib/commonjs/ui/screens/SignUpScreen.js.map +1 -1
  59. package/lib/commonjs/ui/screens/WelcomeNewUserScreen.js +188 -142
  60. package/lib/commonjs/ui/screens/WelcomeNewUserScreen.js.map +1 -1
  61. package/lib/commonjs/ui/screens/internal/SignInPasswordStep.js +10 -10
  62. package/lib/commonjs/ui/screens/internal/SignInPasswordStep.js.map +1 -1
  63. package/lib/commonjs/ui/screens/internal/SignInUsernameStep.js +2 -4
  64. package/lib/commonjs/ui/screens/internal/SignInUsernameStep.js.map +1 -1
  65. package/lib/commonjs/ui/screens/steps/RecoverRequestStep.js +45 -25
  66. package/lib/commonjs/ui/screens/steps/RecoverRequestStep.js.map +1 -1
  67. package/lib/commonjs/ui/screens/steps/RecoverResetPasswordStep.js +88 -53
  68. package/lib/commonjs/ui/screens/steps/RecoverResetPasswordStep.js.map +1 -1
  69. package/lib/commonjs/ui/screens/steps/RecoverSuccessStep.js +79 -58
  70. package/lib/commonjs/ui/screens/steps/RecoverSuccessStep.js.map +1 -1
  71. package/lib/commonjs/ui/screens/steps/RecoverVerifyStep.js +61 -52
  72. package/lib/commonjs/ui/screens/steps/RecoverVerifyStep.js.map +1 -1
  73. package/lib/commonjs/ui/screens/steps/SignInPasswordStep.js +218 -39
  74. package/lib/commonjs/ui/screens/steps/SignInPasswordStep.js.map +1 -1
  75. package/lib/commonjs/ui/screens/steps/SignInTotpStep.js +77 -50
  76. package/lib/commonjs/ui/screens/steps/SignInTotpStep.js.map +1 -1
  77. package/lib/commonjs/ui/screens/steps/SignInUsernameStep.js +424 -71
  78. package/lib/commonjs/ui/screens/steps/SignInUsernameStep.js.map +1 -1
  79. package/lib/commonjs/ui/screens/steps/SignUpIdentityStep.js +55 -30
  80. package/lib/commonjs/ui/screens/steps/SignUpIdentityStep.js.map +1 -1
  81. package/lib/commonjs/ui/screens/steps/SignUpSecurityStep.js +64 -46
  82. package/lib/commonjs/ui/screens/steps/SignUpSecurityStep.js.map +1 -1
  83. package/lib/commonjs/ui/screens/steps/SignUpSummaryStep.js +84 -146
  84. package/lib/commonjs/ui/screens/steps/SignUpSummaryStep.js.map +1 -1
  85. package/lib/commonjs/ui/screens/steps/SignUpWelcomeStep.js +113 -34
  86. package/lib/commonjs/ui/screens/steps/SignUpWelcomeStep.js.map +1 -1
  87. package/lib/commonjs/ui/stores/accountStore.js +237 -0
  88. package/lib/commonjs/ui/stores/accountStore.js.map +1 -0
  89. package/lib/commonjs/ui/stores/authStore.js +17 -20
  90. package/lib/commonjs/ui/stores/authStore.js.map +1 -1
  91. package/lib/commonjs/ui/styles/authStyles.js +16 -8
  92. package/lib/commonjs/ui/styles/authStyles.js.map +1 -1
  93. package/lib/commonjs/ui/styles/index.js +11 -0
  94. package/lib/commonjs/ui/styles/index.js.map +1 -1
  95. package/lib/commonjs/ui/styles/spacing.js +51 -0
  96. package/lib/commonjs/ui/styles/spacing.js.map +1 -0
  97. package/lib/commonjs/utils/asyncUtils.js +9 -22
  98. package/lib/commonjs/utils/asyncUtils.js.map +1 -1
  99. package/lib/commonjs/utils/cache.js +259 -0
  100. package/lib/commonjs/utils/cache.js.map +1 -0
  101. package/lib/commonjs/utils/index.js +99 -0
  102. package/lib/commonjs/utils/index.js.map +1 -1
  103. package/lib/commonjs/utils/languageUtils.js +159 -0
  104. package/lib/commonjs/utils/languageUtils.js.map +1 -0
  105. package/lib/commonjs/utils/requestUtils.js +217 -0
  106. package/lib/commonjs/utils/requestUtils.js.map +1 -0
  107. package/lib/commonjs/utils/sessionUtils.js +191 -0
  108. package/lib/commonjs/utils/sessionUtils.js.map +1 -0
  109. package/lib/commonjs/utils/validationUtils.js +1 -1
  110. package/lib/module/core/HttpClient.js +232 -0
  111. package/lib/module/core/HttpClient.js.map +1 -0
  112. package/lib/module/core/OxyServices.js +528 -326
  113. package/lib/module/core/OxyServices.js.map +1 -1
  114. package/lib/module/core/RequestManager.js +194 -0
  115. package/lib/module/core/RequestManager.js.map +1 -0
  116. package/lib/module/core/index.js +2 -0
  117. package/lib/module/core/index.js.map +1 -1
  118. package/lib/module/i18n/index.js +37 -1
  119. package/lib/module/i18n/index.js.map +1 -1
  120. package/lib/module/i18n/locales/ar-SA.json +128 -0
  121. package/lib/module/i18n/locales/ca-ES.json +128 -0
  122. package/lib/module/i18n/locales/de-DE.json +128 -0
  123. package/lib/module/i18n/locales/en-US.json +85 -12
  124. package/lib/module/i18n/locales/es-ES.json +58 -6
  125. package/lib/module/i18n/locales/fr-FR.json +128 -0
  126. package/lib/module/i18n/locales/it-IT.json +128 -0
  127. package/lib/module/i18n/locales/ja-JP.json +127 -0
  128. package/lib/module/i18n/locales/ko-KR.json +128 -0
  129. package/lib/module/i18n/locales/pt-PT.json +128 -0
  130. package/lib/module/i18n/locales/zh-CN.json +128 -0
  131. package/lib/module/index.js +2 -0
  132. package/lib/module/index.js.map +1 -1
  133. package/lib/module/ui/components/Avatar.js +94 -27
  134. package/lib/module/ui/components/Avatar.js.map +1 -1
  135. package/lib/module/ui/components/FollowButton.js +1 -0
  136. package/lib/module/ui/components/FollowButton.js.map +1 -1
  137. package/lib/module/ui/components/FontLoader.js +23 -43
  138. package/lib/module/ui/components/FontLoader.js.map +1 -1
  139. package/lib/module/ui/components/OxyProvider.js +6 -8
  140. package/lib/module/ui/components/OxyProvider.js.map +1 -1
  141. package/lib/module/ui/components/StepBasedScreen.js +65 -45
  142. package/lib/module/ui/components/StepBasedScreen.js.map +1 -1
  143. package/lib/module/ui/components/internal/GroupedPillButtons.js +14 -35
  144. package/lib/module/ui/components/internal/GroupedPillButtons.js.map +1 -1
  145. package/lib/module/ui/components/internal/PinInput.js +2 -2
  146. package/lib/module/ui/components/internal/PinInput.js.map +1 -1
  147. package/lib/module/ui/components/internal/TextField.js +13 -8
  148. package/lib/module/ui/components/internal/TextField.js.map +1 -1
  149. package/lib/module/ui/context/OxyContext.js +442 -370
  150. package/lib/module/ui/context/OxyContext.js.map +1 -1
  151. package/lib/module/ui/hooks/useSessionSocket.js +80 -22
  152. package/lib/module/ui/hooks/useSessionSocket.js.map +1 -1
  153. package/lib/module/ui/index.js +4 -2
  154. package/lib/module/ui/index.js.map +1 -1
  155. package/lib/module/ui/screens/AccountSettingsScreen.js +33 -2
  156. package/lib/module/ui/screens/AccountSettingsScreen.js.map +1 -1
  157. package/lib/module/ui/screens/AccountSwitcherScreen.js +102 -60
  158. package/lib/module/ui/screens/AccountSwitcherScreen.js.map +1 -1
  159. package/lib/module/ui/screens/FileManagementScreen.js +3 -2
  160. package/lib/module/ui/screens/FileManagementScreen.js.map +1 -1
  161. package/lib/module/ui/screens/LanguageSelectorScreen.js +73 -117
  162. package/lib/module/ui/screens/LanguageSelectorScreen.js.map +1 -1
  163. package/lib/module/ui/screens/SignInScreen.js +44 -51
  164. package/lib/module/ui/screens/SignInScreen.js.map +1 -1
  165. package/lib/module/ui/screens/SignUpScreen.js +14 -16
  166. package/lib/module/ui/screens/SignUpScreen.js.map +1 -1
  167. package/lib/module/ui/screens/WelcomeNewUserScreen.js +187 -143
  168. package/lib/module/ui/screens/WelcomeNewUserScreen.js.map +1 -1
  169. package/lib/module/ui/screens/internal/SignInPasswordStep.js +10 -10
  170. package/lib/module/ui/screens/internal/SignInPasswordStep.js.map +1 -1
  171. package/lib/module/ui/screens/internal/SignInUsernameStep.js +2 -4
  172. package/lib/module/ui/screens/internal/SignInUsernameStep.js.map +1 -1
  173. package/lib/module/ui/screens/steps/RecoverRequestStep.js +45 -25
  174. package/lib/module/ui/screens/steps/RecoverRequestStep.js.map +1 -1
  175. package/lib/module/ui/screens/steps/RecoverResetPasswordStep.js +89 -54
  176. package/lib/module/ui/screens/steps/RecoverResetPasswordStep.js.map +1 -1
  177. package/lib/module/ui/screens/steps/RecoverSuccessStep.js +80 -59
  178. package/lib/module/ui/screens/steps/RecoverSuccessStep.js.map +1 -1
  179. package/lib/module/ui/screens/steps/RecoverVerifyStep.js +62 -53
  180. package/lib/module/ui/screens/steps/RecoverVerifyStep.js.map +1 -1
  181. package/lib/module/ui/screens/steps/SignInPasswordStep.js +219 -40
  182. package/lib/module/ui/screens/steps/SignInPasswordStep.js.map +1 -1
  183. package/lib/module/ui/screens/steps/SignInTotpStep.js +78 -51
  184. package/lib/module/ui/screens/steps/SignInTotpStep.js.map +1 -1
  185. package/lib/module/ui/screens/steps/SignInUsernameStep.js +426 -73
  186. package/lib/module/ui/screens/steps/SignInUsernameStep.js.map +1 -1
  187. package/lib/module/ui/screens/steps/SignUpIdentityStep.js +55 -30
  188. package/lib/module/ui/screens/steps/SignUpIdentityStep.js.map +1 -1
  189. package/lib/module/ui/screens/steps/SignUpSecurityStep.js +65 -47
  190. package/lib/module/ui/screens/steps/SignUpSecurityStep.js.map +1 -1
  191. package/lib/module/ui/screens/steps/SignUpSummaryStep.js +84 -146
  192. package/lib/module/ui/screens/steps/SignUpSummaryStep.js.map +1 -1
  193. package/lib/module/ui/screens/steps/SignUpWelcomeStep.js +114 -35
  194. package/lib/module/ui/screens/steps/SignUpWelcomeStep.js.map +1 -1
  195. package/lib/module/ui/stores/accountStore.js +229 -0
  196. package/lib/module/ui/stores/accountStore.js.map +1 -0
  197. package/lib/module/ui/stores/authStore.js +17 -20
  198. package/lib/module/ui/stores/authStore.js.map +1 -1
  199. package/lib/module/ui/styles/authStyles.js +16 -8
  200. package/lib/module/ui/styles/authStyles.js.map +1 -1
  201. package/lib/module/ui/styles/index.js +1 -0
  202. package/lib/module/ui/styles/index.js.map +1 -1
  203. package/lib/module/ui/styles/spacing.js +48 -0
  204. package/lib/module/ui/styles/spacing.js.map +1 -0
  205. package/lib/module/utils/asyncUtils.js +10 -22
  206. package/lib/module/utils/asyncUtils.js.map +1 -1
  207. package/lib/module/utils/cache.js +250 -0
  208. package/lib/module/utils/cache.js.map +1 -0
  209. package/lib/module/utils/index.js +7 -0
  210. package/lib/module/utils/index.js.map +1 -1
  211. package/lib/module/utils/languageUtils.js +151 -0
  212. package/lib/module/utils/languageUtils.js.map +1 -0
  213. package/lib/module/utils/requestUtils.js +210 -0
  214. package/lib/module/utils/requestUtils.js.map +1 -0
  215. package/lib/module/utils/sessionUtils.js +180 -0
  216. package/lib/module/utils/sessionUtils.js.map +1 -0
  217. package/lib/module/utils/validationUtils.js +1 -1
  218. package/lib/typescript/core/HttpClient.d.ts +64 -0
  219. package/lib/typescript/core/HttpClient.d.ts.map +1 -0
  220. package/lib/typescript/core/OxyServices.d.ts +86 -73
  221. package/lib/typescript/core/OxyServices.d.ts.map +1 -1
  222. package/lib/typescript/core/RequestManager.d.ts +67 -0
  223. package/lib/typescript/core/RequestManager.d.ts.map +1 -0
  224. package/lib/typescript/core/index.d.ts +2 -0
  225. package/lib/typescript/core/index.d.ts.map +1 -1
  226. package/lib/typescript/i18n/index.d.ts.map +1 -1
  227. package/lib/typescript/index.d.ts +2 -0
  228. package/lib/typescript/index.d.ts.map +1 -1
  229. package/lib/typescript/models/interfaces.d.ts +15 -0
  230. package/lib/typescript/models/interfaces.d.ts.map +1 -1
  231. package/lib/typescript/models/session.d.ts +1 -0
  232. package/lib/typescript/models/session.d.ts.map +1 -1
  233. package/lib/typescript/ui/components/Avatar.d.ts +6 -7
  234. package/lib/typescript/ui/components/Avatar.d.ts.map +1 -1
  235. package/lib/typescript/ui/components/FollowButton.d.ts.map +1 -1
  236. package/lib/typescript/ui/components/FontLoader.d.ts +3 -3
  237. package/lib/typescript/ui/components/FontLoader.d.ts.map +1 -1
  238. package/lib/typescript/ui/components/OxyProvider.d.ts +2 -2
  239. package/lib/typescript/ui/components/OxyProvider.d.ts.map +1 -1
  240. package/lib/typescript/ui/components/StepBasedScreen.d.ts.map +1 -1
  241. package/lib/typescript/ui/components/internal/GroupedPillButtons.d.ts.map +1 -1
  242. package/lib/typescript/ui/components/internal/TextField.d.ts.map +1 -1
  243. package/lib/typescript/ui/context/OxyContext.d.ts +5 -0
  244. package/lib/typescript/ui/context/OxyContext.d.ts.map +1 -1
  245. package/lib/typescript/ui/hooks/useSessionSocket.d.ts.map +1 -1
  246. package/lib/typescript/ui/index.d.ts +2 -2
  247. package/lib/typescript/ui/index.d.ts.map +1 -1
  248. package/lib/typescript/ui/screens/AccountSettingsScreen.d.ts.map +1 -1
  249. package/lib/typescript/ui/screens/AccountSwitcherScreen.d.ts.map +1 -1
  250. package/lib/typescript/ui/screens/LanguageSelectorScreen.d.ts +3 -3
  251. package/lib/typescript/ui/screens/LanguageSelectorScreen.d.ts.map +1 -1
  252. package/lib/typescript/ui/screens/SignInScreen.d.ts.map +1 -1
  253. package/lib/typescript/ui/screens/SignUpScreen.d.ts.map +1 -1
  254. package/lib/typescript/ui/screens/WelcomeNewUserScreen.d.ts.map +1 -1
  255. package/lib/typescript/ui/screens/internal/SignInPasswordStep.d.ts.map +1 -1
  256. package/lib/typescript/ui/screens/steps/RecoverRequestStep.d.ts.map +1 -1
  257. package/lib/typescript/ui/screens/steps/RecoverResetPasswordStep.d.ts.map +1 -1
  258. package/lib/typescript/ui/screens/steps/RecoverSuccessStep.d.ts.map +1 -1
  259. package/lib/typescript/ui/screens/steps/RecoverVerifyStep.d.ts.map +1 -1
  260. package/lib/typescript/ui/screens/steps/SignInPasswordStep.d.ts +2 -0
  261. package/lib/typescript/ui/screens/steps/SignInPasswordStep.d.ts.map +1 -1
  262. package/lib/typescript/ui/screens/steps/SignInTotpStep.d.ts.map +1 -1
  263. package/lib/typescript/ui/screens/steps/SignInUsernameStep.d.ts.map +1 -1
  264. package/lib/typescript/ui/screens/steps/SignUpIdentityStep.d.ts.map +1 -1
  265. package/lib/typescript/ui/screens/steps/SignUpSecurityStep.d.ts.map +1 -1
  266. package/lib/typescript/ui/screens/steps/SignUpSummaryStep.d.ts.map +1 -1
  267. package/lib/typescript/ui/screens/steps/SignUpWelcomeStep.d.ts.map +1 -1
  268. package/lib/typescript/ui/stores/accountStore.d.ts +34 -0
  269. package/lib/typescript/ui/stores/accountStore.d.ts.map +1 -0
  270. package/lib/typescript/ui/stores/authStore.d.ts +7 -3
  271. package/lib/typescript/ui/stores/authStore.d.ts.map +1 -1
  272. package/lib/typescript/ui/styles/authStyles.d.ts +19 -2
  273. package/lib/typescript/ui/styles/authStyles.d.ts.map +1 -1
  274. package/lib/typescript/ui/styles/index.d.ts +1 -0
  275. package/lib/typescript/ui/styles/index.d.ts.map +1 -1
  276. package/lib/typescript/ui/styles/spacing.d.ts +43 -0
  277. package/lib/typescript/ui/styles/spacing.d.ts.map +1 -0
  278. package/lib/typescript/utils/asyncUtils.d.ts +2 -0
  279. package/lib/typescript/utils/asyncUtils.d.ts.map +1 -1
  280. package/lib/typescript/utils/cache.d.ts +128 -0
  281. package/lib/typescript/utils/cache.d.ts.map +1 -0
  282. package/lib/typescript/utils/index.d.ts +4 -0
  283. package/lib/typescript/utils/index.d.ts.map +1 -1
  284. package/lib/typescript/utils/languageUtils.d.ts +38 -0
  285. package/lib/typescript/utils/languageUtils.d.ts.map +1 -0
  286. package/lib/typescript/utils/requestUtils.d.ts +122 -0
  287. package/lib/typescript/utils/requestUtils.d.ts.map +1 -0
  288. package/lib/typescript/utils/sessionUtils.d.ts +55 -0
  289. package/lib/typescript/utils/sessionUtils.d.ts.map +1 -0
  290. package/lib/typescript/utils/validationUtils.d.ts +1 -1
  291. package/package.json +1 -1
  292. package/src/core/HttpClient.ts +277 -0
  293. package/src/core/OxyServices.ts +461 -352
  294. package/src/core/RequestManager.ts +240 -0
  295. package/src/core/index.ts +10 -0
  296. package/src/i18n/index.ts +36 -0
  297. package/src/i18n/locales/ar-SA.json +128 -0
  298. package/src/i18n/locales/ca-ES.json +128 -0
  299. package/src/i18n/locales/de-DE.json +128 -0
  300. package/src/i18n/locales/en-US.json +85 -12
  301. package/src/i18n/locales/es-ES.json +58 -6
  302. package/src/i18n/locales/fr-FR.json +128 -0
  303. package/src/i18n/locales/it-IT.json +128 -0
  304. package/src/i18n/locales/ja-JP.json +127 -0
  305. package/src/i18n/locales/ko-KR.json +128 -0
  306. package/src/i18n/locales/pt-PT.json +128 -0
  307. package/src/i18n/locales/zh-CN.json +128 -0
  308. package/src/index.ts +10 -0
  309. package/src/models/interfaces.ts +19 -0
  310. package/src/models/session.ts +1 -1
  311. package/src/ui/components/Avatar.tsx +151 -35
  312. package/src/ui/components/FollowButton.tsx +1 -0
  313. package/src/ui/components/FontLoader.tsx +17 -37
  314. package/src/ui/components/OxyProvider.tsx +14 -13
  315. package/src/ui/components/StepBasedScreen.tsx +66 -43
  316. package/src/ui/components/internal/GroupedPillButtons.tsx +15 -31
  317. package/src/ui/components/internal/PinInput.tsx +2 -2
  318. package/src/ui/components/internal/TextField.tsx +7 -6
  319. package/src/ui/context/OxyContext.tsx +441 -326
  320. package/src/ui/hooks/useSessionSocket.ts +72 -18
  321. package/src/ui/index.ts +4 -1
  322. package/src/ui/screens/AccountSettingsScreen.tsx +34 -2
  323. package/src/ui/screens/AccountSwitcherScreen.tsx +102 -68
  324. package/src/ui/screens/FileManagementScreen.tsx +16 -16
  325. package/src/ui/screens/LanguageSelectorScreen.tsx +86 -143
  326. package/src/ui/screens/SignInScreen.tsx +59 -43
  327. package/src/ui/screens/SignUpScreen.tsx +14 -15
  328. package/src/ui/screens/WelcomeNewUserScreen.tsx +153 -105
  329. package/src/ui/screens/internal/SignInPasswordStep.tsx +4 -6
  330. package/src/ui/screens/internal/SignInUsernameStep.tsx +1 -1
  331. package/src/ui/screens/steps/RecoverRequestStep.tsx +34 -24
  332. package/src/ui/screens/steps/RecoverResetPasswordStep.tsx +65 -36
  333. package/src/ui/screens/steps/RecoverSuccessStep.tsx +71 -47
  334. package/src/ui/screens/steps/RecoverVerifyStep.tsx +60 -50
  335. package/src/ui/screens/steps/SignInPasswordStep.tsx +190 -32
  336. package/src/ui/screens/steps/SignInTotpStep.tsx +68 -34
  337. package/src/ui/screens/steps/SignInUsernameStep.tsx +446 -63
  338. package/src/ui/screens/steps/SignUpIdentityStep.tsx +49 -35
  339. package/src/ui/screens/steps/SignUpSecurityStep.tsx +56 -39
  340. package/src/ui/screens/steps/SignUpSummaryStep.tsx +99 -89
  341. package/src/ui/screens/steps/SignUpWelcomeStep.tsx +88 -20
  342. package/src/ui/stores/accountStore.ts +285 -0
  343. package/src/ui/stores/authStore.ts +16 -19
  344. package/src/ui/styles/authStyles.ts +16 -8
  345. package/src/ui/styles/index.ts +1 -0
  346. package/src/ui/styles/spacing.ts +46 -0
  347. package/src/utils/asyncUtils.ts +10 -24
  348. package/src/utils/cache.ts +264 -0
  349. package/src/utils/index.ts +19 -0
  350. package/src/utils/languageUtils.ts +174 -0
  351. package/src/utils/requestUtils.ts +234 -0
  352. package/src/utils/sessionUtils.ts +206 -0
  353. package/src/utils/validationUtils.ts +1 -1
@@ -1,9 +1,10 @@
1
1
  import type React from 'react';
2
2
  import type { RouteName } from '../../navigation/routes';
3
- import { View, Text, TouchableOpacity } from 'react-native';
3
+ import { View, Text, TouchableOpacity, Platform, StyleSheet, type ViewStyle, type TextStyle } from 'react-native';
4
4
  import { Ionicons } from '@expo/vector-icons';
5
5
  import HighFive from '../../../assets/illustrations/HighFive';
6
6
  import { useI18n } from '../../hooks/useI18n';
7
+ import { STEP_GAP, STEP_INNER_GAP, stepStyles } from '../../styles/spacing';
7
8
 
8
9
  interface SignUpWelcomeStepProps {
9
10
  // Common props from StepBasedScreen
@@ -25,35 +26,102 @@ const SignUpWelcomeStep: React.FC<SignUpWelcomeStepProps> = ({
25
26
  nextStep,
26
27
  }) => {
27
28
  const { t } = useI18n();
29
+ const localStyles = stylesheet;
30
+ const baseStyles = stepStyles;
31
+ const webShadowReset = Platform.OS === 'web' ? ({ boxShadow: 'none' } as any) : null;
32
+
28
33
  return (
29
34
  <>
30
- <HighFive width={120} height={120} />
31
- <View style={styles.modernHeader}>
32
- <Text style={[styles.modernTitle, { color: colors.text }]}>{t('signup.welcome.title')}</Text>
33
- <Text style={[styles.modernSubtitle, { color: colors.secondaryText }]}>{t('signup.welcome.subtitle')}</Text>
34
- </View>
35
-
36
- <View style={styles.modernInputContainer}>
35
+ <View style={[baseStyles.container, baseStyles.sectionSpacing, { alignItems: 'flex-start', position: 'relative' }]}>
36
+ <HighFive width={100} height={100} />
37
37
  <TouchableOpacity
38
- style={[styles.button, { backgroundColor: colors.primary }]}
39
- onPress={nextStep}
40
- testID="get-started-button"
38
+ style={[localStyles.languageButton, { backgroundColor: colors.inputBackground }]}
39
+ onPress={() => navigate('LanguageSelector')}
40
+ activeOpacity={0.7}
41
41
  >
42
- <Ionicons name="rocket-outline" size={20} color={colors.background} />
43
- <Text style={[styles.buttonText, { color: colors.background }]}>{t('common.actions.getStarted')}</Text>
42
+ <Ionicons name="globe-outline" size={20} color={colors.primary} />
44
43
  </TouchableOpacity>
44
+ </View>
45
+ <View style={[baseStyles.container, baseStyles.sectionSpacing, baseStyles.header]}>
46
+ <Text style={[styles.modernTitle, baseStyles.title, { color: colors.text, marginBottom: 0, marginTop: 0 }]}>{t('signup.welcome.title')}</Text>
47
+ <Text style={[styles.modernSubtitle, baseStyles.subtitle, { color: colors.secondaryText, marginBottom: 0, marginTop: 0 }]}>{t('signup.welcome.subtitle')}</Text>
48
+ </View>
45
49
 
46
- <TouchableOpacity
47
- style={[styles.footerTextContainer]}
48
- onPress={() => navigate('SignIn')}
50
+ <View style={[baseStyles.container, baseStyles.sectionSpacing]}>
51
+ <View
52
+ style={[
53
+ localStyles.actionCard,
54
+ { backgroundColor: colors.inputBackground || colors.card || 'rgba(0,0,0,0.04)' },
55
+ webShadowReset,
56
+ ]}
49
57
  >
50
- <Text style={[styles.footerText, { color: colors.secondaryText }]}>
51
- {t('signin.title')}
52
- </Text>
53
- </TouchableOpacity>
58
+ <TouchableOpacity
59
+ style={[
60
+ styles.button,
61
+ localStyles.primaryButton,
62
+ { backgroundColor: colors.primary },
63
+ webShadowReset,
64
+ ]}
65
+ onPress={nextStep}
66
+ testID="get-started-button"
67
+ >
68
+ <Text style={[styles.buttonText, localStyles.buttonText, { color: colors.background }]}>{t('common.actions.getStarted')}</Text>
69
+ </TouchableOpacity>
70
+
71
+ <TouchableOpacity
72
+ style={[styles.footerTextContainer, localStyles.footerLink, { marginTop: 0 }]}
73
+ onPress={() => navigate('SignIn')}
74
+ >
75
+ <Text style={[styles.footerText, { color: colors.secondaryText }]}>
76
+ {t('signup.welcome.haveAccount')}
77
+ <Text style={{ color: colors.primary, fontWeight: '600' }}> {t('signup.welcome.signInCta')}</Text>
78
+ </Text>
79
+ </TouchableOpacity>
80
+ </View>
54
81
  </View>
55
82
  </>
56
83
  );
57
84
  };
58
85
 
59
86
  export default SignUpWelcomeStep;
87
+
88
+ const stylesheet = StyleSheet.create({
89
+ actionCard: {
90
+ width: '100%',
91
+ maxWidth: 420,
92
+ borderRadius: 28,
93
+ paddingHorizontal: 20,
94
+ paddingVertical: 18,
95
+ gap: STEP_INNER_GAP,
96
+ alignItems: 'stretch',
97
+ shadowColor: 'transparent',
98
+ },
99
+ primaryButton: {
100
+ borderRadius: 28,
101
+ width: '100%',
102
+ paddingVertical: 16,
103
+ justifyContent: 'center',
104
+ shadowOpacity: 0,
105
+ shadowRadius: 0,
106
+ shadowOffset: { width: 0, height: 0 },
107
+ elevation: 0,
108
+ },
109
+ buttonText: {
110
+ fontSize: 16,
111
+ fontWeight: '600',
112
+ textAlign: 'center',
113
+ },
114
+ footerLink: {
115
+ alignSelf: 'center',
116
+ },
117
+ languageButton: {
118
+ position: 'absolute',
119
+ top: 0,
120
+ right: 0,
121
+ width: 40,
122
+ height: 40,
123
+ borderRadius: 20,
124
+ alignItems: 'center',
125
+ justifyContent: 'center',
126
+ },
127
+ });
@@ -0,0 +1,285 @@
1
+ import { create } from 'zustand';
2
+ import { shallow } from 'zustand/shallow';
3
+ import type { OxyServices } from '../../core';
4
+
5
+ export interface QuickAccount {
6
+ sessionId: string;
7
+ userId?: string; // User ID for deduplication
8
+ username: string;
9
+ displayName: string;
10
+ avatar?: string;
11
+ avatarUrl?: string; // Cached avatar URL to prevent recalculation
12
+ }
13
+
14
+ interface AccountState {
15
+ // Account data
16
+ accounts: Record<string, QuickAccount>;
17
+ accountOrder: string[]; // Maintain order for display
18
+ accountsArray: QuickAccount[]; // Cached array to prevent infinite loops
19
+
20
+ // Loading states
21
+ loading: boolean;
22
+ loadingSessionIds: Set<string>;
23
+
24
+ // Error state
25
+ error: string | null;
26
+
27
+ // Actions
28
+ setAccounts: (accounts: QuickAccount[]) => void;
29
+ addAccount: (account: QuickAccount) => void;
30
+ updateAccount: (sessionId: string, updates: Partial<QuickAccount>) => void;
31
+ removeAccount: (sessionId: string) => void;
32
+ moveAccountToTop: (sessionId: string) => void;
33
+
34
+ // Loading actions
35
+ setLoading: (loading: boolean) => void;
36
+ setLoadingSession: (sessionId: string, loading: boolean) => void;
37
+
38
+ // Error actions
39
+ setError: (error: string | null) => void;
40
+
41
+ // Load accounts from API
42
+ loadAccounts: (sessionIds: string[], oxyServices: OxyServices, existingAccounts?: QuickAccount[], preserveOrder?: boolean) => Promise<void>;
43
+
44
+ // Reset store
45
+ reset: () => void;
46
+ }
47
+
48
+ const initialState = {
49
+ accounts: {} as Record<string, QuickAccount>,
50
+ accountOrder: [] as string[],
51
+ accountsArray: [] as QuickAccount[],
52
+ loading: false,
53
+ loadingSessionIds: new Set<string>(),
54
+ error: null,
55
+ };
56
+
57
+ // Helper: Build accounts array from accounts map and order
58
+ const buildAccountsArray = (accounts: Record<string, QuickAccount>, order: string[]): QuickAccount[] => {
59
+ const result: QuickAccount[] = [];
60
+ for (const id of order) {
61
+ const account = accounts[id];
62
+ if (account) result.push(account);
63
+ }
64
+ return result;
65
+ };
66
+
67
+ // Helper: Create QuickAccount from user data
68
+ const createQuickAccount = (sessionId: string, userData: any, existingAccount?: QuickAccount, oxyServices?: OxyServices): QuickAccount => {
69
+ const displayName = userData.name?.full || userData.name?.first || userData.username || 'Account';
70
+ const userId = userData.id || userData._id?.toString();
71
+
72
+ // Preserve existing avatarUrl if avatar hasn't changed (prevents image reload)
73
+ let avatarUrl: string | undefined;
74
+ if (existingAccount && existingAccount.avatar === userData.avatar && existingAccount.avatarUrl) {
75
+ avatarUrl = existingAccount.avatarUrl; // Reuse existing URL
76
+ } else if (userData.avatar && oxyServices) {
77
+ avatarUrl = oxyServices.getFileDownloadUrl(userData.avatar, 'thumb');
78
+ }
79
+
80
+ return {
81
+ sessionId,
82
+ userId,
83
+ username: userData.username || '',
84
+ displayName,
85
+ avatar: userData.avatar,
86
+ avatarUrl,
87
+ };
88
+ };
89
+
90
+ export const useAccountStore = create<AccountState>((set, get) => ({
91
+ ...initialState,
92
+
93
+ setAccounts: (accounts) => set((state) => {
94
+ const accountMap: Record<string, QuickAccount> = {};
95
+ const order: string[] = [];
96
+ const seenSessionIds = new Set<string>();
97
+
98
+ for (const account of accounts) {
99
+ if (seenSessionIds.has(account.sessionId)) continue;
100
+ seenSessionIds.add(account.sessionId);
101
+ accountMap[account.sessionId] = account;
102
+ order.push(account.sessionId);
103
+ }
104
+
105
+ const accountsArray = buildAccountsArray(accountMap, order);
106
+ const sameOrder = order.length === state.accountOrder.length &&
107
+ order.every((id, i) => id === state.accountOrder[i]);
108
+ const sameAccounts = sameOrder &&
109
+ order.every(id => {
110
+ const existing = state.accounts[id];
111
+ const newAccount = accountMap[id];
112
+ return existing &&
113
+ existing.sessionId === newAccount.sessionId &&
114
+ existing.userId === newAccount.userId &&
115
+ existing.avatar === newAccount.avatar &&
116
+ existing.avatarUrl === newAccount.avatarUrl;
117
+ });
118
+
119
+ if (sameAccounts) return {} as any;
120
+
121
+ return { accounts: accountMap, accountOrder: order, accountsArray };
122
+ }),
123
+
124
+ addAccount: (account) => set((state) => {
125
+ // Check if account with same sessionId exists
126
+ if (state.accounts[account.sessionId]) {
127
+ // Update existing
128
+ const existing = state.accounts[account.sessionId];
129
+ if (existing.avatar === account.avatar && existing.avatarUrl === account.avatarUrl) {
130
+ return {} as any; // No change
131
+ }
132
+ const newAccounts = { ...state.accounts, [account.sessionId]: account };
133
+ return {
134
+ accounts: newAccounts,
135
+ accountsArray: buildAccountsArray(newAccounts, state.accountOrder),
136
+ };
137
+ }
138
+
139
+ const newAccounts = { ...state.accounts, [account.sessionId]: account };
140
+ const newOrder = [account.sessionId, ...state.accountOrder];
141
+ return {
142
+ accounts: newAccounts,
143
+ accountOrder: newOrder,
144
+ accountsArray: buildAccountsArray(newAccounts, newOrder),
145
+ };
146
+ }),
147
+
148
+ updateAccount: (sessionId, updates) => set((state) => {
149
+ const existing = state.accounts[sessionId];
150
+ if (!existing) return {} as any;
151
+
152
+ const updated = { ...existing, ...updates };
153
+ if (existing.avatar === updated.avatar && existing.avatarUrl === updated.avatarUrl) {
154
+ return {} as any; // No change
155
+ }
156
+
157
+ const newAccounts = { ...state.accounts, [sessionId]: updated };
158
+ return {
159
+ accounts: newAccounts,
160
+ accountsArray: buildAccountsArray(newAccounts, state.accountOrder),
161
+ };
162
+ }),
163
+
164
+ removeAccount: (sessionId) => set((state) => {
165
+ if (!state.accounts[sessionId]) return {} as any;
166
+
167
+ const { [sessionId]: _removed, ...rest } = state.accounts;
168
+ const newOrder = state.accountOrder.filter(id => id !== sessionId);
169
+
170
+ return {
171
+ accounts: rest,
172
+ accountOrder: newOrder,
173
+ accountsArray: buildAccountsArray(rest, newOrder),
174
+ };
175
+ }),
176
+
177
+ moveAccountToTop: (sessionId) => set((state) => {
178
+ if (!state.accounts[sessionId]) return {} as any;
179
+
180
+ const filtered = state.accountOrder.filter(id => id !== sessionId);
181
+ const newOrder = [sessionId, ...filtered];
182
+
183
+ return {
184
+ accountOrder: newOrder,
185
+ accountsArray: buildAccountsArray(state.accounts, newOrder),
186
+ };
187
+ }),
188
+
189
+ setLoading: (loading) => set({ loading }),
190
+
191
+ setLoadingSession: (sessionId, loading) => set((state) => {
192
+ const newSet = new Set(state.loadingSessionIds);
193
+ if (loading) {
194
+ newSet.add(sessionId);
195
+ } else {
196
+ newSet.delete(sessionId);
197
+ }
198
+ return { loadingSessionIds: newSet };
199
+ }),
200
+
201
+ setError: (error) => set({ error }),
202
+
203
+ loadAccounts: async (sessionIds, oxyServices, existingAccounts = [], preserveOrder = true) => {
204
+ const state = get();
205
+
206
+ const uniqueSessionIds = Array.from(new Set(sessionIds));
207
+ if (uniqueSessionIds.length === 0) {
208
+ get().setAccounts([]);
209
+ return;
210
+ }
211
+
212
+ const existingMap = new Map(existingAccounts.map(a => [a.sessionId, a]));
213
+ for (const account of Object.values(state.accounts)) {
214
+ existingMap.set(account.sessionId, account);
215
+ }
216
+
217
+ const missingSessionIds = uniqueSessionIds.filter(id => !existingMap.has(id));
218
+
219
+ if (missingSessionIds.length === 0) {
220
+ const ordered = uniqueSessionIds
221
+ .map(id => existingMap.get(id))
222
+ .filter((acc): acc is QuickAccount => acc !== undefined);
223
+ get().setAccounts(ordered);
224
+ return;
225
+ }
226
+
227
+ if (state.loading) {
228
+ return;
229
+ }
230
+
231
+ set({ loading: true, error: null });
232
+
233
+ try {
234
+ const batchResults = await oxyServices.getUsersBySessions(missingSessionIds);
235
+
236
+ const accountMap = new Map<string, QuickAccount>();
237
+
238
+ for (const { sessionId, user: userData } of batchResults) {
239
+ if (userData && !accountMap.has(sessionId)) {
240
+ const existing = existingMap.get(sessionId);
241
+ accountMap.set(sessionId, createQuickAccount(sessionId, userData, existing, oxyServices));
242
+ }
243
+ }
244
+
245
+ for (const [sessionId, account] of accountMap) {
246
+ existingMap.set(sessionId, account);
247
+ }
248
+
249
+ const orderToUse = preserveOrder ? uniqueSessionIds : [...uniqueSessionIds, ...state.accountOrder];
250
+ const seen = new Set<string>();
251
+ const ordered: QuickAccount[] = [];
252
+
253
+ for (const sessionId of orderToUse) {
254
+ if (seen.has(sessionId)) continue;
255
+ seen.add(sessionId);
256
+
257
+ const account = existingMap.get(sessionId);
258
+ if (account) ordered.push(account);
259
+ }
260
+
261
+ get().setAccounts(ordered);
262
+ } catch (error) {
263
+ const errorMessage = error instanceof Error ? error.message : 'Failed to load accounts';
264
+ if (__DEV__) {
265
+ console.error('AccountStore: Failed to load accounts:', error);
266
+ }
267
+ set({ error: errorMessage });
268
+ } finally {
269
+ set({ loading: false });
270
+ }
271
+ },
272
+
273
+ reset: () => set(initialState),
274
+ }));
275
+
276
+ // Selectors for performance - return cached array to prevent infinite loops
277
+ export const useAccounts = (): QuickAccount[] => {
278
+ return useAccountStore(state => state.accountsArray);
279
+ };
280
+
281
+ export const useAccountLoading = () => useAccountStore(s => s.loading);
282
+ export const useAccountError = () => useAccountStore(s => s.error);
283
+ export const useAccountLoadingSession = (sessionId: string) =>
284
+ useAccountStore(s => s.loadingSessionIds.has(sessionId));
285
+
@@ -7,12 +7,11 @@ interface AuthState {
7
7
  isLoading: boolean;
8
8
  error: string | null;
9
9
  lastUserFetch: number | null; // Timestamp of last user fetch for caching
10
- loginStart: () => void;
11
10
  loginSuccess: (user: User) => void;
12
11
  loginFailure: (error: string) => void;
13
12
  logout: () => void;
14
- fetchUser: (oxyServices: any, forceRefresh?: boolean) => Promise<void>;
15
- updateUser: (updates: Partial<User>, oxyServices: any) => Promise<void>;
13
+ fetchUser: (oxyServices: { getCurrentUser: () => Promise<User> }, forceRefresh?: boolean) => Promise<void>;
14
+ updateUser: (updates: Partial<User>, oxyServices: { updateProfile: (updates: Partial<User>) => Promise<User>; getCurrentUser: () => Promise<User> }) => Promise<void>;
16
15
  setUser: (user: User) => void; // Direct user setter for caching
17
16
  }
18
17
 
@@ -22,7 +21,6 @@ export const useAuthStore = create<AuthState>((set: (state: Partial<AuthState>)
22
21
  isLoading: false,
23
22
  error: null,
24
23
  lastUserFetch: null,
25
- loginStart: () => set({ isLoading: true, error: null }),
26
24
  loginSuccess: (user: User) => set({ isLoading: false, isAuthenticated: true, user, lastUserFetch: Date.now() }),
27
25
  loginFailure: (error: string) => set({ isLoading: false, error }),
28
26
  logout: () => set({ user: null, isAuthenticated: false, lastUserFetch: null }),
@@ -35,38 +33,37 @@ export const useAuthStore = create<AuthState>((set: (state: Partial<AuthState>)
35
33
 
36
34
  // Use cached data if available and not forcing refresh
37
35
  if (!forceRefresh && state.user && cacheValid) {
36
+ if (__DEV__) {
38
37
  console.log('AuthStore: Using cached user data (age:', cacheAge, 'ms)');
38
+ }
39
39
  return;
40
40
  }
41
41
 
42
42
  set({ isLoading: true, error: null });
43
43
  try {
44
- console.log('AuthStore: Fetching user data...');
45
44
  const user = await oxyServices.getCurrentUser();
46
- console.log('AuthStore: Received user data:', {
47
- hasUser: !!user,
48
- userLinksMetadata: user?.linksMetadata,
49
- userLinks: user?.links,
50
- userWebsite: user?.website
51
- });
52
45
  set({ user, isLoading: false, isAuthenticated: true, lastUserFetch: now });
53
- } catch (error: any) {
46
+ } catch (error) {
47
+ const errorMessage = error instanceof Error ? error.message : 'Failed to fetch user';
48
+ if (__DEV__) {
54
49
  console.error('AuthStore: Error fetching user:', error);
55
- set({ error: error.message || 'Failed to fetch user', isLoading: false });
50
+ }
51
+ set({ error: errorMessage, isLoading: false });
56
52
  }
57
53
  },
58
54
  updateUser: async (updates, oxyServices) => {
59
55
  set({ isLoading: true, error: null });
60
56
  try {
61
- console.log('AuthStore: Updating user with:', updates);
62
57
  await oxyServices.updateProfile(updates);
63
- console.log('AuthStore: Profile updated successfully');
64
58
  // Immediately fetch the latest user data after update
65
- await useAuthStore.getState().fetchUser(oxyServices, true); // Force refresh
66
- console.log('AuthStore: User data refreshed');
67
- } catch (error: any) {
59
+ // Use arrow function to preserve 'this' context
60
+ await useAuthStore.getState().fetchUser({ getCurrentUser: () => oxyServices.getCurrentUser() }, true);
61
+ } catch (error) {
62
+ const errorMessage = error instanceof Error ? error.message : 'Failed to update user';
63
+ if (__DEV__) {
68
64
  console.error('AuthStore: Error updating user:', error);
69
- set({ error: error.message || 'Failed to update user', isLoading: false });
65
+ }
66
+ set({ error: errorMessage, isLoading: false });
70
67
  }
71
68
  },
72
69
  }));
@@ -22,7 +22,8 @@ export const createAuthStyles = (colors: AuthThemeColors, theme: string) => Styl
22
22
  scrollContent: {
23
23
  flexGrow: 1,
24
24
  paddingHorizontal: 24,
25
- paddingTop: 4,
25
+ paddingTop: 0,
26
+ paddingBottom: 32,
26
27
  },
27
28
  stepContainer: {
28
29
  flex: 1,
@@ -190,13 +191,20 @@ export const createAuthStyles = (colors: AuthThemeColors, theme: string) => Styl
190
191
  paddingHorizontal: 32,
191
192
  borderRadius: 16,
192
193
  marginVertical: 8,
193
- shadowOffset: {
194
- width: 0,
195
- height: 4,
196
- },
197
- shadowOpacity: 0.3,
198
- shadowRadius: 8,
199
- elevation: 6,
194
+ ...Platform.select({
195
+ web: {
196
+ boxShadow: '0 4px 8px rgba(0,0,0,0.3)',
197
+ },
198
+ default: {
199
+ shadowOffset: {
200
+ width: 0,
201
+ height: 4,
202
+ },
203
+ shadowOpacity: 0.3,
204
+ shadowRadius: 8,
205
+ elevation: 6,
206
+ }
207
+ }),
200
208
  gap: 8,
201
209
  width: '100%',
202
210
  },
@@ -1,3 +1,4 @@
1
1
  export * from './fonts';
2
2
  export * from './theme';
3
3
  export * from './authStyles';
4
+ export * from './spacing';
@@ -0,0 +1,46 @@
1
+ import { StyleSheet } from 'react-native';
2
+
3
+ /**
4
+ * Shared spacing constants for authentication screens
5
+ * These values ensure consistent vertical spacing across all step components
6
+ * All gaps between elements (illustration, title, description, textfield, buttons, etc.) use this value
7
+ */
8
+ export const STEP_GAP = 12; // Vertical gap between ALL elements (illustration, title, description, textfield, buttons, etc.) - must be consistent everywhere
9
+ export const STEP_INNER_GAP = 12; // Gap within sections (headers, cards, etc.) - must match STEP_GAP for uniformity
10
+
11
+ /**
12
+ * Reusable stylesheet for step components
13
+ * All step components should use these base styles for consistency
14
+ */
15
+ export const stepStyles = StyleSheet.create({
16
+ container: {
17
+ width: '100%',
18
+ maxWidth: 420,
19
+ alignSelf: 'center',
20
+ },
21
+ sectionSpacing: {
22
+ marginBottom: STEP_GAP,
23
+ },
24
+ header: {
25
+ alignItems: 'flex-start',
26
+ width: '100%',
27
+ gap: STEP_INNER_GAP,
28
+ },
29
+ title: {
30
+ textAlign: 'left',
31
+ marginBottom: 0,
32
+ marginTop: 0,
33
+ },
34
+ subtitle: {
35
+ textAlign: 'left',
36
+ maxWidth: 320,
37
+ alignSelf: 'flex-start',
38
+ marginBottom: 0,
39
+ marginTop: 0,
40
+ },
41
+ buttonContainer: {
42
+ marginTop: 0,
43
+ marginBottom: 0,
44
+ },
45
+ });
46
+
@@ -2,6 +2,8 @@
2
2
  * Async utilities for common asynchronous patterns and error handling
3
3
  */
4
4
 
5
+ import { TTLCache, registerCacheForCleanup } from './cache';
6
+
5
7
  /**
6
8
  * Wrapper for async operations with automatic error handling
7
9
  */
@@ -196,36 +198,20 @@ export async function withTimeout<T>(
196
198
 
197
199
  /**
198
200
  * Cache async operation results
201
+ * @deprecated Use TTLCache from '../utils/cache' instead
202
+ * This function is kept for backward compatibility but will be removed in a future version
199
203
  */
200
204
  export function createAsyncCache<T>(
201
205
  ttl: number = 5 * 60 * 1000 // 5 minutes default
202
206
  ) {
203
- const cache = new Map<string, { data: T; timestamp: number }>();
207
+ const cache = new TTLCache<T>(ttl);
208
+ registerCacheForCleanup(cache);
204
209
 
205
210
  return {
206
- get: (key: string): T | null => {
207
- const item = cache.get(key);
208
- if (!item) return null;
209
-
210
- if (Date.now() - item.timestamp > ttl) {
211
- cache.delete(key);
212
- return null;
213
- }
214
-
215
- return item.data;
216
- },
217
-
218
- set: (key: string, data: T): void => {
219
- cache.set(key, { data, timestamp: Date.now() });
220
- },
221
-
222
- clear: (): void => {
223
- cache.clear();
224
- },
225
-
226
- delete: (key: string): boolean => {
227
- return cache.delete(key);
228
- }
211
+ get: (key: string): T | null => cache.get(key),
212
+ set: (key: string, data: T): void => cache.set(key, data),
213
+ clear: (): void => cache.clear(),
214
+ delete: (key: string): boolean => cache.delete(key),
229
215
  };
230
216
  }
231
217