@arcblock/ux 2.8.25 → 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 (122) 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/Header/header.js +0 -1
  10. package/es/Img/index.js +7 -6
  11. package/es/Locale/selector.js +15 -13
  12. package/es/NFTDisplay/index.js +2 -1
  13. package/es/QRCode/index.js +2 -1
  14. package/es/SessionBlocklet/index.js +169 -0
  15. package/es/SessionManager/index.js +2 -381
  16. package/es/SessionPermission/index.js +28 -0
  17. package/es/SessionUser/components/logged-in.js +224 -0
  18. package/es/SessionUser/components/session-user-item.js +148 -0
  19. package/es/SessionUser/components/session-user-switch.js +213 -0
  20. package/es/SessionUser/components/un-login.js +64 -0
  21. package/es/SessionUser/components/user-info.js +163 -0
  22. package/es/SessionUser/index.js +49 -0
  23. package/es/SessionUser/libs/translation.js +19 -0
  24. package/es/SessionUser/libs/utils.js +4 -0
  25. package/es/SplitButton/index.js +2 -1
  26. package/es/Toast/index.js +1 -1
  27. package/es/Util/constant.js +10 -0
  28. package/es/Util/index.js +11 -0
  29. package/lib/Address/did-address.js +36 -22
  30. package/lib/AnimationWaiter/index.js +2 -1
  31. package/lib/Avatar/index.js +1 -1
  32. package/lib/BlockletContext/index.js +1 -1
  33. package/lib/CardSelector/index.js +2 -1
  34. package/lib/Colors/index.js +7 -0
  35. package/lib/Colors/themes/temp.js +24 -0
  36. package/lib/Datatable/TableSearch.js +2 -1
  37. package/lib/Header/header.js +1 -1
  38. package/lib/Img/index.js +7 -6
  39. package/lib/Locale/selector.js +14 -13
  40. package/lib/NFTDisplay/index.js +2 -1
  41. package/lib/QRCode/index.js +2 -1
  42. package/lib/SessionBlocklet/index.js +187 -0
  43. package/lib/SessionManager/index.js +2 -390
  44. package/lib/SessionPermission/index.js +38 -0
  45. package/lib/SessionUser/components/logged-in.js +243 -0
  46. package/lib/SessionUser/components/session-user-item.js +163 -0
  47. package/lib/SessionUser/components/session-user-switch.js +232 -0
  48. package/lib/SessionUser/components/un-login.js +72 -0
  49. package/lib/SessionUser/components/user-info.js +175 -0
  50. package/lib/SessionUser/index.js +57 -0
  51. package/lib/SessionUser/libs/translation.js +26 -0
  52. package/lib/{SessionManager → SessionUser}/libs/utils.js +8 -1
  53. package/lib/SplitButton/index.js +2 -1
  54. package/lib/Toast/index.js +5 -5
  55. package/lib/Util/constant.js +26 -0
  56. package/lib/Util/index.js +16 -3
  57. package/package.json +19 -7
  58. package/src/Address/did-address.jsx +34 -20
  59. package/src/AnimationWaiter/index.js +2 -1
  60. package/src/Avatar/index.jsx +1 -1
  61. package/src/BlockletContext/index.jsx +1 -1
  62. package/src/CardSelector/index.jsx +2 -1
  63. package/src/Colors/index.js +1 -0
  64. package/src/Colors/themes/temp.js +18 -0
  65. package/src/Datatable/TableSearch.js +3 -1
  66. package/src/Header/header.jsx +0 -1
  67. package/src/Img/{index.js → index.jsx} +8 -6
  68. package/src/Locale/selector.jsx +11 -8
  69. package/src/NFTDisplay/index.js +2 -1
  70. package/src/QRCode/index.js +2 -1
  71. package/src/SessionBlocklet/index.jsx +181 -0
  72. package/src/SessionManager/index.jsx +2 -369
  73. package/src/SessionPermission/index.jsx +28 -0
  74. package/src/SessionUser/components/logged-in.jsx +194 -0
  75. package/src/SessionUser/components/session-user-item.jsx +96 -0
  76. package/src/SessionUser/components/session-user-switch.jsx +222 -0
  77. package/src/SessionUser/components/un-login.jsx +55 -0
  78. package/src/SessionUser/components/user-info.jsx +165 -0
  79. package/src/SessionUser/index.jsx +38 -0
  80. package/src/SessionUser/libs/translation.js +19 -0
  81. package/src/{SessionManager → SessionUser}/libs/utils.js +4 -0
  82. package/src/SplitButton/index.js +2 -1
  83. package/src/Toast/index.js +1 -1
  84. package/src/Util/constant.js +12 -0
  85. package/src/Util/index.js +13 -0
  86. package/es/SessionManager/components/account-item.js +0 -212
  87. package/es/SessionManager/components/add-account-item.js +0 -57
  88. package/es/SessionManager/components/federated-login-detecter.js +0 -183
  89. package/es/SessionManager/components/manage-accounts.js +0 -219
  90. package/es/SessionManager/components/manage-blocklet.js +0 -70
  91. package/es/SessionManager/components/menu-accordion.js +0 -103
  92. package/es/SessionManager/components/responsive-popper.js +0 -24
  93. package/es/SessionManager/components/user-drawer.js +0 -68
  94. package/es/SessionManager/components/user-info.js +0 -143
  95. package/es/SessionManager/components/user-popper.js +0 -110
  96. package/es/SessionManager/hooks/use-config.js +0 -34
  97. package/es/SessionManager/libs/translation.js +0 -52
  98. package/es/SessionManager/libs/utils.js +0 -2
  99. package/lib/SessionManager/components/account-item.js +0 -219
  100. package/lib/SessionManager/components/add-account-item.js +0 -66
  101. package/lib/SessionManager/components/federated-login-detecter.js +0 -193
  102. package/lib/SessionManager/components/manage-accounts.js +0 -232
  103. package/lib/SessionManager/components/manage-blocklet.js +0 -86
  104. package/lib/SessionManager/components/menu-accordion.js +0 -111
  105. package/lib/SessionManager/components/responsive-popper.js +0 -34
  106. package/lib/SessionManager/components/user-drawer.js +0 -75
  107. package/lib/SessionManager/components/user-info.js +0 -160
  108. package/lib/SessionManager/components/user-popper.js +0 -104
  109. package/lib/SessionManager/hooks/use-config.js +0 -41
  110. package/lib/SessionManager/libs/translation.js +0 -59
  111. package/src/SessionManager/components/account-item.jsx +0 -156
  112. package/src/SessionManager/components/add-account-item.jsx +0 -49
  113. package/src/SessionManager/components/federated-login-detecter.jsx +0 -167
  114. package/src/SessionManager/components/manage-accounts.jsx +0 -228
  115. package/src/SessionManager/components/manage-blocklet.jsx +0 -70
  116. package/src/SessionManager/components/menu-accordion.jsx +0 -93
  117. package/src/SessionManager/components/responsive-popper.jsx +0 -26
  118. package/src/SessionManager/components/user-drawer.jsx +0 -57
  119. package/src/SessionManager/components/user-info.jsx +0 -117
  120. package/src/SessionManager/components/user-popper.jsx +0 -95
  121. package/src/SessionManager/hooks/use-config.js +0 -33
  122. 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
+ };