@oxyhq/services 6.9.42 → 6.9.44

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 (240) hide show
  1. package/lib/commonjs/index.js +9 -0
  2. package/lib/commonjs/index.js.map +1 -1
  3. package/lib/commonjs/ui/components/ActingAsBanner.js +143 -0
  4. package/lib/commonjs/ui/components/ActingAsBanner.js.map +1 -0
  5. package/lib/commonjs/ui/components/BottomSheet.js +3 -3
  6. package/lib/commonjs/ui/components/BottomSheet.js.map +1 -1
  7. package/lib/commonjs/ui/components/BottomSheetRouter.js +4 -3
  8. package/lib/commonjs/ui/components/BottomSheetRouter.js.map +1 -1
  9. package/lib/commonjs/ui/components/OxyProvider.js +48 -43
  10. package/lib/commonjs/ui/components/OxyProvider.js.map +1 -1
  11. package/lib/commonjs/ui/components/fileManagement/FileDetailsModal.js +3 -2
  12. package/lib/commonjs/ui/components/fileManagement/FileDetailsModal.js.map +1 -1
  13. package/lib/commonjs/ui/components/fileManagement/UploadPreview.js +3 -2
  14. package/lib/commonjs/ui/components/fileManagement/UploadPreview.js.map +1 -1
  15. package/lib/commonjs/ui/components/modals/DeleteAccountModal.js +3 -2
  16. package/lib/commonjs/ui/components/modals/DeleteAccountModal.js.map +1 -1
  17. package/lib/commonjs/ui/context/OxyContext.js +94 -6
  18. package/lib/commonjs/ui/context/OxyContext.js.map +1 -1
  19. package/lib/commonjs/ui/context/hooks/useAuthOperations.js +2 -1
  20. package/lib/commonjs/ui/context/hooks/useAuthOperations.js.map +1 -1
  21. package/lib/commonjs/ui/navigation/routes.js +3 -2
  22. package/lib/commonjs/ui/navigation/routes.js.map +1 -1
  23. package/lib/commonjs/ui/screens/AccountCenterScreen.js +29 -7
  24. package/lib/commonjs/ui/screens/AccountCenterScreen.js.map +1 -1
  25. package/lib/commonjs/ui/screens/AccountOverviewScreen.js +8 -6
  26. package/lib/commonjs/ui/screens/AccountOverviewScreen.js.map +1 -1
  27. package/lib/commonjs/ui/screens/AccountSettingsScreen.js +5 -4
  28. package/lib/commonjs/ui/screens/AccountSettingsScreen.js.map +1 -1
  29. package/lib/commonjs/ui/screens/AccountSwitcherScreen.js +240 -3
  30. package/lib/commonjs/ui/screens/AccountSwitcherScreen.js.map +1 -1
  31. package/lib/commonjs/ui/screens/AccountVerificationScreen.js +3 -2
  32. package/lib/commonjs/ui/screens/AccountVerificationScreen.js.map +1 -1
  33. package/lib/commonjs/ui/screens/CreateManagedAccountScreen.js +346 -0
  34. package/lib/commonjs/ui/screens/CreateManagedAccountScreen.js.map +1 -0
  35. package/lib/commonjs/ui/screens/EditProfileFieldScreen.js +3 -2
  36. package/lib/commonjs/ui/screens/EditProfileFieldScreen.js.map +1 -1
  37. package/lib/commonjs/ui/screens/FAQScreen.js +3 -2
  38. package/lib/commonjs/ui/screens/FAQScreen.js.map +1 -1
  39. package/lib/commonjs/ui/screens/FeedbackScreen.js +3 -2
  40. package/lib/commonjs/ui/screens/FeedbackScreen.js.map +1 -1
  41. package/lib/commonjs/ui/screens/HelpSupportScreen.js +3 -2
  42. package/lib/commonjs/ui/screens/HelpSupportScreen.js.map +1 -1
  43. package/lib/commonjs/ui/screens/HistoryViewScreen.js +3 -2
  44. package/lib/commonjs/ui/screens/HistoryViewScreen.js.map +1 -1
  45. package/lib/commonjs/ui/screens/LanguageSelectorScreen.js +3 -2
  46. package/lib/commonjs/ui/screens/LanguageSelectorScreen.js.map +1 -1
  47. package/lib/commonjs/ui/screens/LearnMoreUsernamesScreen.js +3 -2
  48. package/lib/commonjs/ui/screens/LearnMoreUsernamesScreen.js.map +1 -1
  49. package/lib/commonjs/ui/screens/LegalDocumentsScreen.js +6 -4
  50. package/lib/commonjs/ui/screens/LegalDocumentsScreen.js.map +1 -1
  51. package/lib/commonjs/ui/screens/OxyAuthScreen.js +12 -8
  52. package/lib/commonjs/ui/screens/OxyAuthScreen.js.map +1 -1
  53. package/lib/commonjs/ui/screens/PaymentGatewayScreen.js +3 -2
  54. package/lib/commonjs/ui/screens/PaymentGatewayScreen.js.map +1 -1
  55. package/lib/commonjs/ui/screens/PrivacySettingsScreen.js +6 -4
  56. package/lib/commonjs/ui/screens/PrivacySettingsScreen.js.map +1 -1
  57. package/lib/commonjs/ui/screens/ProfileScreen.js +8 -6
  58. package/lib/commonjs/ui/screens/ProfileScreen.js.map +1 -1
  59. package/lib/commonjs/ui/screens/SavesCollectionsScreen.js +3 -2
  60. package/lib/commonjs/ui/screens/SavesCollectionsScreen.js.map +1 -1
  61. package/lib/commonjs/ui/screens/SearchSettingsScreen.js +6 -4
  62. package/lib/commonjs/ui/screens/SearchSettingsScreen.js.map +1 -1
  63. package/lib/commonjs/ui/screens/SessionManagementScreen.js +6 -4
  64. package/lib/commonjs/ui/screens/SessionManagementScreen.js.map +1 -1
  65. package/lib/commonjs/ui/screens/UserLinksScreen.js +3 -2
  66. package/lib/commonjs/ui/screens/UserLinksScreen.js.map +1 -1
  67. package/lib/commonjs/ui/screens/UserListScreen.js +9 -6
  68. package/lib/commonjs/ui/screens/UserListScreen.js.map +1 -1
  69. package/lib/commonjs/ui/screens/karma/KarmaAboutScreen.js +3 -2
  70. package/lib/commonjs/ui/screens/karma/KarmaAboutScreen.js.map +1 -1
  71. package/lib/commonjs/ui/screens/karma/KarmaCenterScreen.js +8 -6
  72. package/lib/commonjs/ui/screens/karma/KarmaCenterScreen.js.map +1 -1
  73. package/lib/commonjs/ui/screens/karma/KarmaFAQScreen.js +3 -2
  74. package/lib/commonjs/ui/screens/karma/KarmaFAQScreen.js.map +1 -1
  75. package/lib/commonjs/ui/screens/karma/KarmaLeaderboardScreen.js +3 -2
  76. package/lib/commonjs/ui/screens/karma/KarmaLeaderboardScreen.js.map +1 -1
  77. package/lib/commonjs/ui/screens/karma/KarmaRewardsScreen.js +6 -4
  78. package/lib/commonjs/ui/screens/karma/KarmaRewardsScreen.js.map +1 -1
  79. package/lib/commonjs/ui/screens/karma/KarmaRulesScreen.js +3 -2
  80. package/lib/commonjs/ui/screens/karma/KarmaRulesScreen.js.map +1 -1
  81. package/lib/module/index.js +3 -0
  82. package/lib/module/index.js.map +1 -1
  83. package/lib/module/ui/components/ActingAsBanner.js +140 -0
  84. package/lib/module/ui/components/ActingAsBanner.js.map +1 -0
  85. package/lib/module/ui/components/BottomSheet.js +3 -3
  86. package/lib/module/ui/components/BottomSheet.js.map +1 -1
  87. package/lib/module/ui/components/BottomSheetRouter.js +4 -3
  88. package/lib/module/ui/components/BottomSheetRouter.js.map +1 -1
  89. package/lib/module/ui/components/OxyProvider.js +49 -44
  90. package/lib/module/ui/components/OxyProvider.js.map +1 -1
  91. package/lib/module/ui/components/fileManagement/FileDetailsModal.js +3 -2
  92. package/lib/module/ui/components/fileManagement/FileDetailsModal.js.map +1 -1
  93. package/lib/module/ui/components/fileManagement/UploadPreview.js +3 -2
  94. package/lib/module/ui/components/fileManagement/UploadPreview.js.map +1 -1
  95. package/lib/module/ui/components/modals/DeleteAccountModal.js +3 -2
  96. package/lib/module/ui/components/modals/DeleteAccountModal.js.map +1 -1
  97. package/lib/module/ui/context/OxyContext.js +94 -6
  98. package/lib/module/ui/context/OxyContext.js.map +1 -1
  99. package/lib/module/ui/context/hooks/useAuthOperations.js +2 -1
  100. package/lib/module/ui/context/hooks/useAuthOperations.js.map +1 -1
  101. package/lib/module/ui/navigation/routes.js +3 -2
  102. package/lib/module/ui/navigation/routes.js.map +1 -1
  103. package/lib/module/ui/screens/AccountCenterScreen.js +29 -7
  104. package/lib/module/ui/screens/AccountCenterScreen.js.map +1 -1
  105. package/lib/module/ui/screens/AccountOverviewScreen.js +8 -6
  106. package/lib/module/ui/screens/AccountOverviewScreen.js.map +1 -1
  107. package/lib/module/ui/screens/AccountSettingsScreen.js +5 -4
  108. package/lib/module/ui/screens/AccountSettingsScreen.js.map +1 -1
  109. package/lib/module/ui/screens/AccountSwitcherScreen.js +240 -3
  110. package/lib/module/ui/screens/AccountSwitcherScreen.js.map +1 -1
  111. package/lib/module/ui/screens/AccountVerificationScreen.js +3 -2
  112. package/lib/module/ui/screens/AccountVerificationScreen.js.map +1 -1
  113. package/lib/module/ui/screens/CreateManagedAccountScreen.js +342 -0
  114. package/lib/module/ui/screens/CreateManagedAccountScreen.js.map +1 -0
  115. package/lib/module/ui/screens/EditProfileFieldScreen.js +3 -2
  116. package/lib/module/ui/screens/EditProfileFieldScreen.js.map +1 -1
  117. package/lib/module/ui/screens/FAQScreen.js +3 -2
  118. package/lib/module/ui/screens/FAQScreen.js.map +1 -1
  119. package/lib/module/ui/screens/FeedbackScreen.js +3 -2
  120. package/lib/module/ui/screens/FeedbackScreen.js.map +1 -1
  121. package/lib/module/ui/screens/HelpSupportScreen.js +3 -2
  122. package/lib/module/ui/screens/HelpSupportScreen.js.map +1 -1
  123. package/lib/module/ui/screens/HistoryViewScreen.js +3 -2
  124. package/lib/module/ui/screens/HistoryViewScreen.js.map +1 -1
  125. package/lib/module/ui/screens/LanguageSelectorScreen.js +3 -2
  126. package/lib/module/ui/screens/LanguageSelectorScreen.js.map +1 -1
  127. package/lib/module/ui/screens/LearnMoreUsernamesScreen.js +3 -2
  128. package/lib/module/ui/screens/LearnMoreUsernamesScreen.js.map +1 -1
  129. package/lib/module/ui/screens/LegalDocumentsScreen.js +6 -4
  130. package/lib/module/ui/screens/LegalDocumentsScreen.js.map +1 -1
  131. package/lib/module/ui/screens/OxyAuthScreen.js +12 -8
  132. package/lib/module/ui/screens/OxyAuthScreen.js.map +1 -1
  133. package/lib/module/ui/screens/PaymentGatewayScreen.js +3 -2
  134. package/lib/module/ui/screens/PaymentGatewayScreen.js.map +1 -1
  135. package/lib/module/ui/screens/PrivacySettingsScreen.js +6 -4
  136. package/lib/module/ui/screens/PrivacySettingsScreen.js.map +1 -1
  137. package/lib/module/ui/screens/ProfileScreen.js +8 -6
  138. package/lib/module/ui/screens/ProfileScreen.js.map +1 -1
  139. package/lib/module/ui/screens/SavesCollectionsScreen.js +3 -2
  140. package/lib/module/ui/screens/SavesCollectionsScreen.js.map +1 -1
  141. package/lib/module/ui/screens/SearchSettingsScreen.js +6 -4
  142. package/lib/module/ui/screens/SearchSettingsScreen.js.map +1 -1
  143. package/lib/module/ui/screens/SessionManagementScreen.js +6 -4
  144. package/lib/module/ui/screens/SessionManagementScreen.js.map +1 -1
  145. package/lib/module/ui/screens/UserLinksScreen.js +3 -2
  146. package/lib/module/ui/screens/UserLinksScreen.js.map +1 -1
  147. package/lib/module/ui/screens/UserListScreen.js +9 -6
  148. package/lib/module/ui/screens/UserListScreen.js.map +1 -1
  149. package/lib/module/ui/screens/karma/KarmaAboutScreen.js +3 -2
  150. package/lib/module/ui/screens/karma/KarmaAboutScreen.js.map +1 -1
  151. package/lib/module/ui/screens/karma/KarmaCenterScreen.js +8 -6
  152. package/lib/module/ui/screens/karma/KarmaCenterScreen.js.map +1 -1
  153. package/lib/module/ui/screens/karma/KarmaFAQScreen.js +3 -2
  154. package/lib/module/ui/screens/karma/KarmaFAQScreen.js.map +1 -1
  155. package/lib/module/ui/screens/karma/KarmaLeaderboardScreen.js +3 -2
  156. package/lib/module/ui/screens/karma/KarmaLeaderboardScreen.js.map +1 -1
  157. package/lib/module/ui/screens/karma/KarmaRewardsScreen.js +6 -4
  158. package/lib/module/ui/screens/karma/KarmaRewardsScreen.js.map +1 -1
  159. package/lib/module/ui/screens/karma/KarmaRulesScreen.js +3 -2
  160. package/lib/module/ui/screens/karma/KarmaRulesScreen.js.map +1 -1
  161. package/lib/typescript/commonjs/index.d.ts +1 -0
  162. package/lib/typescript/commonjs/index.d.ts.map +1 -1
  163. package/lib/typescript/commonjs/ui/components/ActingAsBanner.d.ts +4 -0
  164. package/lib/typescript/commonjs/ui/components/ActingAsBanner.d.ts.map +1 -0
  165. package/lib/typescript/commonjs/ui/components/BottomSheet.d.ts.map +1 -1
  166. package/lib/typescript/commonjs/ui/components/OxyProvider.d.ts.map +1 -1
  167. package/lib/typescript/commonjs/ui/context/OxyContext.d.ts +9 -8
  168. package/lib/typescript/commonjs/ui/context/OxyContext.d.ts.map +1 -1
  169. package/lib/typescript/commonjs/ui/context/hooks/useAuthOperations.d.ts.map +1 -1
  170. package/lib/typescript/commonjs/ui/navigation/routes.d.ts +1 -1
  171. package/lib/typescript/commonjs/ui/navigation/routes.d.ts.map +1 -1
  172. package/lib/typescript/commonjs/ui/screens/AccountCenterScreen.d.ts.map +1 -1
  173. package/lib/typescript/commonjs/ui/screens/AccountSwitcherScreen.d.ts.map +1 -1
  174. package/lib/typescript/commonjs/ui/screens/CreateManagedAccountScreen.d.ts +5 -0
  175. package/lib/typescript/commonjs/ui/screens/CreateManagedAccountScreen.d.ts.map +1 -0
  176. package/lib/typescript/commonjs/ui/screens/EditProfileFieldScreen.d.ts.map +1 -1
  177. package/lib/typescript/commonjs/ui/screens/FeedbackScreen.d.ts.map +1 -1
  178. package/lib/typescript/commonjs/ui/types/navigation.d.ts +3 -0
  179. package/lib/typescript/commonjs/ui/types/navigation.d.ts.map +1 -1
  180. package/lib/typescript/module/index.d.ts +1 -0
  181. package/lib/typescript/module/index.d.ts.map +1 -1
  182. package/lib/typescript/module/ui/components/ActingAsBanner.d.ts +4 -0
  183. package/lib/typescript/module/ui/components/ActingAsBanner.d.ts.map +1 -0
  184. package/lib/typescript/module/ui/components/BottomSheet.d.ts.map +1 -1
  185. package/lib/typescript/module/ui/components/OxyProvider.d.ts.map +1 -1
  186. package/lib/typescript/module/ui/context/OxyContext.d.ts +9 -8
  187. package/lib/typescript/module/ui/context/OxyContext.d.ts.map +1 -1
  188. package/lib/typescript/module/ui/context/hooks/useAuthOperations.d.ts.map +1 -1
  189. package/lib/typescript/module/ui/navigation/routes.d.ts +1 -1
  190. package/lib/typescript/module/ui/navigation/routes.d.ts.map +1 -1
  191. package/lib/typescript/module/ui/screens/AccountCenterScreen.d.ts.map +1 -1
  192. package/lib/typescript/module/ui/screens/AccountSwitcherScreen.d.ts.map +1 -1
  193. package/lib/typescript/module/ui/screens/CreateManagedAccountScreen.d.ts +5 -0
  194. package/lib/typescript/module/ui/screens/CreateManagedAccountScreen.d.ts.map +1 -0
  195. package/lib/typescript/module/ui/screens/EditProfileFieldScreen.d.ts.map +1 -1
  196. package/lib/typescript/module/ui/screens/FeedbackScreen.d.ts.map +1 -1
  197. package/lib/typescript/module/ui/types/navigation.d.ts +3 -0
  198. package/lib/typescript/module/ui/types/navigation.d.ts.map +1 -1
  199. package/package.json +1 -2
  200. package/src/index.ts +3 -0
  201. package/src/ui/components/ActingAsBanner.tsx +135 -0
  202. package/src/ui/components/BottomSheet.tsx +3 -2
  203. package/src/ui/components/BottomSheetRouter.tsx +2 -2
  204. package/src/ui/components/OxyProvider.tsx +55 -50
  205. package/src/ui/components/fileManagement/FileDetailsModal.tsx +1 -1
  206. package/src/ui/components/fileManagement/UploadPreview.tsx +1 -1
  207. package/src/ui/components/modals/DeleteAccountModal.tsx +1 -1
  208. package/src/ui/context/OxyContext.tsx +106 -12
  209. package/src/ui/context/hooks/useAuthOperations.ts +2 -1
  210. package/src/ui/navigation/routes.ts +3 -1
  211. package/src/ui/screens/AccountCenterScreen.tsx +24 -4
  212. package/src/ui/screens/AccountOverviewScreen.tsx +3 -3
  213. package/src/ui/screens/AccountSettingsScreen.tsx +2 -2
  214. package/src/ui/screens/AccountSwitcherScreen.tsx +212 -1
  215. package/src/ui/screens/AccountVerificationScreen.tsx +1 -1
  216. package/src/ui/screens/CreateManagedAccountScreen.tsx +338 -0
  217. package/src/ui/screens/EditProfileFieldScreen.tsx +1 -2
  218. package/src/ui/screens/FAQScreen.tsx +1 -1
  219. package/src/ui/screens/FeedbackScreen.tsx +1 -2
  220. package/src/ui/screens/HelpSupportScreen.tsx +1 -1
  221. package/src/ui/screens/HistoryViewScreen.tsx +1 -1
  222. package/src/ui/screens/LanguageSelectorScreen.tsx +1 -1
  223. package/src/ui/screens/LearnMoreUsernamesScreen.tsx +1 -1
  224. package/src/ui/screens/LegalDocumentsScreen.tsx +2 -2
  225. package/src/ui/screens/OxyAuthScreen.tsx +5 -5
  226. package/src/ui/screens/PaymentGatewayScreen.tsx +1 -1
  227. package/src/ui/screens/PrivacySettingsScreen.tsx +2 -2
  228. package/src/ui/screens/ProfileScreen.tsx +3 -3
  229. package/src/ui/screens/SavesCollectionsScreen.tsx +1 -1
  230. package/src/ui/screens/SearchSettingsScreen.tsx +2 -2
  231. package/src/ui/screens/SessionManagementScreen.tsx +2 -2
  232. package/src/ui/screens/UserLinksScreen.tsx +1 -1
  233. package/src/ui/screens/UserListScreen.tsx +3 -3
  234. package/src/ui/screens/karma/KarmaAboutScreen.tsx +1 -1
  235. package/src/ui/screens/karma/KarmaCenterScreen.tsx +3 -3
  236. package/src/ui/screens/karma/KarmaFAQScreen.tsx +1 -1
  237. package/src/ui/screens/karma/KarmaLeaderboardScreen.tsx +1 -1
  238. package/src/ui/screens/karma/KarmaRewardsScreen.tsx +2 -2
  239. package/src/ui/screens/karma/KarmaRulesScreen.tsx +1 -1
  240. package/src/ui/types/navigation.ts +3 -0
@@ -23,6 +23,7 @@ import { Ionicons } from '@expo/vector-icons';
23
23
  import Avatar from '../components/Avatar';
24
24
  import { Header, GroupedSection, LoadingState } from '../components';
25
25
  import { useI18n } from '../hooks/useI18n';
26
+ import { useTheme } from '@oxyhq/bloom/theme';
26
27
  import { useOxy } from '../context/OxyContext';
27
28
 
28
29
  interface SessionWithUser extends ClientSession {
@@ -46,6 +47,7 @@ const ModernAccountSwitcherScreen: React.FC<BaseScreenProps> = ({
46
47
  navigate,
47
48
  goBack,
48
49
  }) => {
50
+ const bloomTheme = useTheme();
49
51
  // Use useOxy() hook for OxyContext values
50
52
  const {
51
53
  oxyServices,
@@ -58,11 +60,15 @@ const ModernAccountSwitcherScreen: React.FC<BaseScreenProps> = ({
58
60
  refreshSessions,
59
61
  isLoading = false,
60
62
  isAuthenticated = false,
63
+ actingAs,
64
+ managedAccounts,
65
+ setActingAs,
61
66
  } = useOxy();
62
67
 
63
68
  const [sessionsWithUsers, setSessionsWithUsers] = useState<SessionWithUser[]>([]);
64
69
  const [switchingToUserId, setSwitchingToUserId] = useState<string | null>(null);
65
70
  const [removingUserId, setRemovingUserId] = useState<string | null>(null);
71
+ const [switchingManagedId, setSwitchingManagedId] = useState<string | null>(null);
66
72
 
67
73
  // Device session management state
68
74
  const [showDeviceManagement, setShowDeviceManagement] = useState(false);
@@ -208,6 +214,30 @@ const ModernAccountSwitcherScreen: React.FC<BaseScreenProps> = ({
208
214
  );
209
215
  }, [logoutAll, onClose, t]);
210
216
 
217
+ const handleSwitchToManagedAccount = useCallback(async (accountId: string) => {
218
+ if (actingAs === accountId) return; // Already acting as this account
219
+ if (switchingManagedId) return; // Already switching
220
+
221
+ setSwitchingManagedId(accountId);
222
+ try {
223
+ setActingAs(accountId);
224
+ toast.success(t('accountSwitcher.toasts.switchSuccess') || 'Switched identity successfully!');
225
+ onClose?.();
226
+ } catch (error) {
227
+ if (__DEV__) {
228
+ console.error('Switch managed account failed:', error);
229
+ }
230
+ toast.error('Failed to switch identity. Please try again.');
231
+ } finally {
232
+ setSwitchingManagedId(null);
233
+ }
234
+ }, [actingAs, switchingManagedId, setActingAs, t, onClose]);
235
+
236
+ const handleSwitchBackToPrimary = useCallback(() => {
237
+ setActingAs(null);
238
+ toast.success('Switched back to primary account');
239
+ }, [setActingAs]);
240
+
211
241
  // Device session management functions - optimized with useCallback
212
242
  const loadAllDeviceSessions = useCallback(async () => {
213
243
  const currentActiveSessionId = activeSessionId ?? null;
@@ -287,7 +317,7 @@ const ModernAccountSwitcherScreen: React.FC<BaseScreenProps> = ({
287
317
  );
288
318
 
289
319
  return (
290
- <View style={styles.container} className="bg-background">
320
+ <View style={[styles.container, { backgroundColor: bloomTheme.colors.background }]}>
291
321
  {/* Header */}
292
322
  <Header
293
323
  title={t('accountSwitcher.title') || 'Account Switcher'}
@@ -426,6 +456,151 @@ const ModernAccountSwitcherScreen: React.FC<BaseScreenProps> = ({
426
456
  </View>
427
457
  )}
428
458
 
459
+ {/* Acting as banner - show switch-back when acting as a managed account */}
460
+ {actingAs && (
461
+ <View style={styles.section}>
462
+ <TouchableOpacity
463
+ style={[styles.settingItem, styles.firstSettingItem, styles.lastSettingItem, styles.actingAsBanner]}
464
+ onPress={handleSwitchBackToPrimary}
465
+ activeOpacity={0.7}
466
+ >
467
+ <View style={styles.settingInfo}>
468
+ <Text style={styles.settingLabel}>Switch back to primary account</Text>
469
+ <Text style={styles.settingDescription}>You are currently acting as another identity</Text>
470
+ </View>
471
+ <View style={styles.switchBackButton}>
472
+ <Text style={styles.switchBackButtonText}>Switch Back</Text>
473
+ </View>
474
+ </TouchableOpacity>
475
+ </View>
476
+ )}
477
+
478
+ {/* Managed Accounts */}
479
+ {managedAccounts.length > 0 && (
480
+ <View style={styles.section}>
481
+ <Text style={styles.sectionTitle}>Managed Accounts</Text>
482
+ <Text style={styles.sectionSubtitle}>Identities you manage</Text>
483
+
484
+ {managedAccounts.map((managed, index) => {
485
+ const account = managed.account;
486
+ if (!account) return null;
487
+
488
+ const isActive = actingAs === managed.accountId;
489
+ const isSwitching = switchingManagedId === managed.accountId;
490
+ const isFirst = index === 0;
491
+ const isLast = index === managedAccounts.length - 1;
492
+
493
+ const managedDisplayName = typeof account.name === 'object'
494
+ ? account.name.full || account.name.first || account.username
495
+ : account.name || account.username || 'Unknown';
496
+
497
+ // Determine the manager role for badge display
498
+ const myRole = managed.managers?.find(
499
+ (m) => m.userId === user?.id
500
+ )?.role ?? 'owner';
501
+
502
+ return (
503
+ <TouchableOpacity
504
+ key={`managed-${managed.accountId}`}
505
+ style={[
506
+ styles.settingItem,
507
+ isFirst && styles.firstSettingItem,
508
+ isLast && styles.lastSettingItem,
509
+ isActive && styles.currentAccountCard,
510
+ ]}
511
+ onPress={() => handleSwitchToManagedAccount(managed.accountId)}
512
+ disabled={isActive || isSwitching}
513
+ activeOpacity={0.7}
514
+ >
515
+ <View style={styles.userIcon}>
516
+ {account.avatar ? (
517
+ <Image source={{ uri: oxyServices.getFileDownloadUrl(account.avatar, 'thumb') }} style={styles.accountAvatarImage} />
518
+ ) : (
519
+ <View style={[styles.accountAvatarFallback, styles.managedAvatarFallback]}>
520
+ <Text style={styles.accountAvatarText}>
521
+ {managedDisplayName.charAt(0).toUpperCase()}
522
+ </Text>
523
+ </View>
524
+ )}
525
+ {isActive && (
526
+ <View style={styles.activeBadge}>
527
+ <OxyIcon name="checkmark" size={12} color="#fff" />
528
+ </View>
529
+ )}
530
+ </View>
531
+ <View style={styles.settingInfo}>
532
+ <View>
533
+ <Text style={styles.settingLabel}>{managedDisplayName}</Text>
534
+ <Text style={styles.settingDescription}>@{account.username}</Text>
535
+ </View>
536
+ </View>
537
+ <View style={styles.accountActions}>
538
+ <View style={styles.roleBadge}>
539
+ <Text style={styles.roleBadgeText}>{myRole}</Text>
540
+ </View>
541
+ {isActive ? (
542
+ <View style={styles.currentBadge}>
543
+ <Text style={styles.currentBadgeText}>Current</Text>
544
+ </View>
545
+ ) : (
546
+ <TouchableOpacity
547
+ style={styles.switchButton}
548
+ onPress={() => handleSwitchToManagedAccount(managed.accountId)}
549
+ disabled={isSwitching}
550
+ >
551
+ {isSwitching ? (
552
+ <ActivityIndicator size="small" color="#fff" />
553
+ ) : (
554
+ <Text style={styles.switchButtonText}>Act As</Text>
555
+ )}
556
+ </TouchableOpacity>
557
+ )}
558
+ </View>
559
+ </TouchableOpacity>
560
+ );
561
+ })}
562
+
563
+ {/* Create New Identity */}
564
+ <TouchableOpacity
565
+ style={[styles.settingItem, styles.firstSettingItem, styles.lastSettingItem, { marginTop: 8 }]}
566
+ onPress={() => navigate?.('CreateManagedAccount')}
567
+ activeOpacity={0.7}
568
+ >
569
+ <View style={styles.userIcon}>
570
+ <View style={[styles.accountAvatarFallback, { backgroundColor: '#007AFF20' }]}>
571
+ <OxyIcon name="add" size={20} color="#007AFF" />
572
+ </View>
573
+ </View>
574
+ <View style={styles.settingInfo}>
575
+ <Text style={[styles.settingLabel, { color: '#007AFF' }]}>Create New Identity</Text>
576
+ <Text style={styles.settingDescription}>Add a managed sub-account</Text>
577
+ </View>
578
+ </TouchableOpacity>
579
+ </View>
580
+ )}
581
+
582
+ {/* Create first managed account (when none exist yet) */}
583
+ {managedAccounts.length === 0 && isAuthenticated && (
584
+ <View style={styles.section}>
585
+ <Text style={styles.sectionTitle}>Managed Accounts</Text>
586
+ <TouchableOpacity
587
+ style={[styles.settingItem, styles.firstSettingItem, styles.lastSettingItem]}
588
+ onPress={() => navigate?.('CreateManagedAccount')}
589
+ activeOpacity={0.7}
590
+ >
591
+ <View style={styles.userIcon}>
592
+ <View style={[styles.accountAvatarFallback, { backgroundColor: '#007AFF20' }]}>
593
+ <OxyIcon name="add" size={20} color="#007AFF" />
594
+ </View>
595
+ </View>
596
+ <View style={styles.settingInfo}>
597
+ <Text style={[styles.settingLabel, { color: '#007AFF' }]}>Create New Identity</Text>
598
+ <Text style={styles.settingDescription}>Create a managed sub-account you control</Text>
599
+ </View>
600
+ </TouchableOpacity>
601
+ </View>
602
+ )}
603
+
429
604
  {/* Quick Actions */}
430
605
  <View style={styles.section}>
431
606
  <Text style={styles.sectionTitle}>Quick Actions</Text>
@@ -727,6 +902,42 @@ const styles = StyleSheet.create({
727
902
  fontSize: 16,
728
903
  fontWeight: '600',
729
904
  },
905
+ sectionSubtitle: {
906
+ fontSize: 13,
907
+ color: '#888',
908
+ marginBottom: 12,
909
+ },
910
+ managedAvatarFallback: {
911
+ backgroundColor: '#5856D6',
912
+ },
913
+ roleBadge: {
914
+ backgroundColor: '#F2F2F7',
915
+ paddingHorizontal: 8,
916
+ paddingVertical: 3,
917
+ borderRadius: 8,
918
+ },
919
+ roleBadgeText: {
920
+ color: '#666',
921
+ fontSize: 11,
922
+ fontWeight: '500',
923
+ textTransform: 'capitalize',
924
+ },
925
+ actingAsBanner: {
926
+ borderWidth: 2,
927
+ borderColor: '#FF9500',
928
+ backgroundColor: '#FF950010',
929
+ },
930
+ switchBackButton: {
931
+ backgroundColor: '#FF9500',
932
+ paddingHorizontal: 14,
933
+ paddingVertical: 8,
934
+ borderRadius: 16,
935
+ },
936
+ switchBackButtonText: {
937
+ color: '#fff',
938
+ fontSize: 13,
939
+ fontWeight: '600',
940
+ },
730
941
  });
731
942
 
732
943
  export default ModernAccountSwitcherScreen;
@@ -75,7 +75,7 @@ const AccountVerificationScreen: React.FC<BaseScreenProps> = ({
75
75
  }, [reason, evidence, oxyServices, t, goBack]);
76
76
 
77
77
  return (
78
- <View style={styles.container} className="bg-background">
78
+ <View style={[styles.container, { backgroundColor: bloomTheme.colors.background }]}>
79
79
  <Header
80
80
  title={t('accountVerification.title') || 'Account Verification'}
81
81
 
@@ -0,0 +1,338 @@
1
+ import type React from 'react';
2
+ import { useState, useCallback, useRef, useEffect } from 'react';
3
+ import {
4
+ View,
5
+ Text,
6
+ TextInput,
7
+ TouchableOpacity,
8
+ StyleSheet,
9
+ ActivityIndicator,
10
+ ScrollView,
11
+ Platform,
12
+ KeyboardAvoidingView,
13
+ } from 'react-native';
14
+ import type { BaseScreenProps } from '../types/navigation';
15
+ import { fontFamilies } from '../styles/fonts';
16
+ import { Header } from '../components';
17
+ import { useI18n } from '../hooks/useI18n';
18
+ import { useTheme } from '@oxyhq/bloom/theme';
19
+ import { useOxy } from '../context/OxyContext';
20
+ import { toast } from '../../lib/sonner';
21
+ import { screenContentStyle } from '../constants/spacing';
22
+
23
+ type UsernameStatus = 'idle' | 'checking' | 'available' | 'taken' | 'invalid';
24
+
25
+ const USERNAME_REGEX = /^[a-zA-Z0-9_-]{3,30}$/;
26
+ const DEBOUNCE_MS = 400;
27
+
28
+ const CreateManagedAccountScreen: React.FC<BaseScreenProps> = ({
29
+ onClose,
30
+ goBack,
31
+ }) => {
32
+ const bloomTheme = useTheme();
33
+ const { oxyServices, createManagedAccount, setActingAs } = useOxy();
34
+ const { t } = useI18n();
35
+
36
+ const [username, setUsername] = useState('');
37
+ const [displayName, setDisplayName] = useState('');
38
+ const [bio, setBio] = useState('');
39
+ const [usernameStatus, setUsernameStatus] = useState<UsernameStatus>('idle');
40
+ const [usernameMessage, setUsernameMessage] = useState('');
41
+ const [isCreating, setIsCreating] = useState(false);
42
+
43
+ const debounceTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);
44
+
45
+ // Debounced username availability check
46
+ const checkUsername = useCallback((value: string) => {
47
+ if (debounceTimerRef.current) {
48
+ clearTimeout(debounceTimerRef.current);
49
+ }
50
+
51
+ if (!value || value.length < 3) {
52
+ setUsernameStatus(value.length > 0 ? 'invalid' : 'idle');
53
+ setUsernameMessage(value.length > 0 ? 'Username must be at least 3 characters' : '');
54
+ return;
55
+ }
56
+
57
+ if (!USERNAME_REGEX.test(value)) {
58
+ setUsernameStatus('invalid');
59
+ setUsernameMessage('Only letters, numbers, hyphens, and underscores');
60
+ return;
61
+ }
62
+
63
+ setUsernameStatus('checking');
64
+ setUsernameMessage('');
65
+
66
+ debounceTimerRef.current = setTimeout(async () => {
67
+ try {
68
+ const result = await oxyServices.checkUsernameAvailability(value);
69
+ setUsernameStatus(result.available ? 'available' : 'taken');
70
+ setUsernameMessage(result.message || (result.available ? 'Username is available' : 'Username is taken'));
71
+ } catch {
72
+ setUsernameStatus('idle');
73
+ setUsernameMessage('Could not check availability');
74
+ }
75
+ }, DEBOUNCE_MS);
76
+ }, [oxyServices]);
77
+
78
+ const handleUsernameChange = useCallback((value: string) => {
79
+ const cleaned = value.toLowerCase().replace(/[^a-z0-9_-]/g, '');
80
+ setUsername(cleaned);
81
+ checkUsername(cleaned);
82
+ }, [checkUsername]);
83
+
84
+ // Cleanup debounce timer
85
+ useEffect(() => {
86
+ return () => {
87
+ if (debounceTimerRef.current) {
88
+ clearTimeout(debounceTimerRef.current);
89
+ }
90
+ };
91
+ }, []);
92
+
93
+ const canCreate = usernameStatus === 'available' && displayName.trim().length > 0 && !isCreating;
94
+
95
+ const handleCreate = useCallback(async () => {
96
+ if (!canCreate) return;
97
+
98
+ setIsCreating(true);
99
+ try {
100
+ // Split display name into first/last
101
+ const nameParts = displayName.trim().split(/\s+/);
102
+ const firstName = nameParts[0] || '';
103
+ const lastName = nameParts.length > 1 ? nameParts.slice(1).join(' ') : undefined;
104
+
105
+ const account = await createManagedAccount({
106
+ username,
107
+ name: { first: firstName, last: lastName },
108
+ bio: bio.trim() || undefined,
109
+ });
110
+
111
+ toast.success('Identity created successfully');
112
+
113
+ // Switch to the new managed account
114
+ if (account.accountId) {
115
+ setActingAs(account.accountId);
116
+ }
117
+
118
+ onClose?.();
119
+ } catch (error) {
120
+ const message = error instanceof Error ? error.message : 'Failed to create identity';
121
+ toast.error(message);
122
+ } finally {
123
+ setIsCreating(false);
124
+ }
125
+ }, [canCreate, username, displayName, bio, createManagedAccount, setActingAs, onClose]);
126
+
127
+ const getStatusColor = (): string => {
128
+ switch (usernameStatus) {
129
+ case 'available': return '#34C759';
130
+ case 'taken':
131
+ case 'invalid': return bloomTheme.colors.error;
132
+ case 'checking': return bloomTheme.colors.primary;
133
+ default: return 'transparent';
134
+ }
135
+ };
136
+
137
+ return (
138
+ <View style={[styles.container, { backgroundColor: bloomTheme.colors.background }]}>
139
+ <Header
140
+ title="Create Identity"
141
+ onBack={goBack}
142
+ onClose={onClose}
143
+ showBackButton={true}
144
+ showCloseButton={true}
145
+ elevation="subtle"
146
+ />
147
+
148
+ <KeyboardAvoidingView
149
+ style={styles.flex}
150
+ behavior={Platform.OS === 'ios' ? 'padding' : undefined}
151
+ keyboardVerticalOffset={Platform.OS === 'ios' ? 88 : 0}
152
+ >
153
+ <ScrollView
154
+ style={styles.flex}
155
+ contentContainerStyle={screenContentStyle}
156
+ keyboardShouldPersistTaps="handled"
157
+ >
158
+ <Text style={[styles.description, { color: bloomTheme.colors.text }]}>
159
+ Create a managed identity that you control. It will have its own profile, posts, and interactions.
160
+ </Text>
161
+
162
+ {/* Username */}
163
+ <View style={styles.fieldGroup}>
164
+ <Text style={[styles.label, { color: bloomTheme.colors.text }]}>Username</Text>
165
+ <View style={[
166
+ styles.inputContainer,
167
+ { borderColor: usernameStatus !== 'idle' ? getStatusColor() : bloomTheme.colors.border },
168
+ ]}>
169
+ <Text style={[styles.inputPrefix, { color: bloomTheme.colors.text + '80' }]}>@</Text>
170
+ <TextInput
171
+ style={[styles.input, { color: bloomTheme.colors.text }]}
172
+ value={username}
173
+ onChangeText={handleUsernameChange}
174
+ placeholder="username"
175
+ placeholderTextColor={bloomTheme.colors.text + '40'}
176
+ autoCapitalize="none"
177
+ autoCorrect={false}
178
+ autoComplete="off"
179
+ maxLength={30}
180
+ />
181
+ {usernameStatus === 'checking' && (
182
+ <ActivityIndicator size="small" color={bloomTheme.colors.primary} />
183
+ )}
184
+ {usernameStatus === 'available' && (
185
+ <Text style={styles.statusIcon}>OK</Text>
186
+ )}
187
+ </View>
188
+ {usernameMessage ? (
189
+ <Text style={[styles.statusMessage, { color: getStatusColor() }]}>
190
+ {usernameMessage}
191
+ </Text>
192
+ ) : null}
193
+ </View>
194
+
195
+ {/* Display Name */}
196
+ <View style={styles.fieldGroup}>
197
+ <Text style={[styles.label, { color: bloomTheme.colors.text }]}>Display Name</Text>
198
+ <View style={[styles.inputContainer, { borderColor: bloomTheme.colors.border }]}>
199
+ <TextInput
200
+ style={[styles.input, { color: bloomTheme.colors.text }]}
201
+ value={displayName}
202
+ onChangeText={setDisplayName}
203
+ placeholder="Display name"
204
+ placeholderTextColor={bloomTheme.colors.text + '40'}
205
+ maxLength={50}
206
+ />
207
+ </View>
208
+ </View>
209
+
210
+ {/* Bio */}
211
+ <View style={styles.fieldGroup}>
212
+ <Text style={[styles.label, { color: bloomTheme.colors.text }]}>Bio (optional)</Text>
213
+ <View style={[styles.inputContainer, styles.bioContainer, { borderColor: bloomTheme.colors.border }]}>
214
+ <TextInput
215
+ style={[styles.input, styles.bioInput, { color: bloomTheme.colors.text }]}
216
+ value={bio}
217
+ onChangeText={setBio}
218
+ placeholder="Tell people about this identity"
219
+ placeholderTextColor={bloomTheme.colors.text + '40'}
220
+ maxLength={160}
221
+ multiline
222
+ numberOfLines={3}
223
+ textAlignVertical="top"
224
+ />
225
+ </View>
226
+ <Text style={[styles.charCount, { color: bloomTheme.colors.text + '60' }]}>
227
+ {bio.length}/160
228
+ </Text>
229
+ </View>
230
+
231
+ {/* Create Button */}
232
+ <TouchableOpacity
233
+ style={[
234
+ styles.createButton,
235
+ { backgroundColor: bloomTheme.colors.primary },
236
+ !canCreate && styles.createButtonDisabled,
237
+ ]}
238
+ onPress={handleCreate}
239
+ disabled={!canCreate}
240
+ activeOpacity={0.7}
241
+ >
242
+ {isCreating ? (
243
+ <ActivityIndicator size="small" color="#fff" />
244
+ ) : (
245
+ <Text style={styles.createButtonText}>Create Identity</Text>
246
+ )}
247
+ </TouchableOpacity>
248
+ </ScrollView>
249
+ </KeyboardAvoidingView>
250
+ </View>
251
+ );
252
+ };
253
+
254
+ const styles = StyleSheet.create({
255
+ container: {
256
+ flex: 1,
257
+ },
258
+ flex: {
259
+ flex: 1,
260
+ },
261
+ description: {
262
+ fontSize: 15,
263
+ lineHeight: 22,
264
+ marginBottom: 24,
265
+ fontFamily: fontFamilies.inter,
266
+ },
267
+ fieldGroup: {
268
+ marginBottom: 20,
269
+ },
270
+ label: {
271
+ fontSize: 14,
272
+ fontFamily: fontFamilies.interSemiBold,
273
+ fontWeight: Platform.OS === 'web' ? '600' : undefined,
274
+ marginBottom: 8,
275
+ },
276
+ inputContainer: {
277
+ flexDirection: 'row',
278
+ alignItems: 'center',
279
+ borderWidth: 1,
280
+ borderRadius: 12,
281
+ paddingHorizontal: 14,
282
+ height: 48,
283
+ },
284
+ inputPrefix: {
285
+ fontSize: 16,
286
+ fontFamily: fontFamilies.inter,
287
+ marginRight: 2,
288
+ },
289
+ input: {
290
+ flex: 1,
291
+ fontSize: 16,
292
+ fontFamily: fontFamilies.inter,
293
+ paddingVertical: 0,
294
+ },
295
+ bioContainer: {
296
+ height: 88,
297
+ alignItems: 'flex-start',
298
+ paddingVertical: 12,
299
+ },
300
+ bioInput: {
301
+ height: 64,
302
+ },
303
+ statusIcon: {
304
+ fontSize: 13,
305
+ fontFamily: fontFamilies.interSemiBold,
306
+ fontWeight: Platform.OS === 'web' ? '600' : undefined,
307
+ color: '#34C759',
308
+ },
309
+ statusMessage: {
310
+ fontSize: 13,
311
+ fontFamily: fontFamilies.inter,
312
+ marginTop: 6,
313
+ },
314
+ charCount: {
315
+ fontSize: 12,
316
+ fontFamily: fontFamilies.inter,
317
+ textAlign: 'right',
318
+ marginTop: 4,
319
+ },
320
+ createButton: {
321
+ height: 50,
322
+ borderRadius: 25,
323
+ alignItems: 'center',
324
+ justifyContent: 'center',
325
+ marginTop: 12,
326
+ },
327
+ createButtonDisabled: {
328
+ opacity: 0.5,
329
+ },
330
+ createButtonText: {
331
+ color: '#fff',
332
+ fontSize: 16,
333
+ fontFamily: fontFamilies.interSemiBold,
334
+ fontWeight: Platform.OS === 'web' ? '600' : undefined,
335
+ },
336
+ });
337
+
338
+ export default CreateManagedAccountScreen;
@@ -534,8 +534,7 @@ const EditProfileFieldScreen: React.FC<EditProfileFieldScreenProps> = ({
534
534
 
535
535
  return (
536
536
  <KeyboardAvoidingView
537
- style={styles.container}
538
- className="bg-background"
537
+ style={[styles.container, { backgroundColor: bloomTheme.colors.background }]}
539
538
  behavior={Platform.OS === 'ios' ? 'padding' : undefined}
540
539
  >
541
540
  <Header
@@ -96,7 +96,7 @@ const FAQScreen: React.FC<BaseScreenProps> = ({
96
96
  const styles = useMemo(() => createStyles(), []);
97
97
 
98
98
  return (
99
- <View style={styles.container} className="bg-background">
99
+ <View style={[styles.container, { backgroundColor: bloomTheme.colors.background }]}>
100
100
  <Header
101
101
  title={t('faq.title') || 'FAQ'}
102
102
  onBack={goBack || onClose}
@@ -489,8 +489,7 @@ const FeedbackScreen: React.FC<BaseScreenProps> = ({
489
489
 
490
490
  return (
491
491
  <KeyboardAvoidingView
492
- style={styles.container}
493
- className="bg-background"
492
+ style={[styles.container, { backgroundColor: colors.background }]}
494
493
  behavior={Platform.OS === 'ios' ? 'padding' : 'height'}
495
494
  >
496
495
  <StatusBar
@@ -50,7 +50,7 @@ const HelpSupportScreen: React.FC<BaseScreenProps> = ({
50
50
  }, [t]);
51
51
 
52
52
  return (
53
- <View style={styles.container} className="bg-background">
53
+ <View style={[styles.container, { backgroundColor: bloomTheme.colors.background }]}>
54
54
  <Header
55
55
  title={t('help.title') || 'Help & Support'}
56
56
 
@@ -184,7 +184,7 @@ const HistoryViewScreen: React.FC<BaseScreenProps> = ({
184
184
  };
185
185
 
186
186
  return (
187
- <View style={styles.container} className="bg-background">
187
+ <View style={[styles.container, { backgroundColor: bloomTheme.colors.background }]}>
188
188
  <Header
189
189
  title={t('history.title') || 'History'}
190
190
  onBack={goBack || onClose}
@@ -117,7 +117,7 @@ const LanguageSelectorScreen: React.FC<LanguageSelectorScreenProps> = ({
117
117
 
118
118
 
119
119
  return (
120
- <View style={styles.container} className="bg-background">
120
+ <View style={[styles.container, { backgroundColor: bloomTheme.colors.background }]}>
121
121
  <Header
122
122
  title=""
123
123
  subtitle=""