@oxyhq/services 16.0.0 → 17.0.0
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.
- package/lib/commonjs/index.js +21 -51
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/ui/client.js +0 -14
- package/lib/commonjs/ui/client.js.map +1 -1
- package/lib/commonjs/ui/components/OxyAccountDialog.js +764 -0
- package/lib/commonjs/ui/components/OxyAccountDialog.js.map +1 -0
- package/lib/commonjs/ui/components/OxyProvider.js +11 -6
- package/lib/commonjs/ui/components/OxyProvider.js.map +1 -1
- package/lib/commonjs/ui/components/OxySignInButton.js +10 -21
- package/lib/commonjs/ui/components/OxySignInButton.js.map +1 -1
- package/lib/commonjs/ui/components/ProfileButton.js +25 -112
- package/lib/commonjs/ui/components/ProfileButton.js.map +1 -1
- package/lib/commonjs/ui/components/RequireOxyAuth.js +299 -0
- package/lib/commonjs/ui/components/RequireOxyAuth.js.map +1 -0
- package/lib/commonjs/ui/context/OxyContext.js +106 -2
- package/lib/commonjs/ui/context/OxyContext.js.map +1 -1
- package/lib/commonjs/ui/hooks/mutations/useAccountMutations.js +1 -1
- package/lib/commonjs/ui/hooks/useAuth.js +19 -30
- package/lib/commonjs/ui/hooks/useAuth.js.map +1 -1
- package/lib/commonjs/ui/hooks/useSwitchableAccounts.js +37 -267
- package/lib/commonjs/ui/hooks/useSwitchableAccounts.js.map +1 -1
- package/lib/commonjs/ui/index.js +5 -40
- package/lib/commonjs/ui/index.js.map +1 -1
- package/lib/commonjs/ui/navigation/accountDialogManager.js +91 -0
- package/lib/commonjs/ui/navigation/accountDialogManager.js.map +1 -0
- package/lib/commonjs/ui/navigation/routes.js +0 -2
- package/lib/commonjs/ui/navigation/routes.js.map +1 -1
- package/lib/commonjs/ui/screens/ManageAccountScreen.js +4 -3
- package/lib/commonjs/ui/screens/ManageAccountScreen.js.map +1 -1
- package/lib/commonjs/ui/session/createSessionClient.js +10 -2
- package/lib/commonjs/ui/session/createSessionClient.js.map +1 -1
- package/lib/module/index.js +18 -15
- package/lib/module/index.js.map +1 -1
- package/lib/module/ui/client.js +1 -2
- package/lib/module/ui/client.js.map +1 -1
- package/lib/module/ui/components/OxyAccountDialog.js +761 -0
- package/lib/module/ui/components/OxyAccountDialog.js.map +1 -0
- package/lib/module/ui/components/OxyProvider.js +11 -6
- package/lib/module/ui/components/OxyProvider.js.map +1 -1
- package/lib/module/ui/components/OxySignInButton.js +10 -21
- package/lib/module/ui/components/OxySignInButton.js.map +1 -1
- package/lib/module/ui/components/ProfileButton.js +26 -112
- package/lib/module/ui/components/ProfileButton.js.map +1 -1
- package/lib/module/ui/components/RequireOxyAuth.js +294 -0
- package/lib/module/ui/components/RequireOxyAuth.js.map +1 -0
- package/lib/module/ui/context/OxyContext.js +107 -3
- package/lib/module/ui/context/OxyContext.js.map +1 -1
- package/lib/module/ui/hooks/mutations/useAccountMutations.js +1 -1
- package/lib/module/ui/hooks/useAuth.js +19 -30
- package/lib/module/ui/hooks/useAuth.js.map +1 -1
- package/lib/module/ui/hooks/useSwitchableAccounts.js +38 -267
- package/lib/module/ui/hooks/useSwitchableAccounts.js.map +1 -1
- package/lib/module/ui/index.js +1 -5
- package/lib/module/ui/index.js.map +1 -1
- package/lib/module/ui/navigation/accountDialogManager.js +81 -0
- package/lib/module/ui/navigation/accountDialogManager.js.map +1 -0
- package/lib/module/ui/navigation/routes.js +0 -2
- package/lib/module/ui/navigation/routes.js.map +1 -1
- package/lib/module/ui/screens/ManageAccountScreen.js +4 -3
- package/lib/module/ui/screens/ManageAccountScreen.js.map +1 -1
- package/lib/module/ui/session/createSessionClient.js +10 -2
- package/lib/module/ui/session/createSessionClient.js.map +1 -1
- package/lib/typescript/commonjs/index.d.ts +4 -11
- package/lib/typescript/commonjs/index.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/client.d.ts +0 -4
- package/lib/typescript/commonjs/ui/client.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/components/OxyAccountDialog.d.ts +35 -0
- package/lib/typescript/commonjs/ui/components/OxyAccountDialog.d.ts.map +1 -0
- package/lib/typescript/commonjs/ui/components/OxyProvider.d.ts +2 -2
- package/lib/typescript/commonjs/ui/components/OxyProvider.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/components/OxySignInButton.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/components/ProfileButton.d.ts +11 -23
- package/lib/typescript/commonjs/ui/components/ProfileButton.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/components/RequireOxyAuth.d.ts +55 -0
- package/lib/typescript/commonjs/ui/components/RequireOxyAuth.d.ts.map +1 -0
- package/lib/typescript/commonjs/ui/context/OxyContext.d.ts +13 -1
- package/lib/typescript/commonjs/ui/context/OxyContext.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/hooks/mutations/useAccountMutations.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/hooks/useAuth.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/hooks/useSwitchableAccounts.d.ts +13 -152
- package/lib/typescript/commonjs/ui/hooks/useSwitchableAccounts.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/index.d.ts +2 -5
- package/lib/typescript/commonjs/ui/index.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/navigation/accountDialogManager.d.ts +49 -0
- package/lib/typescript/commonjs/ui/navigation/accountDialogManager.d.ts.map +1 -0
- package/lib/typescript/commonjs/ui/navigation/routes.d.ts +1 -1
- package/lib/typescript/commonjs/ui/navigation/routes.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/screens/ManageAccountScreen.d.ts +1 -1
- package/lib/typescript/commonjs/ui/screens/ManageAccountScreen.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/session/createSessionClient.d.ts +9 -2
- package/lib/typescript/commonjs/ui/session/createSessionClient.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/types/navigation.d.ts +9 -0
- package/lib/typescript/commonjs/ui/types/navigation.d.ts.map +1 -1
- package/lib/typescript/module/index.d.ts +4 -11
- package/lib/typescript/module/index.d.ts.map +1 -1
- package/lib/typescript/module/ui/client.d.ts +0 -4
- package/lib/typescript/module/ui/client.d.ts.map +1 -1
- package/lib/typescript/module/ui/components/OxyAccountDialog.d.ts +35 -0
- package/lib/typescript/module/ui/components/OxyAccountDialog.d.ts.map +1 -0
- package/lib/typescript/module/ui/components/OxyProvider.d.ts +2 -2
- package/lib/typescript/module/ui/components/OxyProvider.d.ts.map +1 -1
- package/lib/typescript/module/ui/components/OxySignInButton.d.ts.map +1 -1
- package/lib/typescript/module/ui/components/ProfileButton.d.ts +11 -23
- package/lib/typescript/module/ui/components/ProfileButton.d.ts.map +1 -1
- package/lib/typescript/module/ui/components/RequireOxyAuth.d.ts +55 -0
- package/lib/typescript/module/ui/components/RequireOxyAuth.d.ts.map +1 -0
- package/lib/typescript/module/ui/context/OxyContext.d.ts +13 -1
- package/lib/typescript/module/ui/context/OxyContext.d.ts.map +1 -1
- package/lib/typescript/module/ui/hooks/mutations/useAccountMutations.d.ts.map +1 -1
- package/lib/typescript/module/ui/hooks/useAuth.d.ts.map +1 -1
- package/lib/typescript/module/ui/hooks/useSwitchableAccounts.d.ts +13 -152
- package/lib/typescript/module/ui/hooks/useSwitchableAccounts.d.ts.map +1 -1
- package/lib/typescript/module/ui/index.d.ts +2 -5
- package/lib/typescript/module/ui/index.d.ts.map +1 -1
- package/lib/typescript/module/ui/navigation/accountDialogManager.d.ts +49 -0
- package/lib/typescript/module/ui/navigation/accountDialogManager.d.ts.map +1 -0
- package/lib/typescript/module/ui/navigation/routes.d.ts +1 -1
- package/lib/typescript/module/ui/navigation/routes.d.ts.map +1 -1
- package/lib/typescript/module/ui/screens/ManageAccountScreen.d.ts +1 -1
- package/lib/typescript/module/ui/screens/ManageAccountScreen.d.ts.map +1 -1
- package/lib/typescript/module/ui/session/createSessionClient.d.ts +9 -2
- package/lib/typescript/module/ui/session/createSessionClient.d.ts.map +1 -1
- package/lib/typescript/module/ui/types/navigation.d.ts +9 -0
- package/lib/typescript/module/ui/types/navigation.d.ts.map +1 -1
- package/package.json +2 -2
- package/src/index.ts +21 -26
- package/src/ui/client.ts +0 -4
- package/src/ui/components/OxyAccountDialog.tsx +760 -0
- package/src/ui/components/OxyProvider.tsx +12 -6
- package/src/ui/components/OxySignInButton.tsx +10 -21
- package/src/ui/components/ProfileButton.tsx +23 -126
- package/src/ui/components/RequireOxyAuth.tsx +266 -0
- package/src/ui/context/OxyContext.tsx +146 -7
- package/src/ui/hooks/mutations/useAccountMutations.ts +1 -1
- package/src/ui/hooks/useAuth.ts +19 -31
- package/src/ui/hooks/useSwitchableAccounts.ts +42 -376
- package/src/ui/index.ts +2 -5
- package/src/ui/navigation/accountDialogManager.ts +84 -0
- package/src/ui/navigation/routes.ts +0 -4
- package/src/ui/screens/ManageAccountScreen.tsx +3 -2
- package/src/ui/session/createSessionClient.ts +9 -1
- package/src/ui/types/navigation.ts +9 -0
- package/lib/commonjs/ui/components/AccountMenu.js +0 -598
- package/lib/commonjs/ui/components/AccountMenu.js.map +0 -1
- package/lib/commonjs/ui/components/AccountMenuButton.js +0 -135
- package/lib/commonjs/ui/components/AccountMenuButton.js.map +0 -1
- package/lib/commonjs/ui/components/AccountSwitcher.js +0 -780
- package/lib/commonjs/ui/components/AccountSwitcher.js.map +0 -1
- package/lib/commonjs/ui/components/AnotherDeviceQR.js +0 -116
- package/lib/commonjs/ui/components/AnotherDeviceQR.js.map +0 -1
- package/lib/commonjs/ui/components/ProfileMenu.js +0 -518
- package/lib/commonjs/ui/components/ProfileMenu.js.map +0 -1
- package/lib/commonjs/ui/components/SignInAccountChooser.js +0 -189
- package/lib/commonjs/ui/components/SignInAccountChooser.js.map +0 -1
- package/lib/commonjs/ui/components/SignInModal.js +0 -600
- package/lib/commonjs/ui/components/SignInModal.js.map +0 -1
- package/lib/commonjs/ui/hooks/useOxyAuthSession.js +0 -501
- package/lib/commonjs/ui/hooks/useOxyAuthSession.js.map +0 -1
- package/lib/commonjs/ui/hooks/usePasswordSignIn.js +0 -170
- package/lib/commonjs/ui/hooks/usePasswordSignIn.js.map +0 -1
- package/lib/commonjs/ui/screens/AccountSwitcherScreen.js +0 -51
- package/lib/commonjs/ui/screens/AccountSwitcherScreen.js.map +0 -1
- package/lib/commonjs/ui/screens/OxyAuthScreen.js +0 -312
- package/lib/commonjs/ui/screens/OxyAuthScreen.js.map +0 -1
- package/lib/commonjs/utils/deviceFlowSignIn.js +0 -109
- package/lib/commonjs/utils/deviceFlowSignIn.js.map +0 -1
- package/lib/module/ui/components/AccountMenu.js +0 -593
- package/lib/module/ui/components/AccountMenu.js.map +0 -1
- package/lib/module/ui/components/AccountMenuButton.js +0 -130
- package/lib/module/ui/components/AccountMenuButton.js.map +0 -1
- package/lib/module/ui/components/AccountSwitcher.js +0 -774
- package/lib/module/ui/components/AccountSwitcher.js.map +0 -1
- package/lib/module/ui/components/AnotherDeviceQR.js +0 -110
- package/lib/module/ui/components/AnotherDeviceQR.js.map +0 -1
- package/lib/module/ui/components/ProfileMenu.js +0 -514
- package/lib/module/ui/components/ProfileMenu.js.map +0 -1
- package/lib/module/ui/components/SignInAccountChooser.js +0 -183
- package/lib/module/ui/components/SignInAccountChooser.js.map +0 -1
- package/lib/module/ui/components/SignInModal.js +0 -591
- package/lib/module/ui/components/SignInModal.js.map +0 -1
- package/lib/module/ui/hooks/useOxyAuthSession.js +0 -495
- package/lib/module/ui/hooks/useOxyAuthSession.js.map +0 -1
- package/lib/module/ui/hooks/usePasswordSignIn.js +0 -165
- package/lib/module/ui/hooks/usePasswordSignIn.js.map +0 -1
- package/lib/module/ui/screens/AccountSwitcherScreen.js +0 -48
- package/lib/module/ui/screens/AccountSwitcherScreen.js.map +0 -1
- package/lib/module/ui/screens/OxyAuthScreen.js +0 -306
- package/lib/module/ui/screens/OxyAuthScreen.js.map +0 -1
- package/lib/module/utils/deviceFlowSignIn.js +0 -106
- package/lib/module/utils/deviceFlowSignIn.js.map +0 -1
- package/lib/typescript/commonjs/ui/components/AccountMenu.d.ts +0 -47
- package/lib/typescript/commonjs/ui/components/AccountMenu.d.ts.map +0 -1
- package/lib/typescript/commonjs/ui/components/AccountMenuButton.d.ts +0 -26
- package/lib/typescript/commonjs/ui/components/AccountMenuButton.d.ts.map +0 -1
- package/lib/typescript/commonjs/ui/components/AccountSwitcher.d.ts +0 -46
- package/lib/typescript/commonjs/ui/components/AccountSwitcher.d.ts.map +0 -1
- package/lib/typescript/commonjs/ui/components/AnotherDeviceQR.d.ts +0 -34
- package/lib/typescript/commonjs/ui/components/AnotherDeviceQR.d.ts.map +0 -1
- package/lib/typescript/commonjs/ui/components/ProfileMenu.d.ts +0 -49
- package/lib/typescript/commonjs/ui/components/ProfileMenu.d.ts.map +0 -1
- package/lib/typescript/commonjs/ui/components/SignInAccountChooser.d.ts +0 -29
- package/lib/typescript/commonjs/ui/components/SignInAccountChooser.d.ts.map +0 -1
- package/lib/typescript/commonjs/ui/components/SignInModal.d.ts +0 -28
- package/lib/typescript/commonjs/ui/components/SignInModal.d.ts.map +0 -1
- package/lib/typescript/commonjs/ui/hooks/useOxyAuthSession.d.ts +0 -105
- package/lib/typescript/commonjs/ui/hooks/useOxyAuthSession.d.ts.map +0 -1
- package/lib/typescript/commonjs/ui/hooks/usePasswordSignIn.d.ts +0 -31
- package/lib/typescript/commonjs/ui/hooks/usePasswordSignIn.d.ts.map +0 -1
- package/lib/typescript/commonjs/ui/screens/AccountSwitcherScreen.d.ts +0 -11
- package/lib/typescript/commonjs/ui/screens/AccountSwitcherScreen.d.ts.map +0 -1
- package/lib/typescript/commonjs/ui/screens/OxyAuthScreen.d.ts +0 -22
- package/lib/typescript/commonjs/ui/screens/OxyAuthScreen.d.ts.map +0 -1
- package/lib/typescript/commonjs/utils/deviceFlowSignIn.d.ts +0 -97
- package/lib/typescript/commonjs/utils/deviceFlowSignIn.d.ts.map +0 -1
- package/lib/typescript/module/ui/components/AccountMenu.d.ts +0 -47
- package/lib/typescript/module/ui/components/AccountMenu.d.ts.map +0 -1
- package/lib/typescript/module/ui/components/AccountMenuButton.d.ts +0 -26
- package/lib/typescript/module/ui/components/AccountMenuButton.d.ts.map +0 -1
- package/lib/typescript/module/ui/components/AccountSwitcher.d.ts +0 -46
- package/lib/typescript/module/ui/components/AccountSwitcher.d.ts.map +0 -1
- package/lib/typescript/module/ui/components/AnotherDeviceQR.d.ts +0 -34
- package/lib/typescript/module/ui/components/AnotherDeviceQR.d.ts.map +0 -1
- package/lib/typescript/module/ui/components/ProfileMenu.d.ts +0 -49
- package/lib/typescript/module/ui/components/ProfileMenu.d.ts.map +0 -1
- package/lib/typescript/module/ui/components/SignInAccountChooser.d.ts +0 -29
- package/lib/typescript/module/ui/components/SignInAccountChooser.d.ts.map +0 -1
- package/lib/typescript/module/ui/components/SignInModal.d.ts +0 -28
- package/lib/typescript/module/ui/components/SignInModal.d.ts.map +0 -1
- package/lib/typescript/module/ui/hooks/useOxyAuthSession.d.ts +0 -105
- package/lib/typescript/module/ui/hooks/useOxyAuthSession.d.ts.map +0 -1
- package/lib/typescript/module/ui/hooks/usePasswordSignIn.d.ts +0 -31
- package/lib/typescript/module/ui/hooks/usePasswordSignIn.d.ts.map +0 -1
- package/lib/typescript/module/ui/screens/AccountSwitcherScreen.d.ts +0 -11
- package/lib/typescript/module/ui/screens/AccountSwitcherScreen.d.ts.map +0 -1
- package/lib/typescript/module/ui/screens/OxyAuthScreen.d.ts +0 -22
- package/lib/typescript/module/ui/screens/OxyAuthScreen.d.ts.map +0 -1
- package/lib/typescript/module/utils/deviceFlowSignIn.d.ts +0 -97
- package/lib/typescript/module/utils/deviceFlowSignIn.d.ts.map +0 -1
- package/src/ui/components/AccountMenu.tsx +0 -645
- package/src/ui/components/AccountMenuButton.tsx +0 -126
- package/src/ui/components/AccountSwitcher.tsx +0 -751
- package/src/ui/components/AnotherDeviceQR.tsx +0 -119
- package/src/ui/components/ProfileMenu.tsx +0 -564
- package/src/ui/components/SignInAccountChooser.tsx +0 -162
- package/src/ui/components/SignInModal.tsx +0 -530
- package/src/ui/hooks/useOxyAuthSession.ts +0 -635
- package/src/ui/hooks/usePasswordSignIn.ts +0 -207
- package/src/ui/screens/AccountSwitcherScreen.tsx +0 -43
- package/src/ui/screens/OxyAuthScreen.tsx +0 -324
- package/src/utils/__tests__/deviceFlowSignIn.test.ts +0 -231
- package/src/utils/deviceFlowSignIn.ts +0 -152
|
@@ -1,645 +0,0 @@
|
|
|
1
|
-
import type React from 'react';
|
|
2
|
-
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
|
3
|
-
import {
|
|
4
|
-
View,
|
|
5
|
-
Text,
|
|
6
|
-
TouchableOpacity,
|
|
7
|
-
StyleSheet,
|
|
8
|
-
ScrollView,
|
|
9
|
-
Modal,
|
|
10
|
-
Pressable,
|
|
11
|
-
Platform,
|
|
12
|
-
ActivityIndicator,
|
|
13
|
-
type ViewStyle,
|
|
14
|
-
} from 'react-native';
|
|
15
|
-
import { Ionicons } from '@expo/vector-icons';
|
|
16
|
-
import { toast, useDialogControl, Dialog } from '@oxyhq/bloom';
|
|
17
|
-
import { Divider } from '@oxyhq/bloom/divider';
|
|
18
|
-
import { useTheme } from '@oxyhq/bloom/theme';
|
|
19
|
-
import Avatar from './Avatar';
|
|
20
|
-
import { useOxy } from '../context/OxyContext';
|
|
21
|
-
import { useI18n } from '../hooks/useI18n';
|
|
22
|
-
import { isDev, logger as loggerUtil } from '@oxyhq/core';
|
|
23
|
-
import { useSwitchableAccounts, type SwitchableAccount } from '../hooks/useSwitchableAccounts';
|
|
24
|
-
|
|
25
|
-
/**
|
|
26
|
-
* Web-only anchor for the popover panel. Each field anchors the panel against
|
|
27
|
-
* one viewport edge, so the popover can be placed against ANY corner: a
|
|
28
|
-
* top-right avatar chip opens downward/right-aligned (`{ top, right }`), while a
|
|
29
|
-
* bottom-left account button opens upward/left-aligned (`{ bottom, left }`).
|
|
30
|
-
*
|
|
31
|
-
* Callers MUST supply at most one vertical edge (`top` XOR `bottom`) and at most
|
|
32
|
-
* one horizontal edge (`left` XOR `right`). The panel has a fixed width and
|
|
33
|
-
* `maxHeight`, so a single vertical + single horizontal edge fully positions it.
|
|
34
|
-
* Supplying both opposite edges (e.g. `top` AND `bottom`) would stretch the
|
|
35
|
-
* panel on RN-Web and is unsupported.
|
|
36
|
-
*/
|
|
37
|
-
export interface AccountMenuAnchor {
|
|
38
|
-
/** Distance from the viewport top, when anchoring the panel's TOP edge. */
|
|
39
|
-
top?: number;
|
|
40
|
-
/** Distance from the viewport bottom, when anchoring the panel's BOTTOM edge (opens upward). */
|
|
41
|
-
bottom?: number;
|
|
42
|
-
/** Distance from the viewport left, when anchoring the panel's LEFT edge. */
|
|
43
|
-
left?: number;
|
|
44
|
-
/** Distance from the viewport right, when anchoring the panel's RIGHT edge. */
|
|
45
|
-
right?: number;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
export interface AccountMenuProps {
|
|
49
|
-
open: boolean;
|
|
50
|
-
onClose: () => void;
|
|
51
|
-
onNavigateManage: () => void;
|
|
52
|
-
onAddAccount: () => void;
|
|
53
|
-
/** Optional anchor (web only). Native ignores this and uses bottom-sheet style. */
|
|
54
|
-
anchor?: AccountMenuAnchor | null;
|
|
55
|
-
/** Called before the active identity changes so apps can clear tenant-scoped state. */
|
|
56
|
-
onBeforeSessionChange?: () => void | Promise<void>;
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
const isWeb = Platform.OS === 'web';
|
|
60
|
-
|
|
61
|
-
/** Fixed popover width on web. Callers that compute an anchor (e.g. inbox's
|
|
62
|
-
* MailboxDrawer) key their gutter math off this — keep them consistent. */
|
|
63
|
-
const PANEL_WIDTH = 360;
|
|
64
|
-
|
|
65
|
-
/**
|
|
66
|
-
* Unified, canonical account switcher for the Oxy ecosystem. Gmail-style: the
|
|
67
|
-
* accounts list sits at the top (current account first, with a checkmark), then
|
|
68
|
-
* "Add another account", "Manage account", and the sign-out actions. Lists EVERY
|
|
69
|
-
* switchable account (device sign-ins AND linked graph accounts) and routes every
|
|
70
|
-
* switch through the single `switchToAccount(accountId)` path.
|
|
71
|
-
*
|
|
72
|
-
* Reads everything it needs from `useOxy()` / `useSwitchableAccounts()` — never
|
|
73
|
-
* receives a session via props. Renders as a popover anchored to the trigger on
|
|
74
|
-
* web, and as a full-width bottom-sheet style modal on native.
|
|
75
|
-
*/
|
|
76
|
-
const AccountMenu: React.FC<AccountMenuProps> = ({
|
|
77
|
-
open,
|
|
78
|
-
onClose,
|
|
79
|
-
onNavigateManage,
|
|
80
|
-
onAddAccount,
|
|
81
|
-
anchor,
|
|
82
|
-
onBeforeSessionChange,
|
|
83
|
-
}) => {
|
|
84
|
-
const {
|
|
85
|
-
switchToAccount,
|
|
86
|
-
logout,
|
|
87
|
-
logoutAll,
|
|
88
|
-
removeSession,
|
|
89
|
-
} = useOxy();
|
|
90
|
-
const { t } = useI18n();
|
|
91
|
-
const bloomTheme = useTheme();
|
|
92
|
-
const colors = bloomTheme.colors;
|
|
93
|
-
|
|
94
|
-
// Source EVERY switchable account — device sign-ins AND linked graph
|
|
95
|
-
// accounts (owned orgs + shared-with-you) — from the single
|
|
96
|
-
// `useSwitchableAccounts` hook, each hydrated with real
|
|
97
|
-
// name/email/avatar/color. It also synthesises a live-user row when the
|
|
98
|
-
// device set has not synced yet, so the signed-in user is always represented
|
|
99
|
-
// (no "Not signed in" false negative).
|
|
100
|
-
const { accounts } = useSwitchableAccounts();
|
|
101
|
-
|
|
102
|
-
const [switchingAccountId, setSwitchingAccountId] = useState<string | null>(null);
|
|
103
|
-
const [removingSessionId, setRemovingSessionId] = useState<string | null>(null);
|
|
104
|
-
const [signingOut, setSigningOut] = useState(false);
|
|
105
|
-
const [signingOutAll, setSigningOutAll] = useState(false);
|
|
106
|
-
|
|
107
|
-
const signOutDialog = useDialogControl();
|
|
108
|
-
const signOutAllDialog = useDialogControl();
|
|
109
|
-
|
|
110
|
-
const containerRef = useRef<View | null>(null);
|
|
111
|
-
|
|
112
|
-
// Current account first, then the remaining device sign-ins, then the linked
|
|
113
|
-
// graph accounts — matching the Gmail-style chooser the inbox design ports.
|
|
114
|
-
const rows = useMemo<SwitchableAccount[]>(() => {
|
|
115
|
-
const device = accounts.filter((account) => account.onDevice);
|
|
116
|
-
const graph = accounts.filter((account) => !account.onDevice);
|
|
117
|
-
const current = device.filter((account) => account.isCurrent);
|
|
118
|
-
const others = device.filter((account) => !account.isCurrent);
|
|
119
|
-
return [...current, ...others, ...graph];
|
|
120
|
-
}, [accounts]);
|
|
121
|
-
|
|
122
|
-
// "Sign out of all accounts" only applies to real device sessions.
|
|
123
|
-
const deviceCount = useMemo(
|
|
124
|
-
() => accounts.filter((account) => account.onDevice).length,
|
|
125
|
-
[accounts],
|
|
126
|
-
);
|
|
127
|
-
|
|
128
|
-
// Account ids currently listed — used to indent a graph-only row whose parent
|
|
129
|
-
// account is also shown.
|
|
130
|
-
const listedAccountIds = useMemo(
|
|
131
|
-
() => new Set(rows.map((row) => row.accountId)),
|
|
132
|
-
[rows],
|
|
133
|
-
);
|
|
134
|
-
|
|
135
|
-
const isSwitching = switchingAccountId !== null;
|
|
136
|
-
|
|
137
|
-
// The ONE uniform switch path: every row (device sign-in or linked graph
|
|
138
|
-
// account) routes through `useOxy().switchToAccount(accountId)`. It reuses
|
|
139
|
-
// the device session when the account is already signed in here, and mints a
|
|
140
|
-
// real session only on the first switch into a graph account — a single
|
|
141
|
-
// source of truth for every switch.
|
|
142
|
-
const handleSwitch = useCallback(async (account: SwitchableAccount) => {
|
|
143
|
-
if (account.isCurrent || switchingAccountId) {
|
|
144
|
-
return;
|
|
145
|
-
}
|
|
146
|
-
setSwitchingAccountId(account.accountId);
|
|
147
|
-
try {
|
|
148
|
-
await onBeforeSessionChange?.();
|
|
149
|
-
await switchToAccount(account.accountId);
|
|
150
|
-
toast.success(t('accountSwitcher.toasts.switchSuccess') || 'Switched account');
|
|
151
|
-
onClose();
|
|
152
|
-
} catch (error) {
|
|
153
|
-
if (!isDev()) {
|
|
154
|
-
loggerUtil.warn('Switch account failed', { component: 'AccountMenu' }, error as unknown);
|
|
155
|
-
}
|
|
156
|
-
toast.error(t('accountSwitcher.toasts.switchFailed') || 'Failed to switch account');
|
|
157
|
-
} finally {
|
|
158
|
-
setSwitchingAccountId(null);
|
|
159
|
-
}
|
|
160
|
-
}, [switchingAccountId, switchToAccount, t, onClose, onBeforeSessionChange]);
|
|
161
|
-
|
|
162
|
-
// Sign out a SPECIFIC inactive account from its per-row icon. `removeSession`
|
|
163
|
-
// is the SDK's canonical per-session sign-out: it targets the given session
|
|
164
|
-
// id (cookie-cleared logout via `authuser` slot on web, bearer logout
|
|
165
|
-
// otherwise) and removes ONLY that account without switching/clearing the
|
|
166
|
-
// active session. The menu stays open so the user can keep managing accounts.
|
|
167
|
-
const handleRemove = useCallback(async (sessionId: string) => {
|
|
168
|
-
if (removingSessionId) {
|
|
169
|
-
return;
|
|
170
|
-
}
|
|
171
|
-
setRemovingSessionId(sessionId);
|
|
172
|
-
try {
|
|
173
|
-
await removeSession(sessionId);
|
|
174
|
-
toast.success(t('common.actions.signedOut') || 'Signed out');
|
|
175
|
-
} catch (error) {
|
|
176
|
-
loggerUtil.warn('Remove account failed', { component: 'AccountMenu' }, error as unknown);
|
|
177
|
-
toast.error(t('common.errors.signOutFailed') || 'Failed to sign out');
|
|
178
|
-
} finally {
|
|
179
|
-
setRemovingSessionId(null);
|
|
180
|
-
}
|
|
181
|
-
}, [removingSessionId, removeSession, t]);
|
|
182
|
-
|
|
183
|
-
const performSignOut = useCallback(async () => {
|
|
184
|
-
if (signingOut) {
|
|
185
|
-
return;
|
|
186
|
-
}
|
|
187
|
-
setSigningOut(true);
|
|
188
|
-
try {
|
|
189
|
-
await onBeforeSessionChange?.();
|
|
190
|
-
await logout();
|
|
191
|
-
toast.success(t('common.actions.signedOut') || 'Signed out');
|
|
192
|
-
onClose();
|
|
193
|
-
} catch (error) {
|
|
194
|
-
loggerUtil.warn('Sign out failed', { component: 'AccountMenu' }, error as unknown);
|
|
195
|
-
toast.error(t('common.errors.signOutFailed') || 'Failed to sign out');
|
|
196
|
-
} finally {
|
|
197
|
-
setSigningOut(false);
|
|
198
|
-
}
|
|
199
|
-
}, [signingOut, logout, t, onClose, onBeforeSessionChange]);
|
|
200
|
-
|
|
201
|
-
const performSignOutAll = useCallback(async () => {
|
|
202
|
-
if (signingOutAll) {
|
|
203
|
-
return;
|
|
204
|
-
}
|
|
205
|
-
setSigningOutAll(true);
|
|
206
|
-
try {
|
|
207
|
-
await onBeforeSessionChange?.();
|
|
208
|
-
await logoutAll();
|
|
209
|
-
toast.success(t('accountSwitcher.toasts.signOutAllSuccess') || 'Signed out of all accounts');
|
|
210
|
-
onClose();
|
|
211
|
-
} catch (error) {
|
|
212
|
-
loggerUtil.warn('Sign out all failed', { component: 'AccountMenu' }, error as unknown);
|
|
213
|
-
toast.error(t('common.errors.signOutAllFailed') || 'Failed to sign out of all accounts');
|
|
214
|
-
} finally {
|
|
215
|
-
setSigningOutAll(false);
|
|
216
|
-
}
|
|
217
|
-
}, [signingOutAll, logoutAll, t, onClose, onBeforeSessionChange]);
|
|
218
|
-
|
|
219
|
-
// Escape-to-close + focus management (web only).
|
|
220
|
-
useEffect(() => {
|
|
221
|
-
if (!open || !isWeb || typeof document === 'undefined') {
|
|
222
|
-
return undefined;
|
|
223
|
-
}
|
|
224
|
-
const onKey = (event: KeyboardEvent) => {
|
|
225
|
-
if (event.key === 'Escape') {
|
|
226
|
-
event.stopPropagation();
|
|
227
|
-
onClose();
|
|
228
|
-
}
|
|
229
|
-
};
|
|
230
|
-
document.addEventListener('keydown', onKey, true);
|
|
231
|
-
return () => document.removeEventListener('keydown', onKey, true);
|
|
232
|
-
}, [open, onClose]);
|
|
233
|
-
|
|
234
|
-
if (!open) {
|
|
235
|
-
return null;
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
const overlayStyles: ViewStyle = isWeb
|
|
239
|
-
? styles.webOverlay
|
|
240
|
-
: styles.nativeOverlay;
|
|
241
|
-
|
|
242
|
-
// Apply ONLY the edges the anchor supplies (so the panel never sets
|
|
243
|
-
// conflicting opposite edges). When no anchor is provided, fall back to the
|
|
244
|
-
// historical top-right placement used by `AccountMenuButton`.
|
|
245
|
-
const anchorStyle: ViewStyle = anchor
|
|
246
|
-
? {
|
|
247
|
-
...(anchor.top !== undefined ? { top: anchor.top } : null),
|
|
248
|
-
...(anchor.bottom !== undefined ? { bottom: anchor.bottom } : null),
|
|
249
|
-
...(anchor.left !== undefined ? { left: anchor.left } : null),
|
|
250
|
-
...(anchor.right !== undefined ? { right: anchor.right } : null),
|
|
251
|
-
}
|
|
252
|
-
: { top: 64, right: 16 };
|
|
253
|
-
|
|
254
|
-
const panelStyles: ViewStyle[] = isWeb
|
|
255
|
-
? [
|
|
256
|
-
styles.panelBase,
|
|
257
|
-
styles.panelWeb,
|
|
258
|
-
anchorStyle,
|
|
259
|
-
{ backgroundColor: colors.background, borderColor: colors.border },
|
|
260
|
-
]
|
|
261
|
-
: [
|
|
262
|
-
styles.panelBase,
|
|
263
|
-
styles.panelNative,
|
|
264
|
-
{ backgroundColor: colors.background },
|
|
265
|
-
];
|
|
266
|
-
|
|
267
|
-
const actionDisabled = isSwitching || signingOut || signingOutAll;
|
|
268
|
-
|
|
269
|
-
const content = (
|
|
270
|
-
<Pressable
|
|
271
|
-
ref={containerRef}
|
|
272
|
-
// Swallow taps inside the panel so they never reach the overlay's
|
|
273
|
-
// outside-tap-to-close handler. (On web the panel is a direct,
|
|
274
|
-
// absolutely-positioned child of the overlay so the anchor resolves
|
|
275
|
-
// against the viewport.)
|
|
276
|
-
onPress={() => undefined}
|
|
277
|
-
style={panelStyles}
|
|
278
|
-
accessibilityRole="menu"
|
|
279
|
-
accessibilityLabel={t('accountMenu.label') || 'Account menu'}
|
|
280
|
-
>
|
|
281
|
-
<ScrollView
|
|
282
|
-
style={styles.scroll}
|
|
283
|
-
contentContainerStyle={styles.scrollContent}
|
|
284
|
-
showsVerticalScrollIndicator={false}
|
|
285
|
-
>
|
|
286
|
-
{/* 1) Accounts list — current first (checkmark), then the other
|
|
287
|
-
device sign-ins, then linked graph accounts (role badge,
|
|
288
|
-
indented under their parent). Every row switches the same way. */}
|
|
289
|
-
{rows.map((row) => {
|
|
290
|
-
const sessionId = row.sessionId;
|
|
291
|
-
const isBusy = switchingAccountId === row.accountId;
|
|
292
|
-
const isRemoving = sessionId ? removingSessionId === sessionId : false;
|
|
293
|
-
const isChild = Boolean(
|
|
294
|
-
row.parentAccountId && listedAccountIds.has(row.parentAccountId),
|
|
295
|
-
);
|
|
296
|
-
const role = row.callerMembership?.role;
|
|
297
|
-
return (
|
|
298
|
-
<TouchableOpacity
|
|
299
|
-
key={`account-${row.accountId}`}
|
|
300
|
-
accessibilityRole="menuitem"
|
|
301
|
-
accessibilityLabel={row.displayName}
|
|
302
|
-
accessibilityState={{ selected: row.isCurrent }}
|
|
303
|
-
onPress={() => handleSwitch(row)}
|
|
304
|
-
disabled={row.isCurrent || isBusy || isSwitching}
|
|
305
|
-
activeOpacity={0.6}
|
|
306
|
-
style={[
|
|
307
|
-
styles.accountRow,
|
|
308
|
-
isChild && styles.childRow,
|
|
309
|
-
row.isCurrent && { backgroundColor: colors.primarySubtle },
|
|
310
|
-
isSwitching && !row.isCurrent && styles.rowDisabled,
|
|
311
|
-
]}
|
|
312
|
-
>
|
|
313
|
-
<Avatar
|
|
314
|
-
uri={row.avatarUrl}
|
|
315
|
-
name={row.displayName}
|
|
316
|
-
size={row.isCurrent ? 40 : isChild ? 28 : 32}
|
|
317
|
-
/>
|
|
318
|
-
<View style={styles.accountInfo}>
|
|
319
|
-
<View style={styles.nameRow}>
|
|
320
|
-
<Text
|
|
321
|
-
style={[
|
|
322
|
-
styles.accountName,
|
|
323
|
-
{ color: colors.text },
|
|
324
|
-
row.isCurrent && styles.accountNameActive,
|
|
325
|
-
]}
|
|
326
|
-
numberOfLines={1}
|
|
327
|
-
>
|
|
328
|
-
{row.displayName}
|
|
329
|
-
</Text>
|
|
330
|
-
{role ? (
|
|
331
|
-
<View style={[styles.roleBadge, { backgroundColor: colors.card }]}>
|
|
332
|
-
<Text style={[styles.roleBadgeText, { color: colors.textSecondary }]}>
|
|
333
|
-
{t(`accounts.roles.${role}.label`) || role}
|
|
334
|
-
</Text>
|
|
335
|
-
</View>
|
|
336
|
-
) : null}
|
|
337
|
-
</View>
|
|
338
|
-
{row.email ? (
|
|
339
|
-
<Text
|
|
340
|
-
style={[styles.accountEmail, { color: colors.textSecondary }]}
|
|
341
|
-
numberOfLines={1}
|
|
342
|
-
>
|
|
343
|
-
{row.email}
|
|
344
|
-
</Text>
|
|
345
|
-
) : null}
|
|
346
|
-
</View>
|
|
347
|
-
{isBusy ? (
|
|
348
|
-
<ActivityIndicator color={colors.primary} size="small" />
|
|
349
|
-
) : row.isCurrent ? (
|
|
350
|
-
<Ionicons name="checkmark" size={20} color={colors.primary} />
|
|
351
|
-
) : isRemoving ? (
|
|
352
|
-
<ActivityIndicator color={colors.textSecondary} size="small" />
|
|
353
|
-
) : sessionId ? (
|
|
354
|
-
<TouchableOpacity
|
|
355
|
-
accessibilityRole="button"
|
|
356
|
-
accessibilityLabel={
|
|
357
|
-
t('accountMenu.signOutAccount', { name: row.displayName })
|
|
358
|
-
|| `Sign out ${row.displayName}`
|
|
359
|
-
}
|
|
360
|
-
onPress={() => handleRemove(sessionId)}
|
|
361
|
-
disabled={isSwitching || removingSessionId !== null}
|
|
362
|
-
activeOpacity={0.6}
|
|
363
|
-
hitSlop={{ top: 8, bottom: 8, left: 8, right: 8 }}
|
|
364
|
-
style={styles.rowSignOutButton}
|
|
365
|
-
>
|
|
366
|
-
<Ionicons
|
|
367
|
-
name="log-out-outline"
|
|
368
|
-
size={18}
|
|
369
|
-
color={colors.textSecondary}
|
|
370
|
-
/>
|
|
371
|
-
</TouchableOpacity>
|
|
372
|
-
) : null}
|
|
373
|
-
</TouchableOpacity>
|
|
374
|
-
);
|
|
375
|
-
})}
|
|
376
|
-
|
|
377
|
-
{/* 2) Switching indicator. */}
|
|
378
|
-
{isSwitching ? (
|
|
379
|
-
<View style={styles.switchingRow}>
|
|
380
|
-
<ActivityIndicator color={colors.textSecondary} size="small" />
|
|
381
|
-
<Text style={[styles.switchingText, { color: colors.textSecondary }]}>
|
|
382
|
-
{t('accountMenu.switching') || 'Switching account…'}
|
|
383
|
-
</Text>
|
|
384
|
-
</View>
|
|
385
|
-
) : null}
|
|
386
|
-
|
|
387
|
-
<Divider color={colors.border} spacing={4} />
|
|
388
|
-
|
|
389
|
-
{/* 3) Add another account. */}
|
|
390
|
-
<TouchableOpacity
|
|
391
|
-
accessibilityRole="menuitem"
|
|
392
|
-
accessibilityLabel={t('accountMenu.addAnother') || 'Add another account'}
|
|
393
|
-
onPress={() => {
|
|
394
|
-
onClose();
|
|
395
|
-
onAddAccount();
|
|
396
|
-
}}
|
|
397
|
-
disabled={actionDisabled}
|
|
398
|
-
activeOpacity={0.6}
|
|
399
|
-
style={[styles.actionRow, actionDisabled && styles.rowDisabled]}
|
|
400
|
-
>
|
|
401
|
-
<Ionicons name="person-add-outline" size={20} color={colors.icon} />
|
|
402
|
-
<Text style={[styles.actionText, { color: colors.text }]}>
|
|
403
|
-
{t('accountMenu.addAnother') || 'Add another account'}
|
|
404
|
-
</Text>
|
|
405
|
-
</TouchableOpacity>
|
|
406
|
-
|
|
407
|
-
<Divider color={colors.border} spacing={4} />
|
|
408
|
-
|
|
409
|
-
{/* 4) Manage account / Settings. */}
|
|
410
|
-
<TouchableOpacity
|
|
411
|
-
accessibilityRole="menuitem"
|
|
412
|
-
accessibilityLabel={t('accountMenu.manage') || 'Manage your Oxy Account'}
|
|
413
|
-
onPress={() => {
|
|
414
|
-
onClose();
|
|
415
|
-
onNavigateManage();
|
|
416
|
-
}}
|
|
417
|
-
disabled={actionDisabled}
|
|
418
|
-
activeOpacity={0.6}
|
|
419
|
-
style={[styles.actionRow, actionDisabled && styles.rowDisabled]}
|
|
420
|
-
>
|
|
421
|
-
<Ionicons name="settings-outline" size={18} color={colors.icon} />
|
|
422
|
-
<Text style={[styles.actionText, { color: colors.text }]}>
|
|
423
|
-
{t('accountMenu.manage') || 'Manage your Oxy Account'}
|
|
424
|
-
</Text>
|
|
425
|
-
</TouchableOpacity>
|
|
426
|
-
|
|
427
|
-
{/* 5) Sign out (current). */}
|
|
428
|
-
<TouchableOpacity
|
|
429
|
-
accessibilityRole="menuitem"
|
|
430
|
-
accessibilityLabel={t('common.actions.signOut') || 'Sign out'}
|
|
431
|
-
onPress={() => signOutDialog.open()}
|
|
432
|
-
disabled={actionDisabled}
|
|
433
|
-
activeOpacity={0.6}
|
|
434
|
-
style={[styles.actionRow, actionDisabled && styles.rowDisabled]}
|
|
435
|
-
>
|
|
436
|
-
{signingOut ? (
|
|
437
|
-
<ActivityIndicator color={colors.error} size="small" />
|
|
438
|
-
) : (
|
|
439
|
-
<Ionicons name="log-out-outline" size={18} color={colors.error} />
|
|
440
|
-
)}
|
|
441
|
-
<Text style={[styles.actionText, { color: colors.error }]}>
|
|
442
|
-
{t('common.actions.signOut') || 'Sign out'}
|
|
443
|
-
</Text>
|
|
444
|
-
</TouchableOpacity>
|
|
445
|
-
|
|
446
|
-
{/* 6) Sign out of all accounts (only when >1 device sign-in). */}
|
|
447
|
-
{deviceCount > 1 ? (
|
|
448
|
-
<TouchableOpacity
|
|
449
|
-
accessibilityRole="menuitem"
|
|
450
|
-
accessibilityLabel={t('accountMenu.signOutAll') || 'Sign out of all accounts'}
|
|
451
|
-
onPress={() => signOutAllDialog.open()}
|
|
452
|
-
disabled={actionDisabled}
|
|
453
|
-
activeOpacity={0.6}
|
|
454
|
-
style={[styles.actionRow, actionDisabled && styles.rowDisabled]}
|
|
455
|
-
>
|
|
456
|
-
{signingOutAll ? (
|
|
457
|
-
<ActivityIndicator color={colors.error} size="small" />
|
|
458
|
-
) : (
|
|
459
|
-
<Ionicons name="log-out-outline" size={18} color={colors.error} />
|
|
460
|
-
)}
|
|
461
|
-
<Text style={[styles.actionText, { color: colors.error }]}>
|
|
462
|
-
{t('accountMenu.signOutAll') || 'Sign out of all accounts'}
|
|
463
|
-
</Text>
|
|
464
|
-
</TouchableOpacity>
|
|
465
|
-
) : null}
|
|
466
|
-
</ScrollView>
|
|
467
|
-
</Pressable>
|
|
468
|
-
);
|
|
469
|
-
|
|
470
|
-
return (
|
|
471
|
-
<Modal
|
|
472
|
-
visible={open}
|
|
473
|
-
transparent
|
|
474
|
-
animationType={isWeb ? 'fade' : 'slide'}
|
|
475
|
-
onRequestClose={onClose}
|
|
476
|
-
>
|
|
477
|
-
<Pressable
|
|
478
|
-
accessibilityRole="button"
|
|
479
|
-
accessibilityLabel={t('common.actions.close') || 'Close'}
|
|
480
|
-
onPress={onClose}
|
|
481
|
-
style={overlayStyles}
|
|
482
|
-
>
|
|
483
|
-
{/*
|
|
484
|
-
* Web: the panel is `position: absolute` and rendered as a DIRECT
|
|
485
|
-
* child of the full-viewport overlay, so its anchor edges resolve
|
|
486
|
-
* against the viewport. The panel swallows its own taps.
|
|
487
|
-
*
|
|
488
|
-
* Native: the overlay is `justify-content: flex-end`, so the
|
|
489
|
-
* (statically positioned) panel docks to the bottom as a sheet.
|
|
490
|
-
*/}
|
|
491
|
-
{content}
|
|
492
|
-
</Pressable>
|
|
493
|
-
|
|
494
|
-
<Dialog
|
|
495
|
-
control={signOutDialog}
|
|
496
|
-
title={t('common.actions.signOut') || 'Sign out'}
|
|
497
|
-
description={t('common.confirms.signOut') || 'Are you sure you want to sign out?'}
|
|
498
|
-
actions={[
|
|
499
|
-
{
|
|
500
|
-
label: t('common.actions.signOut') || 'Sign out',
|
|
501
|
-
color: 'destructive',
|
|
502
|
-
onPress: performSignOut,
|
|
503
|
-
},
|
|
504
|
-
{ label: t('common.cancel') || 'Cancel', color: 'cancel' },
|
|
505
|
-
]}
|
|
506
|
-
/>
|
|
507
|
-
<Dialog
|
|
508
|
-
control={signOutAllDialog}
|
|
509
|
-
title={t('accountMenu.signOutAll') || 'Sign out of all accounts'}
|
|
510
|
-
description={t('common.confirms.signOutAll') || 'Are you sure you want to sign out of all accounts?'}
|
|
511
|
-
actions={[
|
|
512
|
-
{
|
|
513
|
-
label: t('accountMenu.signOutAll') || 'Sign out of all accounts',
|
|
514
|
-
color: 'destructive',
|
|
515
|
-
onPress: performSignOutAll,
|
|
516
|
-
},
|
|
517
|
-
{ label: t('common.cancel') || 'Cancel', color: 'cancel' },
|
|
518
|
-
]}
|
|
519
|
-
/>
|
|
520
|
-
</Modal>
|
|
521
|
-
);
|
|
522
|
-
};
|
|
523
|
-
|
|
524
|
-
const styles = StyleSheet.create({
|
|
525
|
-
webOverlay: {
|
|
526
|
-
flex: 1,
|
|
527
|
-
backgroundColor: 'transparent',
|
|
528
|
-
// Explicit positioning context: the absolutely-positioned panel is a
|
|
529
|
-
// direct child and resolves its anchor edges (top/bottom/left/right)
|
|
530
|
-
// against this full-viewport overlay — matching the trigger-rect math
|
|
531
|
-
// callers compute from `window.innerWidth` / `window.innerHeight`.
|
|
532
|
-
position: 'relative',
|
|
533
|
-
},
|
|
534
|
-
nativeOverlay: {
|
|
535
|
-
flex: 1,
|
|
536
|
-
backgroundColor: 'rgba(0,0,0,0.32)',
|
|
537
|
-
justifyContent: 'flex-end',
|
|
538
|
-
},
|
|
539
|
-
panelBase: {
|
|
540
|
-
borderRadius: 12,
|
|
541
|
-
shadowColor: '#000',
|
|
542
|
-
shadowOpacity: 0.18,
|
|
543
|
-
shadowRadius: 24,
|
|
544
|
-
shadowOffset: { width: 0, height: 8 },
|
|
545
|
-
elevation: 12,
|
|
546
|
-
overflow: 'hidden',
|
|
547
|
-
},
|
|
548
|
-
panelWeb: {
|
|
549
|
-
position: 'absolute',
|
|
550
|
-
width: PANEL_WIDTH,
|
|
551
|
-
maxHeight: '85%',
|
|
552
|
-
borderWidth: 1,
|
|
553
|
-
},
|
|
554
|
-
panelNative: {
|
|
555
|
-
marginHorizontal: 0,
|
|
556
|
-
borderTopLeftRadius: 20,
|
|
557
|
-
borderTopRightRadius: 20,
|
|
558
|
-
borderBottomLeftRadius: 0,
|
|
559
|
-
borderBottomRightRadius: 0,
|
|
560
|
-
paddingBottom: 12,
|
|
561
|
-
maxHeight: '85%',
|
|
562
|
-
},
|
|
563
|
-
scroll: {
|
|
564
|
-
flexGrow: 0,
|
|
565
|
-
},
|
|
566
|
-
scrollContent: {
|
|
567
|
-
paddingVertical: 4,
|
|
568
|
-
},
|
|
569
|
-
accountRow: {
|
|
570
|
-
flexDirection: 'row',
|
|
571
|
-
alignItems: 'center',
|
|
572
|
-
paddingHorizontal: 14,
|
|
573
|
-
paddingVertical: 10,
|
|
574
|
-
gap: 10,
|
|
575
|
-
},
|
|
576
|
-
childRow: {
|
|
577
|
-
paddingLeft: 34,
|
|
578
|
-
},
|
|
579
|
-
rowDisabled: {
|
|
580
|
-
opacity: 0.4,
|
|
581
|
-
},
|
|
582
|
-
accountInfo: {
|
|
583
|
-
flex: 1,
|
|
584
|
-
minWidth: 0,
|
|
585
|
-
},
|
|
586
|
-
nameRow: {
|
|
587
|
-
flexDirection: 'row',
|
|
588
|
-
alignItems: 'center',
|
|
589
|
-
gap: 6,
|
|
590
|
-
},
|
|
591
|
-
accountName: {
|
|
592
|
-
fontSize: 13,
|
|
593
|
-
fontWeight: '500',
|
|
594
|
-
flexShrink: 1,
|
|
595
|
-
},
|
|
596
|
-
accountNameActive: {
|
|
597
|
-
fontWeight: '600',
|
|
598
|
-
},
|
|
599
|
-
roleBadge: {
|
|
600
|
-
paddingHorizontal: 6,
|
|
601
|
-
paddingVertical: 1,
|
|
602
|
-
borderRadius: 8,
|
|
603
|
-
},
|
|
604
|
-
roleBadgeText: {
|
|
605
|
-
fontSize: 10,
|
|
606
|
-
fontWeight: '600',
|
|
607
|
-
textTransform: 'capitalize',
|
|
608
|
-
},
|
|
609
|
-
accountEmail: {
|
|
610
|
-
fontSize: 11,
|
|
611
|
-
marginTop: 1,
|
|
612
|
-
},
|
|
613
|
-
rowSignOutButton: {
|
|
614
|
-
width: 28,
|
|
615
|
-
height: 28,
|
|
616
|
-
alignItems: 'center',
|
|
617
|
-
justifyContent: 'center',
|
|
618
|
-
borderRadius: 14,
|
|
619
|
-
opacity: 0.6,
|
|
620
|
-
},
|
|
621
|
-
switchingRow: {
|
|
622
|
-
flexDirection: 'row',
|
|
623
|
-
alignItems: 'center',
|
|
624
|
-
justifyContent: 'center',
|
|
625
|
-
paddingVertical: 8,
|
|
626
|
-
gap: 8,
|
|
627
|
-
},
|
|
628
|
-
switchingText: {
|
|
629
|
-
fontSize: 12,
|
|
630
|
-
fontWeight: '500',
|
|
631
|
-
},
|
|
632
|
-
actionRow: {
|
|
633
|
-
flexDirection: 'row',
|
|
634
|
-
alignItems: 'center',
|
|
635
|
-
paddingHorizontal: 14,
|
|
636
|
-
paddingVertical: 12,
|
|
637
|
-
gap: 10,
|
|
638
|
-
},
|
|
639
|
-
actionText: {
|
|
640
|
-
fontSize: 13,
|
|
641
|
-
fontWeight: '500',
|
|
642
|
-
},
|
|
643
|
-
});
|
|
644
|
-
|
|
645
|
-
export default AccountMenu;
|