@oxyhq/services 6.9.43 → 6.9.45

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 (205) 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/OxyPayButton.js +4 -2
  6. package/lib/commonjs/ui/components/OxyPayButton.js.map +1 -1
  7. package/lib/commonjs/ui/components/OxySignInButton.js +83 -82
  8. package/lib/commonjs/ui/components/OxySignInButton.js.map +1 -1
  9. package/lib/commonjs/ui/components/SettingRow.js +11 -5
  10. package/lib/commonjs/ui/components/SettingRow.js.map +1 -1
  11. package/lib/commonjs/ui/components/fileManagement/FileDetailsModal.js +76 -121
  12. package/lib/commonjs/ui/components/fileManagement/FileDetailsModal.js.map +1 -1
  13. package/lib/commonjs/ui/components/fileManagement/UploadPreview.js +32 -18
  14. package/lib/commonjs/ui/components/fileManagement/UploadPreview.js.map +1 -1
  15. package/lib/commonjs/ui/components/icon/OxyIcon.js +5 -4
  16. package/lib/commonjs/ui/components/icon/OxyIcon.js.map +1 -1
  17. package/lib/commonjs/ui/components/internal/GroupedPillButtons.js +11 -9
  18. package/lib/commonjs/ui/components/internal/GroupedPillButtons.js.map +1 -1
  19. package/lib/commonjs/ui/components/internal/PinInput.js +3 -2
  20. package/lib/commonjs/ui/components/internal/PinInput.js.map +1 -1
  21. package/lib/commonjs/ui/components/modals/DeleteAccountModal.js +83 -219
  22. package/lib/commonjs/ui/components/modals/DeleteAccountModal.js.map +1 -1
  23. package/lib/commonjs/ui/constants/theme.js +2 -2
  24. package/lib/commonjs/ui/constants/theme.js.map +1 -1
  25. package/lib/commonjs/ui/context/OxyContext.js +78 -3
  26. package/lib/commonjs/ui/context/OxyContext.js.map +1 -1
  27. package/lib/commonjs/ui/navigation/routes.js +3 -2
  28. package/lib/commonjs/ui/navigation/routes.js.map +1 -1
  29. package/lib/commonjs/ui/screens/AccountCenterScreen.js +33 -11
  30. package/lib/commonjs/ui/screens/AccountCenterScreen.js.map +1 -1
  31. package/lib/commonjs/ui/screens/AccountOverviewScreen.js +70 -79
  32. package/lib/commonjs/ui/screens/AccountOverviewScreen.js.map +1 -1
  33. package/lib/commonjs/ui/screens/AccountSettingsScreen.js +22 -10
  34. package/lib/commonjs/ui/screens/AccountSettingsScreen.js.map +1 -1
  35. package/lib/commonjs/ui/screens/AccountSwitcherScreen.js +376 -82
  36. package/lib/commonjs/ui/screens/AccountSwitcherScreen.js.map +1 -1
  37. package/lib/commonjs/ui/screens/AccountVerificationScreen.js +21 -9
  38. package/lib/commonjs/ui/screens/AccountVerificationScreen.js.map +1 -1
  39. package/lib/commonjs/ui/screens/CreateManagedAccountScreen.js +346 -0
  40. package/lib/commonjs/ui/screens/CreateManagedAccountScreen.js.map +1 -0
  41. package/lib/commonjs/ui/screens/FileManagementScreen.js +83 -50
  42. package/lib/commonjs/ui/screens/FileManagementScreen.js.map +1 -1
  43. package/lib/commonjs/ui/screens/HistoryViewScreen.js +80 -101
  44. package/lib/commonjs/ui/screens/HistoryViewScreen.js.map +1 -1
  45. package/lib/commonjs/ui/screens/PremiumSubscriptionScreen.js +66 -93
  46. package/lib/commonjs/ui/screens/PremiumSubscriptionScreen.js.map +1 -1
  47. package/lib/commonjs/ui/screens/SessionManagementScreen.js +101 -66
  48. package/lib/commonjs/ui/screens/SessionManagementScreen.js.map +1 -1
  49. package/lib/commonjs/ui/utils/fileManagement.js +0 -21
  50. package/lib/commonjs/ui/utils/fileManagement.js.map +1 -1
  51. package/lib/module/index.js +3 -0
  52. package/lib/module/index.js.map +1 -1
  53. package/lib/module/ui/components/ActingAsBanner.js +140 -0
  54. package/lib/module/ui/components/ActingAsBanner.js.map +1 -0
  55. package/lib/module/ui/components/OxyPayButton.js +4 -2
  56. package/lib/module/ui/components/OxyPayButton.js.map +1 -1
  57. package/lib/module/ui/components/OxySignInButton.js +84 -83
  58. package/lib/module/ui/components/OxySignInButton.js.map +1 -1
  59. package/lib/module/ui/components/SettingRow.js +11 -5
  60. package/lib/module/ui/components/SettingRow.js.map +1 -1
  61. package/lib/module/ui/components/fileManagement/FileDetailsModal.js +76 -122
  62. package/lib/module/ui/components/fileManagement/FileDetailsModal.js.map +1 -1
  63. package/lib/module/ui/components/fileManagement/UploadPreview.js +32 -19
  64. package/lib/module/ui/components/fileManagement/UploadPreview.js.map +1 -1
  65. package/lib/module/ui/components/icon/OxyIcon.js +5 -4
  66. package/lib/module/ui/components/icon/OxyIcon.js.map +1 -1
  67. package/lib/module/ui/components/internal/GroupedPillButtons.js +11 -9
  68. package/lib/module/ui/components/internal/GroupedPillButtons.js.map +1 -1
  69. package/lib/module/ui/components/internal/PinInput.js +3 -2
  70. package/lib/module/ui/components/internal/PinInput.js.map +1 -1
  71. package/lib/module/ui/components/modals/DeleteAccountModal.js +83 -220
  72. package/lib/module/ui/components/modals/DeleteAccountModal.js.map +1 -1
  73. package/lib/module/ui/constants/theme.js +2 -2
  74. package/lib/module/ui/constants/theme.js.map +1 -1
  75. package/lib/module/ui/context/OxyContext.js +78 -3
  76. package/lib/module/ui/context/OxyContext.js.map +1 -1
  77. package/lib/module/ui/navigation/routes.js +3 -2
  78. package/lib/module/ui/navigation/routes.js.map +1 -1
  79. package/lib/module/ui/screens/AccountCenterScreen.js +32 -11
  80. package/lib/module/ui/screens/AccountCenterScreen.js.map +1 -1
  81. package/lib/module/ui/screens/AccountOverviewScreen.js +71 -80
  82. package/lib/module/ui/screens/AccountOverviewScreen.js.map +1 -1
  83. package/lib/module/ui/screens/AccountSettingsScreen.js +22 -10
  84. package/lib/module/ui/screens/AccountSettingsScreen.js.map +1 -1
  85. package/lib/module/ui/screens/AccountSwitcherScreen.js +375 -82
  86. package/lib/module/ui/screens/AccountSwitcherScreen.js.map +1 -1
  87. package/lib/module/ui/screens/AccountVerificationScreen.js +22 -10
  88. package/lib/module/ui/screens/AccountVerificationScreen.js.map +1 -1
  89. package/lib/module/ui/screens/CreateManagedAccountScreen.js +342 -0
  90. package/lib/module/ui/screens/CreateManagedAccountScreen.js.map +1 -0
  91. package/lib/module/ui/screens/FileManagementScreen.js +85 -52
  92. package/lib/module/ui/screens/FileManagementScreen.js.map +1 -1
  93. package/lib/module/ui/screens/HistoryViewScreen.js +80 -101
  94. package/lib/module/ui/screens/HistoryViewScreen.js.map +1 -1
  95. package/lib/module/ui/screens/PremiumSubscriptionScreen.js +66 -94
  96. package/lib/module/ui/screens/PremiumSubscriptionScreen.js.map +1 -1
  97. package/lib/module/ui/screens/SessionManagementScreen.js +101 -67
  98. package/lib/module/ui/screens/SessionManagementScreen.js.map +1 -1
  99. package/lib/module/ui/utils/fileManagement.js +0 -20
  100. package/lib/module/ui/utils/fileManagement.js.map +1 -1
  101. package/lib/typescript/commonjs/index.d.ts +1 -0
  102. package/lib/typescript/commonjs/index.d.ts.map +1 -1
  103. package/lib/typescript/commonjs/ui/components/ActingAsBanner.d.ts +4 -0
  104. package/lib/typescript/commonjs/ui/components/ActingAsBanner.d.ts.map +1 -0
  105. package/lib/typescript/commonjs/ui/components/OxyPayButton.d.ts.map +1 -1
  106. package/lib/typescript/commonjs/ui/components/OxySignInButton.d.ts +0 -1
  107. package/lib/typescript/commonjs/ui/components/OxySignInButton.d.ts.map +1 -1
  108. package/lib/typescript/commonjs/ui/components/SettingRow.d.ts +2 -2
  109. package/lib/typescript/commonjs/ui/components/SettingRow.d.ts.map +1 -1
  110. package/lib/typescript/commonjs/ui/components/fileManagement/FileDetailsModal.d.ts +3 -4
  111. package/lib/typescript/commonjs/ui/components/fileManagement/FileDetailsModal.d.ts.map +1 -1
  112. package/lib/typescript/commonjs/ui/components/fileManagement/UploadPreview.d.ts +2 -3
  113. package/lib/typescript/commonjs/ui/components/fileManagement/UploadPreview.d.ts.map +1 -1
  114. package/lib/typescript/commonjs/ui/components/icon/OxyIcon.d.ts.map +1 -1
  115. package/lib/typescript/commonjs/ui/components/internal/GroupedPillButtons.d.ts.map +1 -1
  116. package/lib/typescript/commonjs/ui/components/internal/PinInput.d.ts.map +1 -1
  117. package/lib/typescript/commonjs/ui/components/modals/DeleteAccountModal.d.ts +2 -2
  118. package/lib/typescript/commonjs/ui/components/modals/DeleteAccountModal.d.ts.map +1 -1
  119. package/lib/typescript/commonjs/ui/context/OxyContext.d.ts +6 -0
  120. package/lib/typescript/commonjs/ui/context/OxyContext.d.ts.map +1 -1
  121. package/lib/typescript/commonjs/ui/navigation/routes.d.ts +1 -1
  122. package/lib/typescript/commonjs/ui/navigation/routes.d.ts.map +1 -1
  123. package/lib/typescript/commonjs/ui/screens/AccountCenterScreen.d.ts.map +1 -1
  124. package/lib/typescript/commonjs/ui/screens/AccountOverviewScreen.d.ts.map +1 -1
  125. package/lib/typescript/commonjs/ui/screens/AccountSettingsScreen.d.ts.map +1 -1
  126. package/lib/typescript/commonjs/ui/screens/AccountSwitcherScreen.d.ts.map +1 -1
  127. package/lib/typescript/commonjs/ui/screens/AccountVerificationScreen.d.ts.map +1 -1
  128. package/lib/typescript/commonjs/ui/screens/CreateManagedAccountScreen.d.ts +5 -0
  129. package/lib/typescript/commonjs/ui/screens/CreateManagedAccountScreen.d.ts.map +1 -0
  130. package/lib/typescript/commonjs/ui/screens/FileManagementScreen.d.ts.map +1 -1
  131. package/lib/typescript/commonjs/ui/screens/HistoryViewScreen.d.ts.map +1 -1
  132. package/lib/typescript/commonjs/ui/screens/PremiumSubscriptionScreen.d.ts.map +1 -1
  133. package/lib/typescript/commonjs/ui/screens/SessionManagementScreen.d.ts.map +1 -1
  134. package/lib/typescript/commonjs/ui/utils/fileManagement.d.ts +0 -4
  135. package/lib/typescript/commonjs/ui/utils/fileManagement.d.ts.map +1 -1
  136. package/lib/typescript/module/index.d.ts +1 -0
  137. package/lib/typescript/module/index.d.ts.map +1 -1
  138. package/lib/typescript/module/ui/components/ActingAsBanner.d.ts +4 -0
  139. package/lib/typescript/module/ui/components/ActingAsBanner.d.ts.map +1 -0
  140. package/lib/typescript/module/ui/components/OxyPayButton.d.ts.map +1 -1
  141. package/lib/typescript/module/ui/components/OxySignInButton.d.ts +0 -1
  142. package/lib/typescript/module/ui/components/OxySignInButton.d.ts.map +1 -1
  143. package/lib/typescript/module/ui/components/SettingRow.d.ts +2 -2
  144. package/lib/typescript/module/ui/components/SettingRow.d.ts.map +1 -1
  145. package/lib/typescript/module/ui/components/fileManagement/FileDetailsModal.d.ts +3 -4
  146. package/lib/typescript/module/ui/components/fileManagement/FileDetailsModal.d.ts.map +1 -1
  147. package/lib/typescript/module/ui/components/fileManagement/UploadPreview.d.ts +2 -3
  148. package/lib/typescript/module/ui/components/fileManagement/UploadPreview.d.ts.map +1 -1
  149. package/lib/typescript/module/ui/components/icon/OxyIcon.d.ts.map +1 -1
  150. package/lib/typescript/module/ui/components/internal/GroupedPillButtons.d.ts.map +1 -1
  151. package/lib/typescript/module/ui/components/internal/PinInput.d.ts.map +1 -1
  152. package/lib/typescript/module/ui/components/modals/DeleteAccountModal.d.ts +2 -2
  153. package/lib/typescript/module/ui/components/modals/DeleteAccountModal.d.ts.map +1 -1
  154. package/lib/typescript/module/ui/context/OxyContext.d.ts +6 -0
  155. package/lib/typescript/module/ui/context/OxyContext.d.ts.map +1 -1
  156. package/lib/typescript/module/ui/navigation/routes.d.ts +1 -1
  157. package/lib/typescript/module/ui/navigation/routes.d.ts.map +1 -1
  158. package/lib/typescript/module/ui/screens/AccountCenterScreen.d.ts.map +1 -1
  159. package/lib/typescript/module/ui/screens/AccountOverviewScreen.d.ts.map +1 -1
  160. package/lib/typescript/module/ui/screens/AccountSettingsScreen.d.ts.map +1 -1
  161. package/lib/typescript/module/ui/screens/AccountSwitcherScreen.d.ts.map +1 -1
  162. package/lib/typescript/module/ui/screens/AccountVerificationScreen.d.ts.map +1 -1
  163. package/lib/typescript/module/ui/screens/CreateManagedAccountScreen.d.ts +5 -0
  164. package/lib/typescript/module/ui/screens/CreateManagedAccountScreen.d.ts.map +1 -0
  165. package/lib/typescript/module/ui/screens/FileManagementScreen.d.ts.map +1 -1
  166. package/lib/typescript/module/ui/screens/HistoryViewScreen.d.ts.map +1 -1
  167. package/lib/typescript/module/ui/screens/PremiumSubscriptionScreen.d.ts.map +1 -1
  168. package/lib/typescript/module/ui/screens/SessionManagementScreen.d.ts.map +1 -1
  169. package/lib/typescript/module/ui/utils/fileManagement.d.ts +0 -4
  170. package/lib/typescript/module/ui/utils/fileManagement.d.ts.map +1 -1
  171. package/package.json +2 -2
  172. package/src/index.ts +3 -0
  173. package/src/ui/components/ActingAsBanner.tsx +135 -0
  174. package/src/ui/components/OxyPayButton.tsx +5 -3
  175. package/src/ui/components/OxySignInButton.tsx +82 -81
  176. package/src/ui/components/SettingRow.tsx +14 -7
  177. package/src/ui/components/fileManagement/FileDetailsModal.tsx +69 -99
  178. package/src/ui/components/fileManagement/UploadPreview.tsx +58 -46
  179. package/src/ui/components/icon/OxyIcon.tsx +5 -4
  180. package/src/ui/components/internal/GroupedPillButtons.tsx +15 -12
  181. package/src/ui/components/internal/PinInput.tsx +4 -3
  182. package/src/ui/components/modals/DeleteAccountModal.tsx +79 -221
  183. package/src/ui/constants/theme.ts +2 -2
  184. package/src/ui/context/OxyContext.tsx +85 -0
  185. package/src/ui/navigation/routes.ts +3 -1
  186. package/src/ui/screens/AccountCenterScreen.tsx +40 -122
  187. package/src/ui/screens/AccountOverviewScreen.tsx +63 -98
  188. package/src/ui/screens/AccountSettingsScreen.tsx +21 -7
  189. package/src/ui/screens/AccountSwitcherScreen.tsx +344 -87
  190. package/src/ui/screens/AccountVerificationScreen.tsx +24 -16
  191. package/src/ui/screens/CreateManagedAccountScreen.tsx +338 -0
  192. package/src/ui/screens/FileManagementScreen.tsx +62 -54
  193. package/src/ui/screens/HistoryViewScreen.tsx +57 -204
  194. package/src/ui/screens/PremiumSubscriptionScreen.tsx +73 -93
  195. package/src/ui/screens/SessionManagementScreen.tsx +101 -73
  196. package/src/ui/utils/fileManagement.ts +0 -30
  197. package/lib/commonjs/ui/utils/confirmAction.js +0 -28
  198. package/lib/commonjs/ui/utils/confirmAction.js.map +0 -1
  199. package/lib/module/ui/utils/confirmAction.js +0 -25
  200. package/lib/module/ui/utils/confirmAction.js.map +0 -1
  201. package/lib/typescript/commonjs/ui/utils/confirmAction.d.ts +0 -7
  202. package/lib/typescript/commonjs/ui/utils/confirmAction.d.ts.map +0 -1
  203. package/lib/typescript/module/ui/utils/confirmAction.d.ts +0 -7
  204. package/lib/typescript/module/ui/utils/confirmAction.d.ts.map +0 -1
  205. package/src/ui/utils/confirmAction.ts +0 -23
@@ -7,7 +7,6 @@ import {
7
7
  StyleSheet,
8
8
  ActivityIndicator,
9
9
  ScrollView,
10
- Alert,
11
10
  Platform,
12
11
  Image,
13
12
  Dimensions,
@@ -17,7 +16,8 @@ import type { ClientSession } from '@oxyhq/core';
17
16
  import { fontFamilies } from '../styles/fonts';
18
17
  import type { User } from '@oxyhq/core';
19
18
  import { toast } from '../../lib/sonner';
20
- import { confirmAction } from '../utils/confirmAction';
19
+ import * as Prompt from '@oxyhq/bloom/prompt';
20
+ import { usePromptControl } from '@oxyhq/bloom/prompt';
21
21
  import OxyIcon from '../components/icon/OxyIcon';
22
22
  import { Ionicons } from '@expo/vector-icons';
23
23
  import Avatar from '../components/Avatar';
@@ -60,11 +60,15 @@ const ModernAccountSwitcherScreen: React.FC<BaseScreenProps> = ({
60
60
  refreshSessions,
61
61
  isLoading = false,
62
62
  isAuthenticated = false,
63
+ actingAs,
64
+ managedAccounts,
65
+ setActingAs,
63
66
  } = useOxy();
64
67
 
65
68
  const [sessionsWithUsers, setSessionsWithUsers] = useState<SessionWithUser[]>([]);
66
69
  const [switchingToUserId, setSwitchingToUserId] = useState<string | null>(null);
67
70
  const [removingUserId, setRemovingUserId] = useState<string | null>(null);
71
+ const [switchingManagedId, setSwitchingManagedId] = useState<string | null>(null);
68
72
 
69
73
  // Device session management state
70
74
  const [showDeviceManagement, setShowDeviceManagement] = useState(false);
@@ -73,6 +77,16 @@ const ModernAccountSwitcherScreen: React.FC<BaseScreenProps> = ({
73
77
  const [remotingLogoutSessionId, setRemoteLogoutSessionId] = useState<string | null>(null);
74
78
  const [loggingOutAllDevices, setLoggingOutAllDevices] = useState(false);
75
79
 
80
+ // Pending state for prompts
81
+ const [pendingRemoveSession, setPendingRemoveSession] = useState<{ sessionId: string; displayName: string } | null>(null);
82
+ const [pendingRemoteLogout, setPendingRemoteLogout] = useState<{ sessionId: string; deviceName: string } | null>(null);
83
+
84
+ // Prompt controls
85
+ const removeSessionPrompt = usePromptControl();
86
+ const logoutAllPrompt = usePromptControl();
87
+ const remoteLogoutPrompt = usePromptControl();
88
+ const logoutAllDevicesPrompt = usePromptControl();
89
+
76
90
  const screenWidth = Dimensions.get('window').width;
77
91
  const { t } = useI18n();
78
92
 
@@ -167,49 +181,74 @@ const ModernAccountSwitcherScreen: React.FC<BaseScreenProps> = ({
167
181
  }
168
182
  }, [activeSessionId, switchSession, onClose, t, switchingToUserId]);
169
183
 
170
- const handleRemoveSession = useCallback(async (sessionId: string, displayName: string) => {
171
- if (removingUserId) return; // Already removing
172
-
173
- confirmAction(
174
- t('accountSwitcher.confirms.remove', { displayName }) || `Are you sure you want to remove ${displayName} from this device? You'll need to sign in again to access this account.`,
175
- async () => {
176
- setRemovingUserId(sessionId);
177
- try {
178
- await removeSession(sessionId);
179
- toast.success(t('accountSwitcher.toasts.removeSuccess') || 'Account removed successfully!');
180
- } catch (error) {
181
- if (__DEV__) {
182
- console.error('Remove session failed:', error);
183
- }
184
- toast.error(t('accountSwitcher.toasts.removeFailed') || 'There was a problem removing the account. Please try again.');
185
- } finally {
186
- setRemovingUserId(null);
187
- }
184
+ const confirmRemoveSession = useCallback((sessionId: string, displayName: string) => {
185
+ if (removingUserId) return;
186
+ setPendingRemoveSession({ sessionId, displayName });
187
+ removeSessionPrompt.open();
188
+ }, [removingUserId, removeSessionPrompt]);
189
+
190
+ const handleRemoveSession = useCallback(async () => {
191
+ if (!pendingRemoveSession) return;
192
+ const { sessionId } = pendingRemoveSession;
193
+ setRemovingUserId(sessionId);
194
+ try {
195
+ await removeSession(sessionId);
196
+ toast.success(t('accountSwitcher.toasts.removeSuccess') || 'Account removed successfully!');
197
+ } catch (error) {
198
+ if (__DEV__) {
199
+ console.error('Remove session failed:', error);
188
200
  }
189
- );
190
- }, [removeSession, t, removingUserId]);
191
-
192
- const handleLogoutAll = useCallback(() => {
193
- confirmAction(
194
- t('accountSwitcher.confirms.logoutAll') || 'Are you sure you want to sign out of all accounts? This will remove all saved accounts from this device.',
195
- async () => {
196
- try {
197
- await logoutAll();
198
- toast.success(t('accountSwitcher.toasts.signOutAllSuccess') || 'All accounts signed out successfully!');
199
- if (onClose) {
200
- onClose();
201
- }
202
- } catch (error) {
203
- if (__DEV__) {
204
- console.error('Logout all failed:', error);
205
- }
206
- const errorMessage = error instanceof Error ? error.message : 'Unknown error occurred';
207
- toast.error(t('accountSwitcher.toasts.signOutAllFailed', { error: errorMessage }) || `There was a problem signing out: ${errorMessage}`);
208
- }
201
+ toast.error(t('accountSwitcher.toasts.removeFailed') || 'There was a problem removing the account. Please try again.');
202
+ } finally {
203
+ setRemovingUserId(null);
204
+ setPendingRemoveSession(null);
205
+ }
206
+ }, [pendingRemoveSession, removeSession, t]);
207
+
208
+ const confirmLogoutAll = useCallback(() => {
209
+ logoutAllPrompt.open();
210
+ }, [logoutAllPrompt]);
211
+
212
+ const handleLogoutAll = useCallback(async () => {
213
+ try {
214
+ await logoutAll();
215
+ toast.success(t('accountSwitcher.toasts.signOutAllSuccess') || 'All accounts signed out successfully!');
216
+ if (onClose) {
217
+ onClose();
218
+ }
219
+ } catch (error) {
220
+ if (__DEV__) {
221
+ console.error('Logout all failed:', error);
209
222
  }
210
- );
223
+ const errorMessage = error instanceof Error ? error.message : 'Unknown error occurred';
224
+ toast.error(t('accountSwitcher.toasts.signOutAllFailed', { error: errorMessage }) || `There was a problem signing out: ${errorMessage}`);
225
+ }
211
226
  }, [logoutAll, onClose, t]);
212
227
 
228
+ const handleSwitchToManagedAccount = useCallback(async (accountId: string) => {
229
+ if (actingAs === accountId) return; // Already acting as this account
230
+ if (switchingManagedId) return; // Already switching
231
+
232
+ setSwitchingManagedId(accountId);
233
+ try {
234
+ setActingAs(accountId);
235
+ toast.success(t('accountSwitcher.toasts.switchSuccess') || 'Switched identity successfully!');
236
+ onClose?.();
237
+ } catch (error) {
238
+ if (__DEV__) {
239
+ console.error('Switch managed account failed:', error);
240
+ }
241
+ toast.error('Failed to switch identity. Please try again.');
242
+ } finally {
243
+ setSwitchingManagedId(null);
244
+ }
245
+ }, [actingAs, switchingManagedId, setActingAs, t, onClose]);
246
+
247
+ const handleSwitchBackToPrimary = useCallback(() => {
248
+ setActingAs(null);
249
+ toast.success('Switched back to primary account');
250
+ }, [setActingAs]);
251
+
213
252
  // Device session management functions - optimized with useCallback
214
253
  const loadAllDeviceSessions = useCallback(async () => {
215
254
  const currentActiveSessionId = activeSessionId ?? null;
@@ -229,30 +268,32 @@ const ModernAccountSwitcherScreen: React.FC<BaseScreenProps> = ({
229
268
  }
230
269
  }, [oxyServices, activeSessionId, t]);
231
270
 
232
- const handleRemoteSessionLogout = useCallback((sessionId: string, deviceName: string) => {
233
- if (remotingLogoutSessionId) return; // Already processing
234
-
235
- confirmAction(
236
- t('accountSwitcher.confirms.remoteLogout', { deviceName }) || `Are you sure you want to sign out from "${deviceName}"? This will end the session on that device.`,
237
- async () => {
238
- setRemoteLogoutSessionId(sessionId);
239
- try {
240
- await oxyServices?.logoutSession((activeSessionId ?? null) || '', sessionId);
241
- await loadAllDeviceSessions();
242
- toast.success(t('accountSwitcher.toasts.remoteSignOutSuccess', { deviceName }) || `Signed out from ${deviceName} successfully!`);
243
- } catch (error) {
244
- if (__DEV__) {
245
- console.error('Remote logout failed:', error);
246
- }
247
- toast.error(t('accountSwitcher.toasts.remoteSignOutFailed') || 'There was a problem signing out from the device. Please try again.');
248
- } finally {
249
- setRemoteLogoutSessionId(null);
250
- }
271
+ const confirmRemoteSessionLogout = useCallback((sessionId: string, deviceName: string) => {
272
+ if (remotingLogoutSessionId) return;
273
+ setPendingRemoteLogout({ sessionId, deviceName });
274
+ remoteLogoutPrompt.open();
275
+ }, [remotingLogoutSessionId, remoteLogoutPrompt]);
276
+
277
+ const handleRemoteSessionLogout = useCallback(async () => {
278
+ if (!pendingRemoteLogout) return;
279
+ const { sessionId } = pendingRemoteLogout;
280
+ setRemoteLogoutSessionId(sessionId);
281
+ try {
282
+ await oxyServices?.logoutSession((activeSessionId ?? null) || '', sessionId);
283
+ await loadAllDeviceSessions();
284
+ toast.success(t('accountSwitcher.toasts.remoteSignOutSuccess', { deviceName: pendingRemoteLogout.deviceName }) || `Signed out from ${pendingRemoteLogout.deviceName} successfully!`);
285
+ } catch (error) {
286
+ if (__DEV__) {
287
+ console.error('Remote logout failed:', error);
251
288
  }
252
- );
253
- }, [activeSessionId, oxyServices, loadAllDeviceSessions, t, remotingLogoutSessionId]);
289
+ toast.error(t('accountSwitcher.toasts.remoteSignOutFailed') || 'There was a problem signing out from the device. Please try again.');
290
+ } finally {
291
+ setRemoteLogoutSessionId(null);
292
+ setPendingRemoteLogout(null);
293
+ }
294
+ }, [pendingRemoteLogout, activeSessionId, oxyServices, loadAllDeviceSessions, t]);
254
295
 
255
- const handleLogoutAllDevices = useCallback(() => {
296
+ const confirmLogoutAllDevices = useCallback(() => {
256
297
  const otherDevicesCount = deviceSessions.filter(session => !session.isCurrent).length;
257
298
 
258
299
  if (otherDevicesCount === 0) {
@@ -260,27 +301,25 @@ const ModernAccountSwitcherScreen: React.FC<BaseScreenProps> = ({
260
301
  return;
261
302
  }
262
303
 
263
- if (loggingOutAllDevices) return; // Already processing
264
-
265
- confirmAction(
266
- t('accountSwitcher.confirms.logoutOthers', { count: otherDevicesCount }) || `Are you sure you want to sign out from all ${otherDevicesCount} other device(s)? This will end sessions on all other devices except this one.`,
267
- async () => {
268
- setLoggingOutAllDevices(true);
269
- try {
270
- await oxyServices?.logoutAllDeviceSessions((activeSessionId ?? null) || '');
271
- await loadAllDeviceSessions();
272
- toast.success(t('accountSwitcher.toasts.signOutOthersSuccess') || 'Signed out from all other devices successfully!');
273
- } catch (error) {
274
- if (__DEV__) {
275
- console.error('Logout all devices failed:', error);
276
- }
277
- toast.error(t('accountSwitcher.toasts.signOutOthersFailed') || 'There was a problem signing out from other devices. Please try again.');
278
- } finally {
279
- setLoggingOutAllDevices(false);
280
- }
304
+ if (loggingOutAllDevices) return;
305
+ logoutAllDevicesPrompt.open();
306
+ }, [deviceSessions, loggingOutAllDevices, logoutAllDevicesPrompt, t]);
307
+
308
+ const handleLogoutAllDevices = useCallback(async () => {
309
+ setLoggingOutAllDevices(true);
310
+ try {
311
+ await oxyServices?.logoutAllDeviceSessions((activeSessionId ?? null) || '');
312
+ await loadAllDeviceSessions();
313
+ toast.success(t('accountSwitcher.toasts.signOutOthersSuccess') || 'Signed out from all other devices successfully!');
314
+ } catch (error) {
315
+ if (__DEV__) {
316
+ console.error('Logout all devices failed:', error);
281
317
  }
282
- );
283
- }, [deviceSessions, activeSessionId, oxyServices, loadAllDeviceSessions, t, loggingOutAllDevices]);
318
+ toast.error(t('accountSwitcher.toasts.signOutOthersFailed') || 'There was a problem signing out from other devices. Please try again.');
319
+ } finally {
320
+ setLoggingOutAllDevices(false);
321
+ }
322
+ }, [activeSessionId, oxyServices, loadAllDeviceSessions, t]);
284
323
 
285
324
  // Memoize filtered sessions for performance
286
325
  const otherSessions = useMemo(
@@ -288,6 +327,11 @@ const ModernAccountSwitcherScreen: React.FC<BaseScreenProps> = ({
288
327
  [sessionsWithUsers, activeSessionId]
289
328
  );
290
329
 
330
+ const otherDevicesCount = useMemo(
331
+ () => deviceSessions.filter(session => !session.isCurrent).length,
332
+ [deviceSessions]
333
+ );
334
+
291
335
  return (
292
336
  <View style={[styles.container, { backgroundColor: bloomTheme.colors.background }]}>
293
337
  {/* Header */}
@@ -412,7 +456,7 @@ const ModernAccountSwitcherScreen: React.FC<BaseScreenProps> = ({
412
456
  </TouchableOpacity>
413
457
  <TouchableOpacity
414
458
  style={styles.removeButton}
415
- onPress={() => handleRemoveSession(sessionWithUser.sessionId, displayName)}
459
+ onPress={() => confirmRemoveSession(sessionWithUser.sessionId, displayName)}
416
460
  disabled={isSwitching || isRemoving}
417
461
  >
418
462
  {isRemoving ? (
@@ -428,6 +472,151 @@ const ModernAccountSwitcherScreen: React.FC<BaseScreenProps> = ({
428
472
  </View>
429
473
  )}
430
474
 
475
+ {/* Acting as banner - show switch-back when acting as a managed account */}
476
+ {actingAs && (
477
+ <View style={styles.section}>
478
+ <TouchableOpacity
479
+ style={[styles.settingItem, styles.firstSettingItem, styles.lastSettingItem, styles.actingAsBanner]}
480
+ onPress={handleSwitchBackToPrimary}
481
+ activeOpacity={0.7}
482
+ >
483
+ <View style={styles.settingInfo}>
484
+ <Text style={styles.settingLabel}>Switch back to primary account</Text>
485
+ <Text style={styles.settingDescription}>You are currently acting as another identity</Text>
486
+ </View>
487
+ <View style={styles.switchBackButton}>
488
+ <Text style={styles.switchBackButtonText}>Switch Back</Text>
489
+ </View>
490
+ </TouchableOpacity>
491
+ </View>
492
+ )}
493
+
494
+ {/* Managed Accounts */}
495
+ {managedAccounts.length > 0 && (
496
+ <View style={styles.section}>
497
+ <Text style={styles.sectionTitle}>Managed Accounts</Text>
498
+ <Text style={styles.sectionSubtitle}>Identities you manage</Text>
499
+
500
+ {managedAccounts.map((managed, index) => {
501
+ const account = managed.account;
502
+ if (!account) return null;
503
+
504
+ const isActive = actingAs === managed.accountId;
505
+ const isSwitching = switchingManagedId === managed.accountId;
506
+ const isFirst = index === 0;
507
+ const isLast = index === managedAccounts.length - 1;
508
+
509
+ const managedDisplayName = typeof account.name === 'object'
510
+ ? account.name.full || account.name.first || account.username
511
+ : account.name || account.username || 'Unknown';
512
+
513
+ // Determine the manager role for badge display
514
+ const myRole = managed.managers?.find(
515
+ (m) => m.userId === user?.id
516
+ )?.role ?? 'owner';
517
+
518
+ return (
519
+ <TouchableOpacity
520
+ key={`managed-${managed.accountId}`}
521
+ style={[
522
+ styles.settingItem,
523
+ isFirst && styles.firstSettingItem,
524
+ isLast && styles.lastSettingItem,
525
+ isActive && styles.currentAccountCard,
526
+ ]}
527
+ onPress={() => handleSwitchToManagedAccount(managed.accountId)}
528
+ disabled={isActive || isSwitching}
529
+ activeOpacity={0.7}
530
+ >
531
+ <View style={styles.userIcon}>
532
+ {account.avatar ? (
533
+ <Image source={{ uri: oxyServices.getFileDownloadUrl(account.avatar, 'thumb') }} style={styles.accountAvatarImage} />
534
+ ) : (
535
+ <View style={[styles.accountAvatarFallback, styles.managedAvatarFallback]}>
536
+ <Text style={styles.accountAvatarText}>
537
+ {managedDisplayName.charAt(0).toUpperCase()}
538
+ </Text>
539
+ </View>
540
+ )}
541
+ {isActive && (
542
+ <View style={styles.activeBadge}>
543
+ <OxyIcon name="checkmark" size={12} color="#fff" />
544
+ </View>
545
+ )}
546
+ </View>
547
+ <View style={styles.settingInfo}>
548
+ <View>
549
+ <Text style={styles.settingLabel}>{managedDisplayName}</Text>
550
+ <Text style={styles.settingDescription}>@{account.username}</Text>
551
+ </View>
552
+ </View>
553
+ <View style={styles.accountActions}>
554
+ <View style={styles.roleBadge}>
555
+ <Text style={styles.roleBadgeText}>{myRole}</Text>
556
+ </View>
557
+ {isActive ? (
558
+ <View style={styles.currentBadge}>
559
+ <Text style={styles.currentBadgeText}>Current</Text>
560
+ </View>
561
+ ) : (
562
+ <TouchableOpacity
563
+ style={styles.switchButton}
564
+ onPress={() => handleSwitchToManagedAccount(managed.accountId)}
565
+ disabled={isSwitching}
566
+ >
567
+ {isSwitching ? (
568
+ <ActivityIndicator size="small" color="#fff" />
569
+ ) : (
570
+ <Text style={styles.switchButtonText}>Act As</Text>
571
+ )}
572
+ </TouchableOpacity>
573
+ )}
574
+ </View>
575
+ </TouchableOpacity>
576
+ );
577
+ })}
578
+
579
+ {/* Create New Identity */}
580
+ <TouchableOpacity
581
+ style={[styles.settingItem, styles.firstSettingItem, styles.lastSettingItem, { marginTop: 8 }]}
582
+ onPress={() => navigate?.('CreateManagedAccount')}
583
+ activeOpacity={0.7}
584
+ >
585
+ <View style={styles.userIcon}>
586
+ <View style={[styles.accountAvatarFallback, { backgroundColor: '#007AFF20' }]}>
587
+ <OxyIcon name="add" size={20} color="#007AFF" />
588
+ </View>
589
+ </View>
590
+ <View style={styles.settingInfo}>
591
+ <Text style={[styles.settingLabel, { color: '#007AFF' }]}>Create New Identity</Text>
592
+ <Text style={styles.settingDescription}>Add a managed sub-account</Text>
593
+ </View>
594
+ </TouchableOpacity>
595
+ </View>
596
+ )}
597
+
598
+ {/* Create first managed account (when none exist yet) */}
599
+ {managedAccounts.length === 0 && isAuthenticated && (
600
+ <View style={styles.section}>
601
+ <Text style={styles.sectionTitle}>Managed Accounts</Text>
602
+ <TouchableOpacity
603
+ style={[styles.settingItem, styles.firstSettingItem, styles.lastSettingItem]}
604
+ onPress={() => navigate?.('CreateManagedAccount')}
605
+ activeOpacity={0.7}
606
+ >
607
+ <View style={styles.userIcon}>
608
+ <View style={[styles.accountAvatarFallback, { backgroundColor: '#007AFF20' }]}>
609
+ <OxyIcon name="add" size={20} color="#007AFF" />
610
+ </View>
611
+ </View>
612
+ <View style={styles.settingInfo}>
613
+ <Text style={[styles.settingLabel, { color: '#007AFF' }]}>Create New Identity</Text>
614
+ <Text style={styles.settingDescription}>Create a managed sub-account you control</Text>
615
+ </View>
616
+ </TouchableOpacity>
617
+ </View>
618
+ )}
619
+
431
620
  {/* Quick Actions */}
432
621
  <View style={styles.section}>
433
622
  <Text style={styles.sectionTitle}>Quick Actions</Text>
@@ -456,7 +645,7 @@ const ModernAccountSwitcherScreen: React.FC<BaseScreenProps> = ({
456
645
  iconColor: '#FF3B30',
457
646
  title: 'Sign Out All Accounts',
458
647
  subtitle: 'Remove all accounts from this device',
459
- onPress: handleLogoutAll,
648
+ onPress: confirmLogoutAll,
460
649
  disabled: sessionsWithUsers.length === 0,
461
650
  },
462
651
  ]}
@@ -508,12 +697,12 @@ const ModernAccountSwitcherScreen: React.FC<BaseScreenProps> = ({
508
697
  iconColor: session.isCurrent ? '#34C759' : '#8E8E93',
509
698
  title: `${session.deviceName} ${session.isCurrent ? `(${t('accountSwitcher.device.thisDevice') || 'This device'})` : ''}`,
510
699
  subtitle: t('accountSwitcher.device.lastActive', { date: new Date(session.lastActive).toLocaleDateString() }) || `Last active: ${new Date(session.lastActive).toLocaleDateString()}`,
511
- onPress: session.isCurrent ? undefined : () => handleRemoteSessionLogout(session.sessionId, session.deviceName),
700
+ onPress: session.isCurrent ? undefined : () => confirmRemoteSessionLogout(session.sessionId, session.deviceName),
512
701
  disabled: session.isCurrent || remotingLogoutSessionId === session.sessionId,
513
702
  customContent: !session.isCurrent ? (
514
703
  <TouchableOpacity
515
704
  style={styles.removeButton}
516
- onPress={() => handleRemoteSessionLogout(session.sessionId, session.deviceName)}
705
+ onPress={() => confirmRemoteSessionLogout(session.sessionId, session.deviceName)}
517
706
  disabled={remotingLogoutSessionId === session.sessionId}
518
707
  >
519
708
  {remotingLogoutSessionId === session.sessionId ? (
@@ -566,6 +755,38 @@ const ModernAccountSwitcherScreen: React.FC<BaseScreenProps> = ({
566
755
  </>
567
756
  )}
568
757
  </ScrollView>
758
+ <Prompt.Basic
759
+ control={removeSessionPrompt}
760
+ title={t('accountSwitcher.confirms.removeTitle') || 'Remove Account'}
761
+ description={pendingRemoveSession ? (t('accountSwitcher.confirms.remove', { displayName: pendingRemoveSession.displayName }) || `Are you sure you want to remove ${pendingRemoveSession.displayName} from this device? You'll need to sign in again to access this account.`) : ''}
762
+ onConfirm={handleRemoveSession}
763
+ confirmButtonCta={t('common.remove') || 'Remove'}
764
+ confirmButtonColor='negative'
765
+ />
766
+ <Prompt.Basic
767
+ control={logoutAllPrompt}
768
+ title={t('accountSwitcher.confirms.logoutAllTitle') || 'Sign Out All'}
769
+ description={t('accountSwitcher.confirms.logoutAll') || 'Are you sure you want to sign out of all accounts? This will remove all saved accounts from this device.'}
770
+ onConfirm={handleLogoutAll}
771
+ confirmButtonCta={t('common.signOutAll') || 'Sign Out All'}
772
+ confirmButtonColor='negative'
773
+ />
774
+ <Prompt.Basic
775
+ control={remoteLogoutPrompt}
776
+ title={t('accountSwitcher.confirms.remoteLogoutTitle') || 'Remote Sign Out'}
777
+ description={pendingRemoteLogout ? (t('accountSwitcher.confirms.remoteLogout', { deviceName: pendingRemoteLogout.deviceName }) || `Are you sure you want to sign out from "${pendingRemoteLogout.deviceName}"? This will end the session on that device.`) : ''}
778
+ onConfirm={handleRemoteSessionLogout}
779
+ confirmButtonCta={t('common.signOut') || 'Sign Out'}
780
+ confirmButtonColor='negative'
781
+ />
782
+ <Prompt.Basic
783
+ control={logoutAllDevicesPrompt}
784
+ title={t('accountSwitcher.confirms.logoutOthersTitle') || 'Sign Out Other Devices'}
785
+ description={t('accountSwitcher.confirms.logoutOthers', { count: otherDevicesCount }) || `Are you sure you want to sign out from all ${otherDevicesCount} other device(s)? This will end sessions on all other devices except this one.`}
786
+ onConfirm={handleLogoutAllDevices}
787
+ confirmButtonCta={t('common.signOutAll') || 'Sign Out All'}
788
+ confirmButtonColor='negative'
789
+ />
569
790
  </View>
570
791
  );
571
792
  };
@@ -729,6 +950,42 @@ const styles = StyleSheet.create({
729
950
  fontSize: 16,
730
951
  fontWeight: '600',
731
952
  },
953
+ sectionSubtitle: {
954
+ fontSize: 13,
955
+ color: '#888',
956
+ marginBottom: 12,
957
+ },
958
+ managedAvatarFallback: {
959
+ backgroundColor: '#5856D6',
960
+ },
961
+ roleBadge: {
962
+ backgroundColor: '#F2F2F7',
963
+ paddingHorizontal: 8,
964
+ paddingVertical: 3,
965
+ borderRadius: 8,
966
+ },
967
+ roleBadgeText: {
968
+ color: '#666',
969
+ fontSize: 11,
970
+ fontWeight: '500',
971
+ textTransform: 'capitalize',
972
+ },
973
+ actingAsBanner: {
974
+ borderWidth: 2,
975
+ borderColor: '#FF9500',
976
+ backgroundColor: '#FF950010',
977
+ },
978
+ switchBackButton: {
979
+ backgroundColor: '#FF9500',
980
+ paddingHorizontal: 14,
981
+ paddingVertical: 8,
982
+ borderRadius: 16,
983
+ },
984
+ switchBackButtonText: {
985
+ color: '#fff',
986
+ fontSize: 13,
987
+ fontWeight: '600',
988
+ },
732
989
  });
733
990
 
734
991
  export default ModernAccountSwitcherScreen;
@@ -7,10 +7,11 @@ import {
7
7
  TextInput,
8
8
  TouchableOpacity,
9
9
  ActivityIndicator,
10
- Alert,
11
10
  } from 'react-native';
12
11
  import type { BaseScreenProps } from '../types/navigation';
13
12
  import { toast } from '../../lib/sonner';
13
+ import * as Prompt from '@oxyhq/bloom/prompt';
14
+ import { usePromptControl } from '@oxyhq/bloom/prompt';
14
15
  import { Header, Section } from '../components';
15
16
  import { useI18n } from '../hooks/useI18n';
16
17
  import { useTheme } from '@oxyhq/bloom/theme';
@@ -27,9 +28,19 @@ const AccountVerificationScreen: React.FC<BaseScreenProps> = ({
27
28
  const [reason, setReason] = useState('');
28
29
  const [evidence, setEvidence] = useState('');
29
30
  const [isSubmitting, setIsSubmitting] = useState(false);
31
+ const [successMessage, setSuccessMessage] = useState('');
30
32
 
31
33
  const bloomTheme = useTheme();
32
34
 
35
+ // Prompt controls
36
+ const successPrompt = usePromptControl();
37
+
38
+ const handleSuccessAcknowledged = useCallback(() => {
39
+ setReason('');
40
+ setEvidence('');
41
+ goBack?.();
42
+ }, [goBack]);
43
+
33
44
  const handleSubmit = useCallback(async () => {
34
45
  if (!reason.trim()) {
35
46
  toast.error(t('accountVerification.reasonRequired') || 'Please provide a reason for verification');
@@ -48,20 +59,10 @@ const AccountVerificationScreen: React.FC<BaseScreenProps> = ({
48
59
  evidence.trim() || undefined
49
60
  );
50
61
 
51
- Alert.alert(
52
- t('accountVerification.successTitle') || 'Request Submitted',
53
- t('accountVerification.successMessage') || `Your verification request has been submitted. Request ID: ${result.requestId}`,
54
- [
55
- {
56
- text: t('accountVerification.ok') || 'OK',
57
- onPress: () => {
58
- setReason('');
59
- setEvidence('');
60
- goBack?.();
61
- },
62
- },
63
- ]
62
+ setSuccessMessage(
63
+ t('accountVerification.successMessage') || `Your verification request has been submitted. Request ID: ${result.requestId}`
64
64
  );
65
+ successPrompt.open();
65
66
  } catch (error: unknown) {
66
67
  if (__DEV__) {
67
68
  console.error('Failed to submit verification request:', error);
@@ -72,7 +73,7 @@ const AccountVerificationScreen: React.FC<BaseScreenProps> = ({
72
73
  } finally {
73
74
  setIsSubmitting(false);
74
75
  }
75
- }, [reason, evidence, oxyServices, t, goBack]);
76
+ }, [reason, evidence, oxyServices, t, successPrompt]);
76
77
 
77
78
  return (
78
79
  <View style={[styles.container, { backgroundColor: bloomTheme.colors.background }]}>
@@ -158,6 +159,14 @@ const AccountVerificationScreen: React.FC<BaseScreenProps> = ({
158
159
  </Text>
159
160
  </Section>
160
161
  </ScrollView>
162
+ <Prompt.Basic
163
+ control={successPrompt}
164
+ title={t('accountVerification.successTitle') || 'Request Submitted'}
165
+ description={successMessage}
166
+ onConfirm={handleSuccessAcknowledged}
167
+ confirmButtonCta={t('accountVerification.ok') || 'OK'}
168
+ showCancel={false}
169
+ />
161
170
  </View>
162
171
  );
163
172
  };
@@ -214,4 +223,3 @@ const styles = StyleSheet.create({
214
223
  });
215
224
 
216
225
  export default React.memo(AccountVerificationScreen);
217
-