@oxyhq/services 26.0.1 → 26.0.3

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 (599) hide show
  1. package/README.md +2 -2
  2. package/android/src/main/java/so/oxy/identity/OxyIdentityStore.kt +21 -127
  3. package/android/src/main/java/so/oxy/session/OxyBackgroundSession.kt +184 -0
  4. package/android/src/main/java/so/oxy/session/OxyBackgroundSessionApi.kt +162 -0
  5. package/android/src/main/java/so/oxy/session/OxyBackgroundSessionModule.kt +116 -0
  6. package/android/src/main/java/so/oxy/session/OxyBackgroundSessionStore.kt +179 -0
  7. package/android/src/main/java/so/oxy/session/OxyBackgroundToken.kt +61 -0
  8. package/android/src/main/java/so/oxy/storage/OxyEncryptedPrefs.kt +241 -0
  9. package/expo-module.config.json +4 -1
  10. package/lib/commonjs/index.js +18 -49
  11. package/lib/commonjs/index.js.map +1 -1
  12. package/lib/commonjs/notifications/deviceNotifications.js +63 -0
  13. package/lib/commonjs/notifications/deviceNotifications.js.map +1 -1
  14. package/lib/commonjs/ui/boot/runProviderColdBoot.js +20 -64
  15. package/lib/commonjs/ui/boot/runProviderColdBoot.js.map +1 -1
  16. package/lib/commonjs/ui/components/AvatarCameraBadge.js +2 -2
  17. package/lib/commonjs/ui/components/AvatarCameraBadge.js.map +1 -1
  18. package/lib/commonjs/ui/components/FollowButton.js +4 -4
  19. package/lib/commonjs/ui/components/FollowButton.js.map +1 -1
  20. package/lib/commonjs/ui/components/OxyAccountDialogScreen.js +13 -1
  21. package/lib/commonjs/ui/components/OxyAccountDialogScreen.js.map +1 -1
  22. package/lib/commonjs/ui/components/OxyAuthChooser.js +29 -24
  23. package/lib/commonjs/ui/components/OxyAuthChooser.js.map +1 -1
  24. package/lib/commonjs/ui/components/OxyProvider.js +8 -7
  25. package/lib/commonjs/ui/components/OxyProvider.js.map +1 -1
  26. package/lib/commonjs/ui/components/OxySignInButton.js.map +1 -1
  27. package/lib/commonjs/ui/components/ProfileButton.js +20 -26
  28. package/lib/commonjs/ui/components/ProfileButton.js.map +1 -1
  29. package/lib/commonjs/ui/components/authChooser/AccountsMenuView.js +68 -58
  30. package/lib/commonjs/ui/components/authChooser/AccountsMenuView.js.map +1 -1
  31. package/lib/commonjs/ui/components/authChooser/types.js.map +1 -1
  32. package/lib/commonjs/ui/components/authChooser/useUsernameAvailability.js +2 -2
  33. package/lib/commonjs/ui/components/authChooser/useUsernameAvailability.js.map +1 -1
  34. package/lib/commonjs/ui/components/fileManagement/UploadPreview.js +2 -2
  35. package/lib/commonjs/ui/components/fileManagement/UploadPreview.js.map +1 -1
  36. package/lib/commonjs/ui/components/internal/PinInput.js +3 -1
  37. package/lib/commonjs/ui/components/internal/PinInput.js.map +1 -1
  38. package/lib/commonjs/ui/components/logo/LogoText.js +4 -4
  39. package/lib/commonjs/ui/components/logo/LogoText.js.map +1 -1
  40. package/lib/commonjs/ui/components/payment/PaymentDetailsStep.js +2 -2
  41. package/lib/commonjs/ui/components/payment/PaymentDetailsStep.js.map +1 -1
  42. package/lib/commonjs/ui/components/payment/PaymentSummaryStep.js +2 -2
  43. package/lib/commonjs/ui/components/payment/PaymentSummaryStep.js.map +1 -1
  44. package/lib/commonjs/ui/components/styles/shadow.js.map +1 -1
  45. package/lib/commonjs/ui/context/OxyContext.js +32 -46
  46. package/lib/commonjs/ui/context/OxyContext.js.map +1 -1
  47. package/lib/commonjs/ui/context/commitSessionFlow.js +3 -43
  48. package/lib/commonjs/ui/context/commitSessionFlow.js.map +1 -1
  49. package/lib/commonjs/ui/context/hooks/useAuthOperations.js +15 -2
  50. package/lib/commonjs/ui/context/hooks/useAuthOperations.js.map +1 -1
  51. package/lib/commonjs/ui/context/useOxyAccountGraph.js +3 -4
  52. package/lib/commonjs/ui/context/useOxyAccountGraph.js.map +1 -1
  53. package/lib/commonjs/ui/hooks/mutations/mutationFactory.js +5 -5
  54. package/lib/commonjs/ui/hooks/mutations/mutationFactory.js.map +1 -1
  55. package/lib/commonjs/ui/hooks/mutations/useAccountMutations.js +11 -11
  56. package/lib/commonjs/ui/hooks/mutations/useAccountMutations.js.map +1 -1
  57. package/lib/commonjs/ui/hooks/mutations/useServicesMutations.js +9 -9
  58. package/lib/commonjs/ui/hooks/mutations/useServicesMutations.js.map +1 -1
  59. package/lib/commonjs/ui/hooks/queries/usePaymentQueries.js +3 -2
  60. package/lib/commonjs/ui/hooks/queries/usePaymentQueries.js.map +1 -1
  61. package/lib/commonjs/ui/hooks/queries/userCache.js +17 -17
  62. package/lib/commonjs/ui/hooks/queries/userCache.js.map +1 -1
  63. package/lib/commonjs/ui/hooks/useAssets.js.map +1 -1
  64. package/lib/commonjs/ui/hooks/useAsyncAction.js +7 -7
  65. package/lib/commonjs/ui/hooks/useAsyncAction.js.map +1 -1
  66. package/lib/commonjs/ui/hooks/useAuth.js +8 -4
  67. package/lib/commonjs/ui/hooks/useAuth.js.map +1 -1
  68. package/lib/commonjs/ui/hooks/useAvatarPicker.js +5 -5
  69. package/lib/commonjs/ui/hooks/useAvatarPicker.js.map +1 -1
  70. package/lib/commonjs/ui/hooks/useOnlineStatus.js +3 -2
  71. package/lib/commonjs/ui/hooks/useOnlineStatus.js.map +1 -1
  72. package/lib/commonjs/ui/hooks/useSessionManagement.js +0 -2
  73. package/lib/commonjs/ui/hooks/useSessionManagement.js.map +1 -1
  74. package/lib/commonjs/ui/hooks/useSettingToggle.js +4 -4
  75. package/lib/commonjs/ui/hooks/useSettingToggle.js.map +1 -1
  76. package/lib/commonjs/ui/hooks/useSurfaceHeader.js +68 -11
  77. package/lib/commonjs/ui/hooks/useSurfaceHeader.js.map +1 -1
  78. package/lib/commonjs/ui/navigation/accountDialogManager.js +2 -0
  79. package/lib/commonjs/ui/navigation/accountDialogManager.js.map +1 -1
  80. package/lib/commonjs/ui/oauth/browserAuthTransport.js +66 -64
  81. package/lib/commonjs/ui/oauth/browserAuthTransport.js.map +1 -1
  82. package/lib/commonjs/ui/oauth/oauthPopup.js +47 -0
  83. package/lib/commonjs/ui/oauth/oauthPopup.js.map +1 -1
  84. package/lib/commonjs/ui/screens/AccountMembersScreen.js +10 -10
  85. package/lib/commonjs/ui/screens/AccountMembersScreen.js.map +1 -1
  86. package/lib/commonjs/ui/screens/AccountSettingsScreen.js +41 -19
  87. package/lib/commonjs/ui/screens/AccountSettingsScreen.js.map +1 -1
  88. package/lib/commonjs/ui/screens/AccountVerificationScreen.js +4 -4
  89. package/lib/commonjs/ui/screens/AccountVerificationScreen.js.map +1 -1
  90. package/lib/commonjs/ui/screens/AppInfoScreen.js +9 -9
  91. package/lib/commonjs/ui/screens/AppInfoScreen.js.map +1 -1
  92. package/lib/commonjs/ui/screens/AvatarCropScreen.js +3 -3
  93. package/lib/commonjs/ui/screens/AvatarCropScreen.js.map +1 -1
  94. package/lib/commonjs/ui/screens/ChangeAvatarScreen.js +6 -7
  95. package/lib/commonjs/ui/screens/ChangeAvatarScreen.js.map +1 -1
  96. package/lib/commonjs/ui/screens/ConnectedAppsScreen.js +4 -4
  97. package/lib/commonjs/ui/screens/ConnectedAppsScreen.js.map +1 -1
  98. package/lib/commonjs/ui/screens/CreateAccountScreen.js +46 -14
  99. package/lib/commonjs/ui/screens/CreateAccountScreen.js.map +1 -1
  100. package/lib/commonjs/ui/screens/EditProfileFieldScreen.js +5 -5
  101. package/lib/commonjs/ui/screens/EditProfileFieldScreen.js.map +1 -1
  102. package/lib/commonjs/ui/screens/EditProfileScreen.js +2 -3
  103. package/lib/commonjs/ui/screens/EditProfileScreen.js.map +1 -1
  104. package/lib/commonjs/ui/screens/FAQScreen.js +2 -2
  105. package/lib/commonjs/ui/screens/FAQScreen.js.map +1 -1
  106. package/lib/commonjs/ui/screens/FeedbackScreen.js +90 -89
  107. package/lib/commonjs/ui/screens/FeedbackScreen.js.map +1 -1
  108. package/lib/commonjs/ui/screens/FileManagementScreen.js +20 -20
  109. package/lib/commonjs/ui/screens/FileManagementScreen.js.map +1 -1
  110. package/lib/commonjs/ui/screens/FollowersListScreen.js.map +1 -1
  111. package/lib/commonjs/ui/screens/FollowingListScreen.js.map +1 -1
  112. package/lib/commonjs/ui/screens/HelpSupportScreen.js +7 -7
  113. package/lib/commonjs/ui/screens/HelpSupportScreen.js.map +1 -1
  114. package/lib/commonjs/ui/screens/HistoryViewScreen.js +9 -34
  115. package/lib/commonjs/ui/screens/HistoryViewScreen.js.map +1 -1
  116. package/lib/commonjs/ui/screens/LanguageSelectorScreen.js +3 -3
  117. package/lib/commonjs/ui/screens/LanguageSelectorScreen.js.map +1 -1
  118. package/lib/commonjs/ui/screens/LegalDocumentsScreen.js +3 -3
  119. package/lib/commonjs/ui/screens/LegalDocumentsScreen.js.map +1 -1
  120. package/lib/commonjs/ui/screens/ManageAccountScreen.js +15 -15
  121. package/lib/commonjs/ui/screens/ManageAccountScreen.js.map +1 -1
  122. package/lib/commonjs/ui/screens/PremiumSubscriptionScreen.js +19 -19
  123. package/lib/commonjs/ui/screens/PremiumSubscriptionScreen.js.map +1 -1
  124. package/lib/commonjs/ui/screens/PrivacySettingsScreen.js +15 -15
  125. package/lib/commonjs/ui/screens/PrivacySettingsScreen.js.map +1 -1
  126. package/lib/commonjs/ui/screens/ProfileScreen.js +17 -7
  127. package/lib/commonjs/ui/screens/ProfileScreen.js.map +1 -1
  128. package/lib/commonjs/ui/screens/SavesCollectionsScreen.js +2 -2
  129. package/lib/commonjs/ui/screens/SavesCollectionsScreen.js.map +1 -1
  130. package/lib/commonjs/ui/screens/UserListScreen.js +13 -7
  131. package/lib/commonjs/ui/screens/UserListScreen.js.map +1 -1
  132. package/lib/commonjs/ui/screens/WelcomeNewUserScreen.js +5 -6
  133. package/lib/commonjs/ui/screens/WelcomeNewUserScreen.js.map +1 -1
  134. package/lib/commonjs/ui/screens/fileManagement/PhotoPickerSection.js +1 -4
  135. package/lib/commonjs/ui/screens/fileManagement/PhotoPickerSection.js.map +1 -1
  136. package/lib/commonjs/ui/screens/fileManagement/hooks/useFileUploadState.js +34 -24
  137. package/lib/commonjs/ui/screens/fileManagement/hooks/useFileUploadState.js.map +1 -1
  138. package/lib/commonjs/ui/screens/trust/TrustCenterScreen.js +1 -1
  139. package/lib/commonjs/ui/screens/trust/TrustCenterScreen.js.map +1 -1
  140. package/lib/commonjs/ui/screens/trust/TrustLeaderboardScreen.js +3 -4
  141. package/lib/commonjs/ui/screens/trust/TrustLeaderboardScreen.js.map +1 -1
  142. package/lib/commonjs/ui/screens/trust/TrustRewardsScreen.js +1 -1
  143. package/lib/commonjs/ui/screens/trust/TrustRewardsScreen.js.map +1 -1
  144. package/lib/commonjs/ui/session/backgroundSession.js +258 -0
  145. package/lib/commonjs/ui/session/backgroundSession.js.map +1 -0
  146. package/lib/commonjs/ui/session/index.js +7 -0
  147. package/lib/commonjs/ui/session/index.js.map +1 -1
  148. package/lib/commonjs/ui/session/useBackgroundSessionSync.js +81 -0
  149. package/lib/commonjs/ui/session/useBackgroundSessionSync.js.map +1 -0
  150. package/lib/commonjs/ui/utils/fileManagement.js +24 -24
  151. package/lib/commonjs/ui/utils/fileManagement.js.map +1 -1
  152. package/lib/commonjs/ui/utils/netConnectivity.js +28 -0
  153. package/lib/commonjs/ui/utils/netConnectivity.js.map +1 -0
  154. package/lib/commonjs/ui/utils/oauthReturn.js +19 -30
  155. package/lib/commonjs/ui/utils/oauthReturn.js.map +1 -1
  156. package/lib/commonjs/ui/utils/userUtils.js +27 -28
  157. package/lib/commonjs/ui/utils/userUtils.js.map +1 -1
  158. package/lib/module/index.js +20 -8
  159. package/lib/module/index.js.map +1 -1
  160. package/lib/module/notifications/deviceNotifications.js +62 -0
  161. package/lib/module/notifications/deviceNotifications.js.map +1 -1
  162. package/lib/module/ui/boot/runProviderColdBoot.js +21 -65
  163. package/lib/module/ui/boot/runProviderColdBoot.js.map +1 -1
  164. package/lib/module/ui/components/AvatarCameraBadge.js +1 -1
  165. package/lib/module/ui/components/AvatarCameraBadge.js.map +1 -1
  166. package/lib/module/ui/components/FollowButton.js +1 -1
  167. package/lib/module/ui/components/FollowButton.js.map +1 -1
  168. package/lib/module/ui/components/OxyAccountDialogScreen.js +13 -1
  169. package/lib/module/ui/components/OxyAccountDialogScreen.js.map +1 -1
  170. package/lib/module/ui/components/OxyAuthChooser.js +25 -20
  171. package/lib/module/ui/components/OxyAuthChooser.js.map +1 -1
  172. package/lib/module/ui/components/OxyProvider.js +7 -6
  173. package/lib/module/ui/components/OxyProvider.js.map +1 -1
  174. package/lib/module/ui/components/OxySignInButton.js.map +1 -1
  175. package/lib/module/ui/components/ProfileButton.js +12 -18
  176. package/lib/module/ui/components/ProfileButton.js.map +1 -1
  177. package/lib/module/ui/components/authChooser/AccountsMenuView.js +68 -58
  178. package/lib/module/ui/components/authChooser/AccountsMenuView.js.map +1 -1
  179. package/lib/module/ui/components/authChooser/types.js.map +1 -1
  180. package/lib/module/ui/components/authChooser/useUsernameAvailability.js +1 -1
  181. package/lib/module/ui/components/authChooser/useUsernameAvailability.js.map +1 -1
  182. package/lib/module/ui/components/fileManagement/UploadPreview.js +1 -1
  183. package/lib/module/ui/components/fileManagement/UploadPreview.js.map +1 -1
  184. package/lib/module/ui/components/internal/PinInput.js +3 -1
  185. package/lib/module/ui/components/internal/PinInput.js.map +1 -1
  186. package/lib/module/ui/components/logo/LogoText.js +4 -4
  187. package/lib/module/ui/components/logo/LogoText.js.map +1 -1
  188. package/lib/module/ui/components/payment/PaymentDetailsStep.js +1 -1
  189. package/lib/module/ui/components/payment/PaymentDetailsStep.js.map +1 -1
  190. package/lib/module/ui/components/payment/PaymentSummaryStep.js +2 -2
  191. package/lib/module/ui/components/payment/PaymentSummaryStep.js.map +1 -1
  192. package/lib/module/ui/components/styles/shadow.js.map +1 -1
  193. package/lib/module/ui/context/OxyContext.js +35 -49
  194. package/lib/module/ui/context/OxyContext.js.map +1 -1
  195. package/lib/module/ui/context/commitSessionFlow.js +3 -42
  196. package/lib/module/ui/context/commitSessionFlow.js.map +1 -1
  197. package/lib/module/ui/context/hooks/useAuthOperations.js +15 -2
  198. package/lib/module/ui/context/hooks/useAuthOperations.js.map +1 -1
  199. package/lib/module/ui/context/useOxyAccountGraph.js +3 -4
  200. package/lib/module/ui/context/useOxyAccountGraph.js.map +1 -1
  201. package/lib/module/ui/hooks/mutations/mutationFactory.js +1 -1
  202. package/lib/module/ui/hooks/mutations/mutationFactory.js.map +1 -1
  203. package/lib/module/ui/hooks/mutations/useAccountMutations.js +1 -1
  204. package/lib/module/ui/hooks/mutations/useAccountMutations.js.map +1 -1
  205. package/lib/module/ui/hooks/mutations/useServicesMutations.js +1 -1
  206. package/lib/module/ui/hooks/mutations/useServicesMutations.js.map +1 -1
  207. package/lib/module/ui/hooks/queries/usePaymentQueries.js +3 -2
  208. package/lib/module/ui/hooks/queries/usePaymentQueries.js.map +1 -1
  209. package/lib/module/ui/hooks/queries/userCache.js +17 -17
  210. package/lib/module/ui/hooks/queries/userCache.js.map +1 -1
  211. package/lib/module/ui/hooks/useAssets.js.map +1 -1
  212. package/lib/module/ui/hooks/useAsyncAction.js +1 -1
  213. package/lib/module/ui/hooks/useAsyncAction.js.map +1 -1
  214. package/lib/module/ui/hooks/useAuth.js +8 -4
  215. package/lib/module/ui/hooks/useAuth.js.map +1 -1
  216. package/lib/module/ui/hooks/useAvatarPicker.js +1 -1
  217. package/lib/module/ui/hooks/useAvatarPicker.js.map +1 -1
  218. package/lib/module/ui/hooks/useOnlineStatus.js +3 -2
  219. package/lib/module/ui/hooks/useOnlineStatus.js.map +1 -1
  220. package/lib/module/ui/hooks/useSessionManagement.js +0 -2
  221. package/lib/module/ui/hooks/useSessionManagement.js.map +1 -1
  222. package/lib/module/ui/hooks/useSettingToggle.js +1 -1
  223. package/lib/module/ui/hooks/useSettingToggle.js.map +1 -1
  224. package/lib/module/ui/hooks/useSurfaceHeader.js +68 -11
  225. package/lib/module/ui/hooks/useSurfaceHeader.js.map +1 -1
  226. package/lib/module/ui/navigation/accountDialogManager.js +2 -0
  227. package/lib/module/ui/navigation/accountDialogManager.js.map +1 -1
  228. package/lib/module/ui/oauth/browserAuthTransport.js +66 -64
  229. package/lib/module/ui/oauth/browserAuthTransport.js.map +1 -1
  230. package/lib/module/ui/oauth/oauthPopup.js +48 -1
  231. package/lib/module/ui/oauth/oauthPopup.js.map +1 -1
  232. package/lib/module/ui/screens/AccountMembersScreen.js +1 -1
  233. package/lib/module/ui/screens/AccountMembersScreen.js.map +1 -1
  234. package/lib/module/ui/screens/AccountSettingsScreen.js +37 -15
  235. package/lib/module/ui/screens/AccountSettingsScreen.js.map +1 -1
  236. package/lib/module/ui/screens/AccountVerificationScreen.js +1 -1
  237. package/lib/module/ui/screens/AccountVerificationScreen.js.map +1 -1
  238. package/lib/module/ui/screens/AppInfoScreen.js +1 -1
  239. package/lib/module/ui/screens/AppInfoScreen.js.map +1 -1
  240. package/lib/module/ui/screens/AvatarCropScreen.js +1 -1
  241. package/lib/module/ui/screens/AvatarCropScreen.js.map +1 -1
  242. package/lib/module/ui/screens/ChangeAvatarScreen.js +4 -5
  243. package/lib/module/ui/screens/ChangeAvatarScreen.js.map +1 -1
  244. package/lib/module/ui/screens/ConnectedAppsScreen.js +2 -2
  245. package/lib/module/ui/screens/ConnectedAppsScreen.js.map +1 -1
  246. package/lib/module/ui/screens/CreateAccountScreen.js +45 -13
  247. package/lib/module/ui/screens/CreateAccountScreen.js.map +1 -1
  248. package/lib/module/ui/screens/EditProfileFieldScreen.js +4 -4
  249. package/lib/module/ui/screens/EditProfileFieldScreen.js.map +1 -1
  250. package/lib/module/ui/screens/EditProfileScreen.js +3 -4
  251. package/lib/module/ui/screens/EditProfileScreen.js.map +1 -1
  252. package/lib/module/ui/screens/FAQScreen.js +1 -1
  253. package/lib/module/ui/screens/FAQScreen.js.map +1 -1
  254. package/lib/module/ui/screens/FeedbackScreen.js +94 -91
  255. package/lib/module/ui/screens/FeedbackScreen.js.map +1 -1
  256. package/lib/module/ui/screens/FileManagementScreen.js +1 -1
  257. package/lib/module/ui/screens/FileManagementScreen.js.map +1 -1
  258. package/lib/module/ui/screens/FollowersListScreen.js.map +1 -1
  259. package/lib/module/ui/screens/FollowingListScreen.js.map +1 -1
  260. package/lib/module/ui/screens/HelpSupportScreen.js +1 -1
  261. package/lib/module/ui/screens/HelpSupportScreen.js.map +1 -1
  262. package/lib/module/ui/screens/HistoryViewScreen.js +5 -30
  263. package/lib/module/ui/screens/HistoryViewScreen.js.map +1 -1
  264. package/lib/module/ui/screens/LanguageSelectorScreen.js +1 -1
  265. package/lib/module/ui/screens/LanguageSelectorScreen.js.map +1 -1
  266. package/lib/module/ui/screens/LegalDocumentsScreen.js +1 -1
  267. package/lib/module/ui/screens/LegalDocumentsScreen.js.map +1 -1
  268. package/lib/module/ui/screens/ManageAccountScreen.js +3 -3
  269. package/lib/module/ui/screens/ManageAccountScreen.js.map +1 -1
  270. package/lib/module/ui/screens/PremiumSubscriptionScreen.js +4 -4
  271. package/lib/module/ui/screens/PremiumSubscriptionScreen.js.map +1 -1
  272. package/lib/module/ui/screens/PrivacySettingsScreen.js +11 -11
  273. package/lib/module/ui/screens/PrivacySettingsScreen.js.map +1 -1
  274. package/lib/module/ui/screens/ProfileScreen.js +18 -8
  275. package/lib/module/ui/screens/ProfileScreen.js.map +1 -1
  276. package/lib/module/ui/screens/SavesCollectionsScreen.js +1 -1
  277. package/lib/module/ui/screens/SavesCollectionsScreen.js.map +1 -1
  278. package/lib/module/ui/screens/UserListScreen.js +14 -8
  279. package/lib/module/ui/screens/UserListScreen.js.map +1 -1
  280. package/lib/module/ui/screens/WelcomeNewUserScreen.js +5 -6
  281. package/lib/module/ui/screens/WelcomeNewUserScreen.js.map +1 -1
  282. package/lib/module/ui/screens/fileManagement/PhotoPickerSection.js +1 -4
  283. package/lib/module/ui/screens/fileManagement/PhotoPickerSection.js.map +1 -1
  284. package/lib/module/ui/screens/fileManagement/hooks/useFileUploadState.js +15 -5
  285. package/lib/module/ui/screens/fileManagement/hooks/useFileUploadState.js.map +1 -1
  286. package/lib/module/ui/screens/trust/TrustCenterScreen.js +1 -1
  287. package/lib/module/ui/screens/trust/TrustCenterScreen.js.map +1 -1
  288. package/lib/module/ui/screens/trust/TrustLeaderboardScreen.js +4 -5
  289. package/lib/module/ui/screens/trust/TrustLeaderboardScreen.js.map +1 -1
  290. package/lib/module/ui/screens/trust/TrustRewardsScreen.js +1 -1
  291. package/lib/module/ui/screens/trust/TrustRewardsScreen.js.map +1 -1
  292. package/lib/module/ui/session/backgroundSession.js +252 -0
  293. package/lib/module/ui/session/backgroundSession.js.map +1 -0
  294. package/lib/module/ui/session/index.js +1 -0
  295. package/lib/module/ui/session/index.js.map +1 -1
  296. package/lib/module/ui/session/useBackgroundSessionSync.js +76 -0
  297. package/lib/module/ui/session/useBackgroundSessionSync.js.map +1 -0
  298. package/lib/module/ui/utils/fileManagement.js +25 -25
  299. package/lib/module/ui/utils/fileManagement.js.map +1 -1
  300. package/lib/module/ui/utils/netConnectivity.js +23 -0
  301. package/lib/module/ui/utils/netConnectivity.js.map +1 -0
  302. package/lib/module/ui/utils/oauthReturn.js +20 -30
  303. package/lib/module/ui/utils/oauthReturn.js.map +1 -1
  304. package/lib/module/ui/utils/userUtils.js +27 -28
  305. package/lib/module/ui/utils/userUtils.js.map +1 -1
  306. package/lib/typescript/commonjs/index.d.ts +1 -2
  307. package/lib/typescript/commonjs/index.d.ts.map +1 -1
  308. package/lib/typescript/commonjs/notifications/deviceNotifications.d.ts +51 -0
  309. package/lib/typescript/commonjs/notifications/deviceNotifications.d.ts.map +1 -1
  310. package/lib/typescript/commonjs/ui/boot/runProviderColdBoot.d.ts +11 -30
  311. package/lib/typescript/commonjs/ui/boot/runProviderColdBoot.d.ts.map +1 -1
  312. package/lib/typescript/commonjs/ui/components/AvatarCameraBadge.d.ts.map +1 -1
  313. package/lib/typescript/commonjs/ui/components/OxyAccountDialogScreen.d.ts.map +1 -1
  314. package/lib/typescript/commonjs/ui/components/OxyAuthChooser.d.ts +7 -0
  315. package/lib/typescript/commonjs/ui/components/OxyAuthChooser.d.ts.map +1 -1
  316. package/lib/typescript/commonjs/ui/components/OxyProvider.d.ts.map +1 -1
  317. package/lib/typescript/commonjs/ui/components/OxySignInButton.d.ts +2 -1
  318. package/lib/typescript/commonjs/ui/components/OxySignInButton.d.ts.map +1 -1
  319. package/lib/typescript/commonjs/ui/components/ProfileButton.d.ts +3 -0
  320. package/lib/typescript/commonjs/ui/components/ProfileButton.d.ts.map +1 -1
  321. package/lib/typescript/commonjs/ui/components/authChooser/AccountsMenuView.d.ts.map +1 -1
  322. package/lib/typescript/commonjs/ui/components/authChooser/types.d.ts +6 -0
  323. package/lib/typescript/commonjs/ui/components/authChooser/types.d.ts.map +1 -1
  324. package/lib/typescript/commonjs/ui/components/fileManagement/UploadPreview.d.ts +1 -1
  325. package/lib/typescript/commonjs/ui/components/fileManagement/UploadPreview.d.ts.map +1 -1
  326. package/lib/typescript/commonjs/ui/components/internal/PinInput.d.ts.map +1 -1
  327. package/lib/typescript/commonjs/ui/components/payment/types.d.ts +6 -6
  328. package/lib/typescript/commonjs/ui/components/payment/types.d.ts.map +1 -1
  329. package/lib/typescript/commonjs/ui/context/OxyContext.d.ts.map +1 -1
  330. package/lib/typescript/commonjs/ui/context/commitSessionFlow.d.ts +0 -40
  331. package/lib/typescript/commonjs/ui/context/commitSessionFlow.d.ts.map +1 -1
  332. package/lib/typescript/commonjs/ui/context/hooks/useAuthOperations.d.ts +11 -2
  333. package/lib/typescript/commonjs/ui/context/hooks/useAuthOperations.d.ts.map +1 -1
  334. package/lib/typescript/commonjs/ui/context/oxyContextTypes.d.ts +26 -7
  335. package/lib/typescript/commonjs/ui/context/oxyContextTypes.d.ts.map +1 -1
  336. package/lib/typescript/commonjs/ui/context/useOxyAccountGraph.d.ts +0 -1
  337. package/lib/typescript/commonjs/ui/context/useOxyAccountGraph.d.ts.map +1 -1
  338. package/lib/typescript/commonjs/ui/hooks/mutations/useAccountMutations.d.ts.map +1 -1
  339. package/lib/typescript/commonjs/ui/hooks/queries/paymentTypes.d.ts +3 -2
  340. package/lib/typescript/commonjs/ui/hooks/queries/paymentTypes.d.ts.map +1 -1
  341. package/lib/typescript/commonjs/ui/hooks/queries/usePaymentQueries.d.ts +3 -2
  342. package/lib/typescript/commonjs/ui/hooks/queries/usePaymentQueries.d.ts.map +1 -1
  343. package/lib/typescript/commonjs/ui/hooks/queries/userCache.d.ts +2 -2
  344. package/lib/typescript/commonjs/ui/hooks/queries/userCache.d.ts.map +1 -1
  345. package/lib/typescript/commonjs/ui/hooks/useAssets.d.ts +1 -1
  346. package/lib/typescript/commonjs/ui/hooks/useAssets.d.ts.map +1 -1
  347. package/lib/typescript/commonjs/ui/hooks/useAsyncAction.d.ts +2 -2
  348. package/lib/typescript/commonjs/ui/hooks/useAsyncAction.d.ts.map +1 -1
  349. package/lib/typescript/commonjs/ui/hooks/useAuth.d.ts +10 -6
  350. package/lib/typescript/commonjs/ui/hooks/useAuth.d.ts.map +1 -1
  351. package/lib/typescript/commonjs/ui/hooks/useOnlineStatus.d.ts +3 -2
  352. package/lib/typescript/commonjs/ui/hooks/useOnlineStatus.d.ts.map +1 -1
  353. package/lib/typescript/commonjs/ui/hooks/useSessionManagement.d.ts.map +1 -1
  354. package/lib/typescript/commonjs/ui/hooks/useSurfaceHeader.d.ts +7 -2
  355. package/lib/typescript/commonjs/ui/hooks/useSurfaceHeader.d.ts.map +1 -1
  356. package/lib/typescript/commonjs/ui/navigation/accountDialogManager.d.ts +8 -0
  357. package/lib/typescript/commonjs/ui/navigation/accountDialogManager.d.ts.map +1 -1
  358. package/lib/typescript/commonjs/ui/oauth/browserAuthTransport.d.ts.map +1 -1
  359. package/lib/typescript/commonjs/ui/oauth/oauthPopup.d.ts +6 -0
  360. package/lib/typescript/commonjs/ui/oauth/oauthPopup.d.ts.map +1 -1
  361. package/lib/typescript/commonjs/ui/screens/AccountSettingsScreen.d.ts.map +1 -1
  362. package/lib/typescript/commonjs/ui/screens/ChangeAvatarScreen.d.ts.map +1 -1
  363. package/lib/typescript/commonjs/ui/screens/CreateAccountScreen.d.ts.map +1 -1
  364. package/lib/typescript/commonjs/ui/screens/EditProfileScreen.d.ts.map +1 -1
  365. package/lib/typescript/commonjs/ui/screens/FeedbackScreen.d.ts +2 -2
  366. package/lib/typescript/commonjs/ui/screens/FeedbackScreen.d.ts.map +1 -1
  367. package/lib/typescript/commonjs/ui/screens/FollowersListScreen.d.ts +3 -0
  368. package/lib/typescript/commonjs/ui/screens/FollowersListScreen.d.ts.map +1 -1
  369. package/lib/typescript/commonjs/ui/screens/FollowingListScreen.d.ts +3 -0
  370. package/lib/typescript/commonjs/ui/screens/FollowingListScreen.d.ts.map +1 -1
  371. package/lib/typescript/commonjs/ui/screens/HistoryViewScreen.d.ts.map +1 -1
  372. package/lib/typescript/commonjs/ui/screens/ManageAccountScreen.d.ts.map +1 -1
  373. package/lib/typescript/commonjs/ui/screens/PrivacySettingsScreen.d.ts.map +1 -1
  374. package/lib/typescript/commonjs/ui/screens/ProfileScreen.d.ts.map +1 -1
  375. package/lib/typescript/commonjs/ui/screens/UserListScreen.d.ts +7 -0
  376. package/lib/typescript/commonjs/ui/screens/UserListScreen.d.ts.map +1 -1
  377. package/lib/typescript/commonjs/ui/screens/WelcomeNewUserScreen.d.ts.map +1 -1
  378. package/lib/typescript/commonjs/ui/screens/fileManagement/hooks/useFileUploadState.d.ts.map +1 -1
  379. package/lib/typescript/commonjs/ui/screens/trust/TrustLeaderboardScreen.d.ts.map +1 -1
  380. package/lib/typescript/commonjs/ui/screens/trust/trustTier.d.ts +1 -1
  381. package/lib/typescript/commonjs/ui/screens/trust/trustTier.d.ts.map +1 -1
  382. package/lib/typescript/commonjs/ui/session/backgroundSession.d.ts +42 -0
  383. package/lib/typescript/commonjs/ui/session/backgroundSession.d.ts.map +1 -0
  384. package/lib/typescript/commonjs/ui/session/index.d.ts +1 -0
  385. package/lib/typescript/commonjs/ui/session/index.d.ts.map +1 -1
  386. package/lib/typescript/commonjs/ui/session/useBackgroundSessionSync.d.ts +23 -0
  387. package/lib/typescript/commonjs/ui/session/useBackgroundSessionSync.d.ts.map +1 -0
  388. package/lib/typescript/commonjs/ui/types/navigation.d.ts +27 -19
  389. package/lib/typescript/commonjs/ui/types/navigation.d.ts.map +1 -1
  390. package/lib/typescript/commonjs/ui/utils/fileManagement.d.ts +5 -5
  391. package/lib/typescript/commonjs/ui/utils/fileManagement.d.ts.map +1 -1
  392. package/lib/typescript/commonjs/ui/utils/netConnectivity.d.ts +17 -0
  393. package/lib/typescript/commonjs/ui/utils/netConnectivity.d.ts.map +1 -0
  394. package/lib/typescript/commonjs/ui/utils/oauthReturn.d.ts +15 -12
  395. package/lib/typescript/commonjs/ui/utils/oauthReturn.d.ts.map +1 -1
  396. package/lib/typescript/commonjs/ui/utils/userUtils.d.ts +7 -14
  397. package/lib/typescript/commonjs/ui/utils/userUtils.d.ts.map +1 -1
  398. package/lib/typescript/module/index.d.ts +1 -2
  399. package/lib/typescript/module/index.d.ts.map +1 -1
  400. package/lib/typescript/module/notifications/deviceNotifications.d.ts +51 -0
  401. package/lib/typescript/module/notifications/deviceNotifications.d.ts.map +1 -1
  402. package/lib/typescript/module/ui/boot/runProviderColdBoot.d.ts +11 -30
  403. package/lib/typescript/module/ui/boot/runProviderColdBoot.d.ts.map +1 -1
  404. package/lib/typescript/module/ui/components/AvatarCameraBadge.d.ts.map +1 -1
  405. package/lib/typescript/module/ui/components/OxyAccountDialogScreen.d.ts.map +1 -1
  406. package/lib/typescript/module/ui/components/OxyAuthChooser.d.ts +7 -0
  407. package/lib/typescript/module/ui/components/OxyAuthChooser.d.ts.map +1 -1
  408. package/lib/typescript/module/ui/components/OxyProvider.d.ts.map +1 -1
  409. package/lib/typescript/module/ui/components/OxySignInButton.d.ts +2 -1
  410. package/lib/typescript/module/ui/components/OxySignInButton.d.ts.map +1 -1
  411. package/lib/typescript/module/ui/components/ProfileButton.d.ts +3 -0
  412. package/lib/typescript/module/ui/components/ProfileButton.d.ts.map +1 -1
  413. package/lib/typescript/module/ui/components/authChooser/AccountsMenuView.d.ts.map +1 -1
  414. package/lib/typescript/module/ui/components/authChooser/types.d.ts +6 -0
  415. package/lib/typescript/module/ui/components/authChooser/types.d.ts.map +1 -1
  416. package/lib/typescript/module/ui/components/fileManagement/UploadPreview.d.ts +1 -1
  417. package/lib/typescript/module/ui/components/fileManagement/UploadPreview.d.ts.map +1 -1
  418. package/lib/typescript/module/ui/components/internal/PinInput.d.ts.map +1 -1
  419. package/lib/typescript/module/ui/components/payment/types.d.ts +6 -6
  420. package/lib/typescript/module/ui/components/payment/types.d.ts.map +1 -1
  421. package/lib/typescript/module/ui/context/OxyContext.d.ts.map +1 -1
  422. package/lib/typescript/module/ui/context/commitSessionFlow.d.ts +0 -40
  423. package/lib/typescript/module/ui/context/commitSessionFlow.d.ts.map +1 -1
  424. package/lib/typescript/module/ui/context/hooks/useAuthOperations.d.ts +11 -2
  425. package/lib/typescript/module/ui/context/hooks/useAuthOperations.d.ts.map +1 -1
  426. package/lib/typescript/module/ui/context/oxyContextTypes.d.ts +26 -7
  427. package/lib/typescript/module/ui/context/oxyContextTypes.d.ts.map +1 -1
  428. package/lib/typescript/module/ui/context/useOxyAccountGraph.d.ts +0 -1
  429. package/lib/typescript/module/ui/context/useOxyAccountGraph.d.ts.map +1 -1
  430. package/lib/typescript/module/ui/hooks/mutations/useAccountMutations.d.ts.map +1 -1
  431. package/lib/typescript/module/ui/hooks/queries/paymentTypes.d.ts +3 -2
  432. package/lib/typescript/module/ui/hooks/queries/paymentTypes.d.ts.map +1 -1
  433. package/lib/typescript/module/ui/hooks/queries/usePaymentQueries.d.ts +3 -2
  434. package/lib/typescript/module/ui/hooks/queries/usePaymentQueries.d.ts.map +1 -1
  435. package/lib/typescript/module/ui/hooks/queries/userCache.d.ts +2 -2
  436. package/lib/typescript/module/ui/hooks/queries/userCache.d.ts.map +1 -1
  437. package/lib/typescript/module/ui/hooks/useAssets.d.ts +1 -1
  438. package/lib/typescript/module/ui/hooks/useAssets.d.ts.map +1 -1
  439. package/lib/typescript/module/ui/hooks/useAsyncAction.d.ts +2 -2
  440. package/lib/typescript/module/ui/hooks/useAsyncAction.d.ts.map +1 -1
  441. package/lib/typescript/module/ui/hooks/useAuth.d.ts +10 -6
  442. package/lib/typescript/module/ui/hooks/useAuth.d.ts.map +1 -1
  443. package/lib/typescript/module/ui/hooks/useOnlineStatus.d.ts +3 -2
  444. package/lib/typescript/module/ui/hooks/useOnlineStatus.d.ts.map +1 -1
  445. package/lib/typescript/module/ui/hooks/useSessionManagement.d.ts.map +1 -1
  446. package/lib/typescript/module/ui/hooks/useSurfaceHeader.d.ts +7 -2
  447. package/lib/typescript/module/ui/hooks/useSurfaceHeader.d.ts.map +1 -1
  448. package/lib/typescript/module/ui/navigation/accountDialogManager.d.ts +8 -0
  449. package/lib/typescript/module/ui/navigation/accountDialogManager.d.ts.map +1 -1
  450. package/lib/typescript/module/ui/oauth/browserAuthTransport.d.ts.map +1 -1
  451. package/lib/typescript/module/ui/oauth/oauthPopup.d.ts +6 -0
  452. package/lib/typescript/module/ui/oauth/oauthPopup.d.ts.map +1 -1
  453. package/lib/typescript/module/ui/screens/AccountSettingsScreen.d.ts.map +1 -1
  454. package/lib/typescript/module/ui/screens/ChangeAvatarScreen.d.ts.map +1 -1
  455. package/lib/typescript/module/ui/screens/CreateAccountScreen.d.ts.map +1 -1
  456. package/lib/typescript/module/ui/screens/EditProfileScreen.d.ts.map +1 -1
  457. package/lib/typescript/module/ui/screens/FeedbackScreen.d.ts +2 -2
  458. package/lib/typescript/module/ui/screens/FeedbackScreen.d.ts.map +1 -1
  459. package/lib/typescript/module/ui/screens/FollowersListScreen.d.ts +3 -0
  460. package/lib/typescript/module/ui/screens/FollowersListScreen.d.ts.map +1 -1
  461. package/lib/typescript/module/ui/screens/FollowingListScreen.d.ts +3 -0
  462. package/lib/typescript/module/ui/screens/FollowingListScreen.d.ts.map +1 -1
  463. package/lib/typescript/module/ui/screens/HistoryViewScreen.d.ts.map +1 -1
  464. package/lib/typescript/module/ui/screens/ManageAccountScreen.d.ts.map +1 -1
  465. package/lib/typescript/module/ui/screens/PrivacySettingsScreen.d.ts.map +1 -1
  466. package/lib/typescript/module/ui/screens/ProfileScreen.d.ts.map +1 -1
  467. package/lib/typescript/module/ui/screens/UserListScreen.d.ts +7 -0
  468. package/lib/typescript/module/ui/screens/UserListScreen.d.ts.map +1 -1
  469. package/lib/typescript/module/ui/screens/WelcomeNewUserScreen.d.ts.map +1 -1
  470. package/lib/typescript/module/ui/screens/fileManagement/hooks/useFileUploadState.d.ts.map +1 -1
  471. package/lib/typescript/module/ui/screens/trust/TrustLeaderboardScreen.d.ts.map +1 -1
  472. package/lib/typescript/module/ui/screens/trust/trustTier.d.ts +1 -1
  473. package/lib/typescript/module/ui/screens/trust/trustTier.d.ts.map +1 -1
  474. package/lib/typescript/module/ui/session/backgroundSession.d.ts +42 -0
  475. package/lib/typescript/module/ui/session/backgroundSession.d.ts.map +1 -0
  476. package/lib/typescript/module/ui/session/index.d.ts +1 -0
  477. package/lib/typescript/module/ui/session/index.d.ts.map +1 -1
  478. package/lib/typescript/module/ui/session/useBackgroundSessionSync.d.ts +23 -0
  479. package/lib/typescript/module/ui/session/useBackgroundSessionSync.d.ts.map +1 -0
  480. package/lib/typescript/module/ui/types/navigation.d.ts +27 -19
  481. package/lib/typescript/module/ui/types/navigation.d.ts.map +1 -1
  482. package/lib/typescript/module/ui/utils/fileManagement.d.ts +5 -5
  483. package/lib/typescript/module/ui/utils/fileManagement.d.ts.map +1 -1
  484. package/lib/typescript/module/ui/utils/netConnectivity.d.ts +17 -0
  485. package/lib/typescript/module/ui/utils/netConnectivity.d.ts.map +1 -0
  486. package/lib/typescript/module/ui/utils/oauthReturn.d.ts +15 -12
  487. package/lib/typescript/module/ui/utils/oauthReturn.d.ts.map +1 -1
  488. package/lib/typescript/module/ui/utils/userUtils.d.ts +7 -14
  489. package/lib/typescript/module/ui/utils/userUtils.d.ts.map +1 -1
  490. package/lib/typescript/types/expo-image-picker.d.ts +35 -0
  491. package/package.json +33 -12
  492. package/src/index.ts +19 -16
  493. package/src/notifications/deviceNotifications.ts +82 -0
  494. package/src/types/expo-image-picker.d.ts +35 -0
  495. package/src/ui/boot/__tests__/coldBootNoIdpRedirect.test.ts +215 -0
  496. package/src/ui/boot/runProviderColdBoot.ts +24 -101
  497. package/src/ui/components/AvatarCameraBadge.tsx +2 -1
  498. package/src/ui/components/FollowButton.tsx +1 -1
  499. package/src/ui/components/OxyAccountDialogScreen.tsx +13 -1
  500. package/src/ui/components/OxyAuthChooser.tsx +31 -20
  501. package/src/ui/components/OxyProvider.tsx +8 -7
  502. package/src/ui/components/OxySignInButton.tsx +2 -1
  503. package/src/ui/components/ProfileButton.tsx +15 -20
  504. package/src/ui/components/authChooser/AccountsMenuView.tsx +66 -57
  505. package/src/ui/components/authChooser/types.ts +6 -0
  506. package/src/ui/components/authChooser/useUsernameAvailability.ts +1 -1
  507. package/src/ui/components/fileManagement/UploadPreview.tsx +1 -1
  508. package/src/ui/components/internal/PinInput.tsx +1 -0
  509. package/src/ui/components/logo/LogoText.tsx +4 -4
  510. package/src/ui/components/payment/PaymentDetailsStep.tsx +1 -1
  511. package/src/ui/components/payment/PaymentSummaryStep.tsx +2 -2
  512. package/src/ui/components/payment/types.ts +24 -24
  513. package/src/ui/components/styles/shadow.tsx +2 -2
  514. package/src/ui/context/OxyContext.tsx +35 -46
  515. package/src/ui/context/__tests__/commitSessionFlow.test.ts +13 -89
  516. package/src/ui/context/commitSessionFlow.ts +3 -61
  517. package/src/ui/context/hooks/useAuthOperations.ts +26 -1
  518. package/src/ui/context/oxyContextTypes.ts +26 -7
  519. package/src/ui/context/useOxyAccountGraph.ts +4 -4
  520. package/src/ui/hooks/mutations/mutationFactory.ts +1 -1
  521. package/src/ui/hooks/mutations/useAccountMutations.ts +1 -1
  522. package/src/ui/hooks/mutations/useServicesMutations.ts +1 -1
  523. package/src/ui/hooks/queries/paymentTypes.ts +3 -2
  524. package/src/ui/hooks/queries/usePaymentQueries.ts +3 -2
  525. package/src/ui/hooks/queries/userCache.ts +169 -148
  526. package/src/ui/hooks/useAssets.ts +1 -1
  527. package/src/ui/hooks/useAsyncAction.ts +3 -3
  528. package/src/ui/hooks/useAuth.ts +12 -6
  529. package/src/ui/hooks/useAvatarPicker.ts +1 -1
  530. package/src/ui/hooks/useOnlineStatus.ts +3 -2
  531. package/src/ui/hooks/useSessionManagement.ts +0 -2
  532. package/src/ui/hooks/useSettingToggle.ts +1 -1
  533. package/src/ui/hooks/useSurfaceHeader.ts +90 -15
  534. package/src/ui/navigation/accountDialogManager.ts +9 -0
  535. package/src/ui/oauth/__tests__/oauthPopup.test.ts +26 -0
  536. package/src/ui/oauth/browserAuthTransport.ts +55 -49
  537. package/src/ui/oauth/oauthPopup.ts +61 -3
  538. package/src/ui/screens/AccountMembersScreen.tsx +1 -1
  539. package/src/ui/screens/AccountSettingsScreen.tsx +45 -17
  540. package/src/ui/screens/AccountVerificationScreen.tsx +1 -1
  541. package/src/ui/screens/AppInfoScreen.tsx +1 -1
  542. package/src/ui/screens/AvatarCropScreen.tsx +1 -1
  543. package/src/ui/screens/ChangeAvatarScreen.tsx +7 -4
  544. package/src/ui/screens/ConnectedAppsScreen.tsx +2 -2
  545. package/src/ui/screens/CreateAccountScreen.tsx +55 -15
  546. package/src/ui/screens/EditProfileFieldScreen.tsx +4 -4
  547. package/src/ui/screens/EditProfileScreen.tsx +6 -3
  548. package/src/ui/screens/FAQScreen.tsx +1 -1
  549. package/src/ui/screens/FeedbackScreen.tsx +741 -575
  550. package/src/ui/screens/FileManagementScreen.tsx +1 -1
  551. package/src/ui/screens/FollowersListScreen.tsx +3 -0
  552. package/src/ui/screens/FollowingListScreen.tsx +3 -0
  553. package/src/ui/screens/HelpSupportScreen.tsx +1 -1
  554. package/src/ui/screens/HistoryViewScreen.tsx +5 -20
  555. package/src/ui/screens/LanguageSelectorScreen.tsx +1 -1
  556. package/src/ui/screens/LegalDocumentsScreen.tsx +1 -1
  557. package/src/ui/screens/ManageAccountScreen.tsx +9 -2
  558. package/src/ui/screens/PremiumSubscriptionScreen.tsx +4 -4
  559. package/src/ui/screens/PrivacySettingsScreen.tsx +15 -12
  560. package/src/ui/screens/ProfileScreen.tsx +24 -6
  561. package/src/ui/screens/SavesCollectionsScreen.tsx +1 -1
  562. package/src/ui/screens/UserListScreen.tsx +18 -8
  563. package/src/ui/screens/WelcomeNewUserScreen.tsx +6 -6
  564. package/src/ui/screens/fileManagement/PhotoPickerSection.tsx +1 -1
  565. package/src/ui/screens/fileManagement/hooks/useFileUploadState.ts +14 -5
  566. package/src/ui/screens/trust/TrustCenterScreen.tsx +2 -2
  567. package/src/ui/screens/trust/TrustLeaderboardScreen.tsx +6 -5
  568. package/src/ui/screens/trust/TrustRewardsScreen.tsx +1 -1
  569. package/src/ui/screens/trust/TrustRulesScreen.tsx +1 -1
  570. package/src/ui/screens/trust/trustTier.ts +1 -1
  571. package/src/ui/session/__tests__/backgroundSession.test.ts +392 -0
  572. package/src/ui/session/backgroundSession.ts +313 -0
  573. package/src/ui/session/index.ts +1 -0
  574. package/src/ui/session/useBackgroundSessionSync.ts +92 -0
  575. package/src/ui/types/navigation.ts +27 -19
  576. package/src/ui/utils/fileManagement.ts +108 -92
  577. package/src/ui/utils/netConnectivity.ts +27 -0
  578. package/src/ui/utils/oauthReturn.ts +23 -33
  579. package/src/ui/utils/userUtils.ts +27 -32
  580. package/lib/commonjs/ui/oauth/legacyRedirectLanes.js +0 -48
  581. package/lib/commonjs/ui/oauth/legacyRedirectLanes.js.map +0 -1
  582. package/lib/commonjs/ui/utils/crossOriginRestore.js +0 -140
  583. package/lib/commonjs/ui/utils/crossOriginRestore.js.map +0 -1
  584. package/lib/module/ui/oauth/legacyRedirectLanes.js +0 -44
  585. package/lib/module/ui/oauth/legacyRedirectLanes.js.map +0 -1
  586. package/lib/module/ui/utils/crossOriginRestore.js +0 -131
  587. package/lib/module/ui/utils/crossOriginRestore.js.map +0 -1
  588. package/lib/typescript/commonjs/ui/oauth/legacyRedirectLanes.d.ts +0 -40
  589. package/lib/typescript/commonjs/ui/oauth/legacyRedirectLanes.d.ts.map +0 -1
  590. package/lib/typescript/commonjs/ui/utils/crossOriginRestore.d.ts +0 -43
  591. package/lib/typescript/commonjs/ui/utils/crossOriginRestore.d.ts.map +0 -1
  592. package/lib/typescript/module/ui/oauth/legacyRedirectLanes.d.ts +0 -40
  593. package/lib/typescript/module/ui/oauth/legacyRedirectLanes.d.ts.map +0 -1
  594. package/lib/typescript/module/ui/utils/crossOriginRestore.d.ts +0 -43
  595. package/lib/typescript/module/ui/utils/crossOriginRestore.d.ts.map +0 -1
  596. package/src/ui/boot/__tests__/coldBootWebAuthMode.test.ts +0 -281
  597. package/src/ui/oauth/legacyRedirectLanes.ts +0 -43
  598. package/src/ui/utils/__tests__/crossOriginRestore.test.ts +0 -143
  599. package/src/ui/utils/crossOriginRestore.ts +0 -169
@@ -1,31 +1,33 @@
1
- import type React from 'react';
2
- import { useState, useRef, useCallback, useMemo } from 'react';
1
+ import Ionicons from "@expo/vector-icons/Ionicons";
2
+ import type MaterialCommunityIcons from "@expo/vector-icons/MaterialCommunityIcons";
3
+ import { Button } from "@oxyhq/bloom/button";
3
4
  import {
4
- View,
5
- Platform,
6
- Animated,
7
- StyleSheet,
8
- } from 'react-native';
9
- import type { BaseScreenProps } from '../types/navigation';
10
- import { normalizeTheme } from '@oxyhq/core';
11
- import { packageInfo } from '@oxyhq/core';
12
- import { useTheme } from '@oxyhq/bloom/theme';
13
- import Ionicons from '@expo/vector-icons/Ionicons';
14
- import type MaterialCommunityIcons from '@expo/vector-icons/MaterialCommunityIcons';
15
- import { toast } from '@oxyhq/bloom';
16
- import { H2, Text } from '@oxyhq/bloom/typography';
17
- import { Button } from '@oxyhq/bloom/button';
18
- import { TextField, TextFieldInput } from '@oxyhq/bloom/text-field';
19
- import { Switch } from '@oxyhq/bloom/switch';
20
- import { SettingsListGroup, SettingsListItem } from '@oxyhq/bloom/settings-list';
21
- import { SettingsIcon } from '../components/SettingsIcon';
22
- import { useI18n } from '../hooks/useI18n';
23
- import { useSurfaceHeader } from '../hooks/useSurfaceHeader';
24
- import { useOxy } from '../context/OxyContext';
25
-
26
- import { useFeedbackForm } from '../components/feedback/useFeedbackForm';
27
- import { FEEDBACK_TYPES, PRIORITY_LEVELS, CATEGORIES } from '../components/feedback/constants';
28
- import type { FeedbackData } from '../components/feedback/types';
5
+ SettingsListGroup,
6
+ SettingsListItem,
7
+ } from "@oxyhq/bloom/settings-list";
8
+ import { Switch } from "@oxyhq/bloom/switch";
9
+ import { TextField, TextFieldInput } from "@oxyhq/bloom/text-field";
10
+ import { useTheme } from "@oxyhq/bloom/theme";
11
+ import { toast } from "@oxyhq/bloom/toast";
12
+ import { H2, Text } from "@oxyhq/bloom/typography";
13
+ import { normalizeTheme } from "@oxyhq/core";
14
+ import { packageInfo } from "@oxyhq/core";
15
+ import type React from "react";
16
+ import { useCallback, useMemo, useRef, useState } from "react";
17
+ import { Animated, Platform, StyleSheet, View } from "react-native";
18
+ import { SettingsIcon } from "../components/SettingsIcon";
19
+ import { useOxy } from "../context/OxyContext";
20
+ import { useI18n } from "../hooks/useI18n";
21
+ import { useSurfaceHeader } from "../hooks/useSurfaceHeader";
22
+ import type { BaseScreenProps } from "../types/navigation";
23
+
24
+ import {
25
+ CATEGORIES,
26
+ FEEDBACK_TYPES,
27
+ PRIORITY_LEVELS,
28
+ } from "../components/feedback/constants";
29
+ import type { FeedbackData } from "../components/feedback/types";
30
+ import { useFeedbackForm } from "../components/feedback/useFeedbackForm";
29
31
 
30
32
  /** Step transition timing — measured animation, not a design token. */
31
33
  const STEP_FADE_OUT_MS = 250;
@@ -37,564 +39,728 @@ const LAST_STEP_INDEX = TOTAL_STEPS - 1;
37
39
  const SUCCESS_RESET_DELAY_MS = 3000;
38
40
 
39
41
  /** Maps each feedback type to a Bloom theme role + MaterialCommunityIcons glyph. */
40
- const TYPE_ICON_GLYPH: Record<FeedbackData['type'], React.ComponentProps<typeof MaterialCommunityIcons>['name']> = {
41
- bug: 'bug',
42
- feature: 'lightbulb-on',
43
- general: 'chat',
44
- support: 'help-circle',
42
+ const TYPE_ICON_GLYPH: Record<
43
+ FeedbackData["type"],
44
+ React.ComponentProps<typeof MaterialCommunityIcons>["name"]
45
+ > = {
46
+ bug: "bug",
47
+ feature: "lightbulb-on",
48
+ general: "chat",
49
+ support: "help-circle",
45
50
  };
46
51
 
47
52
  /** Maps each priority level to a MaterialCommunityIcons glyph. */
48
- const PRIORITY_ICON_GLYPH: Record<FeedbackData['priority'], React.ComponentProps<typeof MaterialCommunityIcons>['name']> = {
49
- low: 'arrow-down',
50
- medium: 'minus',
51
- high: 'arrow-up',
52
- critical: 'alert',
53
+ const PRIORITY_ICON_GLYPH: Record<
54
+ FeedbackData["priority"],
55
+ React.ComponentProps<typeof MaterialCommunityIcons>["name"]
56
+ > = {
57
+ low: "arrow-down",
58
+ medium: "minus",
59
+ high: "arrow-up",
60
+ critical: "alert",
53
61
  };
54
62
 
55
63
  const FeedbackScreen: React.FC<BaseScreenProps> = ({
56
- goBack,
57
- onClose,
58
- theme,
64
+ goBack,
65
+ onClose,
66
+ theme,
59
67
  }) => {
60
- const { user, oxyServices } = useOxy();
61
- const normalizedTheme = normalizeTheme(theme);
62
- const bloomTheme = useTheme();
63
- const colors = bloomTheme.colors;
64
- const { t } = useI18n();
65
-
66
- useSurfaceHeader({ title: t('feedback.title') || 'Feedback' });
67
-
68
- const { feedbackData, feedbackState, setFeedbackState, updateField, resetForm } = useFeedbackForm();
69
-
70
- const [currentStep, setCurrentStep] = useState(0);
71
- const [, setErrorMessage] = useState('');
72
-
73
- const fadeAnim = useRef(new Animated.Value(1)).current;
74
- const slideAnim = useRef(new Animated.Value(0)).current;
75
-
76
- /** Theme-role color for each feedback type pill. */
77
- const typeColor = useCallback((id: FeedbackData['type']): string => {
78
- switch (id) {
79
- case 'bug':
80
- return colors.negative;
81
- case 'feature':
82
- return colors.info;
83
- case 'general':
84
- return colors.success;
85
- case 'support':
86
- return colors.warning;
87
- default:
88
- return colors.primary;
89
- }
90
- }, [colors]);
91
-
92
- /** Theme-role color for each priority level. */
93
- const priorityColor = useCallback((id: FeedbackData['priority']): string => {
94
- switch (id) {
95
- case 'low':
96
- return colors.success;
97
- case 'medium':
98
- return colors.warning;
99
- case 'high':
100
- return colors.negative;
101
- case 'critical':
102
- return colors.negative;
103
- default:
104
- return colors.primary;
105
- }
106
- }, [colors]);
107
-
108
- const animateTransition = useCallback((nextStep: number) => {
109
- Animated.timing(fadeAnim, {
110
- toValue: 0,
111
- duration: STEP_FADE_OUT_MS,
112
- useNativeDriver: Platform.OS !== 'web',
113
- }).start(() => {
114
- setCurrentStep(nextStep);
115
- slideAnim.setValue(STEP_SLIDE_FROM);
116
-
117
- Animated.parallel([
118
- Animated.timing(fadeAnim, {
119
- toValue: 1,
120
- duration: STEP_FADE_IN_MS,
121
- useNativeDriver: Platform.OS !== 'web',
122
- }),
123
- Animated.timing(slideAnim, {
124
- toValue: 0,
125
- duration: STEP_SLIDE_IN_MS,
126
- useNativeDriver: Platform.OS !== 'web',
127
- }),
128
- ]).start();
129
- });
130
- }, [fadeAnim, slideAnim]);
131
-
132
- const nextStep = useCallback(() => {
133
- if (currentStep < LAST_STEP_INDEX) {
134
- animateTransition(currentStep + 1);
135
- }
136
- }, [currentStep, animateTransition]);
137
-
138
- const prevStep = useCallback(() => {
139
- if (currentStep > 0) {
140
- animateTransition(currentStep - 1);
141
- }
142
- }, [currentStep, animateTransition]);
143
-
144
- const isTypeStepValid = useCallback(() => {
145
- return Boolean(feedbackData.type && feedbackData.category);
146
- }, [feedbackData.type, feedbackData.category]);
147
-
148
- const isDetailsStepValid = useCallback(() => {
149
- return Boolean(feedbackData.title.trim() && feedbackData.description.trim());
150
- }, [feedbackData.title, feedbackData.description]);
151
-
152
- const isContactStepValid = useCallback(() => {
153
- return Boolean(feedbackData.contactEmail.trim() || user?.email);
154
- }, [feedbackData.contactEmail, user?.email]);
155
-
156
- const handleSubmitFeedback = useCallback(async () => {
157
- if (!isTypeStepValid() || !isDetailsStepValid() || !isContactStepValid()) {
158
- toast.error(t('feedback.toasts.fillRequired') || 'Please fill in all required fields');
159
- return;
160
- }
161
-
162
- try {
163
- setFeedbackState({ status: 'submitting', message: '' });
164
- setErrorMessage('');
165
-
166
- const feedbackPayload = {
167
- type: feedbackData.type,
168
- title: feedbackData.title,
169
- description: feedbackData.description,
170
- priority: feedbackData.priority,
171
- category: feedbackData.category,
172
- contactEmail: feedbackData.contactEmail || user?.email,
173
- systemInfo: feedbackData.systemInfo ? {
174
- platform: Platform.OS,
175
- version: Platform.Version?.toString() || 'Unknown',
176
- appVersion: packageInfo.version,
177
- userId: user?.id,
178
- username: user?.username,
179
- timestamp: new Date().toISOString(),
180
- } : undefined,
181
- };
182
-
183
- await oxyServices.submitFeedback(feedbackPayload);
184
-
185
- setFeedbackState({ status: 'success', message: t('feedback.toasts.submitSuccess') || 'Feedback submitted successfully!' });
186
- toast.success(t('feedback.toasts.thanks') || 'Thank you for your feedback!');
187
-
188
- setTimeout(() => {
189
- resetForm();
190
- setCurrentStep(0);
191
- }, SUCCESS_RESET_DELAY_MS);
192
-
193
- } catch (error: unknown) {
194
- const message = (error instanceof Error ? error.message : null)
195
- || (t('feedback.toasts.submitFailed') || 'Failed to submit feedback');
196
- setFeedbackState({ status: 'error', message });
197
- toast.error(message);
198
- }
199
- }, [feedbackData, user, oxyServices, isTypeStepValid, isDetailsStepValid, isContactStepValid, resetForm, setFeedbackState, t]);
200
-
201
- const feedbackTypeData = useMemo(() => FEEDBACK_TYPES.map(type => ({
202
- ...type,
203
- isSelected: feedbackData.type === type.id,
204
- })), [feedbackData.type]);
205
-
206
- const categoryData = useMemo(() => (feedbackData.type ? (CATEGORIES[feedbackData.type] || []).map(cat => ({
207
- name: cat,
208
- isSelected: feedbackData.category === cat,
209
- })) : []), [feedbackData.type, feedbackData.category]);
210
-
211
- const priorityData = useMemo(() => PRIORITY_LEVELS.map(p => ({
212
- ...p,
213
- isSelected: feedbackData.priority === p.id,
214
- })), [feedbackData.priority]);
215
-
216
- const renderProgress = () => (
217
- <View
218
- className="flex-row justify-center gap-space-8 pt-space-8 pb-space-16"
219
- accessibilityRole="progressbar"
220
- accessibilityLabel={`Step ${currentStep + 1} of ${TOTAL_STEPS}`}
221
- >
222
- {Array.from({ length: TOTAL_STEPS }, (_, index) => (
223
- <View
224
- key={index}
225
- className={
226
- currentStep === index
227
- ? 'h-space-8 rounded-radius-max bg-fill-brand'
228
- : 'h-space-8 rounded-radius-max bg-fill-secondary'
229
- }
230
- style={currentStep === index ? styles.progressDotActive : styles.progressDot}
231
- />
232
- ))}
233
- </View>
234
- );
235
-
236
- const renderStepHeader = (title: string, subtitle: string) => (
237
- <View className="w-full gap-space-8 mb-space-24">
238
- <H2 className="text-headerBold font-headerBold text-text">{title}</H2>
239
- <Text className="text-body font-body text-text-secondary">{subtitle}</Text>
240
- </View>
241
- );
242
-
243
- const renderTypeStep = () => (
244
- <Animated.View style={[styles.stepContainer, { opacity: fadeAnim, transform: [{ translateX: slideAnim }] }]}>
245
- {renderStepHeader(
246
- t('feedback.type.title') || 'What type of feedback?',
247
- t('feedback.type.subtitle') || 'Choose the category that best describes your feedback',
248
- )}
249
-
250
- <View className="w-full">
251
- <SettingsListGroup>
252
- {feedbackTypeData.map(type => (
253
- <SettingsListItem
254
- key={type.id}
255
- icon={<SettingsIcon name={TYPE_ICON_GLYPH[type.id]} color={typeColor(type.id)} />}
256
- title={type.label}
257
- description={type.description}
258
- onPress={() => { updateField('type', type.id); updateField('category', ''); }}
259
- showChevron={false}
260
- />
261
- ))}
262
- </SettingsListGroup>
263
- </View>
264
-
265
- {feedbackData.type ? (
266
- <View className="w-full mt-space-24">
267
- <Text className="text-caption font-caption text-text-secondary mb-space-8">
268
- {t('feedback.category.label') || 'Category'}
269
- </Text>
270
- <View className="w-full">
271
- <SettingsListGroup>
272
- {categoryData.map(cat => (
273
- <SettingsListItem
274
- key={cat.name}
275
- icon={(
276
- <SettingsIcon
277
- name={cat.isSelected ? 'check-circle' : 'circle-outline'}
278
- color={cat.isSelected ? colors.primary : colors.textSecondary}
279
- />
280
- )}
281
- title={cat.name}
282
- onPress={() => updateField('category', cat.name)}
283
- showChevron={false}
284
- />
285
- ))}
286
- </SettingsListGroup>
287
- </View>
288
- </View>
289
- ) : null}
290
-
291
- <View className="flex-row gap-space-8 mt-space-24 w-full">
292
- <Button
293
- variant="secondary"
294
- onPress={goBack}
295
- accessibilityLabel="Go back"
296
- icon={<Ionicons name="arrow-back" size={16} color={colors.text} />}
297
- style={styles.navButton}
298
- >
299
- {t('common.actions.back') || 'Back'}
300
- </Button>
301
-
302
- <Button
303
- variant="primary"
304
- onPress={nextStep}
305
- disabled={!isTypeStepValid()}
306
- accessibilityLabel="Continue to next step"
307
- iconPosition="right"
308
- icon={<Ionicons name="arrow-forward" size={16} color={colors.primaryForeground} />}
309
- style={styles.navButton}
310
- >
311
- {t('common.actions.next') || 'Next'}
312
- </Button>
313
- </View>
314
- </Animated.View>
315
- );
316
-
317
- const renderDetailsStep = () => (
318
- <Animated.View style={[styles.stepContainer, { opacity: fadeAnim, transform: [{ translateX: slideAnim }] }]}>
319
- {renderStepHeader(
320
- t('feedback.details.title') || 'Tell us more',
321
- t('feedback.details.subtitle') || 'Provide details about your feedback',
322
- )}
323
-
324
- <View className="w-full gap-space-16">
325
- <TextField>
326
- <TextFieldInput
327
- floatingLabel
328
- label={t('feedback.fields.title.label') || 'Title'}
329
- value={feedbackData.title}
330
- onChangeText={(text) => { updateField('title', text); setErrorMessage(''); }}
331
- placeholder={t('feedback.fields.title.placeholder') || 'Brief summary of your feedback'}
332
- testID="feedback-title-input"
333
- accessibilityLabel="Feedback title"
334
- accessibilityHint="Enter a brief summary of your feedback"
335
- />
336
- </TextField>
337
-
338
- <TextField>
339
- <TextFieldInput
340
- floatingLabel
341
- multiline
342
- numberOfLines={6}
343
- label={t('feedback.fields.description.label') || 'Description'}
344
- value={feedbackData.description}
345
- onChangeText={(text) => { updateField('description', text); setErrorMessage(''); }}
346
- placeholder={t('feedback.fields.description.placeholder') || 'Please provide detailed information...'}
347
- testID="feedback-description-input"
348
- accessibilityLabel="Feedback description"
349
- accessibilityHint="Provide detailed information about your feedback"
350
- />
351
- </TextField>
352
- </View>
353
-
354
- <View className="w-full mt-space-24">
355
- <Text className="text-caption font-caption text-text-secondary mb-space-8">
356
- {t('feedback.priority.label') || 'Priority Level'}
357
- </Text>
358
- <View className="w-full">
359
- <SettingsListGroup>
360
- {priorityData.map(p => (
361
- <SettingsListItem
362
- key={p.id}
363
- icon={<SettingsIcon name={PRIORITY_ICON_GLYPH[p.id]} color={priorityColor(p.id)} />}
364
- title={p.label}
365
- onPress={() => updateField('priority', p.id)}
366
- showChevron={false}
367
- />
368
- ))}
369
- </SettingsListGroup>
370
- </View>
371
- </View>
372
-
373
- <View className="flex-row gap-space-8 mt-space-24 w-full">
374
- <Button
375
- variant="secondary"
376
- onPress={prevStep}
377
- accessibilityLabel="Go back"
378
- icon={<Ionicons name="arrow-back" size={16} color={colors.text} />}
379
- style={styles.navButton}
380
- >
381
- {t('common.actions.back') || 'Back'}
382
- </Button>
383
-
384
- <Button
385
- variant="primary"
386
- onPress={nextStep}
387
- disabled={!isDetailsStepValid()}
388
- accessibilityLabel="Continue to next step"
389
- iconPosition="right"
390
- icon={<Ionicons name="arrow-forward" size={16} color={colors.primaryForeground} />}
391
- style={styles.navButton}
392
- >
393
- {t('common.actions.next') || 'Next'}
394
- </Button>
395
- </View>
396
- </Animated.View>
397
- );
398
-
399
- const renderContactStep = () => (
400
- <Animated.View style={[styles.stepContainer, { opacity: fadeAnim, transform: [{ translateX: slideAnim }] }]}>
401
- {renderStepHeader(
402
- t('feedback.contact.title') || 'Contact Information',
403
- t('feedback.contact.subtitle') || 'Help us get back to you',
404
- )}
405
-
406
- <View className="w-full">
407
- <TextField>
408
- <TextFieldInput
409
- floatingLabel
410
- label={t('feedback.fields.email.label') || 'Email Address'}
411
- value={feedbackData.contactEmail}
412
- onChangeText={(text) => { updateField('contactEmail', text); setErrorMessage(''); }}
413
- placeholder={user?.email || (t('feedback.fields.email.placeholder') || 'Enter your email address')}
414
- keyboardType="email-address"
415
- autoCapitalize="none"
416
- autoCorrect={false}
417
- testID="feedback-email-input"
418
- accessibilityLabel="Email address"
419
- accessibilityHint="Enter your email so we can respond"
420
- />
421
- </TextField>
422
- </View>
423
-
424
- <View className="w-full mt-space-16">
425
- <SettingsListGroup>
426
- <SettingsListItem
427
- icon={<SettingsIcon name="information" color={colors.info} />}
428
- title={t('feedback.contact.includeSystemInfo') || 'Include system information to help us better understand your issue'}
429
- rightElement={(
430
- <Switch
431
- value={feedbackData.systemInfo}
432
- onValueChange={(value) => updateField('systemInfo', value)}
433
- testID="feedback-system-info-switch"
434
- />
435
- )}
436
- showChevron={false}
437
- />
438
- </SettingsListGroup>
439
- </View>
440
-
441
- <View className="flex-row gap-space-8 mt-space-24 w-full">
442
- <Button
443
- variant="secondary"
444
- onPress={prevStep}
445
- accessibilityLabel="Go back"
446
- icon={<Ionicons name="arrow-back" size={16} color={colors.text} />}
447
- style={styles.navButton}
448
- >
449
- {t('common.actions.back') || 'Back'}
450
- </Button>
451
-
452
- <Button
453
- variant="primary"
454
- onPress={nextStep}
455
- disabled={!isContactStepValid()}
456
- accessibilityLabel="Continue to summary"
457
- iconPosition="right"
458
- icon={<Ionicons name="arrow-forward" size={16} color={colors.primaryForeground} />}
459
- style={styles.navButton}
460
- >
461
- {t('common.actions.next') || 'Next'}
462
- </Button>
463
- </View>
464
- </Animated.View>
465
- );
466
-
467
- const renderSummaryRow = (label: string, value: string | undefined) => (
468
- <View className="flex-row gap-space-12">
469
- <Text className="text-body font-body text-text-secondary" style={styles.summaryLabel}>{label}</Text>
470
- <Text className="text-body font-body text-text flex-1">{value}</Text>
471
- </View>
472
- );
473
-
474
- const renderSummaryStep = () => (
475
- <Animated.View style={[styles.stepContainer, { opacity: fadeAnim, transform: [{ translateX: slideAnim }] }]}>
476
- {renderStepHeader(
477
- t('feedback.summary.title') || 'Summary',
478
- t('feedback.summary.subtitle') || 'Please review your feedback before submitting',
479
- )}
480
-
481
- <View className="w-full gap-space-12 p-space-16 rounded-radius-20 bg-fill mb-space-24">
482
- {renderSummaryRow(
483
- t('feedback.summary.type') || 'Type:',
484
- FEEDBACK_TYPES.find(ft => ft.id === feedbackData.type)?.label,
485
- )}
486
- {renderSummaryRow(
487
- t('feedback.summary.category') || 'Category:',
488
- feedbackData.category,
489
- )}
490
- {renderSummaryRow(
491
- t('feedback.summary.priority') || 'Priority:',
492
- PRIORITY_LEVELS.find(p => p.id === feedbackData.priority)?.label,
493
- )}
494
- {renderSummaryRow(
495
- t('feedback.summary.titleField') || 'Title:',
496
- feedbackData.title,
497
- )}
498
- {renderSummaryRow(
499
- t('feedback.summary.contact') || 'Contact:',
500
- feedbackData.contactEmail || user?.email,
501
- )}
502
- </View>
503
-
504
- <Button
505
- variant="primary"
506
- onPress={handleSubmitFeedback}
507
- disabled={feedbackState.status === 'submitting'}
508
- loading={feedbackState.status === 'submitting'}
509
- testID="submit-feedback-button"
510
- accessibilityLabel="Submit feedback"
511
- iconPosition="right"
512
- icon={<Ionicons name="send" size={18} color={colors.primaryForeground} />}
513
- style={styles.fullWidthButton}
514
- >
515
- {t('feedback.actions.submit') || 'Submit Feedback'}
516
- </Button>
517
-
518
- <View className="flex-row mt-space-16 w-full">
519
- <Button
520
- variant="secondary"
521
- onPress={prevStep}
522
- accessibilityLabel="Go back"
523
- icon={<Ionicons name="arrow-back" size={16} color={colors.text} />}
524
- style={styles.navButton}
525
- >
526
- {t('common.actions.back') || 'Back'}
527
- </Button>
528
- </View>
529
- </Animated.View>
530
- );
531
-
532
- const renderSuccessStep = () => (
533
- <Animated.View style={[styles.stepContainer, { opacity: fadeAnim, transform: [{ translateX: slideAnim }] }]}>
534
- <View className="w-full items-center justify-center p-space-32 gap-space-16">
535
- <View className="p-space-24 rounded-radius-max bg-fill-secondary">
536
- <Ionicons name="checkmark-circle" size={48} color={colors.success} />
537
- </View>
538
- <H2 className="text-headerBold font-headerBold text-text text-center">
539
- {t('feedback.success.thanks') || 'Thank You!'}
540
- </H2>
541
- <Text className="text-body font-body text-text-secondary text-center">
542
- {t('feedback.success.message') || "Your feedback has been submitted successfully. We'll review it and get back to you soon."}
543
- </Text>
544
- <Button
545
- variant="primary"
546
- onPress={() => { resetForm(); setCurrentStep(0); }}
547
- accessibilityLabel="Submit another feedback"
548
- style={styles.fullWidthButton}
549
- >
550
- {t('feedback.actions.submitAnother') || 'Submit Another'}
551
- </Button>
552
- </View>
553
- </Animated.View>
554
- );
555
-
556
- const renderCurrentStep = () => {
557
- if (feedbackState.status === 'success') return renderSuccessStep();
558
- switch (currentStep) {
559
- case 0: return renderTypeStep();
560
- case 1: return renderDetailsStep();
561
- case 2: return renderContactStep();
562
- case 3: return renderSummaryStep();
563
- default: return renderTypeStep();
564
- }
565
- };
566
-
567
- return (
568
- <>
569
-
570
- <View className="px-screen-margin pt-space-24 pb-space-32">
571
- {feedbackState.status !== 'success' ? renderProgress() : null}
572
- {renderCurrentStep()}
573
- </View>
574
- </>
575
- );
68
+ const { user, oxyServices } = useOxy();
69
+ const normalizedTheme = normalizeTheme(theme);
70
+ const bloomTheme = useTheme();
71
+ const colors = bloomTheme.colors;
72
+ const { t } = useI18n();
73
+
74
+ useSurfaceHeader({ title: t("feedback.title") || "Feedback" });
75
+
76
+ const {
77
+ feedbackData,
78
+ feedbackState,
79
+ setFeedbackState,
80
+ updateField,
81
+ resetForm,
82
+ } = useFeedbackForm();
83
+
84
+ const [currentStep, setCurrentStep] = useState(0);
85
+ const [, setErrorMessage] = useState("");
86
+
87
+ const fadeAnim = useRef(new Animated.Value(1)).current;
88
+ const slideAnim = useRef(new Animated.Value(0)).current;
89
+
90
+ /** Theme-role color for each feedback type pill. */
91
+ const typeColor = useCallback(
92
+ (id: FeedbackData["type"]): string => {
93
+ switch (id) {
94
+ case "bug":
95
+ return colors.negative;
96
+ case "feature":
97
+ return colors.info;
98
+ case "general":
99
+ return colors.success;
100
+ case "support":
101
+ return colors.warning;
102
+ default:
103
+ return colors.primary;
104
+ }
105
+ },
106
+ [colors],
107
+ );
108
+
109
+ /** Theme-role color for each priority level. */
110
+ const priorityColor = useCallback(
111
+ (id: FeedbackData["priority"]): string => {
112
+ switch (id) {
113
+ case "low":
114
+ return colors.success;
115
+ case "medium":
116
+ return colors.warning;
117
+ case "high":
118
+ return colors.negative;
119
+ case "critical":
120
+ return colors.negative;
121
+ default:
122
+ return colors.primary;
123
+ }
124
+ },
125
+ [colors],
126
+ );
127
+
128
+ const animateTransition = useCallback(
129
+ (nextStep: number) => {
130
+ Animated.timing(fadeAnim, {
131
+ toValue: 0,
132
+ duration: STEP_FADE_OUT_MS,
133
+ useNativeDriver: Platform.OS !== "web",
134
+ }).start(() => {
135
+ setCurrentStep(nextStep);
136
+ slideAnim.setValue(STEP_SLIDE_FROM);
137
+
138
+ Animated.parallel([
139
+ Animated.timing(fadeAnim, {
140
+ toValue: 1,
141
+ duration: STEP_FADE_IN_MS,
142
+ useNativeDriver: Platform.OS !== "web",
143
+ }),
144
+ Animated.timing(slideAnim, {
145
+ toValue: 0,
146
+ duration: STEP_SLIDE_IN_MS,
147
+ useNativeDriver: Platform.OS !== "web",
148
+ }),
149
+ ]).start();
150
+ });
151
+ },
152
+ [fadeAnim, slideAnim],
153
+ );
154
+
155
+ const nextStep = useCallback(() => {
156
+ if (currentStep < LAST_STEP_INDEX) {
157
+ animateTransition(currentStep + 1);
158
+ }
159
+ }, [currentStep, animateTransition]);
160
+
161
+ const prevStep = useCallback(() => {
162
+ if (currentStep > 0) {
163
+ animateTransition(currentStep - 1);
164
+ }
165
+ }, [currentStep, animateTransition]);
166
+
167
+ const isTypeStepValid = useCallback(() => {
168
+ return Boolean(feedbackData.type && feedbackData.category);
169
+ }, [feedbackData.type, feedbackData.category]);
170
+
171
+ const isDetailsStepValid = useCallback(() => {
172
+ return Boolean(
173
+ feedbackData.title.trim() && feedbackData.description.trim(),
174
+ );
175
+ }, [feedbackData.title, feedbackData.description]);
176
+
177
+ const isContactStepValid = useCallback(() => {
178
+ return Boolean(feedbackData.contactEmail.trim() || user?.email);
179
+ }, [feedbackData.contactEmail, user?.email]);
180
+
181
+ const handleSubmitFeedback = useCallback(async () => {
182
+ if (!isTypeStepValid() || !isDetailsStepValid() || !isContactStepValid()) {
183
+ toast.error(
184
+ t("feedback.toasts.fillRequired") ||
185
+ "Please fill in all required fields",
186
+ );
187
+ return;
188
+ }
189
+
190
+ try {
191
+ setFeedbackState({ status: "submitting", message: "" });
192
+ setErrorMessage("");
193
+
194
+ const feedbackPayload = {
195
+ type: feedbackData.type,
196
+ title: feedbackData.title,
197
+ description: feedbackData.description,
198
+ priority: feedbackData.priority,
199
+ category: feedbackData.category,
200
+ contactEmail: feedbackData.contactEmail || user?.email,
201
+ systemInfo: feedbackData.systemInfo
202
+ ? {
203
+ platform: Platform.OS,
204
+ version: Platform.Version?.toString() || "Unknown",
205
+ appVersion: packageInfo.version,
206
+ userId: user?.id,
207
+ username: user?.username,
208
+ timestamp: new Date().toISOString(),
209
+ }
210
+ : undefined,
211
+ };
212
+
213
+ await oxyServices.submitFeedback(feedbackPayload);
214
+
215
+ setFeedbackState({
216
+ status: "success",
217
+ message:
218
+ t("feedback.toasts.submitSuccess") ||
219
+ "Feedback submitted successfully!",
220
+ });
221
+ toast.success(
222
+ t("feedback.toasts.thanks") || "Thank you for your feedback!",
223
+ );
224
+
225
+ setTimeout(() => {
226
+ resetForm();
227
+ setCurrentStep(0);
228
+ }, SUCCESS_RESET_DELAY_MS);
229
+ } catch (error: unknown) {
230
+ const message =
231
+ (error instanceof Error ? error.message : null) ||
232
+ t("feedback.toasts.submitFailed") ||
233
+ "Failed to submit feedback";
234
+ setFeedbackState({ status: "error", message });
235
+ toast.error(message);
236
+ }
237
+ }, [
238
+ feedbackData,
239
+ user,
240
+ oxyServices,
241
+ isTypeStepValid,
242
+ isDetailsStepValid,
243
+ isContactStepValid,
244
+ resetForm,
245
+ setFeedbackState,
246
+ t,
247
+ ]);
248
+
249
+ const feedbackTypeData = useMemo(
250
+ () =>
251
+ FEEDBACK_TYPES.map((type) => ({
252
+ ...type,
253
+ isSelected: feedbackData.type === type.id,
254
+ })),
255
+ [feedbackData.type],
256
+ );
257
+
258
+ const categoryData = useMemo(
259
+ () =>
260
+ feedbackData.type
261
+ ? (CATEGORIES[feedbackData.type] || []).map((cat) => ({
262
+ name: cat,
263
+ isSelected: feedbackData.category === cat,
264
+ }))
265
+ : [],
266
+ [feedbackData.type, feedbackData.category],
267
+ );
268
+
269
+ const priorityData = useMemo(
270
+ () =>
271
+ PRIORITY_LEVELS.map((p) => ({
272
+ ...p,
273
+ isSelected: feedbackData.priority === p.id,
274
+ })),
275
+ [feedbackData.priority],
276
+ );
277
+
278
+ const renderProgress = () => (
279
+ <View
280
+ className="flex-row justify-center gap-space-8 pt-space-8 pb-space-16"
281
+ accessibilityRole="progressbar"
282
+ accessibilityLabel={`Step ${currentStep + 1} of ${TOTAL_STEPS}`}
283
+ >
284
+ {Array.from({ length: TOTAL_STEPS }, (_, index) => (
285
+ <View
286
+ // biome-ignore lint/suspicious/noArrayIndexKey: fixed step indicators, order never changes
287
+ key={index}
288
+ className={
289
+ currentStep === index
290
+ ? "h-space-8 rounded-radius-max bg-fill-brand"
291
+ : "h-space-8 rounded-radius-max bg-fill-secondary"
292
+ }
293
+ style={
294
+ currentStep === index
295
+ ? styles.progressDotActive
296
+ : styles.progressDot
297
+ }
298
+ />
299
+ ))}
300
+ </View>
301
+ );
302
+
303
+ const renderStepHeader = (title: string, subtitle: string) => (
304
+ <View className="w-full gap-space-8 mb-space-24">
305
+ <H2 className="text-headerBold font-headerBold text-text">{title}</H2>
306
+ <Text className="text-body font-body text-text-secondary">
307
+ {subtitle}
308
+ </Text>
309
+ </View>
310
+ );
311
+
312
+ const renderTypeStep = () => (
313
+ <Animated.View
314
+ style={[
315
+ styles.stepContainer,
316
+ { opacity: fadeAnim, transform: [{ translateX: slideAnim }] },
317
+ ]}
318
+ >
319
+ {renderStepHeader(
320
+ t("feedback.type.title") || "What type of feedback?",
321
+ t("feedback.type.subtitle") ||
322
+ "Choose the category that best describes your feedback",
323
+ )}
324
+
325
+ <View className="w-full">
326
+ <SettingsListGroup>
327
+ {feedbackTypeData.map((type) => (
328
+ <SettingsListItem
329
+ key={type.id}
330
+ icon={
331
+ <SettingsIcon
332
+ name={TYPE_ICON_GLYPH[type.id]}
333
+ color={typeColor(type.id)}
334
+ />
335
+ }
336
+ title={type.label}
337
+ description={type.description}
338
+ onPress={() => {
339
+ updateField("type", type.id);
340
+ updateField("category", "");
341
+ }}
342
+ showChevron={false}
343
+ />
344
+ ))}
345
+ </SettingsListGroup>
346
+ </View>
347
+
348
+ {feedbackData.type ? (
349
+ <View className="w-full mt-space-24">
350
+ <Text className="text-caption font-caption text-text-secondary mb-space-8">
351
+ {t("feedback.category.label") || "Category"}
352
+ </Text>
353
+ <View className="w-full">
354
+ <SettingsListGroup>
355
+ {categoryData.map((cat) => (
356
+ <SettingsListItem
357
+ key={cat.name}
358
+ icon={
359
+ <SettingsIcon
360
+ name={cat.isSelected ? "check-circle" : "circle-outline"}
361
+ color={
362
+ cat.isSelected ? colors.primary : colors.textSecondary
363
+ }
364
+ />
365
+ }
366
+ title={cat.name}
367
+ onPress={() => updateField("category", cat.name)}
368
+ showChevron={false}
369
+ />
370
+ ))}
371
+ </SettingsListGroup>
372
+ </View>
373
+ </View>
374
+ ) : null}
375
+
376
+ <View className="flex-row gap-space-8 mt-space-24 w-full">
377
+ <Button
378
+ variant="secondary"
379
+ onPress={goBack}
380
+ accessibilityLabel="Go back"
381
+ icon={<Ionicons name="arrow-back" size={16} color={colors.text} />}
382
+ style={styles.navButton}
383
+ >
384
+ {t("common.actions.back") || "Back"}
385
+ </Button>
386
+
387
+ <Button
388
+ variant="primary"
389
+ onPress={nextStep}
390
+ disabled={!isTypeStepValid()}
391
+ accessibilityLabel="Continue to next step"
392
+ iconPosition="right"
393
+ icon={
394
+ <Ionicons
395
+ name="arrow-forward"
396
+ size={16}
397
+ color={colors.primaryForeground}
398
+ />
399
+ }
400
+ style={styles.navButton}
401
+ >
402
+ {t("common.actions.next") || "Next"}
403
+ </Button>
404
+ </View>
405
+ </Animated.View>
406
+ );
407
+
408
+ const renderDetailsStep = () => (
409
+ <Animated.View
410
+ style={[
411
+ styles.stepContainer,
412
+ { opacity: fadeAnim, transform: [{ translateX: slideAnim }] },
413
+ ]}
414
+ >
415
+ {renderStepHeader(
416
+ t("feedback.details.title") || "Tell us more",
417
+ t("feedback.details.subtitle") || "Provide details about your feedback",
418
+ )}
419
+
420
+ <View className="w-full gap-space-16">
421
+ <TextField>
422
+ <TextFieldInput
423
+ floatingLabel
424
+ label={t("feedback.fields.title.label") || "Title"}
425
+ value={feedbackData.title}
426
+ onChangeText={(text) => {
427
+ updateField("title", text);
428
+ setErrorMessage("");
429
+ }}
430
+ placeholder={
431
+ t("feedback.fields.title.placeholder") ||
432
+ "Brief summary of your feedback"
433
+ }
434
+ testID="feedback-title-input"
435
+ accessibilityLabel="Feedback title"
436
+ accessibilityHint="Enter a brief summary of your feedback"
437
+ />
438
+ </TextField>
439
+
440
+ <TextField>
441
+ <TextFieldInput
442
+ floatingLabel
443
+ multiline
444
+ numberOfLines={6}
445
+ label={t("feedback.fields.description.label") || "Description"}
446
+ value={feedbackData.description}
447
+ onChangeText={(text) => {
448
+ updateField("description", text);
449
+ setErrorMessage("");
450
+ }}
451
+ placeholder={
452
+ t("feedback.fields.description.placeholder") ||
453
+ "Please provide detailed information..."
454
+ }
455
+ testID="feedback-description-input"
456
+ accessibilityLabel="Feedback description"
457
+ accessibilityHint="Provide detailed information about your feedback"
458
+ />
459
+ </TextField>
460
+ </View>
461
+
462
+ <View className="w-full mt-space-24">
463
+ <Text className="text-caption font-caption text-text-secondary mb-space-8">
464
+ {t("feedback.priority.label") || "Priority Level"}
465
+ </Text>
466
+ <View className="w-full">
467
+ <SettingsListGroup>
468
+ {priorityData.map((p) => (
469
+ <SettingsListItem
470
+ key={p.id}
471
+ icon={
472
+ <SettingsIcon
473
+ name={PRIORITY_ICON_GLYPH[p.id]}
474
+ color={priorityColor(p.id)}
475
+ />
476
+ }
477
+ title={p.label}
478
+ onPress={() => updateField("priority", p.id)}
479
+ showChevron={false}
480
+ />
481
+ ))}
482
+ </SettingsListGroup>
483
+ </View>
484
+ </View>
485
+
486
+ <View className="flex-row gap-space-8 mt-space-24 w-full">
487
+ <Button
488
+ variant="secondary"
489
+ onPress={prevStep}
490
+ accessibilityLabel="Go back"
491
+ icon={<Ionicons name="arrow-back" size={16} color={colors.text} />}
492
+ style={styles.navButton}
493
+ >
494
+ {t("common.actions.back") || "Back"}
495
+ </Button>
496
+
497
+ <Button
498
+ variant="primary"
499
+ onPress={nextStep}
500
+ disabled={!isDetailsStepValid()}
501
+ accessibilityLabel="Continue to next step"
502
+ iconPosition="right"
503
+ icon={
504
+ <Ionicons
505
+ name="arrow-forward"
506
+ size={16}
507
+ color={colors.primaryForeground}
508
+ />
509
+ }
510
+ style={styles.navButton}
511
+ >
512
+ {t("common.actions.next") || "Next"}
513
+ </Button>
514
+ </View>
515
+ </Animated.View>
516
+ );
517
+
518
+ const renderContactStep = () => (
519
+ <Animated.View
520
+ style={[
521
+ styles.stepContainer,
522
+ { opacity: fadeAnim, transform: [{ translateX: slideAnim }] },
523
+ ]}
524
+ >
525
+ {renderStepHeader(
526
+ t("feedback.contact.title") || "Contact Information",
527
+ t("feedback.contact.subtitle") || "Help us get back to you",
528
+ )}
529
+
530
+ <View className="w-full">
531
+ <TextField>
532
+ <TextFieldInput
533
+ floatingLabel
534
+ label={t("feedback.fields.email.label") || "Email Address"}
535
+ value={feedbackData.contactEmail}
536
+ onChangeText={(text) => {
537
+ updateField("contactEmail", text);
538
+ setErrorMessage("");
539
+ }}
540
+ placeholder={
541
+ user?.email ||
542
+ t("feedback.fields.email.placeholder") ||
543
+ "Enter your email address"
544
+ }
545
+ keyboardType="email-address"
546
+ autoCapitalize="none"
547
+ autoCorrect={false}
548
+ testID="feedback-email-input"
549
+ accessibilityLabel="Email address"
550
+ accessibilityHint="Enter your email so we can respond"
551
+ />
552
+ </TextField>
553
+ </View>
554
+
555
+ <View className="w-full mt-space-16">
556
+ <SettingsListGroup>
557
+ <SettingsListItem
558
+ icon={<SettingsIcon name="information" color={colors.info} />}
559
+ title={
560
+ t("feedback.contact.includeSystemInfo") ||
561
+ "Include system information to help us better understand your issue"
562
+ }
563
+ rightElement={
564
+ <Switch
565
+ value={feedbackData.systemInfo}
566
+ onValueChange={(value) => updateField("systemInfo", value)}
567
+ testID="feedback-system-info-switch"
568
+ />
569
+ }
570
+ showChevron={false}
571
+ />
572
+ </SettingsListGroup>
573
+ </View>
574
+
575
+ <View className="flex-row gap-space-8 mt-space-24 w-full">
576
+ <Button
577
+ variant="secondary"
578
+ onPress={prevStep}
579
+ accessibilityLabel="Go back"
580
+ icon={<Ionicons name="arrow-back" size={16} color={colors.text} />}
581
+ style={styles.navButton}
582
+ >
583
+ {t("common.actions.back") || "Back"}
584
+ </Button>
585
+
586
+ <Button
587
+ variant="primary"
588
+ onPress={nextStep}
589
+ disabled={!isContactStepValid()}
590
+ accessibilityLabel="Continue to summary"
591
+ iconPosition="right"
592
+ icon={
593
+ <Ionicons
594
+ name="arrow-forward"
595
+ size={16}
596
+ color={colors.primaryForeground}
597
+ />
598
+ }
599
+ style={styles.navButton}
600
+ >
601
+ {t("common.actions.next") || "Next"}
602
+ </Button>
603
+ </View>
604
+ </Animated.View>
605
+ );
606
+
607
+ const renderSummaryRow = (label: string, value: string | undefined) => (
608
+ <View className="flex-row gap-space-12">
609
+ <Text
610
+ className="text-body font-body text-text-secondary"
611
+ style={styles.summaryLabel}
612
+ >
613
+ {label}
614
+ </Text>
615
+ <Text className="text-body font-body text-text flex-1">{value}</Text>
616
+ </View>
617
+ );
618
+
619
+ const renderSummaryStep = () => (
620
+ <Animated.View
621
+ style={[
622
+ styles.stepContainer,
623
+ { opacity: fadeAnim, transform: [{ translateX: slideAnim }] },
624
+ ]}
625
+ >
626
+ {renderStepHeader(
627
+ t("feedback.summary.title") || "Summary",
628
+ t("feedback.summary.subtitle") ||
629
+ "Please review your feedback before submitting",
630
+ )}
631
+
632
+ <View className="w-full gap-space-12 p-space-16 rounded-radius-20 bg-fill mb-space-24">
633
+ {renderSummaryRow(
634
+ t("feedback.summary.type") || "Type:",
635
+ FEEDBACK_TYPES.find((ft) => ft.id === feedbackData.type)?.label,
636
+ )}
637
+ {renderSummaryRow(
638
+ t("feedback.summary.category") || "Category:",
639
+ feedbackData.category,
640
+ )}
641
+ {renderSummaryRow(
642
+ t("feedback.summary.priority") || "Priority:",
643
+ PRIORITY_LEVELS.find((p) => p.id === feedbackData.priority)?.label,
644
+ )}
645
+ {renderSummaryRow(
646
+ t("feedback.summary.titleField") || "Title:",
647
+ feedbackData.title,
648
+ )}
649
+ {renderSummaryRow(
650
+ t("feedback.summary.contact") || "Contact:",
651
+ feedbackData.contactEmail || user?.email,
652
+ )}
653
+ </View>
654
+
655
+ <Button
656
+ variant="primary"
657
+ onPress={handleSubmitFeedback}
658
+ disabled={feedbackState.status === "submitting"}
659
+ loading={feedbackState.status === "submitting"}
660
+ testID="submit-feedback-button"
661
+ accessibilityLabel="Submit feedback"
662
+ iconPosition="right"
663
+ icon={
664
+ <Ionicons name="send" size={18} color={colors.primaryForeground} />
665
+ }
666
+ style={styles.fullWidthButton}
667
+ >
668
+ {t("feedback.actions.submit") || "Submit Feedback"}
669
+ </Button>
670
+
671
+ <View className="flex-row mt-space-16 w-full">
672
+ <Button
673
+ variant="secondary"
674
+ onPress={prevStep}
675
+ accessibilityLabel="Go back"
676
+ icon={<Ionicons name="arrow-back" size={16} color={colors.text} />}
677
+ style={styles.navButton}
678
+ >
679
+ {t("common.actions.back") || "Back"}
680
+ </Button>
681
+ </View>
682
+ </Animated.View>
683
+ );
684
+
685
+ const renderSuccessStep = () => (
686
+ <Animated.View
687
+ style={[
688
+ styles.stepContainer,
689
+ { opacity: fadeAnim, transform: [{ translateX: slideAnim }] },
690
+ ]}
691
+ >
692
+ <View className="w-full items-center justify-center p-space-32 gap-space-16">
693
+ <View className="p-space-24 rounded-radius-max bg-fill-secondary">
694
+ <Ionicons name="checkmark-circle" size={48} color={colors.success} />
695
+ </View>
696
+ <H2 className="text-headerBold font-headerBold text-text text-center">
697
+ {t("feedback.success.thanks") || "Thank You!"}
698
+ </H2>
699
+ <Text className="text-body font-body text-text-secondary text-center">
700
+ {t("feedback.success.message") ||
701
+ "Your feedback has been submitted successfully. We'll review it and get back to you soon."}
702
+ </Text>
703
+ <Button
704
+ variant="primary"
705
+ onPress={() => {
706
+ resetForm();
707
+ setCurrentStep(0);
708
+ }}
709
+ accessibilityLabel="Submit another feedback"
710
+ style={styles.fullWidthButton}
711
+ >
712
+ {t("feedback.actions.submitAnother") || "Submit Another"}
713
+ </Button>
714
+ </View>
715
+ </Animated.View>
716
+ );
717
+
718
+ const renderCurrentStep = () => {
719
+ if (feedbackState.status === "success") return renderSuccessStep();
720
+ switch (currentStep) {
721
+ case 0:
722
+ return renderTypeStep();
723
+ case 1:
724
+ return renderDetailsStep();
725
+ case 2:
726
+ return renderContactStep();
727
+ case 3:
728
+ return renderSummaryStep();
729
+ default:
730
+ return renderTypeStep();
731
+ }
732
+ };
733
+
734
+ return (
735
+ <>
736
+ <View className="px-screen-margin pt-space-24 pb-space-32">
737
+ {feedbackState.status !== "success" ? renderProgress() : null}
738
+ {renderCurrentStep()}
739
+ </View>
740
+ </>
741
+ );
576
742
  };
577
743
 
578
744
  const styles = StyleSheet.create({
579
- stepContainer: {
580
- flex: 1,
581
- alignItems: 'flex-start',
582
- },
583
- navButton: {
584
- flex: 1,
585
- },
586
- fullWidthButton: {
587
- width: '100%',
588
- },
589
- summaryLabel: {
590
- width: 90,
591
- },
592
- progressDot: {
593
- width: 8,
594
- },
595
- progressDotActive: {
596
- width: 24,
597
- },
745
+ stepContainer: {
746
+ flex: 1,
747
+ alignItems: "flex-start",
748
+ },
749
+ navButton: {
750
+ flex: 1,
751
+ },
752
+ fullWidthButton: {
753
+ width: "100%",
754
+ },
755
+ summaryLabel: {
756
+ width: 90,
757
+ },
758
+ progressDot: {
759
+ width: 8,
760
+ },
761
+ progressDotActive: {
762
+ width: 24,
763
+ },
598
764
  });
599
765
 
600
766
  export default FeedbackScreen;