@arcblock/ux 2.8.26 → 2.9.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.
Files changed (119) hide show
  1. package/es/Address/did-address.js +33 -21
  2. package/es/AnimationWaiter/index.js +2 -1
  3. package/es/Avatar/index.js +1 -1
  4. package/es/BlockletContext/index.js +1 -1
  5. package/es/CardSelector/index.js +2 -1
  6. package/es/Colors/index.js +2 -1
  7. package/es/Colors/themes/temp.js +17 -0
  8. package/es/Datatable/TableSearch.js +2 -1
  9. package/es/Img/index.js +7 -6
  10. package/es/Locale/selector.js +15 -13
  11. package/es/NFTDisplay/index.js +2 -1
  12. package/es/QRCode/index.js +2 -1
  13. package/es/SessionBlocklet/index.js +169 -0
  14. package/es/SessionManager/index.js +2 -381
  15. package/es/SessionPermission/index.js +28 -0
  16. package/es/SessionUser/components/logged-in.js +224 -0
  17. package/es/SessionUser/components/session-user-item.js +148 -0
  18. package/es/SessionUser/components/session-user-switch.js +213 -0
  19. package/es/SessionUser/components/un-login.js +64 -0
  20. package/es/SessionUser/components/user-info.js +163 -0
  21. package/es/SessionUser/index.js +49 -0
  22. package/es/SessionUser/libs/translation.js +19 -0
  23. package/es/SessionUser/libs/utils.js +4 -0
  24. package/es/SplitButton/index.js +2 -1
  25. package/es/Toast/index.js +1 -1
  26. package/es/Util/constant.js +10 -0
  27. package/es/Util/index.js +11 -0
  28. package/lib/Address/did-address.js +36 -22
  29. package/lib/AnimationWaiter/index.js +2 -1
  30. package/lib/Avatar/index.js +1 -1
  31. package/lib/BlockletContext/index.js +1 -1
  32. package/lib/CardSelector/index.js +2 -1
  33. package/lib/Colors/index.js +7 -0
  34. package/lib/Colors/themes/temp.js +24 -0
  35. package/lib/Datatable/TableSearch.js +2 -1
  36. package/lib/Img/index.js +7 -6
  37. package/lib/Locale/selector.js +14 -13
  38. package/lib/NFTDisplay/index.js +2 -1
  39. package/lib/QRCode/index.js +2 -1
  40. package/lib/SessionBlocklet/index.js +187 -0
  41. package/lib/SessionManager/index.js +2 -390
  42. package/lib/SessionPermission/index.js +38 -0
  43. package/lib/SessionUser/components/logged-in.js +243 -0
  44. package/lib/SessionUser/components/session-user-item.js +163 -0
  45. package/lib/SessionUser/components/session-user-switch.js +232 -0
  46. package/lib/SessionUser/components/un-login.js +72 -0
  47. package/lib/SessionUser/components/user-info.js +175 -0
  48. package/lib/SessionUser/index.js +57 -0
  49. package/lib/SessionUser/libs/translation.js +26 -0
  50. package/lib/{SessionManager → SessionUser}/libs/utils.js +8 -1
  51. package/lib/SplitButton/index.js +2 -1
  52. package/lib/Toast/index.js +5 -5
  53. package/lib/Util/constant.js +26 -0
  54. package/lib/Util/index.js +16 -3
  55. package/package.json +19 -7
  56. package/src/Address/did-address.jsx +34 -20
  57. package/src/AnimationWaiter/index.js +2 -1
  58. package/src/Avatar/index.jsx +1 -1
  59. package/src/BlockletContext/index.jsx +1 -1
  60. package/src/CardSelector/index.jsx +2 -1
  61. package/src/Colors/index.js +1 -0
  62. package/src/Colors/themes/temp.js +18 -0
  63. package/src/Datatable/TableSearch.js +3 -1
  64. package/src/Img/{index.js → index.jsx} +8 -6
  65. package/src/Locale/selector.jsx +11 -8
  66. package/src/NFTDisplay/index.js +2 -1
  67. package/src/QRCode/index.js +2 -1
  68. package/src/SessionBlocklet/index.jsx +181 -0
  69. package/src/SessionManager/index.jsx +2 -369
  70. package/src/SessionPermission/index.jsx +28 -0
  71. package/src/SessionUser/components/logged-in.jsx +194 -0
  72. package/src/SessionUser/components/session-user-item.jsx +96 -0
  73. package/src/SessionUser/components/session-user-switch.jsx +222 -0
  74. package/src/SessionUser/components/un-login.jsx +55 -0
  75. package/src/SessionUser/components/user-info.jsx +165 -0
  76. package/src/SessionUser/index.jsx +38 -0
  77. package/src/SessionUser/libs/translation.js +19 -0
  78. package/src/{SessionManager → SessionUser}/libs/utils.js +4 -0
  79. package/src/SplitButton/index.js +2 -1
  80. package/src/Toast/index.js +1 -1
  81. package/src/Util/constant.js +12 -0
  82. package/src/Util/index.js +13 -0
  83. package/es/SessionManager/components/account-item.js +0 -212
  84. package/es/SessionManager/components/add-account-item.js +0 -57
  85. package/es/SessionManager/components/federated-login-detecter.js +0 -183
  86. package/es/SessionManager/components/manage-accounts.js +0 -219
  87. package/es/SessionManager/components/manage-blocklet.js +0 -70
  88. package/es/SessionManager/components/menu-accordion.js +0 -103
  89. package/es/SessionManager/components/responsive-popper.js +0 -24
  90. package/es/SessionManager/components/user-drawer.js +0 -68
  91. package/es/SessionManager/components/user-info.js +0 -143
  92. package/es/SessionManager/components/user-popper.js +0 -110
  93. package/es/SessionManager/hooks/use-config.js +0 -34
  94. package/es/SessionManager/libs/translation.js +0 -52
  95. package/es/SessionManager/libs/utils.js +0 -2
  96. package/lib/SessionManager/components/account-item.js +0 -219
  97. package/lib/SessionManager/components/add-account-item.js +0 -66
  98. package/lib/SessionManager/components/federated-login-detecter.js +0 -193
  99. package/lib/SessionManager/components/manage-accounts.js +0 -232
  100. package/lib/SessionManager/components/manage-blocklet.js +0 -86
  101. package/lib/SessionManager/components/menu-accordion.js +0 -111
  102. package/lib/SessionManager/components/responsive-popper.js +0 -34
  103. package/lib/SessionManager/components/user-drawer.js +0 -75
  104. package/lib/SessionManager/components/user-info.js +0 -160
  105. package/lib/SessionManager/components/user-popper.js +0 -104
  106. package/lib/SessionManager/hooks/use-config.js +0 -41
  107. package/lib/SessionManager/libs/translation.js +0 -59
  108. package/src/SessionManager/components/account-item.jsx +0 -156
  109. package/src/SessionManager/components/add-account-item.jsx +0 -49
  110. package/src/SessionManager/components/federated-login-detecter.jsx +0 -167
  111. package/src/SessionManager/components/manage-accounts.jsx +0 -228
  112. package/src/SessionManager/components/manage-blocklet.jsx +0 -70
  113. package/src/SessionManager/components/menu-accordion.jsx +0 -93
  114. package/src/SessionManager/components/responsive-popper.jsx +0 -26
  115. package/src/SessionManager/components/user-drawer.jsx +0 -57
  116. package/src/SessionManager/components/user-info.jsx +0 -117
  117. package/src/SessionManager/components/user-popper.jsx +0 -95
  118. package/src/SessionManager/hooks/use-config.js +0 -33
  119. package/src/SessionManager/libs/translation.js +0 -52
@@ -0,0 +1,194 @@
1
+ import PropTypes from 'prop-types';
2
+ import { useRef } from 'react';
3
+ import { useMemoizedFn, useReactive } from 'ahooks';
4
+ import { Box, ClickAwayListener, Divider, Fade, IconButton, MenuItem, MenuList, Paper, Popper } from '@mui/material';
5
+ import { Icon } from '@iconify/react';
6
+ import PersonOutlineRoundedIcon from '@iconify-icons/material-symbols/person-outline-rounded';
7
+ import FilterVintageOutlineRoundedIcon from '@iconify-icons/material-symbols/filter-vintage-outline-rounded';
8
+ import AccountCircleOffOutlineRoundedIcon from '@iconify-icons/material-symbols/account-circle-off-outline-rounded';
9
+ import noop from 'lodash/noop';
10
+
11
+ import DidAvatar from '../../Avatar';
12
+ import { getUserAvatar } from '../../Util';
13
+ import UserInfo from './user-info';
14
+ import { temp as colors } from '../../Colors';
15
+ import { DASHBOARD_URL, PROFILE_URL } from '../../Util/constant';
16
+ import SessionPermission from '../../SessionPermission';
17
+ import { translations } from '../libs/translation';
18
+ import { translate } from '../../Locale/util';
19
+
20
+ export default function LoggedIn({ session, dark, onBindWallet, isBlocklet, locale, size }) {
21
+ const t = useMemoizedFn((key, data = {}) => {
22
+ return translate(translations, key, locale, 'en', data);
23
+ });
24
+ const popperAnchorRef = useRef(null);
25
+ const currentState = useReactive({
26
+ open: false,
27
+ });
28
+ const onTogglePopper = useMemoizedFn((value = !currentState.open) => {
29
+ currentState.open = value;
30
+ });
31
+ // base64 img maybe have some blank char, need encodeURIComponent to transform it
32
+ const avatar = getUserAvatar(session.user?.avatar?.replace(/\s/g, encodeURIComponent(' ')));
33
+ const handleSwitchPassport = useMemoizedFn(() => {
34
+ onTogglePopper(false);
35
+ session.switchPassport();
36
+ });
37
+ const handleSwitchAccount = useMemoizedFn(({ userSession } = {}) => {
38
+ return new Promise((resolve) => {
39
+ const options = {};
40
+ if (!userSession) {
41
+ onTogglePopper(false);
42
+ options.showQuickConnect = false;
43
+ } else {
44
+ options.userSession = userSession;
45
+ }
46
+ session.switchDid(
47
+ () => {
48
+ onTogglePopper(false);
49
+ resolve();
50
+ },
51
+ {},
52
+ options
53
+ );
54
+ });
55
+ });
56
+ const handleSwitchProfile = useMemoizedFn(() => {
57
+ onTogglePopper(false);
58
+ session.switchProfile();
59
+ });
60
+ const onLogout = useMemoizedFn(() => {
61
+ onTogglePopper(false);
62
+ session.logout();
63
+ });
64
+
65
+ const handleBindWallet = useMemoizedFn(() => {
66
+ onTogglePopper(false);
67
+ session.bindWallet(onBindWallet);
68
+ });
69
+ return (
70
+ <>
71
+ <IconButton
72
+ ref={popperAnchorRef}
73
+ onClick={() => onTogglePopper()}
74
+ size="medium"
75
+ data-cy="sessionManager-logout-popup"
76
+ aria-label="User info button">
77
+ <DidAvatar variant="circle" did={session.user.did} src={avatar} size={size} shape="circle" />
78
+ </IconButton>
79
+
80
+ <Popper
81
+ open={currentState.open}
82
+ onClose={() => onTogglePopper(false)}
83
+ anchorEl={popperAnchorRef.current}
84
+ dark={dark}
85
+ transition
86
+ placement="bottom-end"
87
+ sx={{ zIndex: 1600 }}>
88
+ {({ TransitionProps }) => (
89
+ <ClickAwayListener
90
+ onClickAway={(e) => {
91
+ e.preventDefault();
92
+ e.stopPropagation();
93
+ onTogglePopper(false);
94
+ }}>
95
+ <Fade {...TransitionProps} timeout={350}>
96
+ <Paper
97
+ variant="outlined"
98
+ sx={{
99
+ borderRadius: 3,
100
+ width: 350,
101
+ maxWidth: '90vw',
102
+ borderColor: colors.lineStep,
103
+ border: '0 !important',
104
+ boxShadow: `0px 8px 16px 0px ${colors.gray6}, 0px 0px 0px 1px ${colors.gray6}`,
105
+ }}>
106
+ <UserInfo
107
+ locale={locale}
108
+ isBlocklet={isBlocklet}
109
+ session={session}
110
+ onSwitchPassport={handleSwitchPassport}
111
+ onSwitchAccount={handleSwitchAccount}
112
+ onSwitchProfile={handleSwitchProfile}
113
+ onBindWallet={handleBindWallet}
114
+ />
115
+ <MenuList sx={{ p: 0 }}>
116
+ {isBlocklet ? (
117
+ <>
118
+ <SessionPermission session={session}>
119
+ <SessionMenuItem
120
+ icon={FilterVintageOutlineRoundedIcon}
121
+ title={t('dashboard')}
122
+ component="a"
123
+ href={DASHBOARD_URL}
124
+ sx={{ display: 'block', textDecoration: 'none', color: 'inherit' }}
125
+ />
126
+ </SessionPermission>
127
+ <SessionMenuItem
128
+ icon={PersonOutlineRoundedIcon}
129
+ title={t('profile')}
130
+ component="a"
131
+ href={PROFILE_URL}
132
+ sx={{ display: 'block', textDecoration: 'none', color: 'inherit' }}
133
+ />
134
+ <Divider sx={{ m: '0!important', borderColor: colors.lineStep }} />
135
+ </>
136
+ ) : null}
137
+ <SessionMenuItem
138
+ icon={AccountCircleOffOutlineRoundedIcon}
139
+ title={t('logout')}
140
+ sx={{ color: 'error.main' }}
141
+ onClick={onLogout}
142
+ data-cy="sessionManager-logout-trigger"
143
+ />
144
+ </MenuList>
145
+ </Paper>
146
+ </Fade>
147
+ </ClickAwayListener>
148
+ )}
149
+ </Popper>
150
+ </>
151
+ );
152
+ }
153
+
154
+ LoggedIn.propTypes = {
155
+ session: PropTypes.object.isRequired,
156
+ onBindWallet: PropTypes.func,
157
+ dark: PropTypes.bool,
158
+ isBlocklet: PropTypes.bool,
159
+ locale: PropTypes.string,
160
+ size: PropTypes.number,
161
+ };
162
+ LoggedIn.defaultProps = {
163
+ dark: false,
164
+ isBlocklet: true,
165
+ onBindWallet: noop,
166
+ locale: 'en',
167
+ size: 24,
168
+ };
169
+
170
+ function SessionMenuItem({ icon, title, ...rest }) {
171
+ return (
172
+ <Box {...rest} sx={{ p: 0.5, ...rest?.sx }}>
173
+ <MenuItem
174
+ sx={{
175
+ display: 'flex',
176
+ gap: 1,
177
+ alignItems: 'center',
178
+ borderRadius: 2,
179
+ '&:hover': {
180
+ backgroundColor: `${colors.surfacePrimarySubtitle} !important`,
181
+ },
182
+ py: 1,
183
+ }}>
184
+ <Icon icon={icon} fontSize={24} />
185
+ {title}
186
+ </MenuItem>
187
+ </Box>
188
+ );
189
+ }
190
+
191
+ SessionMenuItem.propTypes = {
192
+ icon: PropTypes.string.isRequired,
193
+ title: PropTypes.string.isRequired,
194
+ };
@@ -0,0 +1,96 @@
1
+ import PropTypes from 'prop-types';
2
+ import { forwardRef } from 'react';
3
+ import { Box, IconButton, Typography } from '@mui/material';
4
+ import { useCreation } from 'ahooks';
5
+ import { Icon } from '@iconify/react';
6
+ import ApiIcon from '@iconify-icons/mdi/api';
7
+ import IOSRoundedIcon from '@iconify-icons/material-symbols/ios-rounded';
8
+ import LanguageIcon from '@iconify-icons/material-symbols/language';
9
+ import LensIcon from '@iconify-icons/material-symbols/lens';
10
+ import AndroidIcon from '@iconify-icons/material-symbols/android';
11
+ import Auth0Icon from '@iconify-icons/logos/auth0-icon';
12
+
13
+ import Avatar from '../../Avatar';
14
+ import DID from '../../DID';
15
+ import { temp as colors } from '../../Colors';
16
+ import { getSourceProvider } from '../libs/utils';
17
+
18
+ const SessionUserItem = forwardRef(({ sessionItem, statusContent, active, ...rest }, ref) => {
19
+ const isRawWalletAccount = getSourceProvider(sessionItem?.user) === 'wallet';
20
+ const walletIcon = useCreation(() => {
21
+ const { walletOS, provider } = sessionItem?.extra || {};
22
+ if (provider === 'auth0') {
23
+ return <Icon icon={Auth0Icon} width={10} height={10} style={{ color: 'black' }} />;
24
+ }
25
+ if (walletOS === 'ios') {
26
+ return <Icon icon={IOSRoundedIcon} width={16} height={16} style={{ color: 'black' }} />;
27
+ }
28
+ if (walletOS === 'android') {
29
+ return <Icon icon={AndroidIcon} width={14} height={14} style={{ color: 'black' }} />;
30
+ }
31
+ if (walletOS === 'web') {
32
+ return <Icon icon={LanguageIcon} style={{ color: 'black' }} />;
33
+ }
34
+ if (walletOS === 'api') {
35
+ return <Icon icon={ApiIcon} width={14} height={14} style={{ color: 'black' }} />;
36
+ }
37
+ return null;
38
+ }, [sessionItem?.extra?.walletOS, sessionItem?.extra?.provider]);
39
+
40
+ return (
41
+ <Box
42
+ {...rest}
43
+ ref={ref}
44
+ sx={{
45
+ display: 'flex',
46
+ alignItems: 'center',
47
+ justifyContent: 'space-between',
48
+ py: 0.75,
49
+ px: 1,
50
+ width: '100%',
51
+ ...rest?.sx,
52
+ }}>
53
+ <Box
54
+ sx={{
55
+ display: 'flex',
56
+ alignItems: 'center',
57
+ gap: 0.5,
58
+ '& .did-address-avatar': {
59
+ display: 'none !important',
60
+ },
61
+ '& .did-address-text': {
62
+ color: `${colors.textBase} !important`,
63
+ },
64
+ }}>
65
+ <Box sx={{ mr: 0.5, fontSize: 0 }}>
66
+ <Avatar did={sessionItem.userDid} size={36} />
67
+ </Box>
68
+ {walletIcon}
69
+ {isRawWalletAccount ? (
70
+ <DID did={sessionItem.userDid} copyable={false} size={14} responsive={false} compact sx={{ lineHeight: 1 }} />
71
+ ) : (
72
+ <Typography sx={{ fontSize: 14 }}>{sessionItem.user.email}</Typography>
73
+ )}
74
+ </Box>
75
+ {statusContent ||
76
+ (active && (
77
+ <IconButton size="small" disableRipple>
78
+ <Icon icon={LensIcon} fontSize={6} color={colors.surfaceSuccess} />
79
+ </IconButton>
80
+ ))}
81
+ </Box>
82
+ );
83
+ });
84
+
85
+ SessionUserItem.propTypes = {
86
+ sessionItem: PropTypes.object.isRequired,
87
+ statusContent: PropTypes.node,
88
+ active: PropTypes.bool,
89
+ };
90
+
91
+ SessionUserItem.defaultProps = {
92
+ statusContent: null,
93
+ active: false,
94
+ };
95
+
96
+ export default SessionUserItem;
@@ -0,0 +1,222 @@
1
+ import PropTypes from 'prop-types';
2
+ import {
3
+ Box,
4
+ ClickAwayListener,
5
+ Divider,
6
+ Fade,
7
+ LinearProgress,
8
+ MenuItem,
9
+ MenuList,
10
+ Paper,
11
+ Popper,
12
+ } from '@mui/material';
13
+ import { useRef } from 'react';
14
+ import { useCreation, useMemoizedFn, useReactive, useSize, useMount } from 'ahooks';
15
+ import { Icon } from '@iconify/react';
16
+ import AddCircleOutlineRoundedIcon from '@iconify-icons/material-symbols/add-circle-outline-rounded';
17
+ import ExpandMoreRoundedIcon from '@iconify-icons/material-symbols/expand-more-rounded';
18
+ import SwapHorizRoundedIcon from '@iconify-icons/material-symbols/swap-horiz-rounded';
19
+ import pick from 'lodash/pick';
20
+
21
+ import SessionUserItem from './session-user-item';
22
+ import { temp as colors } from '../../Colors';
23
+ import { getVisitorId } from '../../Util';
24
+ import { translate } from '../../Locale/util';
25
+ import { translations } from '../libs/translation';
26
+
27
+ export default function SessionUserSwitch({ session, onSwitch, isBlocklet, locale }) {
28
+ const popperAnchorRef = useRef(null);
29
+ const t = useMemoizedFn((key, data = {}) => {
30
+ return translate(translations, key, locale, 'en', data);
31
+ });
32
+
33
+ const currentState = useReactive({
34
+ open: false,
35
+ userSessions: [],
36
+ loadingSessionId: null,
37
+ });
38
+
39
+ useMount(async () => {
40
+ if (isBlocklet) {
41
+ const userSessions = await session.getUserSessions();
42
+ currentState.userSessions = userSessions;
43
+ }
44
+ });
45
+
46
+ const currentSession = useCreation(() => {
47
+ const matchSession = (currentState.userSessions || []).find(
48
+ (item) => item.appPid === globalThis?.blocklet?.appPid && item.userDid === session?.user?.did
49
+ );
50
+ if (matchSession) {
51
+ return matchSession;
52
+ }
53
+
54
+ return {
55
+ appName: globalThis?.blocklet?.appName || globalThis?.env?.appName,
56
+ appPid: globalThis?.blocklet?.appPid || globalThis?.env?.appPid,
57
+ userDid: session?.user?.did,
58
+ visitorId: getVisitorId(),
59
+ // passportId: '', // 无法从当前 session 获取 passportId 的值
60
+ // updatedAt: '', // 当前 session 拼凑的信息无法得到 userSession 的更新时间
61
+ user: pick(session?.user, [
62
+ 'did',
63
+ 'sourceProvider',
64
+ 'fullName',
65
+ 'email',
66
+ 'avatar',
67
+ 'remark',
68
+ 'sourceAppPid',
69
+ 'role',
70
+ ]),
71
+ };
72
+ }, [currentState.userSessions, session?.user]);
73
+ const onTogglePopper = useMemoizedFn((value = !currentState.open) => {
74
+ currentState.open = value;
75
+ });
76
+ const size = useSize(popperAnchorRef.current);
77
+ const handleAddAccount = useMemoizedFn(() => {
78
+ onTogglePopper(false);
79
+ onSwitch();
80
+ });
81
+ const handleSwitch = useMemoizedFn(async (userSession) => {
82
+ try {
83
+ currentState.loadingSessionId = userSession?.id;
84
+ await onSwitch({ userSession });
85
+ onTogglePopper(false);
86
+ } finally {
87
+ currentState.loadingSessionId = null;
88
+ }
89
+ });
90
+
91
+ if (!isBlocklet) {
92
+ return (
93
+ <SessionUserItem
94
+ sessionItem={currentSession}
95
+ statusContent={<Icon icon={SwapHorizRoundedIcon} color={colors.textMuted} />}
96
+ sx={{
97
+ border: `1px solid ${colors.borderBase}`,
98
+ borderRadius: 2,
99
+ cursor: 'pointer',
100
+ py: 1.25,
101
+ px: 1.5,
102
+ }}
103
+ data-cy="sessionManager-switch-trigger"
104
+ onClick={handleAddAccount}
105
+ ref={popperAnchorRef}
106
+ />
107
+ );
108
+ }
109
+ return (
110
+ <>
111
+ <SessionUserItem
112
+ sessionItem={currentSession}
113
+ statusContent={<Icon icon={ExpandMoreRoundedIcon} color={colors.textMuted} />}
114
+ sx={{
115
+ border: `1px solid ${colors.borderBase}`,
116
+ borderRadius: 2,
117
+ cursor: 'pointer',
118
+ py: 1.25,
119
+ px: 1.5,
120
+ }}
121
+ onClick={() => onTogglePopper()}
122
+ ref={popperAnchorRef}
123
+ />
124
+ <Popper
125
+ open={currentState.open}
126
+ onClose={() => onTogglePopper(false)}
127
+ anchorEl={popperAnchorRef.current}
128
+ transition
129
+ sx={{ zIndex: 1600 }}>
130
+ {({ TransitionProps }) => (
131
+ <ClickAwayListener
132
+ onClickAway={(e) => {
133
+ e.preventDefault();
134
+ e.stopPropagation();
135
+ onTogglePopper(false);
136
+ }}>
137
+ <Fade {...TransitionProps} timeout={350}>
138
+ <Paper
139
+ variant="outlined"
140
+ sx={{
141
+ borderRadius: 3,
142
+ width: size?.width || 0,
143
+ borderColor: colors.lineStep,
144
+ mt: 0.5,
145
+ border: '0 !important',
146
+ boxShadow: `0px 8px 16px 0px ${colors.gray6}, 0px 0px 0px 1px ${colors.gray6}`,
147
+ }}>
148
+ <MenuList sx={{ p: 0.5 }}>
149
+ {currentState.userSessions.map((userSessionItem) => {
150
+ const isLoading = currentState.loadingSessionId === userSessionItem.id;
151
+ const isActive = userSessionItem.id === currentSession.id;
152
+
153
+ return (
154
+ <MenuItem
155
+ key={userSessionItem.id}
156
+ sx={{
157
+ position: 'relative',
158
+ p: 0,
159
+ '&:hover': {
160
+ backgroundColor: `${colors.surfacePrimarySubtitle} !important`,
161
+ },
162
+ }}
163
+ onClick={() => {
164
+ if (!isActive) {
165
+ handleSwitch(userSessionItem);
166
+ }
167
+ }}>
168
+ {isLoading && (
169
+ <LinearProgress
170
+ sx={{
171
+ height: '2px',
172
+ position: 'absolute',
173
+ top: 0,
174
+ left: 0,
175
+ right: 0,
176
+ }}
177
+ />
178
+ )}
179
+ <SessionUserItem sessionItem={userSessionItem} active={isActive} />
180
+ </MenuItem>
181
+ );
182
+ })}
183
+ {currentState.userSessions.length > 0 ? (
184
+ <Divider sx={{ m: '0!important', borderColor: colors.lineStep }} />
185
+ ) : null}
186
+ <MenuItem
187
+ sx={{
188
+ color: colors.primaryBase,
189
+ borderRadius: 2,
190
+ '&:hover': {
191
+ backgroundColor: `${colors.surfacePrimarySubtitle} !important`,
192
+ },
193
+ px: 1,
194
+ py: 1.5,
195
+ lineHeight: 1,
196
+ }}
197
+ onClick={handleAddAccount}
198
+ data-cy="sessionManager-switch-trigger">
199
+ <Box component={Icon} icon={AddCircleOutlineRoundedIcon} fontSize={20} sx={{ mr: 0.5 }} />
200
+ {t('addAnotherAccount')}
201
+ </MenuItem>
202
+ </MenuList>
203
+ </Paper>
204
+ </Fade>
205
+ </ClickAwayListener>
206
+ )}
207
+ </Popper>
208
+ </>
209
+ );
210
+ }
211
+
212
+ SessionUserSwitch.propTypes = {
213
+ session: PropTypes.object.isRequired,
214
+ onSwitch: PropTypes.func.isRequired,
215
+ isBlocklet: PropTypes.bool,
216
+ locale: PropTypes.string,
217
+ };
218
+
219
+ SessionUserSwitch.defaultProps = {
220
+ isBlocklet: true,
221
+ locale: 'en',
222
+ };
@@ -0,0 +1,55 @@
1
+ import PropTypes from 'prop-types';
2
+ import { Box, CircularProgress, IconButton } from '@mui/material';
3
+ import { Icon } from '@iconify/react';
4
+ import PersonOutlineRoundedIcon from '@iconify-icons/material-symbols/person-outline-rounded';
5
+ import { useRef } from 'react';
6
+ import { useMemoizedFn } from 'ahooks';
7
+ import noop from 'lodash/noop';
8
+
9
+ export default function UnLogin({ session, onLogin, size, dark }) {
10
+ const isFirstLoading = false;
11
+ const userAnchorRef = useRef(null);
12
+ const _onLogin = useMemoizedFn(() => {
13
+ if (isFirstLoading) {
14
+ return;
15
+ }
16
+ session.login(onLogin);
17
+ });
18
+
19
+ return (
20
+ <Box>
21
+ <IconButton
22
+ ref={userAnchorRef}
23
+ onClick={_onLogin}
24
+ data-cy="sessionManager-login"
25
+ size="medium"
26
+ aria-label="Login button">
27
+ {isFirstLoading ? (
28
+ <Box width={size} height={size} display="flex" justifyContent="center" alignItems="center">
29
+ <CircularProgress style={{ width: size - 4, height: size - 4, color: dark ? '#fff' : '' }} />
30
+ </Box>
31
+ ) : (
32
+ <Icon
33
+ icon={PersonOutlineRoundedIcon}
34
+ fontSize={size}
35
+ color={dark ? '#fff' : 'inherit'}
36
+ style={{ transform: 'scale(1.08)' }}
37
+ />
38
+ )}
39
+ </IconButton>
40
+ </Box>
41
+ );
42
+ }
43
+
44
+ UnLogin.propTypes = {
45
+ session: PropTypes.object.isRequired,
46
+ onLogin: PropTypes.func,
47
+ size: PropTypes.number,
48
+ dark: PropTypes.bool,
49
+ };
50
+
51
+ UnLogin.defaultProps = {
52
+ onLogin: noop,
53
+ size: 24,
54
+ dark: false,
55
+ };