@oxyhq/services 6.9.44 → 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 (160) hide show
  1. package/lib/commonjs/ui/components/OxyPayButton.js +4 -2
  2. package/lib/commonjs/ui/components/OxyPayButton.js.map +1 -1
  3. package/lib/commonjs/ui/components/OxySignInButton.js +83 -82
  4. package/lib/commonjs/ui/components/OxySignInButton.js.map +1 -1
  5. package/lib/commonjs/ui/components/SettingRow.js +11 -5
  6. package/lib/commonjs/ui/components/SettingRow.js.map +1 -1
  7. package/lib/commonjs/ui/components/fileManagement/FileDetailsModal.js +76 -121
  8. package/lib/commonjs/ui/components/fileManagement/FileDetailsModal.js.map +1 -1
  9. package/lib/commonjs/ui/components/fileManagement/UploadPreview.js +32 -18
  10. package/lib/commonjs/ui/components/fileManagement/UploadPreview.js.map +1 -1
  11. package/lib/commonjs/ui/components/icon/OxyIcon.js +5 -4
  12. package/lib/commonjs/ui/components/icon/OxyIcon.js.map +1 -1
  13. package/lib/commonjs/ui/components/internal/GroupedPillButtons.js +11 -9
  14. package/lib/commonjs/ui/components/internal/GroupedPillButtons.js.map +1 -1
  15. package/lib/commonjs/ui/components/internal/PinInput.js +3 -2
  16. package/lib/commonjs/ui/components/internal/PinInput.js.map +1 -1
  17. package/lib/commonjs/ui/components/modals/DeleteAccountModal.js +83 -219
  18. package/lib/commonjs/ui/components/modals/DeleteAccountModal.js.map +1 -1
  19. package/lib/commonjs/ui/constants/theme.js +2 -2
  20. package/lib/commonjs/ui/constants/theme.js.map +1 -1
  21. package/lib/commonjs/ui/screens/AccountCenterScreen.js +12 -10
  22. package/lib/commonjs/ui/screens/AccountCenterScreen.js.map +1 -1
  23. package/lib/commonjs/ui/screens/AccountOverviewScreen.js +70 -79
  24. package/lib/commonjs/ui/screens/AccountOverviewScreen.js.map +1 -1
  25. package/lib/commonjs/ui/screens/AccountSettingsScreen.js +22 -10
  26. package/lib/commonjs/ui/screens/AccountSettingsScreen.js.map +1 -1
  27. package/lib/commonjs/ui/screens/AccountSwitcherScreen.js +141 -81
  28. package/lib/commonjs/ui/screens/AccountSwitcherScreen.js.map +1 -1
  29. package/lib/commonjs/ui/screens/AccountVerificationScreen.js +21 -9
  30. package/lib/commonjs/ui/screens/AccountVerificationScreen.js.map +1 -1
  31. package/lib/commonjs/ui/screens/FileManagementScreen.js +83 -50
  32. package/lib/commonjs/ui/screens/FileManagementScreen.js.map +1 -1
  33. package/lib/commonjs/ui/screens/HistoryViewScreen.js +80 -101
  34. package/lib/commonjs/ui/screens/HistoryViewScreen.js.map +1 -1
  35. package/lib/commonjs/ui/screens/PremiumSubscriptionScreen.js +66 -93
  36. package/lib/commonjs/ui/screens/PremiumSubscriptionScreen.js.map +1 -1
  37. package/lib/commonjs/ui/screens/SessionManagementScreen.js +101 -66
  38. package/lib/commonjs/ui/screens/SessionManagementScreen.js.map +1 -1
  39. package/lib/commonjs/ui/utils/fileManagement.js +0 -21
  40. package/lib/commonjs/ui/utils/fileManagement.js.map +1 -1
  41. package/lib/module/ui/components/OxyPayButton.js +4 -2
  42. package/lib/module/ui/components/OxyPayButton.js.map +1 -1
  43. package/lib/module/ui/components/OxySignInButton.js +84 -83
  44. package/lib/module/ui/components/OxySignInButton.js.map +1 -1
  45. package/lib/module/ui/components/SettingRow.js +11 -5
  46. package/lib/module/ui/components/SettingRow.js.map +1 -1
  47. package/lib/module/ui/components/fileManagement/FileDetailsModal.js +76 -122
  48. package/lib/module/ui/components/fileManagement/FileDetailsModal.js.map +1 -1
  49. package/lib/module/ui/components/fileManagement/UploadPreview.js +32 -19
  50. package/lib/module/ui/components/fileManagement/UploadPreview.js.map +1 -1
  51. package/lib/module/ui/components/icon/OxyIcon.js +5 -4
  52. package/lib/module/ui/components/icon/OxyIcon.js.map +1 -1
  53. package/lib/module/ui/components/internal/GroupedPillButtons.js +11 -9
  54. package/lib/module/ui/components/internal/GroupedPillButtons.js.map +1 -1
  55. package/lib/module/ui/components/internal/PinInput.js +3 -2
  56. package/lib/module/ui/components/internal/PinInput.js.map +1 -1
  57. package/lib/module/ui/components/modals/DeleteAccountModal.js +83 -220
  58. package/lib/module/ui/components/modals/DeleteAccountModal.js.map +1 -1
  59. package/lib/module/ui/constants/theme.js +2 -2
  60. package/lib/module/ui/constants/theme.js.map +1 -1
  61. package/lib/module/ui/screens/AccountCenterScreen.js +11 -10
  62. package/lib/module/ui/screens/AccountCenterScreen.js.map +1 -1
  63. package/lib/module/ui/screens/AccountOverviewScreen.js +71 -80
  64. package/lib/module/ui/screens/AccountOverviewScreen.js.map +1 -1
  65. package/lib/module/ui/screens/AccountSettingsScreen.js +22 -10
  66. package/lib/module/ui/screens/AccountSettingsScreen.js.map +1 -1
  67. package/lib/module/ui/screens/AccountSwitcherScreen.js +140 -81
  68. package/lib/module/ui/screens/AccountSwitcherScreen.js.map +1 -1
  69. package/lib/module/ui/screens/AccountVerificationScreen.js +22 -10
  70. package/lib/module/ui/screens/AccountVerificationScreen.js.map +1 -1
  71. package/lib/module/ui/screens/FileManagementScreen.js +85 -52
  72. package/lib/module/ui/screens/FileManagementScreen.js.map +1 -1
  73. package/lib/module/ui/screens/HistoryViewScreen.js +80 -101
  74. package/lib/module/ui/screens/HistoryViewScreen.js.map +1 -1
  75. package/lib/module/ui/screens/PremiumSubscriptionScreen.js +66 -94
  76. package/lib/module/ui/screens/PremiumSubscriptionScreen.js.map +1 -1
  77. package/lib/module/ui/screens/SessionManagementScreen.js +101 -67
  78. package/lib/module/ui/screens/SessionManagementScreen.js.map +1 -1
  79. package/lib/module/ui/utils/fileManagement.js +0 -20
  80. package/lib/module/ui/utils/fileManagement.js.map +1 -1
  81. package/lib/typescript/commonjs/ui/components/OxyPayButton.d.ts.map +1 -1
  82. package/lib/typescript/commonjs/ui/components/OxySignInButton.d.ts +0 -1
  83. package/lib/typescript/commonjs/ui/components/OxySignInButton.d.ts.map +1 -1
  84. package/lib/typescript/commonjs/ui/components/SettingRow.d.ts +2 -2
  85. package/lib/typescript/commonjs/ui/components/SettingRow.d.ts.map +1 -1
  86. package/lib/typescript/commonjs/ui/components/fileManagement/FileDetailsModal.d.ts +3 -4
  87. package/lib/typescript/commonjs/ui/components/fileManagement/FileDetailsModal.d.ts.map +1 -1
  88. package/lib/typescript/commonjs/ui/components/fileManagement/UploadPreview.d.ts +2 -3
  89. package/lib/typescript/commonjs/ui/components/fileManagement/UploadPreview.d.ts.map +1 -1
  90. package/lib/typescript/commonjs/ui/components/icon/OxyIcon.d.ts.map +1 -1
  91. package/lib/typescript/commonjs/ui/components/internal/GroupedPillButtons.d.ts.map +1 -1
  92. package/lib/typescript/commonjs/ui/components/internal/PinInput.d.ts.map +1 -1
  93. package/lib/typescript/commonjs/ui/components/modals/DeleteAccountModal.d.ts +2 -2
  94. package/lib/typescript/commonjs/ui/components/modals/DeleteAccountModal.d.ts.map +1 -1
  95. package/lib/typescript/commonjs/ui/screens/AccountCenterScreen.d.ts.map +1 -1
  96. package/lib/typescript/commonjs/ui/screens/AccountOverviewScreen.d.ts.map +1 -1
  97. package/lib/typescript/commonjs/ui/screens/AccountSettingsScreen.d.ts.map +1 -1
  98. package/lib/typescript/commonjs/ui/screens/AccountSwitcherScreen.d.ts.map +1 -1
  99. package/lib/typescript/commonjs/ui/screens/AccountVerificationScreen.d.ts.map +1 -1
  100. package/lib/typescript/commonjs/ui/screens/FileManagementScreen.d.ts.map +1 -1
  101. package/lib/typescript/commonjs/ui/screens/HistoryViewScreen.d.ts.map +1 -1
  102. package/lib/typescript/commonjs/ui/screens/PremiumSubscriptionScreen.d.ts.map +1 -1
  103. package/lib/typescript/commonjs/ui/screens/SessionManagementScreen.d.ts.map +1 -1
  104. package/lib/typescript/commonjs/ui/utils/fileManagement.d.ts +0 -4
  105. package/lib/typescript/commonjs/ui/utils/fileManagement.d.ts.map +1 -1
  106. package/lib/typescript/module/ui/components/OxyPayButton.d.ts.map +1 -1
  107. package/lib/typescript/module/ui/components/OxySignInButton.d.ts +0 -1
  108. package/lib/typescript/module/ui/components/OxySignInButton.d.ts.map +1 -1
  109. package/lib/typescript/module/ui/components/SettingRow.d.ts +2 -2
  110. package/lib/typescript/module/ui/components/SettingRow.d.ts.map +1 -1
  111. package/lib/typescript/module/ui/components/fileManagement/FileDetailsModal.d.ts +3 -4
  112. package/lib/typescript/module/ui/components/fileManagement/FileDetailsModal.d.ts.map +1 -1
  113. package/lib/typescript/module/ui/components/fileManagement/UploadPreview.d.ts +2 -3
  114. package/lib/typescript/module/ui/components/fileManagement/UploadPreview.d.ts.map +1 -1
  115. package/lib/typescript/module/ui/components/icon/OxyIcon.d.ts.map +1 -1
  116. package/lib/typescript/module/ui/components/internal/GroupedPillButtons.d.ts.map +1 -1
  117. package/lib/typescript/module/ui/components/internal/PinInput.d.ts.map +1 -1
  118. package/lib/typescript/module/ui/components/modals/DeleteAccountModal.d.ts +2 -2
  119. package/lib/typescript/module/ui/components/modals/DeleteAccountModal.d.ts.map +1 -1
  120. package/lib/typescript/module/ui/screens/AccountCenterScreen.d.ts.map +1 -1
  121. package/lib/typescript/module/ui/screens/AccountOverviewScreen.d.ts.map +1 -1
  122. package/lib/typescript/module/ui/screens/AccountSettingsScreen.d.ts.map +1 -1
  123. package/lib/typescript/module/ui/screens/AccountSwitcherScreen.d.ts.map +1 -1
  124. package/lib/typescript/module/ui/screens/AccountVerificationScreen.d.ts.map +1 -1
  125. package/lib/typescript/module/ui/screens/FileManagementScreen.d.ts.map +1 -1
  126. package/lib/typescript/module/ui/screens/HistoryViewScreen.d.ts.map +1 -1
  127. package/lib/typescript/module/ui/screens/PremiumSubscriptionScreen.d.ts.map +1 -1
  128. package/lib/typescript/module/ui/screens/SessionManagementScreen.d.ts.map +1 -1
  129. package/lib/typescript/module/ui/utils/fileManagement.d.ts +0 -4
  130. package/lib/typescript/module/ui/utils/fileManagement.d.ts.map +1 -1
  131. package/package.json +2 -2
  132. package/src/ui/components/OxyPayButton.tsx +5 -3
  133. package/src/ui/components/OxySignInButton.tsx +82 -81
  134. package/src/ui/components/SettingRow.tsx +14 -7
  135. package/src/ui/components/fileManagement/FileDetailsModal.tsx +69 -99
  136. package/src/ui/components/fileManagement/UploadPreview.tsx +58 -46
  137. package/src/ui/components/icon/OxyIcon.tsx +5 -4
  138. package/src/ui/components/internal/GroupedPillButtons.tsx +15 -12
  139. package/src/ui/components/internal/PinInput.tsx +4 -3
  140. package/src/ui/components/modals/DeleteAccountModal.tsx +79 -221
  141. package/src/ui/constants/theme.ts +2 -2
  142. package/src/ui/screens/AccountCenterScreen.tsx +34 -136
  143. package/src/ui/screens/AccountOverviewScreen.tsx +63 -98
  144. package/src/ui/screens/AccountSettingsScreen.tsx +21 -7
  145. package/src/ui/screens/AccountSwitcherScreen.tsx +135 -87
  146. package/src/ui/screens/AccountVerificationScreen.tsx +24 -16
  147. package/src/ui/screens/FileManagementScreen.tsx +62 -54
  148. package/src/ui/screens/HistoryViewScreen.tsx +57 -204
  149. package/src/ui/screens/PremiumSubscriptionScreen.tsx +73 -93
  150. package/src/ui/screens/SessionManagementScreen.tsx +101 -73
  151. package/src/ui/utils/fileManagement.ts +0 -30
  152. package/lib/commonjs/ui/utils/confirmAction.js +0 -28
  153. package/lib/commonjs/ui/utils/confirmAction.js.map +0 -1
  154. package/lib/module/ui/utils/confirmAction.js +0 -25
  155. package/lib/module/ui/utils/confirmAction.js.map +0 -1
  156. package/lib/typescript/commonjs/ui/utils/confirmAction.d.ts +0 -7
  157. package/lib/typescript/commonjs/ui/utils/confirmAction.d.ts.map +0 -1
  158. package/lib/typescript/module/ui/utils/confirmAction.d.ts +0 -7
  159. package/lib/typescript/module/ui/utils/confirmAction.d.ts.map +0 -1
  160. 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';
@@ -77,6 +77,16 @@ const ModernAccountSwitcherScreen: React.FC<BaseScreenProps> = ({
77
77
  const [remotingLogoutSessionId, setRemoteLogoutSessionId] = useState<string | null>(null);
78
78
  const [loggingOutAllDevices, setLoggingOutAllDevices] = useState(false);
79
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
+
80
90
  const screenWidth = Dimensions.get('window').width;
81
91
  const { t } = useI18n();
82
92
 
@@ -171,47 +181,48 @@ const ModernAccountSwitcherScreen: React.FC<BaseScreenProps> = ({
171
181
  }
172
182
  }, [activeSessionId, switchSession, onClose, t, switchingToUserId]);
173
183
 
174
- const handleRemoveSession = useCallback(async (sessionId: string, displayName: string) => {
175
- if (removingUserId) return; // Already removing
176
-
177
- confirmAction(
178
- 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.`,
179
- async () => {
180
- setRemovingUserId(sessionId);
181
- try {
182
- await removeSession(sessionId);
183
- toast.success(t('accountSwitcher.toasts.removeSuccess') || 'Account removed successfully!');
184
- } catch (error) {
185
- if (__DEV__) {
186
- console.error('Remove session failed:', error);
187
- }
188
- toast.error(t('accountSwitcher.toasts.removeFailed') || 'There was a problem removing the account. Please try again.');
189
- } finally {
190
- setRemovingUserId(null);
191
- }
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);
192
200
  }
193
- );
194
- }, [removeSession, t, removingUserId]);
195
-
196
- const handleLogoutAll = useCallback(() => {
197
- confirmAction(
198
- t('accountSwitcher.confirms.logoutAll') || 'Are you sure you want to sign out of all accounts? This will remove all saved accounts from this device.',
199
- async () => {
200
- try {
201
- await logoutAll();
202
- toast.success(t('accountSwitcher.toasts.signOutAllSuccess') || 'All accounts signed out successfully!');
203
- if (onClose) {
204
- onClose();
205
- }
206
- } catch (error) {
207
- if (__DEV__) {
208
- console.error('Logout all failed:', error);
209
- }
210
- const errorMessage = error instanceof Error ? error.message : 'Unknown error occurred';
211
- toast.error(t('accountSwitcher.toasts.signOutAllFailed', { error: errorMessage }) || `There was a problem signing out: ${errorMessage}`);
212
- }
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();
213
218
  }
214
- );
219
+ } catch (error) {
220
+ if (__DEV__) {
221
+ console.error('Logout all failed:', error);
222
+ }
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
+ }
215
226
  }, [logoutAll, onClose, t]);
216
227
 
217
228
  const handleSwitchToManagedAccount = useCallback(async (accountId: string) => {
@@ -257,30 +268,32 @@ const ModernAccountSwitcherScreen: React.FC<BaseScreenProps> = ({
257
268
  }
258
269
  }, [oxyServices, activeSessionId, t]);
259
270
 
260
- const handleRemoteSessionLogout = useCallback((sessionId: string, deviceName: string) => {
261
- if (remotingLogoutSessionId) return; // Already processing
262
-
263
- confirmAction(
264
- t('accountSwitcher.confirms.remoteLogout', { deviceName }) || `Are you sure you want to sign out from "${deviceName}"? This will end the session on that device.`,
265
- async () => {
266
- setRemoteLogoutSessionId(sessionId);
267
- try {
268
- await oxyServices?.logoutSession((activeSessionId ?? null) || '', sessionId);
269
- await loadAllDeviceSessions();
270
- toast.success(t('accountSwitcher.toasts.remoteSignOutSuccess', { deviceName }) || `Signed out from ${deviceName} successfully!`);
271
- } catch (error) {
272
- if (__DEV__) {
273
- console.error('Remote logout failed:', error);
274
- }
275
- toast.error(t('accountSwitcher.toasts.remoteSignOutFailed') || 'There was a problem signing out from the device. Please try again.');
276
- } finally {
277
- setRemoteLogoutSessionId(null);
278
- }
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);
279
288
  }
280
- );
281
- }, [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]);
282
295
 
283
- const handleLogoutAllDevices = useCallback(() => {
296
+ const confirmLogoutAllDevices = useCallback(() => {
284
297
  const otherDevicesCount = deviceSessions.filter(session => !session.isCurrent).length;
285
298
 
286
299
  if (otherDevicesCount === 0) {
@@ -288,27 +301,25 @@ const ModernAccountSwitcherScreen: React.FC<BaseScreenProps> = ({
288
301
  return;
289
302
  }
290
303
 
291
- if (loggingOutAllDevices) return; // Already processing
292
-
293
- confirmAction(
294
- 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.`,
295
- async () => {
296
- setLoggingOutAllDevices(true);
297
- try {
298
- await oxyServices?.logoutAllDeviceSessions((activeSessionId ?? null) || '');
299
- await loadAllDeviceSessions();
300
- toast.success(t('accountSwitcher.toasts.signOutOthersSuccess') || 'Signed out from all other devices successfully!');
301
- } catch (error) {
302
- if (__DEV__) {
303
- console.error('Logout all devices failed:', error);
304
- }
305
- toast.error(t('accountSwitcher.toasts.signOutOthersFailed') || 'There was a problem signing out from other devices. Please try again.');
306
- } finally {
307
- setLoggingOutAllDevices(false);
308
- }
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);
309
317
  }
310
- );
311
- }, [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]);
312
323
 
313
324
  // Memoize filtered sessions for performance
314
325
  const otherSessions = useMemo(
@@ -316,6 +327,11 @@ const ModernAccountSwitcherScreen: React.FC<BaseScreenProps> = ({
316
327
  [sessionsWithUsers, activeSessionId]
317
328
  );
318
329
 
330
+ const otherDevicesCount = useMemo(
331
+ () => deviceSessions.filter(session => !session.isCurrent).length,
332
+ [deviceSessions]
333
+ );
334
+
319
335
  return (
320
336
  <View style={[styles.container, { backgroundColor: bloomTheme.colors.background }]}>
321
337
  {/* Header */}
@@ -440,7 +456,7 @@ const ModernAccountSwitcherScreen: React.FC<BaseScreenProps> = ({
440
456
  </TouchableOpacity>
441
457
  <TouchableOpacity
442
458
  style={styles.removeButton}
443
- onPress={() => handleRemoveSession(sessionWithUser.sessionId, displayName)}
459
+ onPress={() => confirmRemoveSession(sessionWithUser.sessionId, displayName)}
444
460
  disabled={isSwitching || isRemoving}
445
461
  >
446
462
  {isRemoving ? (
@@ -629,7 +645,7 @@ const ModernAccountSwitcherScreen: React.FC<BaseScreenProps> = ({
629
645
  iconColor: '#FF3B30',
630
646
  title: 'Sign Out All Accounts',
631
647
  subtitle: 'Remove all accounts from this device',
632
- onPress: handleLogoutAll,
648
+ onPress: confirmLogoutAll,
633
649
  disabled: sessionsWithUsers.length === 0,
634
650
  },
635
651
  ]}
@@ -681,12 +697,12 @@ const ModernAccountSwitcherScreen: React.FC<BaseScreenProps> = ({
681
697
  iconColor: session.isCurrent ? '#34C759' : '#8E8E93',
682
698
  title: `${session.deviceName} ${session.isCurrent ? `(${t('accountSwitcher.device.thisDevice') || 'This device'})` : ''}`,
683
699
  subtitle: t('accountSwitcher.device.lastActive', { date: new Date(session.lastActive).toLocaleDateString() }) || `Last active: ${new Date(session.lastActive).toLocaleDateString()}`,
684
- onPress: session.isCurrent ? undefined : () => handleRemoteSessionLogout(session.sessionId, session.deviceName),
700
+ onPress: session.isCurrent ? undefined : () => confirmRemoteSessionLogout(session.sessionId, session.deviceName),
685
701
  disabled: session.isCurrent || remotingLogoutSessionId === session.sessionId,
686
702
  customContent: !session.isCurrent ? (
687
703
  <TouchableOpacity
688
704
  style={styles.removeButton}
689
- onPress={() => handleRemoteSessionLogout(session.sessionId, session.deviceName)}
705
+ onPress={() => confirmRemoteSessionLogout(session.sessionId, session.deviceName)}
690
706
  disabled={remotingLogoutSessionId === session.sessionId}
691
707
  >
692
708
  {remotingLogoutSessionId === session.sessionId ? (
@@ -739,6 +755,38 @@ const ModernAccountSwitcherScreen: React.FC<BaseScreenProps> = ({
739
755
  </>
740
756
  )}
741
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
+ />
742
790
  </View>
743
791
  );
744
792
  };
@@ -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
-
@@ -11,7 +11,6 @@ import {
11
11
  Image,
12
12
  Animated,
13
13
  Easing,
14
- Alert,
15
14
  } from 'react-native';
16
15
  import { Image as ExpoImage } from 'expo-image';
17
16
  import type { FileManagementScreenProps } from '../types/fileManagement';
@@ -29,6 +28,8 @@ const loadDocumentPicker = async () => {
29
28
  }
30
29
  };
31
30
  import { toast } from '../../lib/sonner';
31
+ import * as Prompt from '@oxyhq/bloom/prompt';
32
+ import { usePromptControl } from '@oxyhq/bloom/prompt';
32
33
  import { Ionicons } from '@expo/vector-icons';
33
34
  // @ts-ignore - MaterialCommunityIcons is available at runtime
34
35
  import { MaterialCommunityIcons } from '@expo/vector-icons';
@@ -42,7 +43,6 @@ import { useOxy } from '../context/OxyContext';
42
43
  import { useI18n } from '../hooks/useI18n';
43
44
  import { useUploadFile } from '../hooks/mutations/useAccountMutations';
44
45
  import {
45
- confirmAction,
46
46
  convertDocumentPickerAssetToFile,
47
47
  formatFileSize,
48
48
  getFileIcon,
@@ -51,6 +51,7 @@ import {
51
51
  import { FileViewer } from '../components/fileManagement/FileViewer';
52
52
  import { FileDetailsModal } from '../components/fileManagement/FileDetailsModal';
53
53
  import { UploadPreview } from '../components/fileManagement/UploadPreview';
54
+ import { useDialogControl } from '@oxyhq/bloom/dialog';
54
55
  import { fileManagementStyles } from '../components/fileManagement/styles';
55
56
  import type { OnConfirmFileSelection } from '../types/fileManagement';
56
57
 
@@ -133,6 +134,11 @@ const FileManagementScreen: React.FC<FileManagementScreenProps> = ({
133
134
  const { user, oxyServices } = useOxy();
134
135
  const { t } = useI18n();
135
136
  const uploadFileMutation = useUploadFile();
137
+ // Prompt controls
138
+ const fileDeletePrompt = usePromptControl();
139
+ const bulkDeletePrompt = usePromptControl();
140
+ const visibilityChangePrompt = usePromptControl();
141
+ const [pendingDeleteFile, setPendingDeleteFile] = useState<{ id: string; name: string } | null>(null);
136
142
  const files = useFiles();
137
143
  // Ensure containerWidth is a number (TypeScript guard)
138
144
  const safeContainerWidth: number = typeof containerWidth === 'number' ? containerWidth : 400;
@@ -143,7 +149,7 @@ const FileManagementScreen: React.FC<FileManagementScreenProps> = ({
143
149
  const [refreshing, setRefreshing] = useState(false);
144
150
  const [paging, setPaging] = useState({ offset: 0, limit: 40, total: 0, hasMore: true, loadingMore: false });
145
151
  const [selectedFile, setSelectedFile] = useState<FileMetadata | null>(null);
146
- const [showFileDetails, setShowFileDetails] = useState(false);
152
+ const fileDetailsControl = useDialogControl();
147
153
  // In selectMode we never open the detailed viewer
148
154
  const [openedFile, setOpenedFile] = useState<FileMetadata | null>(null);
149
155
  const [fileContent, setFileContent] = useState<string | null>(null);
@@ -889,18 +895,14 @@ const FileManagementScreen: React.FC<FileManagementScreenProps> = ({
889
895
  }
890
896
  };
891
897
 
892
- const handleFileDelete = async (fileId: string, filename: string) => {
893
- // Use platform-aware confirmation dialog
894
- const confirmed = await confirmAction(
895
- t('fileManagement.confirms.deleteFile', { filename }),
896
- t('fileManagement.deleteFile'),
897
- t('fileManagement.confirm'),
898
- t('common.cancel')
899
- );
898
+ const confirmFileDelete = useCallback((fileId: string, filename: string) => {
899
+ setPendingDeleteFile({ id: fileId, name: filename });
900
+ fileDeletePrompt.open();
901
+ }, [fileDeletePrompt]);
900
902
 
901
- if (!confirmed) {
902
- return;
903
- }
903
+ const handleFileDelete = useCallback(async () => {
904
+ if (!pendingDeleteFile) return;
905
+ const { id: fileId } = pendingDeleteFile;
904
906
 
905
907
  try {
906
908
  storeSetDeleting(fileId);
@@ -927,24 +929,17 @@ const FileManagementScreen: React.FC<FileManagementScreenProps> = ({
927
929
  }
928
930
  } finally {
929
931
  storeSetDeleting(null);
932
+ setPendingDeleteFile(null);
930
933
  }
931
- };
934
+ }, [pendingDeleteFile, storeSetDeleting, oxyServices, loadFiles, t]);
932
935
 
933
- const handleBulkDelete = useCallback(async () => {
936
+ const confirmBulkDelete = useCallback(() => {
934
937
  if (selectedIds.size === 0) return;
938
+ bulkDeletePrompt.open();
939
+ }, [selectedIds.size, bulkDeletePrompt]);
935
940
 
936
- const fileMap: Record<string, FileMetadata> = {};
937
- files.forEach(f => { fileMap[f.id] = f; });
938
- const selectedFiles = Array.from(selectedIds).map(id => fileMap[id]).filter(Boolean);
939
-
940
- const confirmed = await confirmAction(
941
- t('fileManagement.confirms.deleteFiles', { count: selectedFiles.length }),
942
- t('fileManagement.deleteFiles'),
943
- t('fileManagement.confirm'),
944
- t('common.cancel')
945
- );
946
-
947
- if (!confirmed) return;
941
+ const handleBulkDelete = useCallback(async () => {
942
+ if (selectedIds.size === 0) return;
948
943
 
949
944
  try {
950
945
  const deletePromises = Array.from(selectedIds).map(async (fileId) => {
@@ -1119,7 +1114,7 @@ const FileManagementScreen: React.FC<FileManagementScreenProps> = ({
1119
1114
 
1120
1115
  const showFileDetailsModal = (file: FileMetadata) => {
1121
1116
  setSelectedFile(file);
1122
- setShowFileDetails(true);
1117
+ fileDetailsControl.open();
1123
1118
  };
1124
1119
 
1125
1120
  const renderSimplePhotoItem = useCallback((photo: FileMetadata, index: number) => {
@@ -1350,9 +1345,7 @@ const FileManagementScreen: React.FC<FileManagementScreenProps> = ({
1350
1345
  {/* Always show delete button for debugging */}
1351
1346
  <TouchableOpacity
1352
1347
  style={[fileManagementStyles.actionButton, { backgroundColor: bloomTheme.isDark ? '#400000' : '#FFEBEE' }]}
1353
- onPress={() => {
1354
- handleFileDelete(file.id, file.filename);
1355
- }}
1348
+ onPress={() => confirmFileDelete(file.id, file.filename)}
1356
1349
  disabled={deleting === file.id}
1357
1350
  >
1358
1351
  {deleting === file.id ? (
@@ -1480,7 +1473,7 @@ const FileManagementScreen: React.FC<FileManagementScreenProps> = ({
1480
1473
  </TouchableOpacity>
1481
1474
  <TouchableOpacity
1482
1475
  style={[fileManagementStyles.groupedActionBtn, { backgroundColor: bloomTheme.isDark ? '#400000' : '#FFEBEE' }]}
1483
- onPress={() => handleFileDelete(file.id, file.filename)}
1476
+ onPress={() => confirmFileDelete(file.id, file.filename)}
1484
1477
  disabled={deleting === file.id}
1485
1478
  >
1486
1479
  {deleting === file.id ? (
@@ -1498,7 +1491,7 @@ const FileManagementScreen: React.FC<FileManagementScreenProps> = ({
1498
1491
  ) : undefined,
1499
1492
  };
1500
1493
  });
1501
- }, [filteredFiles, theme, deleting, handleFileDownload, handleFileDelete, handleFileOpen, getSafeDownloadUrlCallback, selectMode, selectedIds]);
1494
+ }, [filteredFiles, theme, deleting, handleFileDownload, confirmFileDelete, handleFileOpen, getSafeDownloadUrlCallback, selectMode, selectedIds]);
1502
1495
 
1503
1496
  // Scroll to selected file after selection
1504
1497
  useEffect(() => {
@@ -1952,15 +1945,14 @@ const FileManagementScreen: React.FC<FileManagementScreenProps> = ({
1952
1945
  onToggleDetails={() => setShowFileDetailsInViewer(!showFileDetailsInViewer)}
1953
1946
  onClose={handleCloseFile}
1954
1947
  onDownload={handleFileDownload}
1955
- onDelete={handleFileDelete}
1948
+ onDelete={confirmFileDelete}
1956
1949
  isOwner={user?.id === targetUserId}
1957
1950
  />
1958
1951
  <FileDetailsModal
1959
- visible={showFileDetails}
1952
+ control={fileDetailsControl}
1960
1953
  file={selectedFile}
1961
- onClose={() => setShowFileDetails(false)}
1962
1954
  onDownload={handleFileDownload}
1963
- onDelete={handleFileDelete}
1955
+ onDelete={confirmFileDelete}
1964
1956
  isOwner={user?.id === targetUserId}
1965
1957
  />
1966
1958
  </>
@@ -1981,7 +1973,6 @@ const FileManagementScreen: React.FC<FileManagementScreenProps> = ({
1981
1973
  titleAlignment="left"
1982
1974
  />
1983
1975
  <UploadPreview
1984
- visible={true}
1985
1976
  pendingFiles={pendingFiles}
1986
1977
  onConfirm={handleConfirmUpload}
1987
1978
  onCancel={handleCancelUpload}
@@ -2019,24 +2010,14 @@ const FileManagementScreen: React.FC<FileManagementScreenProps> = ({
2019
2010
  {
2020
2011
  key: 'delete',
2021
2012
  text: t('fileManagement.delete', { count: selectedIds.size }),
2022
- onPress: handleBulkDelete,
2013
+ onPress: confirmBulkDelete,
2023
2014
  icon: 'delete',
2024
2015
  },
2025
2016
  {
2026
2017
  key: 'visibility',
2027
2018
  text: t('fileManagement.visibility'),
2028
2019
  onPress: () => {
2029
- // Show visibility options menu
2030
- Alert.alert(
2031
- t('fileManagement.changeVisibility'),
2032
- t('fileManagement.changeVisibilityConfirm', { count: selectedIds.size }),
2033
- [
2034
- { text: t('common.cancel'), style: 'cancel' },
2035
- { text: t('fileManagement.private'), onPress: () => handleBulkVisibilityChange('private') },
2036
- { text: t('fileManagement.public'), onPress: () => handleBulkVisibilityChange('public') },
2037
- { text: t('fileManagement.unlisted'), onPress: () => handleBulkVisibilityChange('unlisted') },
2038
- ]
2039
- );
2020
+ visibilityChangePrompt.open();
2040
2021
  },
2041
2022
  icon: 'eye',
2042
2023
  }
@@ -2273,11 +2254,10 @@ const FileManagementScreen: React.FC<FileManagementScreenProps> = ({
2273
2254
 
2274
2255
  {!selectMode && (
2275
2256
  <FileDetailsModal
2276
- visible={showFileDetails}
2257
+ control={fileDetailsControl}
2277
2258
  file={selectedFile}
2278
- onClose={() => setShowFileDetails(false)}
2279
2259
  onDownload={handleFileDownload}
2280
- onDelete={handleFileDelete}
2260
+ onDelete={confirmFileDelete}
2281
2261
  isOwner={user?.id === targetUserId}
2282
2262
  />
2283
2263
  )}
@@ -2312,6 +2292,34 @@ const FileManagementScreen: React.FC<FileManagementScreenProps> = ({
2312
2292
 
2313
2293
  {/* Selection bar removed; actions are now in header */}
2314
2294
  {/* Global loadingMore bar removed; now inline in scroll areas */}
2295
+ <Prompt.Basic
2296
+ control={fileDeletePrompt}
2297
+ title={t('fileManagement.deleteFile') || 'Delete File'}
2298
+ description={pendingDeleteFile ? t('fileManagement.confirms.deleteFile', { filename: pendingDeleteFile.name }) : ''}
2299
+ onConfirm={handleFileDelete}
2300
+ confirmButtonCta={t('fileManagement.confirm') || 'Delete'}
2301
+ confirmButtonColor='negative'
2302
+ />
2303
+ <Prompt.Basic
2304
+ control={bulkDeletePrompt}
2305
+ title={t('fileManagement.deleteFiles') || 'Delete Files'}
2306
+ description={t('fileManagement.confirms.deleteFiles', { count: selectedIds.size })}
2307
+ onConfirm={handleBulkDelete}
2308
+ confirmButtonCta={t('fileManagement.confirm') || 'Delete'}
2309
+ confirmButtonColor='negative'
2310
+ />
2311
+ <Prompt.Outer control={visibilityChangePrompt}>
2312
+ <Prompt.Content>
2313
+ <Prompt.TitleText>{t('fileManagement.changeVisibility') || 'Change Visibility'}</Prompt.TitleText>
2314
+ <Prompt.DescriptionText>{t('fileManagement.changeVisibilityConfirm', { count: selectedIds.size })}</Prompt.DescriptionText>
2315
+ </Prompt.Content>
2316
+ <Prompt.Actions>
2317
+ <Prompt.Action cta={t('fileManagement.private') || 'Private'} onPress={() => handleBulkVisibilityChange('private')} color='primary' />
2318
+ <Prompt.Action cta={t('fileManagement.public') || 'Public'} onPress={() => handleBulkVisibilityChange('public')} color='primary_subtle' />
2319
+ <Prompt.Action cta={t('fileManagement.unlisted') || 'Unlisted'} onPress={() => handleBulkVisibilityChange('unlisted')} color='primary_subtle' />
2320
+ <Prompt.Cancel cta={t('common.cancel') || 'Cancel'} />
2321
+ </Prompt.Actions>
2322
+ </Prompt.Outer>
2315
2323
  </View>
2316
2324
  );
2317
2325
  };