@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
@@ -4,7 +4,8 @@ import { useState, useEffect, useMemo, useCallback } from 'react';
4
4
  import { View, Text, TouchableOpacity, StyleSheet, ActivityIndicator, ScrollView, Platform, Image, Dimensions } from 'react-native';
5
5
  import { fontFamilies } from "../styles/fonts.js";
6
6
  import { toast } from '../../lib/sonner';
7
- import { confirmAction } from "../utils/confirmAction.js";
7
+ import * as Prompt from '@oxyhq/bloom/prompt';
8
+ import { usePromptControl } from '@oxyhq/bloom/prompt';
8
9
  import OxyIcon from "../components/icon/OxyIcon.js";
9
10
  import { Header, GroupedSection, LoadingState } from "../components/index.js";
10
11
  import { useI18n } from "../hooks/useI18n.js";
@@ -29,11 +30,15 @@ const ModernAccountSwitcherScreen = ({
29
30
  logoutAll,
30
31
  refreshSessions,
31
32
  isLoading = false,
32
- isAuthenticated = false
33
+ isAuthenticated = false,
34
+ actingAs,
35
+ managedAccounts,
36
+ setActingAs
33
37
  } = useOxy();
34
38
  const [sessionsWithUsers, setSessionsWithUsers] = useState([]);
35
39
  const [switchingToUserId, setSwitchingToUserId] = useState(null);
36
40
  const [removingUserId, setRemovingUserId] = useState(null);
41
+ const [switchingManagedId, setSwitchingManagedId] = useState(null);
37
42
 
38
43
  // Device session management state
39
44
  const [showDeviceManagement, setShowDeviceManagement] = useState(false);
@@ -41,6 +46,16 @@ const ModernAccountSwitcherScreen = ({
41
46
  const [loadingDeviceSessions, setLoadingDeviceSessions] = useState(false);
42
47
  const [remotingLogoutSessionId, setRemoteLogoutSessionId] = useState(null);
43
48
  const [loggingOutAllDevices, setLoggingOutAllDevices] = useState(false);
49
+
50
+ // Pending state for prompts
51
+ const [pendingRemoveSession, setPendingRemoveSession] = useState(null);
52
+ const [pendingRemoteLogout, setPendingRemoteLogout] = useState(null);
53
+
54
+ // Prompt controls
55
+ const removeSessionPrompt = usePromptControl();
56
+ const logoutAllPrompt = usePromptControl();
57
+ const remoteLogoutPrompt = usePromptControl();
58
+ const logoutAllDevicesPrompt = usePromptControl();
44
59
  const screenWidth = Dimensions.get('window').width;
45
60
  const {
46
61
  t
@@ -135,45 +150,75 @@ const ModernAccountSwitcherScreen = ({
135
150
  setSwitchingToUserId(null);
136
151
  }
137
152
  }, [activeSessionId, switchSession, onClose, t, switchingToUserId]);
138
- const handleRemoveSession = useCallback(async (sessionId, displayName) => {
139
- if (removingUserId) return; // Already removing
140
-
141
- confirmAction(t('accountSwitcher.confirms.remove', {
153
+ const confirmRemoveSession = useCallback((sessionId, displayName) => {
154
+ if (removingUserId) return;
155
+ setPendingRemoveSession({
156
+ sessionId,
142
157
  displayName
143
- }) || `Are you sure you want to remove ${displayName} from this device? You'll need to sign in again to access this account.`, async () => {
144
- setRemovingUserId(sessionId);
145
- try {
146
- await removeSession(sessionId);
147
- toast.success(t('accountSwitcher.toasts.removeSuccess') || 'Account removed successfully!');
148
- } catch (error) {
149
- if (__DEV__) {
150
- console.error('Remove session failed:', error);
151
- }
152
- toast.error(t('accountSwitcher.toasts.removeFailed') || 'There was a problem removing the account. Please try again.');
153
- } finally {
154
- setRemovingUserId(null);
155
- }
156
158
  });
157
- }, [removeSession, t, removingUserId]);
158
- const handleLogoutAll = useCallback(() => {
159
- confirmAction(t('accountSwitcher.confirms.logoutAll') || 'Are you sure you want to sign out of all accounts? This will remove all saved accounts from this device.', async () => {
160
- try {
161
- await logoutAll();
162
- toast.success(t('accountSwitcher.toasts.signOutAllSuccess') || 'All accounts signed out successfully!');
163
- if (onClose) {
164
- onClose();
165
- }
166
- } catch (error) {
167
- if (__DEV__) {
168
- console.error('Logout all failed:', error);
169
- }
170
- const errorMessage = error instanceof Error ? error.message : 'Unknown error occurred';
171
- toast.error(t('accountSwitcher.toasts.signOutAllFailed', {
172
- error: errorMessage
173
- }) || `There was a problem signing out: ${errorMessage}`);
159
+ removeSessionPrompt.open();
160
+ }, [removingUserId, removeSessionPrompt]);
161
+ const handleRemoveSession = useCallback(async () => {
162
+ if (!pendingRemoveSession) return;
163
+ const {
164
+ sessionId
165
+ } = pendingRemoveSession;
166
+ setRemovingUserId(sessionId);
167
+ try {
168
+ await removeSession(sessionId);
169
+ toast.success(t('accountSwitcher.toasts.removeSuccess') || 'Account removed successfully!');
170
+ } catch (error) {
171
+ if (__DEV__) {
172
+ console.error('Remove session failed:', error);
174
173
  }
175
- });
174
+ toast.error(t('accountSwitcher.toasts.removeFailed') || 'There was a problem removing the account. Please try again.');
175
+ } finally {
176
+ setRemovingUserId(null);
177
+ setPendingRemoveSession(null);
178
+ }
179
+ }, [pendingRemoveSession, removeSession, t]);
180
+ const confirmLogoutAll = useCallback(() => {
181
+ logoutAllPrompt.open();
182
+ }, [logoutAllPrompt]);
183
+ const handleLogoutAll = useCallback(async () => {
184
+ try {
185
+ await logoutAll();
186
+ toast.success(t('accountSwitcher.toasts.signOutAllSuccess') || 'All accounts signed out successfully!');
187
+ if (onClose) {
188
+ onClose();
189
+ }
190
+ } catch (error) {
191
+ if (__DEV__) {
192
+ console.error('Logout all failed:', error);
193
+ }
194
+ const errorMessage = error instanceof Error ? error.message : 'Unknown error occurred';
195
+ toast.error(t('accountSwitcher.toasts.signOutAllFailed', {
196
+ error: errorMessage
197
+ }) || `There was a problem signing out: ${errorMessage}`);
198
+ }
176
199
  }, [logoutAll, onClose, t]);
200
+ const handleSwitchToManagedAccount = useCallback(async accountId => {
201
+ if (actingAs === accountId) return; // Already acting as this account
202
+ if (switchingManagedId) return; // Already switching
203
+
204
+ setSwitchingManagedId(accountId);
205
+ try {
206
+ setActingAs(accountId);
207
+ toast.success(t('accountSwitcher.toasts.switchSuccess') || 'Switched identity successfully!');
208
+ onClose?.();
209
+ } catch (error) {
210
+ if (__DEV__) {
211
+ console.error('Switch managed account failed:', error);
212
+ }
213
+ toast.error('Failed to switch identity. Please try again.');
214
+ } finally {
215
+ setSwitchingManagedId(null);
216
+ }
217
+ }, [actingAs, switchingManagedId, setActingAs, t, onClose]);
218
+ const handleSwitchBackToPrimary = useCallback(() => {
219
+ setActingAs(null);
220
+ toast.success('Switched back to primary account');
221
+ }, [setActingAs]);
177
222
 
178
223
  // Device session management functions - optimized with useCallback
179
224
  const loadAllDeviceSessions = useCallback(async () => {
@@ -192,58 +237,64 @@ const ModernAccountSwitcherScreen = ({
192
237
  setLoadingDeviceSessions(false);
193
238
  }
194
239
  }, [oxyServices, activeSessionId, t]);
195
- const handleRemoteSessionLogout = useCallback((sessionId, deviceName) => {
196
- if (remotingLogoutSessionId) return; // Already processing
197
-
198
- confirmAction(t('accountSwitcher.confirms.remoteLogout', {
240
+ const confirmRemoteSessionLogout = useCallback((sessionId, deviceName) => {
241
+ if (remotingLogoutSessionId) return;
242
+ setPendingRemoteLogout({
243
+ sessionId,
199
244
  deviceName
200
- }) || `Are you sure you want to sign out from "${deviceName}"? This will end the session on that device.`, async () => {
201
- setRemoteLogoutSessionId(sessionId);
202
- try {
203
- await oxyServices?.logoutSession((activeSessionId ?? null) || '', sessionId);
204
- await loadAllDeviceSessions();
205
- toast.success(t('accountSwitcher.toasts.remoteSignOutSuccess', {
206
- deviceName
207
- }) || `Signed out from ${deviceName} successfully!`);
208
- } catch (error) {
209
- if (__DEV__) {
210
- console.error('Remote logout failed:', error);
211
- }
212
- toast.error(t('accountSwitcher.toasts.remoteSignOutFailed') || 'There was a problem signing out from the device. Please try again.');
213
- } finally {
214
- setRemoteLogoutSessionId(null);
215
- }
216
245
  });
217
- }, [activeSessionId, oxyServices, loadAllDeviceSessions, t, remotingLogoutSessionId]);
218
- const handleLogoutAllDevices = useCallback(() => {
246
+ remoteLogoutPrompt.open();
247
+ }, [remotingLogoutSessionId, remoteLogoutPrompt]);
248
+ const handleRemoteSessionLogout = useCallback(async () => {
249
+ if (!pendingRemoteLogout) return;
250
+ const {
251
+ sessionId
252
+ } = pendingRemoteLogout;
253
+ setRemoteLogoutSessionId(sessionId);
254
+ try {
255
+ await oxyServices?.logoutSession((activeSessionId ?? null) || '', sessionId);
256
+ await loadAllDeviceSessions();
257
+ toast.success(t('accountSwitcher.toasts.remoteSignOutSuccess', {
258
+ deviceName: pendingRemoteLogout.deviceName
259
+ }) || `Signed out from ${pendingRemoteLogout.deviceName} successfully!`);
260
+ } catch (error) {
261
+ if (__DEV__) {
262
+ console.error('Remote logout failed:', error);
263
+ }
264
+ toast.error(t('accountSwitcher.toasts.remoteSignOutFailed') || 'There was a problem signing out from the device. Please try again.');
265
+ } finally {
266
+ setRemoteLogoutSessionId(null);
267
+ setPendingRemoteLogout(null);
268
+ }
269
+ }, [pendingRemoteLogout, activeSessionId, oxyServices, loadAllDeviceSessions, t]);
270
+ const confirmLogoutAllDevices = useCallback(() => {
219
271
  const otherDevicesCount = deviceSessions.filter(session => !session.isCurrent).length;
220
272
  if (otherDevicesCount === 0) {
221
273
  toast.info(t('accountSwitcher.toasts.noOtherDeviceSessions') || 'No other device sessions found to sign out from.');
222
274
  return;
223
275
  }
224
- if (loggingOutAllDevices) return; // Already processing
225
-
226
- confirmAction(t('accountSwitcher.confirms.logoutOthers', {
227
- count: otherDevicesCount
228
- }) || `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.`, async () => {
229
- setLoggingOutAllDevices(true);
230
- try {
231
- await oxyServices?.logoutAllDeviceSessions((activeSessionId ?? null) || '');
232
- await loadAllDeviceSessions();
233
- toast.success(t('accountSwitcher.toasts.signOutOthersSuccess') || 'Signed out from all other devices successfully!');
234
- } catch (error) {
235
- if (__DEV__) {
236
- console.error('Logout all devices failed:', error);
237
- }
238
- toast.error(t('accountSwitcher.toasts.signOutOthersFailed') || 'There was a problem signing out from other devices. Please try again.');
239
- } finally {
240
- setLoggingOutAllDevices(false);
276
+ if (loggingOutAllDevices) return;
277
+ logoutAllDevicesPrompt.open();
278
+ }, [deviceSessions, loggingOutAllDevices, logoutAllDevicesPrompt, t]);
279
+ const handleLogoutAllDevices = useCallback(async () => {
280
+ setLoggingOutAllDevices(true);
281
+ try {
282
+ await oxyServices?.logoutAllDeviceSessions((activeSessionId ?? null) || '');
283
+ await loadAllDeviceSessions();
284
+ toast.success(t('accountSwitcher.toasts.signOutOthersSuccess') || 'Signed out from all other devices successfully!');
285
+ } catch (error) {
286
+ if (__DEV__) {
287
+ console.error('Logout all devices failed:', error);
241
288
  }
242
- });
243
- }, [deviceSessions, activeSessionId, oxyServices, loadAllDeviceSessions, t, loggingOutAllDevices]);
289
+ toast.error(t('accountSwitcher.toasts.signOutOthersFailed') || 'There was a problem signing out from other devices. Please try again.');
290
+ } finally {
291
+ setLoggingOutAllDevices(false);
292
+ }
293
+ }, [activeSessionId, oxyServices, loadAllDeviceSessions, t]);
244
294
 
245
295
  // Memoize filtered sessions for performance
246
296
  const otherSessions = useMemo(() => sessionsWithUsers.filter(s => s.sessionId !== (activeSessionId ?? null)), [sessionsWithUsers, activeSessionId]);
297
+ const otherDevicesCount = useMemo(() => deviceSessions.filter(session => !session.isCurrent).length, [deviceSessions]);
247
298
  return /*#__PURE__*/_jsxs(View, {
248
299
  style: [styles.container, {
249
300
  backgroundColor: bloomTheme.colors.background
@@ -377,7 +428,7 @@ const ModernAccountSwitcherScreen = ({
377
428
  })
378
429
  }), /*#__PURE__*/_jsx(TouchableOpacity, {
379
430
  style: styles.removeButton,
380
- onPress: () => handleRemoveSession(sessionWithUser.sessionId, displayName),
431
+ onPress: () => confirmRemoveSession(sessionWithUser.sessionId, displayName),
381
432
  disabled: isSwitching || isRemoving,
382
433
  children: isRemoving ? /*#__PURE__*/_jsx(ActivityIndicator, {
383
434
  size: "small",
@@ -391,6 +442,178 @@ const ModernAccountSwitcherScreen = ({
391
442
  })]
392
443
  }, `session-${sessionWithUser.sessionId}-${index}`);
393
444
  })]
445
+ }), actingAs && /*#__PURE__*/_jsx(View, {
446
+ style: styles.section,
447
+ children: /*#__PURE__*/_jsxs(TouchableOpacity, {
448
+ style: [styles.settingItem, styles.firstSettingItem, styles.lastSettingItem, styles.actingAsBanner],
449
+ onPress: handleSwitchBackToPrimary,
450
+ activeOpacity: 0.7,
451
+ children: [/*#__PURE__*/_jsxs(View, {
452
+ style: styles.settingInfo,
453
+ children: [/*#__PURE__*/_jsx(Text, {
454
+ style: styles.settingLabel,
455
+ children: "Switch back to primary account"
456
+ }), /*#__PURE__*/_jsx(Text, {
457
+ style: styles.settingDescription,
458
+ children: "You are currently acting as another identity"
459
+ })]
460
+ }), /*#__PURE__*/_jsx(View, {
461
+ style: styles.switchBackButton,
462
+ children: /*#__PURE__*/_jsx(Text, {
463
+ style: styles.switchBackButtonText,
464
+ children: "Switch Back"
465
+ })
466
+ })]
467
+ })
468
+ }), managedAccounts.length > 0 && /*#__PURE__*/_jsxs(View, {
469
+ style: styles.section,
470
+ children: [/*#__PURE__*/_jsx(Text, {
471
+ style: styles.sectionTitle,
472
+ children: "Managed Accounts"
473
+ }), /*#__PURE__*/_jsx(Text, {
474
+ style: styles.sectionSubtitle,
475
+ children: "Identities you manage"
476
+ }), managedAccounts.map((managed, index) => {
477
+ const account = managed.account;
478
+ if (!account) return null;
479
+ const isActive = actingAs === managed.accountId;
480
+ const isSwitching = switchingManagedId === managed.accountId;
481
+ const isFirst = index === 0;
482
+ const isLast = index === managedAccounts.length - 1;
483
+ const managedDisplayName = typeof account.name === 'object' ? account.name.full || account.name.first || account.username : account.name || account.username || 'Unknown';
484
+
485
+ // Determine the manager role for badge display
486
+ const myRole = managed.managers?.find(m => m.userId === user?.id)?.role ?? 'owner';
487
+ return /*#__PURE__*/_jsxs(TouchableOpacity, {
488
+ style: [styles.settingItem, isFirst && styles.firstSettingItem, isLast && styles.lastSettingItem, isActive && styles.currentAccountCard],
489
+ onPress: () => handleSwitchToManagedAccount(managed.accountId),
490
+ disabled: isActive || isSwitching,
491
+ activeOpacity: 0.7,
492
+ children: [/*#__PURE__*/_jsxs(View, {
493
+ style: styles.userIcon,
494
+ children: [account.avatar ? /*#__PURE__*/_jsx(Image, {
495
+ source: {
496
+ uri: oxyServices.getFileDownloadUrl(account.avatar, 'thumb')
497
+ },
498
+ style: styles.accountAvatarImage
499
+ }) : /*#__PURE__*/_jsx(View, {
500
+ style: [styles.accountAvatarFallback, styles.managedAvatarFallback],
501
+ children: /*#__PURE__*/_jsx(Text, {
502
+ style: styles.accountAvatarText,
503
+ children: managedDisplayName.charAt(0).toUpperCase()
504
+ })
505
+ }), isActive && /*#__PURE__*/_jsx(View, {
506
+ style: styles.activeBadge,
507
+ children: /*#__PURE__*/_jsx(OxyIcon, {
508
+ name: "checkmark",
509
+ size: 12,
510
+ color: "#fff"
511
+ })
512
+ })]
513
+ }), /*#__PURE__*/_jsx(View, {
514
+ style: styles.settingInfo,
515
+ children: /*#__PURE__*/_jsxs(View, {
516
+ children: [/*#__PURE__*/_jsx(Text, {
517
+ style: styles.settingLabel,
518
+ children: managedDisplayName
519
+ }), /*#__PURE__*/_jsxs(Text, {
520
+ style: styles.settingDescription,
521
+ children: ["@", account.username]
522
+ })]
523
+ })
524
+ }), /*#__PURE__*/_jsxs(View, {
525
+ style: styles.accountActions,
526
+ children: [/*#__PURE__*/_jsx(View, {
527
+ style: styles.roleBadge,
528
+ children: /*#__PURE__*/_jsx(Text, {
529
+ style: styles.roleBadgeText,
530
+ children: myRole
531
+ })
532
+ }), isActive ? /*#__PURE__*/_jsx(View, {
533
+ style: styles.currentBadge,
534
+ children: /*#__PURE__*/_jsx(Text, {
535
+ style: styles.currentBadgeText,
536
+ children: "Current"
537
+ })
538
+ }) : /*#__PURE__*/_jsx(TouchableOpacity, {
539
+ style: styles.switchButton,
540
+ onPress: () => handleSwitchToManagedAccount(managed.accountId),
541
+ disabled: isSwitching,
542
+ children: isSwitching ? /*#__PURE__*/_jsx(ActivityIndicator, {
543
+ size: "small",
544
+ color: "#fff"
545
+ }) : /*#__PURE__*/_jsx(Text, {
546
+ style: styles.switchButtonText,
547
+ children: "Act As"
548
+ })
549
+ })]
550
+ })]
551
+ }, `managed-${managed.accountId}`);
552
+ }), /*#__PURE__*/_jsxs(TouchableOpacity, {
553
+ style: [styles.settingItem, styles.firstSettingItem, styles.lastSettingItem, {
554
+ marginTop: 8
555
+ }],
556
+ onPress: () => navigate?.('CreateManagedAccount'),
557
+ activeOpacity: 0.7,
558
+ children: [/*#__PURE__*/_jsx(View, {
559
+ style: styles.userIcon,
560
+ children: /*#__PURE__*/_jsx(View, {
561
+ style: [styles.accountAvatarFallback, {
562
+ backgroundColor: '#007AFF20'
563
+ }],
564
+ children: /*#__PURE__*/_jsx(OxyIcon, {
565
+ name: "add",
566
+ size: 20,
567
+ color: "#007AFF"
568
+ })
569
+ })
570
+ }), /*#__PURE__*/_jsxs(View, {
571
+ style: styles.settingInfo,
572
+ children: [/*#__PURE__*/_jsx(Text, {
573
+ style: [styles.settingLabel, {
574
+ color: '#007AFF'
575
+ }],
576
+ children: "Create New Identity"
577
+ }), /*#__PURE__*/_jsx(Text, {
578
+ style: styles.settingDescription,
579
+ children: "Add a managed sub-account"
580
+ })]
581
+ })]
582
+ })]
583
+ }), managedAccounts.length === 0 && isAuthenticated && /*#__PURE__*/_jsxs(View, {
584
+ style: styles.section,
585
+ children: [/*#__PURE__*/_jsx(Text, {
586
+ style: styles.sectionTitle,
587
+ children: "Managed Accounts"
588
+ }), /*#__PURE__*/_jsxs(TouchableOpacity, {
589
+ style: [styles.settingItem, styles.firstSettingItem, styles.lastSettingItem],
590
+ onPress: () => navigate?.('CreateManagedAccount'),
591
+ activeOpacity: 0.7,
592
+ children: [/*#__PURE__*/_jsx(View, {
593
+ style: styles.userIcon,
594
+ children: /*#__PURE__*/_jsx(View, {
595
+ style: [styles.accountAvatarFallback, {
596
+ backgroundColor: '#007AFF20'
597
+ }],
598
+ children: /*#__PURE__*/_jsx(OxyIcon, {
599
+ name: "add",
600
+ size: 20,
601
+ color: "#007AFF"
602
+ })
603
+ })
604
+ }), /*#__PURE__*/_jsxs(View, {
605
+ style: styles.settingInfo,
606
+ children: [/*#__PURE__*/_jsx(Text, {
607
+ style: [styles.settingLabel, {
608
+ color: '#007AFF'
609
+ }],
610
+ children: "Create New Identity"
611
+ }), /*#__PURE__*/_jsx(Text, {
612
+ style: styles.settingDescription,
613
+ children: "Create a managed sub-account you control"
614
+ })]
615
+ })]
616
+ })]
394
617
  }), /*#__PURE__*/_jsxs(View, {
395
618
  style: styles.section,
396
619
  children: [/*#__PURE__*/_jsx(Text, {
@@ -417,7 +640,7 @@ const ModernAccountSwitcherScreen = ({
417
640
  iconColor: '#FF3B30',
418
641
  title: 'Sign Out All Accounts',
419
642
  subtitle: 'Remove all accounts from this device',
420
- onPress: handleLogoutAll,
643
+ onPress: confirmLogoutAll,
421
644
  disabled: sessionsWithUsers.length === 0
422
645
  }]
423
646
  })]
@@ -460,11 +683,11 @@ const ModernAccountSwitcherScreen = ({
460
683
  subtitle: t('accountSwitcher.device.lastActive', {
461
684
  date: new Date(session.lastActive).toLocaleDateString()
462
685
  }) || `Last active: ${new Date(session.lastActive).toLocaleDateString()}`,
463
- onPress: session.isCurrent ? undefined : () => handleRemoteSessionLogout(session.sessionId, session.deviceName),
686
+ onPress: session.isCurrent ? undefined : () => confirmRemoteSessionLogout(session.sessionId, session.deviceName),
464
687
  disabled: session.isCurrent || remotingLogoutSessionId === session.sessionId,
465
688
  customContent: !session.isCurrent ? /*#__PURE__*/_jsx(TouchableOpacity, {
466
689
  style: styles.removeButton,
467
- onPress: () => handleRemoteSessionLogout(session.sessionId, session.deviceName),
690
+ onPress: () => confirmRemoteSessionLogout(session.sessionId, session.deviceName),
468
691
  disabled: remotingLogoutSessionId === session.sessionId,
469
692
  children: remotingLogoutSessionId === session.sessionId ? /*#__PURE__*/_jsx(ActivityIndicator, {
470
693
  size: "small",
@@ -512,6 +735,40 @@ const ModernAccountSwitcherScreen = ({
512
735
  })
513
736
  })]
514
737
  })
738
+ }), /*#__PURE__*/_jsx(Prompt.Basic, {
739
+ control: removeSessionPrompt,
740
+ title: t('accountSwitcher.confirms.removeTitle') || 'Remove Account',
741
+ description: pendingRemoveSession ? t('accountSwitcher.confirms.remove', {
742
+ displayName: pendingRemoveSession.displayName
743
+ }) || `Are you sure you want to remove ${pendingRemoveSession.displayName} from this device? You'll need to sign in again to access this account.` : '',
744
+ onConfirm: handleRemoveSession,
745
+ confirmButtonCta: t('common.remove') || 'Remove',
746
+ confirmButtonColor: "negative"
747
+ }), /*#__PURE__*/_jsx(Prompt.Basic, {
748
+ control: logoutAllPrompt,
749
+ title: t('accountSwitcher.confirms.logoutAllTitle') || 'Sign Out All',
750
+ 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.',
751
+ onConfirm: handleLogoutAll,
752
+ confirmButtonCta: t('common.signOutAll') || 'Sign Out All',
753
+ confirmButtonColor: "negative"
754
+ }), /*#__PURE__*/_jsx(Prompt.Basic, {
755
+ control: remoteLogoutPrompt,
756
+ title: t('accountSwitcher.confirms.remoteLogoutTitle') || 'Remote Sign Out',
757
+ description: pendingRemoteLogout ? t('accountSwitcher.confirms.remoteLogout', {
758
+ deviceName: pendingRemoteLogout.deviceName
759
+ }) || `Are you sure you want to sign out from "${pendingRemoteLogout.deviceName}"? This will end the session on that device.` : '',
760
+ onConfirm: handleRemoteSessionLogout,
761
+ confirmButtonCta: t('common.signOut') || 'Sign Out',
762
+ confirmButtonColor: "negative"
763
+ }), /*#__PURE__*/_jsx(Prompt.Basic, {
764
+ control: logoutAllDevicesPrompt,
765
+ title: t('accountSwitcher.confirms.logoutOthersTitle') || 'Sign Out Other Devices',
766
+ description: t('accountSwitcher.confirms.logoutOthers', {
767
+ count: otherDevicesCount
768
+ }) || `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.`,
769
+ onConfirm: handleLogoutAllDevices,
770
+ confirmButtonCta: t('common.signOutAll') || 'Sign Out All',
771
+ confirmButtonColor: "negative"
515
772
  })]
516
773
  });
517
774
  };
@@ -672,6 +929,42 @@ const styles = StyleSheet.create({
672
929
  color: '#fff',
673
930
  fontSize: 16,
674
931
  fontWeight: '600'
932
+ },
933
+ sectionSubtitle: {
934
+ fontSize: 13,
935
+ color: '#888',
936
+ marginBottom: 12
937
+ },
938
+ managedAvatarFallback: {
939
+ backgroundColor: '#5856D6'
940
+ },
941
+ roleBadge: {
942
+ backgroundColor: '#F2F2F7',
943
+ paddingHorizontal: 8,
944
+ paddingVertical: 3,
945
+ borderRadius: 8
946
+ },
947
+ roleBadgeText: {
948
+ color: '#666',
949
+ fontSize: 11,
950
+ fontWeight: '500',
951
+ textTransform: 'capitalize'
952
+ },
953
+ actingAsBanner: {
954
+ borderWidth: 2,
955
+ borderColor: '#FF9500',
956
+ backgroundColor: '#FF950010'
957
+ },
958
+ switchBackButton: {
959
+ backgroundColor: '#FF9500',
960
+ paddingHorizontal: 14,
961
+ paddingVertical: 8,
962
+ borderRadius: 16
963
+ },
964
+ switchBackButtonText: {
965
+ color: '#fff',
966
+ fontSize: 13,
967
+ fontWeight: '600'
675
968
  }
676
969
  });
677
970
  export default ModernAccountSwitcherScreen;