@oxyhq/services 13.3.0 → 14.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 +11 -17
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/ui/components/AccountMenu.js +103 -65
- package/lib/commonjs/ui/components/AccountMenu.js.map +1 -1
- package/lib/commonjs/ui/components/AccountSwitcher.js +84 -126
- package/lib/commonjs/ui/components/AccountSwitcher.js.map +1 -1
- package/lib/commonjs/ui/components/ProfileMenu.js +140 -153
- package/lib/commonjs/ui/components/ProfileMenu.js.map +1 -1
- package/lib/commonjs/ui/components/SignInModal.js +4 -4
- package/lib/commonjs/ui/components/SignInModal.js.map +1 -1
- package/lib/commonjs/ui/context/OxyContext.js +506 -466
- package/lib/commonjs/ui/context/OxyContext.js.map +1 -1
- package/lib/commonjs/ui/context/hooks/useAuthOperations.js +59 -57
- package/lib/commonjs/ui/context/hooks/useAuthOperations.js.map +1 -1
- package/lib/commonjs/ui/context/inSessionTokenRefresh.js +23 -42
- package/lib/commonjs/ui/context/inSessionTokenRefresh.js.map +1 -1
- package/lib/commonjs/ui/context/silentSessionRestore.js +12 -21
- package/lib/commonjs/ui/context/silentSessionRestore.js.map +1 -1
- package/lib/commonjs/ui/hooks/useAuth.js +4 -3
- package/lib/commonjs/ui/hooks/useAuth.js.map +1 -1
- package/lib/commonjs/ui/hooks/useOxyAuthSession.js +12 -7
- package/lib/commonjs/ui/hooks/useOxyAuthSession.js.map +1 -1
- package/lib/commonjs/ui/hooks/useSessionManagement.js +17 -65
- package/lib/commonjs/ui/hooks/useSessionManagement.js.map +1 -1
- package/lib/commonjs/ui/hooks/useSwitchableAccounts.js +288 -0
- package/lib/commonjs/ui/hooks/useSwitchableAccounts.js.map +1 -0
- package/lib/commonjs/ui/hooks/useWebSSO.js +12 -191
- package/lib/commonjs/ui/hooks/useWebSSO.js.map +1 -1
- package/lib/commonjs/ui/index.js.map +1 -1
- package/lib/commonjs/ui/screens/OxyAuthScreen.js +2 -2
- package/lib/commonjs/ui/screens/OxyAuthScreen.js.map +1 -1
- package/lib/commonjs/ui/session/createSessionClient.js +28 -0
- package/lib/commonjs/ui/session/createSessionClient.js.map +1 -0
- package/lib/commonjs/ui/session/index.js +52 -0
- package/lib/commonjs/ui/session/index.js.map +1 -0
- package/lib/commonjs/ui/session/projectSessionState.js +86 -0
- package/lib/commonjs/ui/session/projectSessionState.js.map +1 -0
- package/lib/commonjs/ui/session/sessionClientHost.js +30 -0
- package/lib/commonjs/ui/session/sessionClientHost.js.map +1 -0
- package/lib/commonjs/ui/session/tokenTransport.js +77 -0
- package/lib/commonjs/ui/session/tokenTransport.js.map +1 -0
- package/lib/commonjs/ui/utils/activeAuthuser.js +35 -79
- package/lib/commonjs/ui/utils/activeAuthuser.js.map +1 -1
- package/lib/commonjs/ui/utils/sessionHelpers.js +1 -51
- package/lib/commonjs/ui/utils/sessionHelpers.js.map +1 -1
- package/lib/commonjs/utils/deviceFlowSignIn.js +70 -15
- package/lib/commonjs/utils/deviceFlowSignIn.js.map +1 -1
- package/lib/module/index.js +5 -5
- package/lib/module/index.js.map +1 -1
- package/lib/module/ui/components/AccountMenu.js +103 -65
- package/lib/module/ui/components/AccountMenu.js.map +1 -1
- package/lib/module/ui/components/AccountSwitcher.js +85 -127
- package/lib/module/ui/components/AccountSwitcher.js.map +1 -1
- package/lib/module/ui/components/ProfileMenu.js +143 -156
- package/lib/module/ui/components/ProfileMenu.js.map +1 -1
- package/lib/module/ui/components/SignInModal.js +4 -4
- package/lib/module/ui/components/SignInModal.js.map +1 -1
- package/lib/module/ui/context/OxyContext.js +510 -470
- package/lib/module/ui/context/OxyContext.js.map +1 -1
- package/lib/module/ui/context/hooks/useAuthOperations.js +61 -60
- package/lib/module/ui/context/hooks/useAuthOperations.js.map +1 -1
- package/lib/module/ui/context/inSessionTokenRefresh.js +24 -43
- package/lib/module/ui/context/inSessionTokenRefresh.js.map +1 -1
- package/lib/module/ui/context/silentSessionRestore.js +12 -20
- package/lib/module/ui/context/silentSessionRestore.js.map +1 -1
- package/lib/module/ui/hooks/useAuth.js +4 -3
- package/lib/module/ui/hooks/useAuth.js.map +1 -1
- package/lib/module/ui/hooks/useOxyAuthSession.js +12 -7
- package/lib/module/ui/hooks/useOxyAuthSession.js.map +1 -1
- package/lib/module/ui/hooks/useSessionManagement.js +18 -66
- package/lib/module/ui/hooks/useSessionManagement.js.map +1 -1
- package/lib/module/ui/hooks/useSwitchableAccounts.js +283 -0
- package/lib/module/ui/hooks/useSwitchableAccounts.js.map +1 -0
- package/lib/module/ui/hooks/useWebSSO.js +13 -192
- package/lib/module/ui/hooks/useWebSSO.js.map +1 -1
- package/lib/module/ui/index.js +0 -1
- package/lib/module/ui/index.js.map +1 -1
- package/lib/module/ui/screens/OxyAuthScreen.js +2 -2
- package/lib/module/ui/screens/OxyAuthScreen.js.map +1 -1
- package/lib/module/ui/session/createSessionClient.js +25 -0
- package/lib/module/ui/session/createSessionClient.js.map +1 -0
- package/lib/module/ui/session/index.js +17 -0
- package/lib/module/ui/session/index.js.map +1 -0
- package/lib/module/ui/session/projectSessionState.js +79 -0
- package/lib/module/ui/session/projectSessionState.js.map +1 -0
- package/lib/module/ui/session/sessionClientHost.js +26 -0
- package/lib/module/ui/session/sessionClientHost.js.map +1 -0
- package/lib/module/ui/session/tokenTransport.js +74 -0
- package/lib/module/ui/session/tokenTransport.js.map +1 -0
- package/lib/module/ui/utils/activeAuthuser.js +34 -76
- package/lib/module/ui/utils/activeAuthuser.js.map +1 -1
- package/lib/module/ui/utils/sessionHelpers.js +0 -49
- package/lib/module/ui/utils/sessionHelpers.js.map +1 -1
- package/lib/module/utils/deviceFlowSignIn.js +71 -16
- package/lib/module/utils/deviceFlowSignIn.js.map +1 -1
- package/lib/typescript/commonjs/index.d.ts +2 -3
- package/lib/typescript/commonjs/index.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/components/AccountMenu.d.ts +4 -2
- package/lib/typescript/commonjs/ui/components/AccountMenu.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/components/AccountSwitcher.d.ts +7 -8
- package/lib/typescript/commonjs/ui/components/AccountSwitcher.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/components/ProfileMenu.d.ts +12 -9
- package/lib/typescript/commonjs/ui/components/ProfileMenu.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/context/OxyContext.d.ts +16 -13
- package/lib/typescript/commonjs/ui/context/OxyContext.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/context/hooks/useAuthOperations.d.ts +27 -3
- package/lib/typescript/commonjs/ui/context/hooks/useAuthOperations.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/context/inSessionTokenRefresh.d.ts +22 -17
- package/lib/typescript/commonjs/ui/context/inSessionTokenRefresh.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/context/silentSessionRestore.d.ts +12 -18
- package/lib/typescript/commonjs/ui/context/silentSessionRestore.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/hooks/mutations/useAccountMutations.d.ts +1 -0
- package/lib/typescript/commonjs/ui/hooks/mutations/useAccountMutations.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/hooks/useAuth.d.ts +1 -1
- package/lib/typescript/commonjs/ui/hooks/useAuth.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/hooks/useOxyAuthSession.d.ts +2 -2
- package/lib/typescript/commonjs/ui/hooks/useOxyAuthSession.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/hooks/useSessionManagement.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/hooks/useSwitchableAccounts.d.ts +162 -0
- package/lib/typescript/commonjs/ui/hooks/useSwitchableAccounts.d.ts.map +1 -0
- package/lib/typescript/commonjs/ui/hooks/useWebSSO.d.ts +13 -52
- package/lib/typescript/commonjs/ui/hooks/useWebSSO.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/index.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/session/createSessionClient.d.ts +15 -0
- package/lib/typescript/commonjs/ui/session/createSessionClient.d.ts.map +1 -0
- package/lib/typescript/commonjs/ui/session/index.d.ts +15 -0
- package/lib/typescript/commonjs/ui/session/index.d.ts.map +1 -0
- package/lib/typescript/commonjs/ui/session/projectSessionState.d.ts +45 -0
- package/lib/typescript/commonjs/ui/session/projectSessionState.d.ts.map +1 -0
- package/lib/typescript/commonjs/ui/session/sessionClientHost.d.ts +14 -0
- package/lib/typescript/commonjs/ui/session/sessionClientHost.d.ts.map +1 -0
- package/lib/typescript/commonjs/ui/session/tokenTransport.d.ts +24 -0
- package/lib/typescript/commonjs/ui/session/tokenTransport.d.ts.map +1 -0
- package/lib/typescript/commonjs/ui/utils/activeAuthuser.d.ts +21 -29
- package/lib/typescript/commonjs/ui/utils/activeAuthuser.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/utils/sessionHelpers.d.ts +0 -19
- package/lib/typescript/commonjs/ui/utils/sessionHelpers.d.ts.map +1 -1
- package/lib/typescript/commonjs/utils/deviceFlowSignIn.d.ts +51 -19
- package/lib/typescript/commonjs/utils/deviceFlowSignIn.d.ts.map +1 -1
- package/lib/typescript/module/index.d.ts +2 -3
- package/lib/typescript/module/index.d.ts.map +1 -1
- package/lib/typescript/module/ui/components/AccountMenu.d.ts +4 -2
- package/lib/typescript/module/ui/components/AccountMenu.d.ts.map +1 -1
- package/lib/typescript/module/ui/components/AccountSwitcher.d.ts +7 -8
- package/lib/typescript/module/ui/components/AccountSwitcher.d.ts.map +1 -1
- package/lib/typescript/module/ui/components/ProfileMenu.d.ts +12 -9
- package/lib/typescript/module/ui/components/ProfileMenu.d.ts.map +1 -1
- package/lib/typescript/module/ui/context/OxyContext.d.ts +16 -13
- package/lib/typescript/module/ui/context/OxyContext.d.ts.map +1 -1
- package/lib/typescript/module/ui/context/hooks/useAuthOperations.d.ts +27 -3
- package/lib/typescript/module/ui/context/hooks/useAuthOperations.d.ts.map +1 -1
- package/lib/typescript/module/ui/context/inSessionTokenRefresh.d.ts +22 -17
- package/lib/typescript/module/ui/context/inSessionTokenRefresh.d.ts.map +1 -1
- package/lib/typescript/module/ui/context/silentSessionRestore.d.ts +12 -18
- package/lib/typescript/module/ui/context/silentSessionRestore.d.ts.map +1 -1
- package/lib/typescript/module/ui/hooks/mutations/useAccountMutations.d.ts +1 -0
- package/lib/typescript/module/ui/hooks/mutations/useAccountMutations.d.ts.map +1 -1
- package/lib/typescript/module/ui/hooks/useAuth.d.ts +1 -1
- package/lib/typescript/module/ui/hooks/useAuth.d.ts.map +1 -1
- package/lib/typescript/module/ui/hooks/useOxyAuthSession.d.ts +2 -2
- package/lib/typescript/module/ui/hooks/useOxyAuthSession.d.ts.map +1 -1
- package/lib/typescript/module/ui/hooks/useSessionManagement.d.ts.map +1 -1
- package/lib/typescript/module/ui/hooks/useSwitchableAccounts.d.ts +162 -0
- package/lib/typescript/module/ui/hooks/useSwitchableAccounts.d.ts.map +1 -0
- package/lib/typescript/module/ui/hooks/useWebSSO.d.ts +13 -52
- package/lib/typescript/module/ui/hooks/useWebSSO.d.ts.map +1 -1
- package/lib/typescript/module/ui/index.d.ts.map +1 -1
- package/lib/typescript/module/ui/session/createSessionClient.d.ts +15 -0
- package/lib/typescript/module/ui/session/createSessionClient.d.ts.map +1 -0
- package/lib/typescript/module/ui/session/index.d.ts +15 -0
- package/lib/typescript/module/ui/session/index.d.ts.map +1 -0
- package/lib/typescript/module/ui/session/projectSessionState.d.ts +45 -0
- package/lib/typescript/module/ui/session/projectSessionState.d.ts.map +1 -0
- package/lib/typescript/module/ui/session/sessionClientHost.d.ts +14 -0
- package/lib/typescript/module/ui/session/sessionClientHost.d.ts.map +1 -0
- package/lib/typescript/module/ui/session/tokenTransport.d.ts +24 -0
- package/lib/typescript/module/ui/session/tokenTransport.d.ts.map +1 -0
- package/lib/typescript/module/ui/utils/activeAuthuser.d.ts +21 -29
- package/lib/typescript/module/ui/utils/activeAuthuser.d.ts.map +1 -1
- package/lib/typescript/module/ui/utils/sessionHelpers.d.ts +0 -19
- package/lib/typescript/module/ui/utils/sessionHelpers.d.ts.map +1 -1
- package/lib/typescript/module/utils/deviceFlowSignIn.d.ts +51 -19
- package/lib/typescript/module/utils/deviceFlowSignIn.d.ts.map +1 -1
- package/package.json +4 -4
- package/src/index.ts +9 -9
- package/src/ui/components/AccountMenu.tsx +117 -70
- package/src/ui/components/AccountSwitcher.tsx +88 -134
- package/src/ui/components/ProfileMenu.tsx +158 -162
- package/src/ui/components/SignInModal.tsx +5 -5
- package/src/ui/context/OxyContext.tsx +560 -475
- package/src/ui/context/hooks/useAuthOperations.ts +72 -63
- package/src/ui/context/inSessionTokenRefresh.ts +23 -42
- package/src/ui/context/silentSessionRestore.ts +12 -26
- package/src/ui/hooks/useAuth.ts +4 -3
- package/src/ui/hooks/useOxyAuthSession.ts +13 -8
- package/src/ui/hooks/useSessionManagement.ts +16 -87
- package/src/ui/hooks/useSwitchableAccounts.ts +397 -0
- package/src/ui/hooks/useWebSSO.ts +13 -227
- package/src/ui/index.ts +0 -1
- package/src/ui/screens/OxyAuthScreen.tsx +2 -2
- package/src/ui/session/__tests__/createSessionClient.test.ts +41 -0
- package/src/ui/session/__tests__/projectSessionState.test.ts +114 -0
- package/src/ui/session/__tests__/sessionClientHost.test.ts +43 -0
- package/src/ui/session/__tests__/tokenTransport.test.ts +142 -0
- package/src/ui/session/createSessionClient.ts +21 -0
- package/src/ui/session/index.ts +19 -0
- package/src/ui/session/projectSessionState.ts +85 -0
- package/src/ui/session/sessionClientHost.ts +27 -0
- package/src/ui/session/tokenTransport.ts +76 -0
- package/src/ui/utils/activeAuthuser.ts +34 -76
- package/src/ui/utils/sessionHelpers.ts +0 -66
- package/src/utils/__tests__/deviceFlowSignIn.test.ts +243 -34
- package/src/utils/deviceFlowSignIn.ts +98 -21
- package/lib/commonjs/ui/components/accountMenuRows.js +0 -33
- package/lib/commonjs/ui/components/accountMenuRows.js.map +0 -1
- package/lib/commonjs/ui/hooks/useDeviceAccounts.js +0 -280
- package/lib/commonjs/ui/hooks/useDeviceAccounts.js.map +0 -1
- package/lib/commonjs/ui/hooks/useSessionSocket.js +0 -203
- package/lib/commonjs/ui/hooks/useSessionSocket.js.map +0 -1
- package/lib/commonjs/utils/silentGuardKey.js +0 -54
- package/lib/commonjs/utils/silentGuardKey.js.map +0 -1
- package/lib/module/ui/components/accountMenuRows.js +0 -29
- package/lib/module/ui/components/accountMenuRows.js.map +0 -1
- package/lib/module/ui/hooks/useDeviceAccounts.js +0 -276
- package/lib/module/ui/hooks/useDeviceAccounts.js.map +0 -1
- package/lib/module/ui/hooks/useSessionSocket.js +0 -199
- package/lib/module/ui/hooks/useSessionSocket.js.map +0 -1
- package/lib/module/utils/silentGuardKey.js +0 -49
- package/lib/module/utils/silentGuardKey.js.map +0 -1
- package/lib/typescript/commonjs/ui/components/accountMenuRows.d.ts +0 -34
- package/lib/typescript/commonjs/ui/components/accountMenuRows.d.ts.map +0 -1
- package/lib/typescript/commonjs/ui/hooks/useDeviceAccounts.d.ts +0 -133
- package/lib/typescript/commonjs/ui/hooks/useDeviceAccounts.d.ts.map +0 -1
- package/lib/typescript/commonjs/ui/hooks/useSessionSocket.d.ts +0 -14
- package/lib/typescript/commonjs/ui/hooks/useSessionSocket.d.ts.map +0 -1
- package/lib/typescript/commonjs/utils/silentGuardKey.d.ts +0 -31
- package/lib/typescript/commonjs/utils/silentGuardKey.d.ts.map +0 -1
- package/lib/typescript/module/ui/components/accountMenuRows.d.ts +0 -34
- package/lib/typescript/module/ui/components/accountMenuRows.d.ts.map +0 -1
- package/lib/typescript/module/ui/hooks/useDeviceAccounts.d.ts +0 -133
- package/lib/typescript/module/ui/hooks/useDeviceAccounts.d.ts.map +0 -1
- package/lib/typescript/module/ui/hooks/useSessionSocket.d.ts +0 -14
- package/lib/typescript/module/ui/hooks/useSessionSocket.d.ts.map +0 -1
- package/lib/typescript/module/utils/silentGuardKey.d.ts +0 -31
- package/lib/typescript/module/utils/silentGuardKey.d.ts.map +0 -1
- package/src/ui/components/accountMenuRows.ts +0 -48
- package/src/ui/hooks/useDeviceAccounts.ts +0 -344
- package/src/ui/hooks/useSessionSocket.ts +0 -233
- package/src/ui/utils/__tests__/activeAuthuser.test.ts +0 -75
- package/src/utils/__tests__/silentGuardKey.test.ts +0 -82
- package/src/utils/silentGuardKey.ts +0 -46
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import type React from 'react';
|
|
2
|
-
import { useCallback, useEffect, useState } from 'react';
|
|
2
|
+
import { useCallback, useEffect, useMemo, useState } from 'react';
|
|
3
3
|
import {
|
|
4
4
|
View,
|
|
5
5
|
Pressable,
|
|
6
6
|
Modal,
|
|
7
7
|
ScrollView,
|
|
8
8
|
ActivityIndicator,
|
|
9
|
-
StyleSheet,
|
|
10
9
|
Platform,
|
|
10
|
+
StyleSheet,
|
|
11
11
|
type ViewStyle,
|
|
12
12
|
} from 'react-native';
|
|
13
13
|
import { MaterialCommunityIcons } from '@expo/vector-icons';
|
|
@@ -19,7 +19,7 @@ import { Divider } from '@oxyhq/bloom/divider';
|
|
|
19
19
|
import { isDev, logger as loggerUtil } from '@oxyhq/core';
|
|
20
20
|
import { useOxy } from '../context/OxyContext';
|
|
21
21
|
import { useI18n } from '../hooks/useI18n';
|
|
22
|
-
import {
|
|
22
|
+
import { useSwitchableAccounts, type SwitchableAccount } from '../hooks/useSwitchableAccounts';
|
|
23
23
|
|
|
24
24
|
const isWeb = Platform.OS === 'web';
|
|
25
25
|
|
|
@@ -58,58 +58,67 @@ export interface ProfileMenuProps {
|
|
|
58
58
|
onBeforeSessionChange?: () => void | Promise<void>;
|
|
59
59
|
}
|
|
60
60
|
|
|
61
|
-
/** Everything `ProfileMenuContent` needs, minus the `open` flag (always open). */
|
|
62
|
-
type ProfileMenuContentProps = Omit<ProfileMenuProps, 'open'>;
|
|
63
|
-
|
|
64
61
|
/**
|
|
65
|
-
* Clean
|
|
66
|
-
*
|
|
67
|
-
*
|
|
68
|
-
*
|
|
69
|
-
*
|
|
70
|
-
*
|
|
62
|
+
* Clean account switcher, written with react-native `StyleSheet` + Bloom
|
|
63
|
+
* theme colors (the package convention — no NativeWind, which is only an
|
|
64
|
+
* optional peer and absent in the primary `accounts` consumer). Lists EVERY
|
|
65
|
+
* switchable account from {@link useSwitchableAccounts}
|
|
66
|
+
* — device sign-ins AND linked graph accounts (owned orgs + shared-with-you) —
|
|
67
|
+
* and routes EVERY switch through the context's single
|
|
68
|
+
* `switchToAccount(accountId)` dispatcher (there is no separate device-only
|
|
69
|
+
* path). Each on-device inactive row carries a per-account sign-out icon;
|
|
70
|
+
* graph-only rows carry a role badge and indent under their parent. Below the
|
|
71
|
+
* list: Add account, Manage account, optional View profile, and Sign out of all.
|
|
71
72
|
*
|
|
72
|
-
*
|
|
73
|
-
*
|
|
74
|
-
* outer {@link ProfileMenu} mounts this only when `open`. This component may
|
|
75
|
-
* therefore assume it is always open.
|
|
73
|
+
* Renders as an upward-opening popover anchored to the trigger on web, and a
|
|
74
|
+
* bottom-sheet style modal on native.
|
|
76
75
|
*/
|
|
77
|
-
const
|
|
76
|
+
const ProfileMenu: React.FC<ProfileMenuProps> = ({
|
|
77
|
+
open,
|
|
78
78
|
onClose,
|
|
79
|
+
anchor,
|
|
79
80
|
onNavigateManage,
|
|
80
81
|
onAddAccount,
|
|
81
82
|
onNavigateProfile,
|
|
82
83
|
onBeforeSessionChange,
|
|
83
84
|
}) => {
|
|
84
85
|
const {
|
|
85
|
-
|
|
86
|
-
switchSession,
|
|
86
|
+
switchToAccount,
|
|
87
87
|
logoutAll,
|
|
88
88
|
removeSession,
|
|
89
89
|
} = useOxy();
|
|
90
90
|
const { t } = useI18n();
|
|
91
91
|
const { colors } = useTheme();
|
|
92
92
|
|
|
93
|
-
const { accounts } =
|
|
93
|
+
const { accounts } = useSwitchableAccounts();
|
|
94
94
|
|
|
95
|
-
const [
|
|
95
|
+
const [busyAccountId, setBusyAccountId] = useState<string | null>(null);
|
|
96
96
|
const [removingSessionId, setRemovingSessionId] = useState<string | null>(null);
|
|
97
97
|
const [signingOutAll, setSigningOutAll] = useState(false);
|
|
98
98
|
|
|
99
99
|
const signOutAllDialog = useDialogControl();
|
|
100
100
|
|
|
101
|
-
const isSwitching =
|
|
101
|
+
const isSwitching = busyAccountId !== null;
|
|
102
102
|
const actionDisabled = isSwitching || removingSessionId !== null || signingOutAll;
|
|
103
103
|
|
|
104
|
-
//
|
|
105
|
-
|
|
106
|
-
|
|
104
|
+
// Account ids currently in the list — used to decide whether a graph-only
|
|
105
|
+
// row is a CHILD (its parent is also shown) so it can be indented.
|
|
106
|
+
const listedAccountIds = useMemo(
|
|
107
|
+
() => new Set(accounts.map((account) => account.accountId)),
|
|
108
|
+
[accounts],
|
|
109
|
+
);
|
|
110
|
+
|
|
111
|
+
// The ONE uniform switch path: every row (device or linked) routes through
|
|
112
|
+
// `switchToAccount(accountId)`. It reuses the device session when the account
|
|
113
|
+
// is already signed in here, and mints one only on first entry.
|
|
114
|
+
const handleSwitch = useCallback(async (account: SwitchableAccount) => {
|
|
115
|
+
if (account.isCurrent || busyAccountId) {
|
|
107
116
|
return;
|
|
108
117
|
}
|
|
109
|
-
|
|
118
|
+
setBusyAccountId(account.accountId);
|
|
110
119
|
try {
|
|
111
120
|
await onBeforeSessionChange?.();
|
|
112
|
-
await
|
|
121
|
+
await switchToAccount(account.accountId);
|
|
113
122
|
toast.success(t('accountSwitcher.toasts.switchSuccess') || 'Switched account');
|
|
114
123
|
onClose();
|
|
115
124
|
} catch (error) {
|
|
@@ -118,14 +127,14 @@ const ProfileMenuContent: React.FC<ProfileMenuContentProps> = ({
|
|
|
118
127
|
}
|
|
119
128
|
toast.error(t('accountSwitcher.toasts.switchFailed') || 'Failed to switch account');
|
|
120
129
|
} finally {
|
|
121
|
-
|
|
130
|
+
setBusyAccountId(null);
|
|
122
131
|
}
|
|
123
|
-
}, [
|
|
132
|
+
}, [busyAccountId, switchToAccount, t, onClose, onBeforeSessionChange]);
|
|
124
133
|
|
|
125
134
|
// Sign out a specific inactive account without switching/clearing the active
|
|
126
135
|
// one. The menu stays open so the user can keep managing accounts.
|
|
127
136
|
const handleRemove = useCallback(async (sessionId: string) => {
|
|
128
|
-
if (
|
|
137
|
+
if (removingSessionId) {
|
|
129
138
|
return;
|
|
130
139
|
}
|
|
131
140
|
setRemovingSessionId(sessionId);
|
|
@@ -138,7 +147,7 @@ const ProfileMenuContent: React.FC<ProfileMenuContentProps> = ({
|
|
|
138
147
|
} finally {
|
|
139
148
|
setRemovingSessionId(null);
|
|
140
149
|
}
|
|
141
|
-
}, [
|
|
150
|
+
}, [removingSessionId, removeSession, t]);
|
|
142
151
|
|
|
143
152
|
const performSignOutAll = useCallback(async () => {
|
|
144
153
|
if (signingOutAll) {
|
|
@@ -158,10 +167,9 @@ const ProfileMenuContent: React.FC<ProfileMenuContentProps> = ({
|
|
|
158
167
|
}
|
|
159
168
|
}, [signingOutAll, logoutAll, t, onClose, onBeforeSessionChange]);
|
|
160
169
|
|
|
161
|
-
// Escape-to-close (web only).
|
|
162
|
-
// listener is attached exactly for the menu's lifetime.
|
|
170
|
+
// Escape-to-close (web only).
|
|
163
171
|
useEffect(() => {
|
|
164
|
-
if (!isWeb || typeof document === 'undefined') {
|
|
172
|
+
if (!open || !isWeb || typeof document === 'undefined') {
|
|
165
173
|
return undefined;
|
|
166
174
|
}
|
|
167
175
|
const onKey = (event: KeyboardEvent) => {
|
|
@@ -172,30 +180,74 @@ const ProfileMenuContent: React.FC<ProfileMenuContentProps> = ({
|
|
|
172
180
|
};
|
|
173
181
|
document.addEventListener('keydown', onKey, true);
|
|
174
182
|
return () => document.removeEventListener('keydown', onKey, true);
|
|
175
|
-
}, [onClose]);
|
|
183
|
+
}, [open, onClose]);
|
|
176
184
|
|
|
177
|
-
|
|
178
|
-
|
|
185
|
+
if (!open) {
|
|
186
|
+
return null;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
// Web: anchor the panel to the measured trigger. When the anchor pins `top`
|
|
190
|
+
// the panel opens DOWNWARD from the trigger; otherwise it pins `bottom` and
|
|
191
|
+
// opens UPWARD (the default footer behavior). With no anchor captured, fall
|
|
192
|
+
// back to a bottom-left placement. Native ignores this (the panel docks to
|
|
193
|
+
// the bottom via the overlay's flex-end).
|
|
194
|
+
const panelAnchorStyle: ViewStyle | undefined = isWeb
|
|
195
|
+
? {
|
|
196
|
+
position: 'absolute',
|
|
197
|
+
width: MENU_WIDTH,
|
|
198
|
+
left: anchor?.left ?? 8,
|
|
199
|
+
...(typeof anchor?.top === 'number'
|
|
200
|
+
? { top: anchor.top }
|
|
201
|
+
: { bottom: anchor?.bottom ?? 8 }),
|
|
202
|
+
}
|
|
203
|
+
: undefined;
|
|
204
|
+
|
|
205
|
+
const content = (
|
|
206
|
+
<Pressable
|
|
207
|
+
// Swallow taps inside the panel so they never reach the overlay's
|
|
208
|
+
// outside-tap-to-close handler.
|
|
209
|
+
onPress={() => undefined}
|
|
210
|
+
style={[
|
|
211
|
+
isWeb ? styles.panelWeb : styles.panelNative,
|
|
212
|
+
{ backgroundColor: colors.background },
|
|
213
|
+
isWeb ? { borderColor: colors.border } : null,
|
|
214
|
+
panelAnchorStyle,
|
|
215
|
+
styles.panelBounds,
|
|
216
|
+
styles.shadow,
|
|
217
|
+
]}
|
|
218
|
+
accessibilityRole="menu"
|
|
219
|
+
accessibilityLabel={t('accountMenu.label') || 'Account menu'}
|
|
220
|
+
>
|
|
179
221
|
<ScrollView
|
|
180
222
|
style={styles.scroll}
|
|
181
223
|
contentContainerStyle={styles.scrollContent}
|
|
182
224
|
showsVerticalScrollIndicator={false}
|
|
183
225
|
>
|
|
184
|
-
{/* 1)
|
|
226
|
+
{/* 1) Every switchable account — device sign-ins AND linked graph
|
|
227
|
+
accounts. Active first (checkmark); on-device rows carry a
|
|
228
|
+
per-account sign-out icon; graph-only rows show a role badge
|
|
229
|
+
and indent under their parent. Every row switches through the
|
|
230
|
+
SAME `switchToAccount(accountId)` path. */}
|
|
185
231
|
{accounts.map((account) => {
|
|
186
232
|
const isActive = account.isCurrent;
|
|
187
|
-
const isBusy =
|
|
188
|
-
const
|
|
233
|
+
const isBusy = busyAccountId === account.accountId;
|
|
234
|
+
const sessionId = account.sessionId;
|
|
235
|
+
const isRemoving = sessionId ? removingSessionId === sessionId : false;
|
|
236
|
+
const isChild = Boolean(
|
|
237
|
+
account.parentAccountId && listedAccountIds.has(account.parentAccountId),
|
|
238
|
+
);
|
|
239
|
+
const role = account.callerMembership?.role;
|
|
189
240
|
return (
|
|
190
241
|
<Pressable
|
|
191
|
-
key={`account-${account.
|
|
242
|
+
key={`account-${account.accountId}`}
|
|
192
243
|
accessibilityRole="menuitem"
|
|
193
244
|
accessibilityLabel={account.displayName}
|
|
194
245
|
accessibilityState={{ selected: isActive }}
|
|
195
|
-
onPress={() => handleSwitch(account
|
|
246
|
+
onPress={() => handleSwitch(account)}
|
|
196
247
|
disabled={isActive || isBusy || isSwitching}
|
|
197
248
|
style={[
|
|
198
249
|
styles.accountRow,
|
|
250
|
+
isChild && styles.childRow,
|
|
199
251
|
isActive && { backgroundColor: colors.backgroundSecondary },
|
|
200
252
|
isSwitching && !isActive && styles.rowDimmed,
|
|
201
253
|
]}
|
|
@@ -205,18 +257,28 @@ const ProfileMenuContent: React.FC<ProfileMenuContentProps> = ({
|
|
|
205
257
|
uri={account.avatarUrl}
|
|
206
258
|
variant="thumb"
|
|
207
259
|
name={account.displayName}
|
|
208
|
-
size={isActive ? 40 : 32}
|
|
260
|
+
size={isActive ? 40 : isChild ? 28 : 32}
|
|
209
261
|
/>
|
|
210
262
|
<View style={styles.accountInfo}>
|
|
211
|
-
<
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
263
|
+
<View style={styles.nameRow}>
|
|
264
|
+
<Text
|
|
265
|
+
style={[
|
|
266
|
+
styles.accountName,
|
|
267
|
+
{ color: colors.text },
|
|
268
|
+
isActive && styles.accountNameActive,
|
|
269
|
+
]}
|
|
270
|
+
numberOfLines={1}
|
|
271
|
+
>
|
|
272
|
+
{account.displayName}
|
|
273
|
+
</Text>
|
|
274
|
+
{role ? (
|
|
275
|
+
<View style={[styles.roleBadge, { backgroundColor: colors.card }]}>
|
|
276
|
+
<Text style={[styles.roleBadgeText, { color: colors.textSecondary }]}>
|
|
277
|
+
{t(`accounts.roles.${role}.label`) || role}
|
|
278
|
+
</Text>
|
|
279
|
+
</View>
|
|
280
|
+
) : null}
|
|
281
|
+
</View>
|
|
220
282
|
{account.email ? (
|
|
221
283
|
<Text
|
|
222
284
|
style={[styles.accountEmail, { color: colors.textSecondary }]}
|
|
@@ -232,14 +294,14 @@ const ProfileMenuContent: React.FC<ProfileMenuContentProps> = ({
|
|
|
232
294
|
<MaterialCommunityIcons name="check" size={20} color={colors.primary} />
|
|
233
295
|
) : isRemoving ? (
|
|
234
296
|
<ActivityIndicator color={colors.textSecondary} size="small" />
|
|
235
|
-
) : (
|
|
297
|
+
) : sessionId ? (
|
|
236
298
|
<Pressable
|
|
237
299
|
accessibilityRole="button"
|
|
238
300
|
accessibilityLabel={
|
|
239
301
|
t('accountMenu.signOutAccount', { name: account.displayName })
|
|
240
302
|
|| `Sign out ${account.displayName}`
|
|
241
303
|
}
|
|
242
|
-
onPress={() => handleRemove(
|
|
304
|
+
onPress={() => handleRemove(sessionId)}
|
|
243
305
|
disabled={actionDisabled}
|
|
244
306
|
hitSlop={{ top: 8, bottom: 8, left: 8, right: 8 }}
|
|
245
307
|
style={styles.rowSignOutButton}
|
|
@@ -250,7 +312,7 @@ const ProfileMenuContent: React.FC<ProfileMenuContentProps> = ({
|
|
|
250
312
|
color={colors.textSecondary}
|
|
251
313
|
/>
|
|
252
314
|
</Pressable>
|
|
253
|
-
)}
|
|
315
|
+
) : null}
|
|
254
316
|
</Pressable>
|
|
255
317
|
);
|
|
256
318
|
})}
|
|
@@ -315,7 +377,7 @@ const ProfileMenuContent: React.FC<ProfileMenuContentProps> = ({
|
|
|
315
377
|
accessibilityLabel={t('accountMenu.signOutAll') || 'Sign out of all accounts'}
|
|
316
378
|
onPress={() => signOutAllDialog.open()}
|
|
317
379
|
disabled={actionDisabled}
|
|
318
|
-
style={[styles.
|
|
380
|
+
style={[styles.actionRow, actionDisabled && styles.rowDimmed]}
|
|
319
381
|
>
|
|
320
382
|
{signingOutAll ? (
|
|
321
383
|
<ActivityIndicator color={colors.error} size="small" />
|
|
@@ -327,63 +389,8 @@ const ProfileMenuContent: React.FC<ProfileMenuContentProps> = ({
|
|
|
327
389
|
</Text>
|
|
328
390
|
</Pressable>
|
|
329
391
|
</ScrollView>
|
|
330
|
-
|
|
331
|
-
<Dialog
|
|
332
|
-
control={signOutAllDialog}
|
|
333
|
-
title={t('accountMenu.signOutAll') || 'Sign out of all accounts'}
|
|
334
|
-
description={t('common.confirms.signOutAll') || 'Are you sure you want to sign out of all accounts?'}
|
|
335
|
-
actions={[
|
|
336
|
-
{
|
|
337
|
-
label: t('accountMenu.signOutAll') || 'Sign out of all accounts',
|
|
338
|
-
color: 'destructive',
|
|
339
|
-
onPress: performSignOutAll,
|
|
340
|
-
},
|
|
341
|
-
{ label: t('common.cancel') || 'Cancel', color: 'cancel' },
|
|
342
|
-
]}
|
|
343
|
-
/>
|
|
344
|
-
</>
|
|
392
|
+
</Pressable>
|
|
345
393
|
);
|
|
346
|
-
};
|
|
347
|
-
|
|
348
|
-
/**
|
|
349
|
-
* Public wrapper. The RN `Modal` shell is ALWAYS mounted (only `visible` toggles)
|
|
350
|
-
* so the react-native-web portal is created up front — mounting a web `Modal`
|
|
351
|
-
* already-`visible` is fragile (the first interaction can be eaten / the button
|
|
352
|
-
* "does nothing"). Only the heavy {@link ProfileMenuContent} mounts when open,
|
|
353
|
-
* keeping the account hooks off the render path when the menu is closed. On
|
|
354
|
-
* native that closed render is `<Modal visible={false}>{null}</Modal>` → no heavy
|
|
355
|
-
* hooks run (preserving the native-drawer crash fix).
|
|
356
|
-
*
|
|
357
|
-
* This outer component calls ONLY light, always-safe hooks (`useTheme`,
|
|
358
|
-
* `useI18n` for the overlay a11y label) and computes the panel/overlay layout.
|
|
359
|
-
*/
|
|
360
|
-
const ProfileMenu: React.FC<ProfileMenuProps> = ({
|
|
361
|
-
open,
|
|
362
|
-
onClose,
|
|
363
|
-
anchor,
|
|
364
|
-
onNavigateManage,
|
|
365
|
-
onAddAccount,
|
|
366
|
-
onNavigateProfile,
|
|
367
|
-
onBeforeSessionChange,
|
|
368
|
-
}) => {
|
|
369
|
-
const { t } = useI18n();
|
|
370
|
-
const { colors } = useTheme();
|
|
371
|
-
|
|
372
|
-
// Web: anchor the panel to the measured trigger. When the anchor pins `top`
|
|
373
|
-
// the panel opens DOWNWARD from the trigger; otherwise it pins `bottom` and
|
|
374
|
-
// opens UPWARD (the default footer behavior). With no anchor captured, fall
|
|
375
|
-
// back to a bottom-left placement. Native ignores this (the panel docks to
|
|
376
|
-
// the bottom via the overlay's flex-end).
|
|
377
|
-
const panelAnchorStyle: ViewStyle | undefined = isWeb
|
|
378
|
-
? {
|
|
379
|
-
position: 'absolute',
|
|
380
|
-
width: MENU_WIDTH,
|
|
381
|
-
left: anchor?.left ?? 8,
|
|
382
|
-
...(typeof anchor?.top === 'number'
|
|
383
|
-
? { top: anchor.top }
|
|
384
|
-
: { bottom: anchor?.bottom ?? 8 }),
|
|
385
|
-
}
|
|
386
|
-
: undefined;
|
|
387
394
|
|
|
388
395
|
return (
|
|
389
396
|
<Modal
|
|
@@ -398,33 +405,22 @@ const ProfileMenu: React.FC<ProfileMenuProps> = ({
|
|
|
398
405
|
onPress={onClose}
|
|
399
406
|
style={isWeb ? styles.webOverlay : styles.nativeOverlay}
|
|
400
407
|
>
|
|
401
|
-
|
|
402
|
-
// Swallow taps inside the panel so they never reach the overlay's
|
|
403
|
-
// outside-tap-to-close handler.
|
|
404
|
-
onPress={() => undefined}
|
|
405
|
-
style={[
|
|
406
|
-
isWeb ? styles.panelWeb : styles.panelNative,
|
|
407
|
-
{ backgroundColor: colors.background },
|
|
408
|
-
isWeb && { borderColor: colors.border },
|
|
409
|
-
panelAnchorStyle,
|
|
410
|
-
styles.panelBounds,
|
|
411
|
-
styles.shadow,
|
|
412
|
-
]}
|
|
413
|
-
accessibilityRole="menu"
|
|
414
|
-
accessibilityLabel={t('accountMenu.label') || 'Account menu'}
|
|
415
|
-
>
|
|
416
|
-
{open ? (
|
|
417
|
-
<ProfileMenuContent
|
|
418
|
-
onClose={onClose}
|
|
419
|
-
anchor={anchor}
|
|
420
|
-
onNavigateManage={onNavigateManage}
|
|
421
|
-
onAddAccount={onAddAccount}
|
|
422
|
-
onNavigateProfile={onNavigateProfile}
|
|
423
|
-
onBeforeSessionChange={onBeforeSessionChange}
|
|
424
|
-
/>
|
|
425
|
-
) : null}
|
|
426
|
-
</Pressable>
|
|
408
|
+
{content}
|
|
427
409
|
</Pressable>
|
|
410
|
+
|
|
411
|
+
<Dialog
|
|
412
|
+
control={signOutAllDialog}
|
|
413
|
+
title={t('accountMenu.signOutAll') || 'Sign out of all accounts'}
|
|
414
|
+
description={t('common.confirms.signOutAll') || 'Are you sure you want to sign out of all accounts?'}
|
|
415
|
+
actions={[
|
|
416
|
+
{
|
|
417
|
+
label: t('accountMenu.signOutAll') || 'Sign out of all accounts',
|
|
418
|
+
color: 'destructive',
|
|
419
|
+
onPress: performSignOutAll,
|
|
420
|
+
},
|
|
421
|
+
{ label: t('common.cancel') || 'Cancel', color: 'cancel' },
|
|
422
|
+
]}
|
|
423
|
+
/>
|
|
428
424
|
</Modal>
|
|
429
425
|
);
|
|
430
426
|
};
|
|
@@ -451,7 +447,8 @@ const ActionRow: React.FC<{
|
|
|
451
447
|
);
|
|
452
448
|
|
|
453
449
|
const styles = StyleSheet.create({
|
|
454
|
-
// Overlay
|
|
450
|
+
// Overlay: web is a positioning context for the anchored panel; native dims
|
|
451
|
+
// the backdrop and docks the sheet to the bottom.
|
|
455
452
|
webOverlay: {
|
|
456
453
|
flex: 1,
|
|
457
454
|
position: 'relative',
|
|
@@ -461,24 +458,23 @@ const styles = StyleSheet.create({
|
|
|
461
458
|
justifyContent: 'flex-end',
|
|
462
459
|
backgroundColor: 'rgba(0,0,0,0.32)',
|
|
463
460
|
},
|
|
464
|
-
// Panel shell — web popover
|
|
461
|
+
// Panel shell — web popover / native bottom sheet.
|
|
465
462
|
panelWeb: {
|
|
466
463
|
overflow: 'hidden',
|
|
467
464
|
borderRadius: 16,
|
|
468
465
|
borderWidth: 1,
|
|
469
466
|
},
|
|
470
|
-
// Panel shell — native bottom sheet (`overflow-hidden rounded-t-3xl pb-3`).
|
|
471
467
|
panelNative: {
|
|
472
468
|
overflow: 'hidden',
|
|
473
469
|
borderTopLeftRadius: 24,
|
|
474
470
|
borderTopRightRadius: 24,
|
|
475
471
|
paddingBottom: 12,
|
|
476
472
|
},
|
|
477
|
-
// Shared
|
|
473
|
+
// Shared height cap applied to both panel variants.
|
|
478
474
|
panelBounds: {
|
|
479
475
|
maxHeight: '85%',
|
|
480
476
|
},
|
|
481
|
-
// The panel's drop shadow
|
|
477
|
+
// The panel's drop shadow (dynamic elevation).
|
|
482
478
|
shadow: {
|
|
483
479
|
shadowColor: '#000',
|
|
484
480
|
shadowOpacity: 0.18,
|
|
@@ -486,14 +482,12 @@ const styles = StyleSheet.create({
|
|
|
486
482
|
shadowOffset: { width: 0, height: 8 },
|
|
487
483
|
elevation: 12,
|
|
488
484
|
},
|
|
489
|
-
// Scroll region (`grow-0` + `py-1` content).
|
|
490
485
|
scroll: {
|
|
491
486
|
flexGrow: 0,
|
|
492
487
|
},
|
|
493
488
|
scrollContent: {
|
|
494
489
|
paddingVertical: 4,
|
|
495
490
|
},
|
|
496
|
-
// Account row (`flex-row items-center gap-3 px-4 py-2.5`).
|
|
497
491
|
accountRow: {
|
|
498
492
|
flexDirection: 'row',
|
|
499
493
|
alignItems: 'center',
|
|
@@ -501,28 +495,41 @@ const styles = StyleSheet.create({
|
|
|
501
495
|
paddingHorizontal: 16,
|
|
502
496
|
paddingVertical: 10,
|
|
503
497
|
},
|
|
504
|
-
|
|
498
|
+
childRow: {
|
|
499
|
+
paddingLeft: 40,
|
|
500
|
+
},
|
|
505
501
|
rowDimmed: {
|
|
506
502
|
opacity: 0.4,
|
|
507
503
|
},
|
|
508
|
-
// Identity block (`min-w-0 flex-1`).
|
|
509
504
|
accountInfo: {
|
|
510
505
|
flex: 1,
|
|
511
506
|
minWidth: 0,
|
|
512
507
|
},
|
|
513
|
-
|
|
508
|
+
nameRow: {
|
|
509
|
+
flexDirection: 'row',
|
|
510
|
+
alignItems: 'center',
|
|
511
|
+
gap: 6,
|
|
512
|
+
},
|
|
514
513
|
accountName: {
|
|
515
514
|
fontWeight: '500',
|
|
515
|
+
flexShrink: 1,
|
|
516
516
|
},
|
|
517
|
-
// Active account name (`font-semibold`).
|
|
518
517
|
accountNameActive: {
|
|
519
518
|
fontWeight: '600',
|
|
520
519
|
},
|
|
521
|
-
// Secondary email line (`text-xs`).
|
|
522
520
|
accountEmail: {
|
|
523
521
|
fontSize: 12,
|
|
524
522
|
},
|
|
525
|
-
|
|
523
|
+
roleBadge: {
|
|
524
|
+
paddingHorizontal: 6,
|
|
525
|
+
paddingVertical: 1,
|
|
526
|
+
borderRadius: 8,
|
|
527
|
+
},
|
|
528
|
+
roleBadgeText: {
|
|
529
|
+
fontSize: 10,
|
|
530
|
+
fontWeight: '600',
|
|
531
|
+
textTransform: 'capitalize',
|
|
532
|
+
},
|
|
526
533
|
rowSignOutButton: {
|
|
527
534
|
width: 28,
|
|
528
535
|
height: 28,
|
|
@@ -531,7 +538,6 @@ const styles = StyleSheet.create({
|
|
|
531
538
|
borderRadius: 9999,
|
|
532
539
|
opacity: 0.6,
|
|
533
540
|
},
|
|
534
|
-
// Switching indicator (`flex-row items-center justify-center gap-2 py-2`).
|
|
535
541
|
switchingRow: {
|
|
536
542
|
flexDirection: 'row',
|
|
537
543
|
alignItems: 'center',
|
|
@@ -543,7 +549,6 @@ const styles = StyleSheet.create({
|
|
|
543
549
|
fontSize: 12,
|
|
544
550
|
fontWeight: '500',
|
|
545
551
|
},
|
|
546
|
-
// Bottom action rows (`flex-row items-center gap-3 px-4 py-3`).
|
|
547
552
|
actionRow: {
|
|
548
553
|
flexDirection: 'row',
|
|
549
554
|
alignItems: 'center',
|
|
@@ -551,15 +556,6 @@ const styles = StyleSheet.create({
|
|
|
551
556
|
paddingHorizontal: 16,
|
|
552
557
|
paddingVertical: 12,
|
|
553
558
|
},
|
|
554
|
-
// Sign-out-of-all row shares the action-row geometry.
|
|
555
|
-
signOutAllRow: {
|
|
556
|
-
flexDirection: 'row',
|
|
557
|
-
alignItems: 'center',
|
|
558
|
-
gap: 12,
|
|
559
|
-
paddingHorizontal: 16,
|
|
560
|
-
paddingVertical: 12,
|
|
561
|
-
},
|
|
562
|
-
// Action / sign-out label (`font-medium`).
|
|
563
559
|
actionText: {
|
|
564
560
|
fontWeight: '500',
|
|
565
561
|
},
|
|
@@ -62,7 +62,7 @@ const SignInModal: React.FC = () => {
|
|
|
62
62
|
|
|
63
63
|
const insets = useSafeAreaInsets();
|
|
64
64
|
const theme = useTheme();
|
|
65
|
-
const { oxyServices,
|
|
65
|
+
const { oxyServices, handleWebSession, clientId } = useOxy();
|
|
66
66
|
|
|
67
67
|
// Register the imperative visibility callback.
|
|
68
68
|
useEffect(() => {
|
|
@@ -83,7 +83,7 @@ const SignInModal: React.FC = () => {
|
|
|
83
83
|
theme={theme}
|
|
84
84
|
insets={insets}
|
|
85
85
|
oxyServices={oxyServices}
|
|
86
|
-
|
|
86
|
+
handleWebSession={handleWebSession}
|
|
87
87
|
clientId={clientId}
|
|
88
88
|
/>
|
|
89
89
|
);
|
|
@@ -93,7 +93,7 @@ interface SignInModalContentProps {
|
|
|
93
93
|
theme: ReturnType<typeof useTheme>;
|
|
94
94
|
insets: ReturnType<typeof useSafeAreaInsets>;
|
|
95
95
|
oxyServices: ReturnType<typeof useOxy>['oxyServices'];
|
|
96
|
-
|
|
96
|
+
handleWebSession: ReturnType<typeof useOxy>['handleWebSession'];
|
|
97
97
|
clientId: ReturnType<typeof useOxy>['clientId'];
|
|
98
98
|
}
|
|
99
99
|
|
|
@@ -101,13 +101,13 @@ const SignInModalContent: React.FC<SignInModalContentProps> = ({
|
|
|
101
101
|
theme,
|
|
102
102
|
insets,
|
|
103
103
|
oxyServices,
|
|
104
|
-
|
|
104
|
+
handleWebSession,
|
|
105
105
|
clientId,
|
|
106
106
|
}) => {
|
|
107
107
|
const { qrData, qrPayload, isLoading, error, isWaiting, openAuthApproval, openSameDeviceApproval, retry } = useOxyAuthSession(
|
|
108
108
|
oxyServices,
|
|
109
109
|
clientId,
|
|
110
|
-
|
|
110
|
+
handleWebSession,
|
|
111
111
|
{ onSignedIn: hideSignInModal },
|
|
112
112
|
);
|
|
113
113
|
|