@oxyhq/services 14.1.0 → 16.0.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 (292) hide show
  1. package/lib/commonjs/index.js +4 -21
  2. package/lib/commonjs/index.js.map +1 -1
  3. package/lib/commonjs/ui/components/SignInAccountChooser.js +189 -0
  4. package/lib/commonjs/ui/components/SignInAccountChooser.js.map +1 -0
  5. package/lib/commonjs/ui/components/SignInModal.js +350 -131
  6. package/lib/commonjs/ui/components/SignInModal.js.map +1 -1
  7. package/lib/commonjs/ui/context/OxyContext.js +340 -1547
  8. package/lib/commonjs/ui/context/OxyContext.js.map +1 -1
  9. package/lib/commonjs/ui/context/hooks/useAuthOperations.js +61 -64
  10. package/lib/commonjs/ui/context/hooks/useAuthOperations.js.map +1 -1
  11. package/lib/commonjs/ui/hooks/mutations/mutationKeys.js +1 -1
  12. package/lib/commonjs/ui/hooks/mutations/useAccountMutations.js +9 -9
  13. package/lib/commonjs/ui/hooks/mutations/useAccountMutations.js.map +1 -1
  14. package/lib/commonjs/ui/hooks/queries/queryKeys.js +1 -1
  15. package/lib/commonjs/ui/hooks/queries/useAccountQueries.js +7 -8
  16. package/lib/commonjs/ui/hooks/queries/useAccountQueries.js.map +1 -1
  17. package/lib/commonjs/ui/hooks/useAuth.js +14 -33
  18. package/lib/commonjs/ui/hooks/useAuth.js.map +1 -1
  19. package/lib/commonjs/ui/hooks/usePasswordSignIn.js +170 -0
  20. package/lib/commonjs/ui/hooks/usePasswordSignIn.js.map +1 -0
  21. package/lib/commonjs/ui/hooks/useProfileEditing.js +2 -5
  22. package/lib/commonjs/ui/hooks/useProfileEditing.js.map +1 -1
  23. package/lib/commonjs/ui/hooks/useSessionManagement.js +2 -2
  24. package/lib/commonjs/ui/hooks/useSessionManagement.js.map +1 -1
  25. package/lib/commonjs/ui/navigation/routes.js +1 -0
  26. package/lib/commonjs/ui/navigation/routes.js.map +1 -1
  27. package/lib/commonjs/ui/screens/ConnectedAppsScreen.js +17 -18
  28. package/lib/commonjs/ui/screens/ConnectedAppsScreen.js.map +1 -1
  29. package/lib/commonjs/ui/screens/EditProfileFieldScreen.js +93 -68
  30. package/lib/commonjs/ui/screens/EditProfileFieldScreen.js.map +1 -1
  31. package/lib/commonjs/ui/screens/EditProfileScreen.js +187 -0
  32. package/lib/commonjs/ui/screens/EditProfileScreen.js.map +1 -0
  33. package/lib/commonjs/ui/screens/ManageAccountScreen.js +3 -7
  34. package/lib/commonjs/ui/screens/ManageAccountScreen.js.map +1 -1
  35. package/lib/commonjs/ui/screens/OxyAuthScreen.js +231 -95
  36. package/lib/commonjs/ui/screens/OxyAuthScreen.js.map +1 -1
  37. package/lib/commonjs/ui/screens/ProfileScreen.js +15 -2
  38. package/lib/commonjs/ui/screens/ProfileScreen.js.map +1 -1
  39. package/lib/commonjs/ui/screens/linkFormat.js +38 -0
  40. package/lib/commonjs/ui/screens/linkFormat.js.map +1 -0
  41. package/lib/commonjs/ui/session/authStore.js +146 -0
  42. package/lib/commonjs/ui/session/authStore.js.map +1 -0
  43. package/lib/commonjs/ui/session/createSessionClient.js +23 -17
  44. package/lib/commonjs/ui/session/createSessionClient.js.map +1 -1
  45. package/lib/commonjs/ui/session/index.js +13 -7
  46. package/lib/commonjs/ui/session/index.js.map +1 -1
  47. package/lib/commonjs/ui/session/tokenTransport.js +19 -31
  48. package/lib/commonjs/ui/session/tokenTransport.js.map +1 -1
  49. package/lib/commonjs/ui/utils/isWebBrowser.js +13 -0
  50. package/lib/commonjs/ui/utils/isWebBrowser.js.map +1 -0
  51. package/lib/commonjs/utils/deviceFlowSignIn.js +13 -16
  52. package/lib/commonjs/utils/deviceFlowSignIn.js.map +1 -1
  53. package/lib/module/index.js +2 -7
  54. package/lib/module/index.js.map +1 -1
  55. package/lib/module/ui/components/SignInAccountChooser.js +183 -0
  56. package/lib/module/ui/components/SignInAccountChooser.js.map +1 -0
  57. package/lib/module/ui/components/SignInModal.js +352 -134
  58. package/lib/module/ui/components/SignInModal.js.map +1 -1
  59. package/lib/module/ui/context/OxyContext.js +342 -1551
  60. package/lib/module/ui/context/OxyContext.js.map +1 -1
  61. package/lib/module/ui/context/hooks/useAuthOperations.js +60 -63
  62. package/lib/module/ui/context/hooks/useAuthOperations.js.map +1 -1
  63. package/lib/module/ui/hooks/mutations/mutationKeys.js +1 -1
  64. package/lib/module/ui/hooks/mutations/useAccountMutations.js +7 -7
  65. package/lib/module/ui/hooks/mutations/useAccountMutations.js.map +1 -1
  66. package/lib/module/ui/hooks/queries/queryKeys.js +1 -1
  67. package/lib/module/ui/hooks/queries/useAccountQueries.js +5 -6
  68. package/lib/module/ui/hooks/queries/useAccountQueries.js.map +1 -1
  69. package/lib/module/ui/hooks/useAuth.js +14 -33
  70. package/lib/module/ui/hooks/useAuth.js.map +1 -1
  71. package/lib/module/ui/hooks/usePasswordSignIn.js +165 -0
  72. package/lib/module/ui/hooks/usePasswordSignIn.js.map +1 -0
  73. package/lib/module/ui/hooks/useProfileEditing.js +2 -5
  74. package/lib/module/ui/hooks/useProfileEditing.js.map +1 -1
  75. package/lib/module/ui/hooks/useSessionManagement.js +1 -1
  76. package/lib/module/ui/hooks/useSessionManagement.js.map +1 -1
  77. package/lib/module/ui/navigation/routes.js +1 -0
  78. package/lib/module/ui/navigation/routes.js.map +1 -1
  79. package/lib/module/ui/screens/ConnectedAppsScreen.js +19 -20
  80. package/lib/module/ui/screens/ConnectedAppsScreen.js.map +1 -1
  81. package/lib/module/ui/screens/EditProfileFieldScreen.js +91 -66
  82. package/lib/module/ui/screens/EditProfileFieldScreen.js.map +1 -1
  83. package/lib/module/ui/screens/EditProfileScreen.js +182 -0
  84. package/lib/module/ui/screens/EditProfileScreen.js.map +1 -0
  85. package/lib/module/ui/screens/ManageAccountScreen.js +3 -7
  86. package/lib/module/ui/screens/ManageAccountScreen.js.map +1 -1
  87. package/lib/module/ui/screens/OxyAuthScreen.js +233 -97
  88. package/lib/module/ui/screens/OxyAuthScreen.js.map +1 -1
  89. package/lib/module/ui/screens/ProfileScreen.js +15 -2
  90. package/lib/module/ui/screens/ProfileScreen.js.map +1 -1
  91. package/lib/module/ui/screens/linkFormat.js +31 -0
  92. package/lib/module/ui/screens/linkFormat.js.map +1 -0
  93. package/lib/module/ui/session/authStore.js +143 -0
  94. package/lib/module/ui/session/authStore.js.map +1 -0
  95. package/lib/module/ui/session/createSessionClient.js +22 -16
  96. package/lib/module/ui/session/createSessionClient.js.map +1 -1
  97. package/lib/module/ui/session/index.js +9 -9
  98. package/lib/module/ui/session/index.js.map +1 -1
  99. package/lib/module/ui/session/tokenTransport.js +20 -33
  100. package/lib/module/ui/session/tokenTransport.js.map +1 -1
  101. package/lib/module/ui/utils/isWebBrowser.js +11 -0
  102. package/lib/module/ui/utils/isWebBrowser.js.map +1 -0
  103. package/lib/module/utils/deviceFlowSignIn.js +14 -17
  104. package/lib/module/utils/deviceFlowSignIn.js.map +1 -1
  105. package/lib/typescript/commonjs/index.d.ts +2 -3
  106. package/lib/typescript/commonjs/index.d.ts.map +1 -1
  107. package/lib/typescript/commonjs/ui/components/SignInAccountChooser.d.ts +29 -0
  108. package/lib/typescript/commonjs/ui/components/SignInAccountChooser.d.ts.map +1 -0
  109. package/lib/typescript/commonjs/ui/components/SignInModal.d.ts +15 -10
  110. package/lib/typescript/commonjs/ui/components/SignInModal.d.ts.map +1 -1
  111. package/lib/typescript/commonjs/ui/context/OxyContext.d.ts +36 -42
  112. package/lib/typescript/commonjs/ui/context/OxyContext.d.ts.map +1 -1
  113. package/lib/typescript/commonjs/ui/context/hooks/useAuthOperations.d.ts +18 -23
  114. package/lib/typescript/commonjs/ui/context/hooks/useAuthOperations.d.ts.map +1 -1
  115. package/lib/typescript/commonjs/ui/hooks/mutations/useAccountMutations.d.ts +4 -6
  116. package/lib/typescript/commonjs/ui/hooks/mutations/useAccountMutations.d.ts.map +1 -1
  117. package/lib/typescript/commonjs/ui/hooks/queries/useAccountQueries.d.ts +6 -7
  118. package/lib/typescript/commonjs/ui/hooks/queries/useAccountQueries.d.ts.map +1 -1
  119. package/lib/typescript/commonjs/ui/hooks/useAuth.d.ts.map +1 -1
  120. package/lib/typescript/commonjs/ui/hooks/usePasswordSignIn.d.ts +31 -0
  121. package/lib/typescript/commonjs/ui/hooks/usePasswordSignIn.d.ts.map +1 -0
  122. package/lib/typescript/commonjs/ui/hooks/useProfileEditing.d.ts +0 -1
  123. package/lib/typescript/commonjs/ui/hooks/useProfileEditing.d.ts.map +1 -1
  124. package/lib/typescript/commonjs/ui/navigation/routes.d.ts +1 -1
  125. package/lib/typescript/commonjs/ui/navigation/routes.d.ts.map +1 -1
  126. package/lib/typescript/commonjs/ui/screens/ConnectedAppsScreen.d.ts.map +1 -1
  127. package/lib/typescript/commonjs/ui/screens/EditProfileFieldScreen.d.ts.map +1 -1
  128. package/lib/typescript/commonjs/ui/screens/EditProfileScreen.d.ts +14 -0
  129. package/lib/typescript/commonjs/ui/screens/EditProfileScreen.d.ts.map +1 -0
  130. package/lib/typescript/commonjs/ui/screens/ManageAccountScreen.d.ts +1 -1
  131. package/lib/typescript/commonjs/ui/screens/ManageAccountScreen.d.ts.map +1 -1
  132. package/lib/typescript/commonjs/ui/screens/OxyAuthScreen.d.ts +13 -12
  133. package/lib/typescript/commonjs/ui/screens/OxyAuthScreen.d.ts.map +1 -1
  134. package/lib/typescript/commonjs/ui/screens/ProfileScreen.d.ts.map +1 -1
  135. package/lib/typescript/commonjs/ui/screens/linkFormat.d.ts +23 -0
  136. package/lib/typescript/commonjs/ui/screens/linkFormat.d.ts.map +1 -0
  137. package/lib/typescript/commonjs/ui/session/authStore.d.ts +33 -0
  138. package/lib/typescript/commonjs/ui/session/authStore.d.ts.map +1 -0
  139. package/lib/typescript/commonjs/ui/session/createSessionClient.d.ts +19 -15
  140. package/lib/typescript/commonjs/ui/session/createSessionClient.d.ts.map +1 -1
  141. package/lib/typescript/commonjs/ui/session/index.d.ts +9 -9
  142. package/lib/typescript/commonjs/ui/session/index.d.ts.map +1 -1
  143. package/lib/typescript/commonjs/ui/session/tokenTransport.d.ts +13 -19
  144. package/lib/typescript/commonjs/ui/session/tokenTransport.d.ts.map +1 -1
  145. package/lib/typescript/commonjs/ui/utils/isWebBrowser.d.ts +9 -0
  146. package/lib/typescript/commonjs/ui/utils/isWebBrowser.d.ts.map +1 -0
  147. package/lib/typescript/commonjs/ui/utils/storageHelpers.d.ts +7 -7
  148. package/lib/typescript/commonjs/utils/deviceFlowSignIn.d.ts +15 -13
  149. package/lib/typescript/commonjs/utils/deviceFlowSignIn.d.ts.map +1 -1
  150. package/lib/typescript/module/index.d.ts +2 -3
  151. package/lib/typescript/module/index.d.ts.map +1 -1
  152. package/lib/typescript/module/ui/components/SignInAccountChooser.d.ts +29 -0
  153. package/lib/typescript/module/ui/components/SignInAccountChooser.d.ts.map +1 -0
  154. package/lib/typescript/module/ui/components/SignInModal.d.ts +15 -10
  155. package/lib/typescript/module/ui/components/SignInModal.d.ts.map +1 -1
  156. package/lib/typescript/module/ui/context/OxyContext.d.ts +36 -42
  157. package/lib/typescript/module/ui/context/OxyContext.d.ts.map +1 -1
  158. package/lib/typescript/module/ui/context/hooks/useAuthOperations.d.ts +18 -23
  159. package/lib/typescript/module/ui/context/hooks/useAuthOperations.d.ts.map +1 -1
  160. package/lib/typescript/module/ui/hooks/mutations/useAccountMutations.d.ts +4 -6
  161. package/lib/typescript/module/ui/hooks/mutations/useAccountMutations.d.ts.map +1 -1
  162. package/lib/typescript/module/ui/hooks/queries/useAccountQueries.d.ts +6 -7
  163. package/lib/typescript/module/ui/hooks/queries/useAccountQueries.d.ts.map +1 -1
  164. package/lib/typescript/module/ui/hooks/useAuth.d.ts.map +1 -1
  165. package/lib/typescript/module/ui/hooks/usePasswordSignIn.d.ts +31 -0
  166. package/lib/typescript/module/ui/hooks/usePasswordSignIn.d.ts.map +1 -0
  167. package/lib/typescript/module/ui/hooks/useProfileEditing.d.ts +0 -1
  168. package/lib/typescript/module/ui/hooks/useProfileEditing.d.ts.map +1 -1
  169. package/lib/typescript/module/ui/navigation/routes.d.ts +1 -1
  170. package/lib/typescript/module/ui/navigation/routes.d.ts.map +1 -1
  171. package/lib/typescript/module/ui/screens/ConnectedAppsScreen.d.ts.map +1 -1
  172. package/lib/typescript/module/ui/screens/EditProfileFieldScreen.d.ts.map +1 -1
  173. package/lib/typescript/module/ui/screens/EditProfileScreen.d.ts +14 -0
  174. package/lib/typescript/module/ui/screens/EditProfileScreen.d.ts.map +1 -0
  175. package/lib/typescript/module/ui/screens/ManageAccountScreen.d.ts +1 -1
  176. package/lib/typescript/module/ui/screens/ManageAccountScreen.d.ts.map +1 -1
  177. package/lib/typescript/module/ui/screens/OxyAuthScreen.d.ts +13 -12
  178. package/lib/typescript/module/ui/screens/OxyAuthScreen.d.ts.map +1 -1
  179. package/lib/typescript/module/ui/screens/ProfileScreen.d.ts.map +1 -1
  180. package/lib/typescript/module/ui/screens/linkFormat.d.ts +23 -0
  181. package/lib/typescript/module/ui/screens/linkFormat.d.ts.map +1 -0
  182. package/lib/typescript/module/ui/session/authStore.d.ts +33 -0
  183. package/lib/typescript/module/ui/session/authStore.d.ts.map +1 -0
  184. package/lib/typescript/module/ui/session/createSessionClient.d.ts +19 -15
  185. package/lib/typescript/module/ui/session/createSessionClient.d.ts.map +1 -1
  186. package/lib/typescript/module/ui/session/index.d.ts +9 -9
  187. package/lib/typescript/module/ui/session/index.d.ts.map +1 -1
  188. package/lib/typescript/module/ui/session/tokenTransport.d.ts +13 -19
  189. package/lib/typescript/module/ui/session/tokenTransport.d.ts.map +1 -1
  190. package/lib/typescript/module/ui/utils/isWebBrowser.d.ts +9 -0
  191. package/lib/typescript/module/ui/utils/isWebBrowser.d.ts.map +1 -0
  192. package/lib/typescript/module/ui/utils/storageHelpers.d.ts +7 -7
  193. package/lib/typescript/module/utils/deviceFlowSignIn.d.ts +15 -13
  194. package/lib/typescript/module/utils/deviceFlowSignIn.d.ts.map +1 -1
  195. package/package.json +4 -4
  196. package/src/index.ts +2 -6
  197. package/src/ui/components/SignInAccountChooser.tsx +162 -0
  198. package/src/ui/components/SignInModal.tsx +309 -139
  199. package/src/ui/context/OxyContext.tsx +532 -1785
  200. package/src/ui/context/hooks/useAuthOperations.ts +65 -76
  201. package/src/ui/hooks/mutations/mutationKeys.ts +1 -1
  202. package/src/ui/hooks/mutations/useAccountMutations.ts +7 -7
  203. package/src/ui/hooks/queries/queryKeys.ts +1 -1
  204. package/src/ui/hooks/queries/useAccountQueries.ts +8 -9
  205. package/src/ui/hooks/useAuth.ts +14 -35
  206. package/src/ui/hooks/usePasswordSignIn.ts +207 -0
  207. package/src/ui/hooks/useProfileEditing.ts +2 -8
  208. package/src/ui/hooks/useSessionManagement.ts +1 -1
  209. package/src/ui/navigation/routes.ts +3 -1
  210. package/src/ui/screens/ConnectedAppsScreen.tsx +23 -24
  211. package/src/ui/screens/EditProfileFieldScreen.tsx +102 -66
  212. package/src/ui/screens/EditProfileScreen.tsx +155 -0
  213. package/src/ui/screens/ManageAccountScreen.tsx +3 -7
  214. package/src/ui/screens/OxyAuthScreen.tsx +259 -112
  215. package/src/ui/screens/ProfileScreen.tsx +15 -2
  216. package/src/ui/screens/__tests__/linkFormat.test.ts +73 -0
  217. package/src/ui/screens/linkFormat.ts +37 -0
  218. package/src/ui/session/__tests__/createSessionClient.test.ts +22 -7
  219. package/src/ui/session/__tests__/tokenTransport.test.ts +37 -49
  220. package/src/ui/session/authStore.ts +164 -0
  221. package/src/ui/session/createSessionClient.ts +30 -17
  222. package/src/ui/session/index.ts +10 -9
  223. package/src/ui/session/tokenTransport.ts +26 -36
  224. package/src/ui/utils/isWebBrowser.ts +8 -0
  225. package/src/ui/utils/storageHelpers.ts +7 -7
  226. package/src/utils/__tests__/deviceFlowSignIn.test.ts +50 -131
  227. package/src/utils/deviceFlowSignIn.ts +19 -26
  228. package/lib/commonjs/ui/context/inSessionTokenRefresh.js +0 -243
  229. package/lib/commonjs/ui/context/inSessionTokenRefresh.js.map +0 -1
  230. package/lib/commonjs/ui/context/silentSessionRestore.js +0 -56
  231. package/lib/commonjs/ui/context/silentSessionRestore.js.map +0 -1
  232. package/lib/commonjs/ui/hooks/useWebSSO.js +0 -28
  233. package/lib/commonjs/ui/hooks/useWebSSO.js.map +0 -1
  234. package/lib/commonjs/ui/session/projectSessionState.js +0 -86
  235. package/lib/commonjs/ui/session/projectSessionState.js.map +0 -1
  236. package/lib/commonjs/ui/session/sessionClientHost.js +0 -30
  237. package/lib/commonjs/ui/session/sessionClientHost.js.map +0 -1
  238. package/lib/commonjs/ui/utils/activeAuthuser.js +0 -142
  239. package/lib/commonjs/ui/utils/activeAuthuser.js.map +0 -1
  240. package/lib/commonjs/utils/crossApex.js +0 -74
  241. package/lib/commonjs/utils/crossApex.js.map +0 -1
  242. package/lib/module/ui/context/inSessionTokenRefresh.js +0 -238
  243. package/lib/module/ui/context/inSessionTokenRefresh.js.map +0 -1
  244. package/lib/module/ui/context/silentSessionRestore.js +0 -53
  245. package/lib/module/ui/context/silentSessionRestore.js.map +0 -1
  246. package/lib/module/ui/hooks/useWebSSO.js +0 -24
  247. package/lib/module/ui/hooks/useWebSSO.js.map +0 -1
  248. package/lib/module/ui/session/projectSessionState.js +0 -79
  249. package/lib/module/ui/session/projectSessionState.js.map +0 -1
  250. package/lib/module/ui/session/sessionClientHost.js +0 -26
  251. package/lib/module/ui/session/sessionClientHost.js.map +0 -1
  252. package/lib/module/ui/utils/activeAuthuser.js +0 -134
  253. package/lib/module/ui/utils/activeAuthuser.js.map +0 -1
  254. package/lib/module/utils/crossApex.js +0 -69
  255. package/lib/module/utils/crossApex.js.map +0 -1
  256. package/lib/typescript/commonjs/ui/context/inSessionTokenRefresh.d.ts +0 -106
  257. package/lib/typescript/commonjs/ui/context/inSessionTokenRefresh.d.ts.map +0 -1
  258. package/lib/typescript/commonjs/ui/context/silentSessionRestore.d.ts +0 -36
  259. package/lib/typescript/commonjs/ui/context/silentSessionRestore.d.ts.map +0 -1
  260. package/lib/typescript/commonjs/ui/hooks/useWebSSO.d.ts +0 -19
  261. package/lib/typescript/commonjs/ui/hooks/useWebSSO.d.ts.map +0 -1
  262. package/lib/typescript/commonjs/ui/session/projectSessionState.d.ts +0 -45
  263. package/lib/typescript/commonjs/ui/session/projectSessionState.d.ts.map +0 -1
  264. package/lib/typescript/commonjs/ui/session/sessionClientHost.d.ts +0 -14
  265. package/lib/typescript/commonjs/ui/session/sessionClientHost.d.ts.map +0 -1
  266. package/lib/typescript/commonjs/ui/utils/activeAuthuser.d.ts +0 -67
  267. package/lib/typescript/commonjs/ui/utils/activeAuthuser.d.ts.map +0 -1
  268. package/lib/typescript/commonjs/utils/crossApex.d.ts +0 -55
  269. package/lib/typescript/commonjs/utils/crossApex.d.ts.map +0 -1
  270. package/lib/typescript/module/ui/context/inSessionTokenRefresh.d.ts +0 -106
  271. package/lib/typescript/module/ui/context/inSessionTokenRefresh.d.ts.map +0 -1
  272. package/lib/typescript/module/ui/context/silentSessionRestore.d.ts +0 -36
  273. package/lib/typescript/module/ui/context/silentSessionRestore.d.ts.map +0 -1
  274. package/lib/typescript/module/ui/hooks/useWebSSO.d.ts +0 -19
  275. package/lib/typescript/module/ui/hooks/useWebSSO.d.ts.map +0 -1
  276. package/lib/typescript/module/ui/session/projectSessionState.d.ts +0 -45
  277. package/lib/typescript/module/ui/session/projectSessionState.d.ts.map +0 -1
  278. package/lib/typescript/module/ui/session/sessionClientHost.d.ts +0 -14
  279. package/lib/typescript/module/ui/session/sessionClientHost.d.ts.map +0 -1
  280. package/lib/typescript/module/ui/utils/activeAuthuser.d.ts +0 -67
  281. package/lib/typescript/module/ui/utils/activeAuthuser.d.ts.map +0 -1
  282. package/lib/typescript/module/utils/crossApex.d.ts +0 -55
  283. package/lib/typescript/module/utils/crossApex.d.ts.map +0 -1
  284. package/src/ui/context/inSessionTokenRefresh.ts +0 -264
  285. package/src/ui/context/silentSessionRestore.ts +0 -53
  286. package/src/ui/hooks/useWebSSO.ts +0 -23
  287. package/src/ui/session/__tests__/projectSessionState.test.ts +0 -114
  288. package/src/ui/session/__tests__/sessionClientHost.test.ts +0 -43
  289. package/src/ui/session/projectSessionState.ts +0 -85
  290. package/src/ui/session/sessionClientHost.ts +0 -27
  291. package/src/ui/utils/activeAuthuser.ts +0 -142
  292. package/src/utils/crossApex.ts +0 -75
@@ -26,6 +26,7 @@ export type RouteName =
26
26
  | 'UserLinks'
27
27
  | 'HistoryView'
28
28
  | 'SavesCollections'
29
+ | 'EditProfile' // Profile-editing hub: one row per editable field
29
30
  | 'EditProfileField' // Dedicated screen for editing a single profile field
30
31
  | 'LearnMoreUsernames' // Informational screen about usernames
31
32
  | 'TrustCenter'
@@ -42,7 +43,7 @@ export type RouteName =
42
43
  | 'AccountSettings' // Per-account profile edit + members + danger zone
43
44
  | 'AvatarCrop' // Square-crop editor presented before avatar upload
44
45
  | 'Notifications' // Per-channel notification preferences
45
- | 'ConnectedApps' // FedCM-authorized RP apps the user can revoke
46
+ | 'ConnectedApps' // OAuth-authorized third-party apps the user can revoke
46
47
  | 'Preferences'; // General user preferences (theme, reduce-motion, etc.)
47
48
 
48
49
  // Lazy screen loaders - functions that return screen components on-demand
@@ -67,6 +68,7 @@ const screenLoaders: Record<RouteName, () => ComponentType<BaseScreenProps>> = {
67
68
  UserLinks: () => require('../screens/UserLinksScreen').default,
68
69
  HistoryView: () => require('../screens/HistoryViewScreen').default,
69
70
  SavesCollections: () => require('../screens/SavesCollectionsScreen').default,
71
+ EditProfile: () => require('../screens/EditProfileScreen').default,
70
72
  EditProfileField: () => require('../screens/EditProfileFieldScreen').default,
71
73
  // Informational screens
72
74
  LearnMoreUsernames: () => require('../screens/LearnMoreUsernamesScreen').default,
@@ -3,7 +3,7 @@ import { ActivityIndicator, FlatList, RefreshControl, StyleSheet, View } from 'r
3
3
  import { Dialog, toast, useDialogControl } from '@oxyhq/bloom';
4
4
  import { useTheme } from '@oxyhq/bloom/theme';
5
5
  import { SettingsListGroup, SettingsListItem } from '@oxyhq/bloom/settings-list';
6
- import type { AuthorizedApp } from '@oxyhq/core';
6
+ import type { ConnectedApp } from '@oxyhq/core';
7
7
  import { logger as loggerUtil } from '@oxyhq/core';
8
8
  import type { BaseScreenProps } from '../types/navigation';
9
9
  import Header from '../components/Header';
@@ -12,8 +12,8 @@ import EmptyState from '../components/EmptyState';
12
12
  import LoadingState from '../components/LoadingState';
13
13
  import { useI18n } from '../hooks/useI18n';
14
14
  import { useOxy } from '../context/OxyContext';
15
- import { useAuthorizedApps } from '../hooks/queries/useAccountQueries';
16
- import { useRevokeAuthorizedApp } from '../hooks/mutations/useAccountMutations';
15
+ import { useConnectedApps } from '../hooks/queries/useAccountQueries';
16
+ import { useRevokeConnectedApp } from '../hooks/mutations/useAccountMutations';
17
17
 
18
18
  const APP_ICON_SIZE = 40;
19
19
 
@@ -39,12 +39,11 @@ const formatRelative = (iso: string): string => {
39
39
  };
40
40
 
41
41
  /**
42
- * ConnectedAppsScreen — list and revoke FedCM-authorized RP applications.
42
+ * ConnectedAppsScreen — list and revoke connected OAuth applications.
43
43
  *
44
- * Fetches via `useAuthorizedApps` (drives `GET /fedcm/me/authorized-apps`)
45
- * and exposes a "Revoke" action that hits `DELETE /fedcm/me/authorized-apps/
46
- * :origin`. Each revoke invalidates the connected-apps query so the list
47
- * refreshes immediately.
44
+ * Fetches via `useConnectedApps` (drives `GET /auth/grants`) and exposes a
45
+ * "Revoke" action that hits `DELETE /auth/grants/:applicationId`. Each revoke
46
+ * invalidates the connected-apps query so the list refreshes immediately.
48
47
  */
49
48
  const ConnectedAppsScreen: React.FC<BaseScreenProps> = ({ onClose, goBack }) => {
50
49
  const bloomTheme = useTheme();
@@ -55,14 +54,14 @@ const ConnectedAppsScreen: React.FC<BaseScreenProps> = ({ onClose, goBack }) =>
55
54
  isLoading,
56
55
  refetch,
57
56
  isRefetching,
58
- } = useAuthorizedApps({ enabled: isAuthenticated });
59
- const revokeMutation = useRevokeAuthorizedApp();
57
+ } = useConnectedApps({ enabled: isAuthenticated });
58
+ const revokeMutation = useRevokeConnectedApp();
60
59
  const revokeDialog = useDialogControl();
61
- const [pendingRevoke, setPendingRevoke] = useState<AuthorizedApp | null>(null);
62
- const [revokingOrigin, setRevokingOrigin] = useState<string | null>(null);
60
+ const [pendingRevoke, setPendingRevoke] = useState<ConnectedApp | null>(null);
61
+ const [revokingAppId, setRevokingAppId] = useState<string | null>(null);
63
62
 
64
63
  const confirmRevoke = useCallback(
65
- (app: AuthorizedApp) => {
64
+ (app: ConnectedApp) => {
66
65
  setPendingRevoke(app);
67
66
  revokeDialog.open();
68
67
  },
@@ -74,16 +73,16 @@ const ConnectedAppsScreen: React.FC<BaseScreenProps> = ({ onClose, goBack }) =>
74
73
  return;
75
74
  }
76
75
  const target = pendingRevoke;
77
- setRevokingOrigin(target.origin);
76
+ setRevokingAppId(target.applicationId);
78
77
  try {
79
- await revokeMutation.mutateAsync(target.origin);
78
+ await revokeMutation.mutateAsync(target.applicationId);
80
79
  toast.success(
81
80
  t('connectedApps.toasts.revoked', { name: target.name })
82
81
  || `Revoked access for ${target.name}`,
83
82
  );
84
83
  } catch (error) {
85
84
  loggerUtil.warn(
86
- 'Revoke authorized app failed',
85
+ 'Revoke connected app failed',
87
86
  { component: 'ConnectedAppsScreen' },
88
87
  error,
89
88
  );
@@ -92,7 +91,7 @@ const ConnectedAppsScreen: React.FC<BaseScreenProps> = ({ onClose, goBack }) =>
92
91
  || 'Failed to revoke access',
93
92
  );
94
93
  } finally {
95
- setRevokingOrigin(null);
94
+ setRevokingAppId(null);
96
95
  setPendingRevoke(null);
97
96
  }
98
97
  }, [pendingRevoke, revokeMutation, t]);
@@ -113,18 +112,18 @@ const ConnectedAppsScreen: React.FC<BaseScreenProps> = ({ onClose, goBack }) =>
113
112
  );
114
113
 
115
114
  const renderItem = useCallback(
116
- ({ item }: { item: AuthorizedApp }) => {
117
- const isRevoking = revokingOrigin === item.origin;
115
+ ({ item }: { item: ConnectedApp }) => {
116
+ const isRevoking = revokingAppId === item.applicationId;
118
117
  return (
119
118
  <SettingsListGroup>
120
119
  <SettingsListItem
121
120
  icon={<Avatar name={item.name} size={APP_ICON_SIZE} />}
122
121
  title={item.name}
123
122
  description={
124
- t('connectedApps.item.lastUsed', {
125
- relative: formatRelative(item.lastUsedAt),
123
+ t('connectedApps.item.granted', {
124
+ relative: formatRelative(item.firstGrantedAt),
126
125
  })
127
- || `Last used ${formatRelative(item.lastUsedAt)}`
126
+ || `Granted ${formatRelative(item.firstGrantedAt)}`
128
127
  }
129
128
  onPress={isRevoking ? undefined : () => confirmRevoke(item)}
130
129
  disabled={isRevoking}
@@ -142,7 +141,7 @@ const ConnectedAppsScreen: React.FC<BaseScreenProps> = ({ onClose, goBack }) =>
142
141
  </SettingsListGroup>
143
142
  );
144
143
  },
145
- [bloomTheme.colors.error, confirmRevoke, revokingOrigin, t],
144
+ [bloomTheme.colors.error, confirmRevoke, revokingAppId, t],
146
145
  );
147
146
 
148
147
  return (
@@ -158,7 +157,7 @@ const ConnectedAppsScreen: React.FC<BaseScreenProps> = ({ onClose, goBack }) =>
158
157
  ) : (
159
158
  <FlatList
160
159
  data={apps ?? []}
161
- keyExtractor={(item) => item.origin}
160
+ keyExtractor={(item) => item.applicationId}
162
161
  renderItem={renderItem}
163
162
  contentContainerClassName="px-screen-margin py-space-16"
164
163
  contentContainerStyle={styles.listContent}
@@ -1,4 +1,4 @@
1
- import React, { useState, useEffect, useCallback, useMemo } from 'react';
1
+ import React, { useState, useCallback, useMemo } from 'react';
2
2
  import {
3
3
  View,
4
4
  Platform,
@@ -16,12 +16,14 @@ import { H1, Text } from '@oxyhq/bloom/typography';
16
16
  import { Button } from '@oxyhq/bloom/button';
17
17
  import { TextField, TextFieldInput } from '@oxyhq/bloom/text-field';
18
18
  import { normalizeTheme } from '@oxyhq/core';
19
+ import type { User } from '@oxyhq/core';
19
20
  import Header from '../components/Header';
20
21
  import { useI18n } from '../hooks/useI18n';
21
22
  import { useOxy } from '../context/OxyContext';
22
23
  import { useProfileEditing } from '../hooks/useProfileEditing';
23
24
  import { toast } from '@oxyhq/bloom';
24
- import { EMAIL_REGEX } from '@oxyhq/core';
25
+ import { EMAIL_REGEX, isValidDisplayName } from '@oxyhq/core';
26
+ import { getLinkTitle, getLinkDescription, linksToListItems } from './linkFormat';
25
27
 
26
28
  /**
27
29
  * Field types supported by EditProfileFieldScreen
@@ -71,8 +73,82 @@ type EditableListItem = {
71
73
  coordinates?: { lat: number; lon: number };
72
74
  };
73
75
 
74
- const getLinkTitle = (url: string) => url.replace(/^https?:\/\//, '').replace(/\/$/, '');
75
- const getLinkDescription = (url: string) => `Link to ${url}`;
76
+
77
+ /**
78
+ * Pure seeding function: derives the initial `fieldValues` / `listItems` for a
79
+ * given field type from the active account snapshot. Called ONCE per state via
80
+ * lazy `useState` initializers — never from an effect — so a background
81
+ * `refreshSessions()` / `useCurrentUser()` swap of the `user` reference can't
82
+ * wipe in-progress typing. Each editor mounts with a fixed `fieldType`, so the
83
+ * seed is stable for the lifetime of the mount.
84
+ */
85
+ function buildInitialProfileState(
86
+ user: User | null,
87
+ fieldType: ProfileFieldType,
88
+ ): { fieldValues: Record<string, string>; listItems: EditableListItem[] } {
89
+ if (!user) {
90
+ return { fieldValues: {}, listItems: [] };
91
+ }
92
+ const userData = user;
93
+
94
+ if (fieldType === 'locations') {
95
+ const locations = Array.isArray(userData.locations) ? userData.locations : [];
96
+ return {
97
+ fieldValues: {},
98
+ listItems: locations.map((loc, i) => ({
99
+ id: String(loc.id || `location-${i}`),
100
+ name: String(loc.name || ''),
101
+ ...loc,
102
+ })),
103
+ };
104
+ }
105
+
106
+ if (fieldType === 'links') {
107
+ const linksMetadata = Array.isArray(userData.linksMetadata) ? userData.linksMetadata : [];
108
+ const links = Array.isArray(userData.links) ? userData.links : [];
109
+ // Prefer rich link metadata; fall back to the plain links array.
110
+ if (linksMetadata.length > 0) {
111
+ return {
112
+ fieldValues: {},
113
+ listItems: linksMetadata.map((link, i) => ({
114
+ ...link,
115
+ id: String(link.id || `link-${i}`),
116
+ url: String(link.url || ''),
117
+ title: String(link.title || getLinkTitle(String(link.url || ''))),
118
+ description: String(link.description || getLinkDescription(String(link.url || ''))),
119
+ })),
120
+ };
121
+ }
122
+ return {
123
+ fieldValues: {},
124
+ listItems: linksToListItems(links),
125
+ };
126
+ }
127
+
128
+ // Scalar fields: seed only the keys this field type edits.
129
+ const fieldValues: Record<string, string> = {};
130
+ switch (fieldType) {
131
+ case 'displayName':
132
+ fieldValues.firstName = String(userData.name?.first || '');
133
+ fieldValues.lastName = String(userData.lastName || userData.name?.last || '');
134
+ break;
135
+ case 'birthday':
136
+ fieldValues.birthday = String(userData.birthday || userData.dateOfBirth || '');
137
+ break;
138
+ case 'address':
139
+ fieldValues.address = String(userData.address || '');
140
+ break;
141
+ case 'username':
142
+ case 'email':
143
+ case 'bio':
144
+ case 'phone':
145
+ fieldValues[fieldType] = String(userData[fieldType] || '');
146
+ break;
147
+ default:
148
+ break;
149
+ }
150
+ return { fieldValues, listItems: [] };
151
+ }
76
152
 
77
153
  /**
78
154
  * EditProfileFieldScreen - A dedicated screen for editing profile fields
@@ -98,12 +174,18 @@ const EditProfileFieldScreen: React.FC<EditProfileFieldScreenProps> = ({
98
174
  const bloomTheme = useTheme();
99
175
  const normalizedTheme = normalizeTheme(theme);
100
176
 
101
- // State for field values
102
- const [fieldValues, setFieldValues] = useState<Record<string, string>>({});
177
+ // State for field values — seeded ONCE from the active account snapshot at
178
+ // mount via lazy initializers. See buildInitialProfileState: no effect
179
+ // reseeds these, so a background user-ref swap never wipes typing.
180
+ const [fieldValues, setFieldValues] = useState<Record<string, string>>(
181
+ () => buildInitialProfileState(user, fieldType).fieldValues,
182
+ );
103
183
  const [fieldErrors, setFieldErrors] = useState<Record<string, string | undefined>>({});
104
184
 
105
- // State for list fields (locations, links)
106
- const [listItems, setListItems] = useState<EditableListItem[]>([]);
185
+ // State for list fields (locations, links) — same one-time mount seeding.
186
+ const [listItems, setListItems] = useState<EditableListItem[]>(
187
+ () => buildInitialProfileState(user, fieldType).listItems,
188
+ );
107
189
  const [newItemValue, setNewItemValue] = useState('');
108
190
 
109
191
  // Get field configuration based on fieldType
@@ -118,11 +200,21 @@ const EditProfileFieldScreen: React.FC<EditProfileFieldScreenProps> = ({
118
200
  key: 'firstName',
119
201
  label: t('editProfile.items.displayName.firstName') || 'First Name',
120
202
  placeholder: t('editProfile.items.displayName.firstNamePlaceholder') || 'Enter first name',
203
+ validation: (value) =>
204
+ isValidDisplayName(value)
205
+ ? undefined
206
+ : (t('editProfile.items.displayName.invalidChars')
207
+ || 'Use letters and spaces only'),
121
208
  },
122
209
  {
123
210
  key: 'lastName',
124
211
  label: t('editProfile.items.displayName.lastName') || 'Last Name',
125
212
  placeholder: t('editProfile.items.displayName.lastNamePlaceholder') || 'Enter last name (optional)',
213
+ validation: (value) =>
214
+ isValidDisplayName(value)
215
+ ? undefined
216
+ : (t('editProfile.items.displayName.invalidChars')
217
+ || 'Use letters and spaces only'),
126
218
  },
127
219
  ],
128
220
  };
@@ -266,62 +358,6 @@ const EditProfileFieldScreen: React.FC<EditProfileFieldScreenProps> = ({
266
358
  }
267
359
  }, [fieldType, t]);
268
360
 
269
- // Initialize field values from the active account's data
270
- useEffect(() => {
271
- if (!user) return;
272
-
273
- const userData = user;
274
-
275
- if (fieldConfig.isList) {
276
- if (fieldType === 'locations') {
277
- const locations = Array.isArray(userData.locations) ? userData.locations : [];
278
- setListItems(locations.map((loc, i) => ({
279
- id: String(loc.id || `location-${i}`),
280
- name: String(loc.name || ''),
281
- ...loc,
282
- })));
283
- } else if (fieldType === 'links') {
284
- const linksMetadata = Array.isArray(userData.linksMetadata) ? userData.linksMetadata : [];
285
- const links = Array.isArray(userData.links) ? userData.links : [];
286
- // Use linksMetadata if available, otherwise convert links array
287
- if (linksMetadata.length > 0) {
288
- setListItems(linksMetadata.map((link, i) => ({
289
- ...link,
290
- id: String(link.id || `link-${i}`),
291
- url: String(link.url || ''),
292
- title: String(link.title || getLinkTitle(String(link.url || ''))),
293
- description: String(link.description || getLinkDescription(String(link.url || ''))),
294
- })));
295
- } else {
296
- setListItems(links.map((item, i) => {
297
- return {
298
- id: `link-${i}`,
299
- url: item,
300
- title: getLinkTitle(item),
301
- description: getLinkDescription(item),
302
- };
303
- }));
304
- }
305
- }
306
- } else {
307
- const initialValues: Record<string, string> = {};
308
- fieldConfig.fields.forEach(field => {
309
- if (field.key === 'firstName') {
310
- initialValues[field.key] = String(userData.name?.first || '');
311
- } else if (field.key === 'lastName') {
312
- initialValues[field.key] = String(userData.lastName || userData.name?.last || '');
313
- } else if (field.key === 'birthday') {
314
- initialValues[field.key] = String(userData.birthday || userData.dateOfBirth || '');
315
- } else if (field.key === 'address') {
316
- initialValues[field.key] = String(userData.address || userData.location || '');
317
- } else {
318
- initialValues[field.key] = String(userData[field.key] || '');
319
- }
320
- });
321
- setFieldValues(initialValues);
322
- }
323
- }, [user, fieldConfig, fieldType]);
324
-
325
361
  // Field change handler
326
362
  const handleFieldChange = useCallback((key: string, value: string) => {
327
363
  setFieldValues(prev => ({ ...prev, [key]: value }));
@@ -335,7 +371,7 @@ const EditProfileFieldScreen: React.FC<EditProfileFieldScreenProps> = ({
335
371
  const errors: Record<string, string | undefined> = {};
336
372
  let isValid = true;
337
373
 
338
- fieldConfig.fields.forEach(field => {
374
+ for (const field of fieldConfig.fields) {
339
375
  if (field.validation) {
340
376
  const error = field.validation(fieldValues[field.key] || '');
341
377
  if (error) {
@@ -343,7 +379,7 @@ const EditProfileFieldScreen: React.FC<EditProfileFieldScreenProps> = ({
343
379
  isValid = false;
344
380
  }
345
381
  }
346
- });
382
+ }
347
383
 
348
384
  setFieldErrors(errors);
349
385
  return isValid;
@@ -0,0 +1,155 @@
1
+ import type React from 'react';
2
+ import { useMemo } from 'react';
3
+ import { View, ScrollView } from 'react-native';
4
+ import { useTheme } from '@oxyhq/bloom/theme';
5
+ import { H4, Text } from '@oxyhq/bloom/typography';
6
+ import { SettingsListGroup, SettingsListItem } from '@oxyhq/bloom/settings-list';
7
+ import { getAccountDisplayName } from '@oxyhq/core';
8
+ import type { BaseScreenProps } from '../types/navigation';
9
+ import Header from '../components/Header';
10
+ import Avatar from '../components/Avatar';
11
+ import { SettingsIcon } from '../components/SettingsIcon';
12
+ import { useOxy } from '../context/OxyContext';
13
+ import { useI18n } from '../hooks/useI18n';
14
+ import type { ProfileFieldType } from './EditProfileFieldScreen';
15
+
16
+ /**
17
+ * EditProfileScreen — the profile-editing HUB.
18
+ *
19
+ * Lists every editable profile field as its own row; each row deep-links into
20
+ * {@link EditProfileFieldScreen} with the matching `fieldType`. The avatar row
21
+ * reuses the exact same `openAvatarPicker` entry point that
22
+ * {@link ManageAccountScreen} uses. This is the single entry into per-field
23
+ * editing — reached from ManageAccount's "Edit profile" row.
24
+ */
25
+ const EditProfileScreen: React.FC<BaseScreenProps> = ({ onClose, goBack, navigate }) => {
26
+ const bloomTheme = useTheme();
27
+ const { t, locale } = useI18n();
28
+ const { user, oxyServices, openAvatarPicker } = useOxy();
29
+
30
+ const displayName = useMemo(() => getAccountDisplayName(user, locale), [user, locale]);
31
+ const avatarUri = useMemo(
32
+ () => (user?.avatar ? oxyServices.getFileDownloadUrl(user.avatar, 'thumb') : undefined),
33
+ [user?.avatar, oxyServices],
34
+ );
35
+
36
+ const notSet = t('editProfile.notSet') || 'Not set';
37
+
38
+ // Current value previews for each row. Typed User fields resolve directly;
39
+ // `locations` is only reachable via the User index signature (typed
40
+ // `unknown`), so it is narrowed defensively.
41
+ const linkPreview = user?.linksMetadata?.[0]?.url ?? user?.links?.[0] ?? notSet;
42
+ const locationPreview = ((): string => {
43
+ const locations = user?.locations;
44
+ const first: unknown = Array.isArray(locations) ? locations[0] : undefined;
45
+ if (first && typeof first === 'object' && 'name' in first && typeof first.name === 'string' && first.name) {
46
+ return first.name;
47
+ }
48
+ return notSet;
49
+ })();
50
+
51
+ const goToField = (fieldType: ProfileFieldType) => navigate?.('EditProfileField', { fieldType });
52
+
53
+ return (
54
+ <View className="flex-1 bg-bg">
55
+ <Header
56
+ title={t('editProfile.title') || 'Edit Profile'}
57
+ onBack={goBack || onClose}
58
+ elevation="subtle"
59
+ />
60
+ <ScrollView
61
+ className="flex-1"
62
+ contentContainerClassName="px-screen-margin pb-space-24"
63
+ showsVerticalScrollIndicator={false}
64
+ >
65
+ {/* Profile card */}
66
+ <View className="items-center bg-fill-secondary rounded-radius-20 px-space-20 py-space-24 mb-space-16">
67
+ <Avatar uri={avatarUri} name={displayName} size={72} />
68
+ <H4 className="text-text mt-space-12" numberOfLines={1}>
69
+ {displayName}
70
+ </H4>
71
+ {user?.username ? (
72
+ <Text className="text-text-secondary text-sm mt-space-2" numberOfLines={1}>
73
+ @{user.username}
74
+ </Text>
75
+ ) : null}
76
+ </View>
77
+
78
+ {/* Profile picture */}
79
+ <SettingsListGroup title={t('editProfile.sections.profilePicture') || 'Profile Picture'}>
80
+ <SettingsListItem
81
+ icon={<SettingsIcon name="camera" color={bloomTheme.colors.primary} />}
82
+ title={t('editProfile.changeAvatar') || 'Change avatar'}
83
+ description={t('editProfile.items.avatar.subtitle') || 'Update your profile photo'}
84
+ onPress={openAvatarPicker}
85
+ rightElement={<Avatar uri={avatarUri} name={displayName} size={32} />}
86
+ />
87
+ </SettingsListGroup>
88
+
89
+ {/* Basic information */}
90
+ <SettingsListGroup title={t('editProfile.sections.basicInfo') || 'Basic Information'}>
91
+ <SettingsListItem
92
+ icon={<SettingsIcon name="account" color={bloomTheme.colors.primary} />}
93
+ title={t('editProfile.items.displayName.title') || 'Display Name'}
94
+ description={displayName || notSet}
95
+ onPress={() => goToField('displayName')}
96
+ />
97
+ <SettingsListItem
98
+ icon={<SettingsIcon name="at" color={bloomTheme.colors.info} />}
99
+ title={t('editProfile.items.username.title') || 'Username'}
100
+ description={user?.username ? `@${user.username}` : notSet}
101
+ onPress={() => goToField('username')}
102
+ />
103
+ <SettingsListItem
104
+ icon={<SettingsIcon name="email" color={bloomTheme.colors.success} />}
105
+ title={t('editProfile.items.email.title') || 'Email'}
106
+ description={user?.email || notSet}
107
+ onPress={() => goToField('email')}
108
+ />
109
+ <SettingsListItem
110
+ icon={<SettingsIcon name="phone" color={bloomTheme.colors.warning} />}
111
+ title={t('editProfile.items.phone.title') || 'Phone Number'}
112
+ description={user?.phone || notSet}
113
+ onPress={() => goToField('phone')}
114
+ />
115
+ </SettingsListGroup>
116
+
117
+ {/* About you */}
118
+ <SettingsListGroup title={t('editProfile.sections.about') || 'About You'}>
119
+ <SettingsListItem
120
+ icon={<SettingsIcon name="text" color={bloomTheme.colors.primary} />}
121
+ title={t('editProfile.items.bio.title') || 'Bio'}
122
+ description={user?.bio || notSet}
123
+ onPress={() => goToField('bio')}
124
+ />
125
+ <SettingsListItem
126
+ icon={<SettingsIcon name="map-marker" color={bloomTheme.colors.info} />}
127
+ title={t('editProfile.items.address.title') || 'Address'}
128
+ description={user?.address || notSet}
129
+ onPress={() => goToField('address')}
130
+ />
131
+ <SettingsListItem
132
+ icon={<SettingsIcon name="cake-variant" color={bloomTheme.colors.warning} />}
133
+ title={t('editProfile.items.birthday.title') || 'Birthday'}
134
+ description={user?.birthday || notSet}
135
+ onPress={() => goToField('birthday')}
136
+ />
137
+ <SettingsListItem
138
+ icon={<SettingsIcon name="link-variant" color={bloomTheme.colors.success} />}
139
+ title={t('editProfile.items.links.title') || 'Links'}
140
+ description={linkPreview}
141
+ onPress={() => goToField('links')}
142
+ />
143
+ <SettingsListItem
144
+ icon={<SettingsIcon name="map-marker-multiple" color={bloomTheme.colors.primary} />}
145
+ title={t('editProfile.items.locations.title') || 'Locations'}
146
+ description={locationPreview}
147
+ onPress={() => goToField('locations')}
148
+ />
149
+ </SettingsListGroup>
150
+ </ScrollView>
151
+ </View>
152
+ );
153
+ };
154
+
155
+ export default EditProfileScreen;
@@ -78,7 +78,7 @@ const formatRelative = (dateString?: string): string => {
78
78
  * Replaces AccountOverview + AccountSettings + the per-account half of
79
79
  * SessionManagement. Lists ONLY the active user's profile, sessions on this
80
80
  * device, and security/destructive actions for THIS account. Multi-account
81
- * surface lives in {@link AccountMenu} — keep these concerns separate.
81
+ * surface lives in {@link AccountSwitcher} — keep these concerns separate.
82
82
  */
83
83
  const ManageAccountScreen: React.FC<BaseScreenProps> = ({
84
84
  onClose,
@@ -384,9 +384,7 @@ const ManageAccountScreen: React.FC<BaseScreenProps> = ({
384
384
  t('manageAccount.items.editProfile.subtitle')
385
385
  || 'Name, username, bio, links'
386
386
  }
387
- onPress={() =>
388
- navigate?.('EditProfileField', { field: 'username' })
389
- }
387
+ onPress={() => navigate?.('EditProfile')}
390
388
  />
391
389
  <SettingsListItem
392
390
  icon={
@@ -400,9 +398,7 @@ const ManageAccountScreen: React.FC<BaseScreenProps> = ({
400
398
  t('manageAccount.items.theme.subtitle')
401
399
  || 'Personalize your Bloom color'
402
400
  }
403
- onPress={() =>
404
- navigate?.('EditProfileField', { field: 'color' })
405
- }
401
+ onPress={() => navigate?.('Preferences')}
406
402
  />
407
403
  <SettingsListItem
408
404
  icon={