@arcblock/ux 2.7.15 → 2.7.16

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 (51) hide show
  1. package/es/Dialog/confirm.js +10 -8
  2. package/es/Img/index.js +7 -7
  3. package/es/SessionManager/account-item.js +132 -0
  4. package/es/SessionManager/add-account-item.js +118 -0
  5. package/es/SessionManager/federated-login-detecter.js +5 -7
  6. package/es/SessionManager/index.js +117 -244
  7. package/es/SessionManager/manage-accounts.js +143 -0
  8. package/es/SessionManager/manage-blocklet.js +62 -0
  9. package/es/SessionManager/menu-accordion.js +95 -0
  10. package/es/SessionManager/translation.js +52 -0
  11. package/es/SessionManager/use-accounts.js +19 -0
  12. package/es/SessionManager/user-info.js +139 -0
  13. package/es/SessionManager/user-popper.js +10 -36
  14. package/es/SessionManager/utils.js +2 -0
  15. package/es/Util/index.js +7 -0
  16. package/lib/Dialog/confirm.js +9 -7
  17. package/lib/Img/index.js +7 -7
  18. package/lib/SessionManager/account-item.js +140 -0
  19. package/lib/SessionManager/add-account-item.js +126 -0
  20. package/lib/SessionManager/federated-login-detecter.js +5 -7
  21. package/lib/SessionManager/index.js +120 -257
  22. package/lib/SessionManager/manage-accounts.js +155 -0
  23. package/lib/SessionManager/manage-blocklet.js +78 -0
  24. package/lib/SessionManager/menu-accordion.js +103 -0
  25. package/lib/SessionManager/translation.js +59 -0
  26. package/lib/SessionManager/use-accounts.js +25 -0
  27. package/lib/SessionManager/user-info.js +155 -0
  28. package/lib/SessionManager/user-popper.js +8 -3
  29. package/lib/SessionManager/utils.js +16 -0
  30. package/lib/Util/index.js +11 -2
  31. package/package.json +8 -5
  32. package/src/Dialog/confirm.js +9 -6
  33. package/src/Img/index.js +5 -5
  34. package/src/SessionManager/account-item.jsx +111 -0
  35. package/src/SessionManager/add-account-item.jsx +115 -0
  36. package/src/SessionManager/federated-login-detecter.jsx +3 -3
  37. package/src/SessionManager/index.jsx +130 -238
  38. package/src/SessionManager/manage-accounts.jsx +143 -0
  39. package/src/SessionManager/manage-blocklet.jsx +64 -0
  40. package/src/SessionManager/menu-accordion.jsx +87 -0
  41. package/src/SessionManager/translation.js +52 -0
  42. package/src/SessionManager/use-accounts.js +18 -0
  43. package/src/SessionManager/user-info.jsx +116 -0
  44. package/src/SessionManager/user-popper.jsx +6 -36
  45. package/src/SessionManager/utils.js +3 -0
  46. package/src/Util/index.js +8 -0
  47. /package/src/Avatar/{did-motif.js → did-motif.jsx} +0 -0
  48. /package/src/Avatar/{index.js → index.jsx} +0 -0
  49. /package/src/Header/{auto-hidden.js → auto-hidden.jsx} +0 -0
  50. /package/src/Header/{header.js → header.jsx} +0 -0
  51. /package/src/Header/{responsive-header.js → responsive-header.jsx} +0 -0
@@ -1,60 +1,25 @@
1
- /* eslint-disable react/no-array-index-key */
1
+ /* eslint-disable react/prop-types */
2
2
  /* eslint-disable react/jsx-no-bind */
3
- import { useMemo, useRef, useState } from 'react';
3
+ import { useEffect, useMemo, useRef, useState } from 'react';
4
4
  import PropTypes from 'prop-types';
5
- import { Box, IconButton, MenuList, MenuItem, SvgIcon, Button, Chip, Link, CircularProgress } from '@mui/material';
6
- import SwitchProfileIcon from '@mui/icons-material/PersonOutline';
7
- import BindWalletIcon from '@mui/icons-material/Link';
8
- import SwitchPassportIcon from '@mui/icons-material/VpnKeyOutlined';
9
- import ShieldCheck from 'mdi-material-ui/ShieldCheck';
5
+ import { Box, IconButton, MenuList, MenuItem, SvgIcon, Button, CircularProgress, Divider } from '@mui/material';
10
6
  import AccountIcon from '@arcblock/icons/lib/Account';
11
- import OpenInIcon from '@arcblock/icons/lib/OpenIn';
12
7
  import DisconnectIcon from '@arcblock/icons/lib/Disconnect';
13
- import SwitchDidIcon from '@arcblock/icons/lib/Switch';
14
- import useBrowser from '@arcblock/react-hooks/lib/useBrowser';
15
8
  import noop from 'lodash/noop';
16
9
  import isEmpty from 'lodash/isEmpty';
10
+ import { useLatest, useMemoizedFn } from 'ahooks';
17
11
 
18
12
  import DidAvatar from '../Avatar';
19
- import DidAddress from '../Address';
20
- import { getUserAvatar } from '../Util';
13
+ import { getUserAvatar, sleep } from '../Util';
21
14
  import FederatedLoginDetecter from './federated-login-detecter';
22
15
  import UserPopper from './user-popper';
23
-
24
- const translations = {
25
- en: {
26
- account: 'account',
27
- switchDid: 'Switch DID',
28
- switchTo: 'Switch to',
29
- switchProfile: 'Switch Profile',
30
- switchPassport: 'Switch Passport',
31
- disconnect: 'Disconnect',
32
- connect: 'Connect',
33
- openInWallet: 'Open DID Wallet',
34
- alreadyBindOAuth: 'Already bind Auth0',
35
- bind: 'Bind ',
36
- thirdParty: 'Third Party Login',
37
- connectedWith: 'Connected with',
38
- },
39
- zh: {
40
- account: '账号',
41
- switchDid: '切换账户',
42
- switchTo: '切换至',
43
- switchProfile: '切换用户信息',
44
- switchPassport: '切换通行证',
45
- disconnect: '退出',
46
- connect: '登录',
47
- openInWallet: '打开 DID 钱包',
48
- // NOTE: 目前只有 Auth0,展示出具体的第三方名字会更好
49
- alreadyBindOAuth: '已绑定 Auth0 账号',
50
- bind: '绑定',
51
- thirdParty: '第三方登录',
52
- connectedWith: '连接至',
53
- },
54
- };
55
-
56
- const getConnectedAccounts = (user) => user?.connectedAccounts || user?.extraConfigs?.connectedAccounts || [];
57
- const getSourceProvider = (user) => user?.sourceProvider || user?.extraConfigs?.sourceProvider || 'wallet';
16
+ import UserInfo from './user-info';
17
+ import { translate } from '../Locale/util';
18
+ import ManageAccounts from './manage-accounts';
19
+ import ManageBlocklet from './manage-blocklet';
20
+ import { translations } from './translation';
21
+ import { getConnectedAccounts, getSourceProvider } from './utils';
22
+ import useAccounts from './use-accounts';
58
23
 
59
24
  function SessionManager({
60
25
  session,
@@ -77,25 +42,26 @@ function SessionManager({
77
42
  size,
78
43
  ...rest
79
44
  }) {
80
- const translation = translations[locale] || translations.en;
45
+ const latestSession = useLatest(session);
46
+ const { connectAccount } = useAccounts();
47
+ const t = useMemoizedFn((key, data = {}) => {
48
+ return translate(translations, key, locale, 'en', data);
49
+ });
81
50
  const userAnchorRef = useRef(null);
82
- // eslint-disable-next-line react/prop-types
83
- const { logoutOAuth, bindOAuth, configs: oauthConfigs, switchOAuthPassport } = session.useOAuth();
51
+ const { logoutOAuth, switchOAuthPassport } = session.useOAuth();
84
52
  const [userOpen, setUserOpen] = useState(false);
85
53
 
86
54
  // base64 img maybe have some blank char, need encodeURIComponent to transform it
87
55
  const avatar = getUserAvatar(session.user?.avatar?.replace(/\s/g, encodeURIComponent(' ')));
88
- const currentRole = useMemo(
89
- () => session.user?.passports?.find((item) => item.name === session.user.role),
90
- [session.user]
91
- );
92
- const browser = useBrowser();
93
- // eslint-disable-next-line react/prop-types
94
- const { walletDid } = session.useDid({ session });
95
56
 
96
57
  const isRawWalletAccount = getSourceProvider(session.user) === 'wallet';
97
58
  const connectedAccounts = getConnectedAccounts(session.user);
98
- const federatedAccount = connectedAccounts.find((item) => item.provider === 'federated');
59
+
60
+ const isFirstLoading = useMemo(() => {
61
+ return session?.initialized === false && session?.loading === true;
62
+ }, [session?.initialized, session?.loading]);
63
+
64
+ // const federatedAccount = connectedAccounts.find((item) => item.provider === 'federated');
99
65
  let hasBindWallet = false;
100
66
  let hasBindAccount = false;
101
67
  if (isRawWalletAccount) {
@@ -108,20 +74,59 @@ function SessionManager({
108
74
  hasBindWallet = true;
109
75
  }
110
76
 
111
- const oauthConfigList = Object.entries(oauthConfigs)
112
- .map(([key, value]) => {
113
- return { ...value, provider: key };
114
- })
115
- .filter((item) => item.enabled);
116
-
117
- const isFirstLoading = useMemo(() => {
118
- // eslint-disable-next-line react/prop-types
119
- return session?.initialized === false && session?.loading === true;
120
- // eslint-disable-next-line react/prop-types
121
- }, [session?.initialized, session?.loading]);
77
+ const _connectAccount = useMemoizedFn(async () => {
78
+ // HACK: 强制等待组件渲染一轮,以拿到最新的 session 值
79
+ await sleep();
80
+ if (!latestSession.current?.user) {
81
+ return;
82
+ }
83
+ if (typeof window === 'undefined') {
84
+ return;
85
+ }
86
+ const blocklet = window?.blocklet;
87
+ if (!blocklet) {
88
+ return;
89
+ }
90
+ const currentApp = {
91
+ appId: blocklet.appId,
92
+ appPid: blocklet.appPid,
93
+ appName: blocklet.appName,
94
+ appDescription: blocklet.appDescription,
95
+ appLogo: blocklet.appLogo,
96
+ appUrl: blocklet.appUrl,
97
+ version: blocklet.version,
98
+ provider: 'wallet',
99
+ };
100
+ const federatedMaster = blocklet.settings?.federated?.master;
101
+ const masterApp = isEmpty(federatedMaster)
102
+ ? null
103
+ : {
104
+ appId: federatedMaster.appId,
105
+ appName: federatedMaster.appName,
106
+ appDescription: federatedMaster.appDescription,
107
+ appLogo: federatedMaster.appLogo,
108
+ appPid: federatedMaster.appPid,
109
+ appUrl: federatedMaster.appUrl,
110
+ version: federatedMaster.version,
111
+ provider: 'federated',
112
+ };
113
+ const loginAccount = {
114
+ did: latestSession.current.user.did,
115
+ avatar: latestSession.current.user.avatar,
116
+ provider: latestSession.current.provider,
117
+ ...(latestSession.current.provider === 'federated' ? masterApp : currentApp),
118
+ };
119
+ connectAccount(loginAccount);
120
+ });
122
121
 
123
- const masterSiteInfo = window.blocklet?.settings?.federated?.master;
124
- const currentSiteInfo = window.blocklet;
122
+ // HACK: 用于处理 统一登录 的自动登录情况,添加一个已连接的账号
123
+ // 同时可用于以前的站点,会自动生成一个已连接的账号
124
+ useEffect(() => {
125
+ if (session.user) {
126
+ _connectAccount();
127
+ }
128
+ // eslint-disable-next-line react-hooks/exhaustive-deps
129
+ }, [session.user]);
125
130
 
126
131
  if (!session.user) {
127
132
  return (
@@ -137,7 +142,7 @@ function SessionManager({
137
142
  {...rest}
138
143
  data-cy="sessionManager-login">
139
144
  {isFirstLoading ? <CircularProgress /> : <AccountIcon />}
140
- <span style={{ lineHeight: '25px' }}>{translation.connect}</span>
145
+ <span style={{ lineHeight: '25px' }}>{t('connect')}</span>
141
146
  </Button>
142
147
  ) : (
143
148
  <IconButton
@@ -167,16 +172,23 @@ function SessionManager({
167
172
  setUserOpen((prevOpen) => !prevOpen);
168
173
  }
169
174
 
175
+ function close() {
176
+ setUserOpen(false);
177
+ }
178
+
170
179
  function onCloseUser(e) {
171
180
  if (userAnchorRef.current && userAnchorRef.current.contains(e.target)) {
172
181
  return;
173
182
  }
174
- setUserOpen(false);
183
+ close();
175
184
  }
176
185
 
177
186
  function _onLogin() {
178
187
  if (!isFirstLoading) {
179
- session.login(onLogin);
188
+ session.login((...args) => {
189
+ _connectAccount();
190
+ onLogin(...args);
191
+ });
180
192
  }
181
193
  }
182
194
  function _onLogout() {
@@ -189,7 +201,7 @@ function SessionManager({
189
201
  console.error(err);
190
202
  })
191
203
  .finally(() => {
192
- setUserOpen(false);
204
+ close();
193
205
  });
194
206
  });
195
207
  }
@@ -197,58 +209,27 @@ function SessionManager({
197
209
  * @name 切换账户
198
210
  * @description 该功能仅在登录后才能使用,目前仅用于切换普通登录和统一登录的账户,所以会增加一些与统一登录相关的逻辑
199
211
  */
200
- function _onSwitchDid() {
201
- const { provider, user } = session;
202
- if (!user) return;
203
- let targetProvider = provider;
204
- if (provider === 'federated') {
205
- targetProvider = 'wallet';
206
- } else if (['auth0', 'wallet'].includes(provider)) {
207
- targetProvider = 'federated';
208
- }
209
- session.switchDid(
210
- (...args) => {
211
- setUserOpen(false);
212
- onSwitchDid(...args);
213
- },
214
- {
215
- provider: targetProvider,
216
- providerMode: 'paramsFirst',
217
- }
218
- );
219
- }
212
+
220
213
  function _onSwitchProfile() {
221
214
  session.switchProfile((...args) => {
222
- setUserOpen(false);
215
+ close();
223
216
  onSwitchProfile(...args);
224
217
  });
225
218
  }
219
+
226
220
  function _onSwitchPassport() {
227
221
  const { user, provider } = session;
228
222
  if (!isRawWalletAccount && provider !== 'federated') {
229
223
  switchOAuthPassport(user);
230
224
  } else {
231
- setUserOpen(false);
225
+ close();
232
226
  session.switchPassport((...args) => {
233
- setUserOpen(false);
227
+ close();
234
228
  onSwitchPassport(...args);
235
229
  });
236
230
  }
237
231
  }
238
232
 
239
- function _onBindWallet() {
240
- setUserOpen(false);
241
- // FIXME: @zhanghan 暂时切换回 isRawWalletAccount 的方式来判断,在 did-connect 改版时,简化这里的关系判断
242
- if (!isRawWalletAccount) {
243
- session.bindWallet((...args) => {
244
- setUserOpen(false);
245
- onBindWallet(...args);
246
- });
247
- } else {
248
- bindOAuth();
249
- }
250
- }
251
-
252
233
  return (
253
234
  <>
254
235
  <IconButton
@@ -265,110 +246,43 @@ function SessionManager({
265
246
 
266
247
  <UserPopper open={userOpen} onClose={onCloseUser} anchorEl={userAnchorRef.current} dark={dark}>
267
248
  <MenuList sx={{ p: 0 }}>
268
- <div className="session-manager-user">
269
- <div className="session-manager-user-name" role="button" aria-label="User info panel">
270
- <span>{session.user.fullName}</span>
271
- {!!showRole && (currentRole?.title || session.user?.role.toUpperCase()) && (
272
- <Chip
273
- label={currentRole?.title || session.user?.role.toUpperCase()}
274
- size="small"
275
- variant="outlined"
276
- sx={{ height: 'auto', marginRight: 0 }}
277
- icon={<SvgIcon component={ShieldCheck} size="small" />}
278
- />
279
- )}
280
- </div>
281
- <div className="session-manager-id-list" aria-label="User DID list">
282
- {walletDid && (
283
- <div className="session-manager-id-item">
284
- <DidAddress responsive={false}>{walletDid}</DidAddress>
285
- </div>
286
- )}
287
- {federatedAccount && (
288
- <div className="session-manager-id-item">
289
- <DidAddress responsive={false}>{federatedAccount.did}</DidAddress>
290
- </div>
291
- )}
292
- {session?.user?.email && (
293
- <div className="session-manager-id-item">
294
- <DidAddress responsive={false}>{session.user.email}</DidAddress>
295
- </div>
296
- )}
297
- </div>
298
- </div>
299
- {Array.isArray(menu) &&
300
- menu.map((menuItem, index) => {
301
- const { svgIcon, ...menuProps } = menuItem;
302
- return (
303
- <MenuItem
304
- key={index}
305
- className="session-manager-menu-item"
306
- {...{
307
- ...menuProps,
308
- icon: undefined,
309
- label: undefined,
310
- }}>
311
- {svgIcon
312
- ? svgIcon && <SvgIcon component={svgIcon} className="session-manager-menu-icon" />
313
- : menuItem.icon}
314
- {menuItem.label}
315
- </MenuItem>
316
- );
317
- })}
318
- {menuRender({
319
- classes: {
320
- menuItem: 'session-manager-menu-item',
321
- menuIcon: 'session-manager-menu-icon',
322
- },
323
- })}
324
- {!browser.wallet && (
325
- <MenuItem
326
- component="a"
327
- className="session-manager-menu-item"
328
- data-cy="sessionManager-openInWallet"
329
- href="https://www.abtwallet.io/"
330
- aria-label={translation.openInWallet}
331
- target="_blank">
332
- <SvgIcon component={OpenInIcon} className="session-manager-menu-icon" />
333
- {translation.openInWallet}
334
- </MenuItem>
335
- )}
336
- {!isEmpty(masterSiteInfo) && !!switchDid && (
337
- <MenuItem
338
- className="session-manager-menu-item"
339
- onClick={_onSwitchDid}
340
- aria-label={translation.switchDid}
341
- data-cy="sessionManager-switch-trigger">
342
- <SvgIcon component={SwitchDidIcon} className="session-manager-menu-icon" />
343
- <Box sx={{ whiteSpace: 'normal', wordBreak: 'break-all' }}>
344
- {translation.switchTo}
345
- {session.provider === 'federated' ? (
346
- <Link
347
- mx={1}
348
- href={currentSiteInfo.appUrl}
349
- underline="hover"
350
- target="_blank"
351
- title={currentSiteInfo.appName}
352
- aria-label="Open current site url">
353
- {currentSiteInfo.appName}
354
- </Link>
355
- ) : (
356
- <Link
357
- mx={1}
358
- href={masterSiteInfo.appUrl}
359
- underline="hover"
360
- target="_blank"
361
- title={masterSiteInfo.appName}
362
- aria-label="Open federated master site url">
363
- {masterSiteInfo.appName}
364
- </Link>
365
- )}
366
- {translation.account}
367
- </Box>
368
- </MenuItem>
369
- )}
249
+ <UserInfo
250
+ session={session}
251
+ size={size}
252
+ locale={locale}
253
+ onEditUser={() => {
254
+ close();
255
+ _onSwitchProfile();
256
+ }}
257
+ onSwitchPassport={() => {
258
+ close();
259
+ _onSwitchPassport();
260
+ }}
261
+ close={close}
262
+ switchProfile={switchProfile}
263
+ hasBindWallet={hasBindWallet}
264
+ />
265
+
266
+ <Divider />
267
+
268
+ <ManageAccounts
269
+ session={session}
270
+ locale={locale}
271
+ onBindWallet={onBindWallet}
272
+ onSwitchDid={onSwitchDid}
273
+ connectAccount={_connectAccount}
274
+ close={close}
275
+ hasBindAccount={hasBindAccount}
276
+ />
277
+
278
+ <Divider />
279
+
280
+ <ManageBlocklet menu={menu} menuRender={menuRender} locale={locale} />
281
+
282
+ <Divider />
283
+
370
284
  {/* NOTE: federated 登录方式不允许切换 profile */}
371
- {!!switchProfile && hasBindWallet && session.provider !== 'federated' && (
285
+ {/* {!!switchProfile && hasBindWallet && session.provider !== 'federated' && (
372
286
  <MenuItem
373
287
  className="session-manager-menu-item"
374
288
  onClick={_onSwitchProfile}
@@ -377,29 +291,7 @@ function SessionManager({
377
291
  <SvgIcon component={SwitchProfileIcon} className="session-manager-menu-icon" />
378
292
  {translation.switchProfile}
379
293
  </MenuItem>
380
- )}
381
- {!!switchPassport && (
382
- <MenuItem
383
- className="session-manager-menu-item"
384
- onClick={_onSwitchPassport}
385
- aria-label={translation.switchPassport}
386
- data-cy="sessionManager-switch-passport-trigger">
387
- <SvgIcon component={SwitchPassportIcon} className="session-manager-menu-icon" />
388
- {translation.switchPassport}
389
- </MenuItem>
390
- )}
391
- {oauthConfigList.length > 0 && !hasBindAccount && session.provider !== 'federated' && (
392
- <MenuItem
393
- className="session-manager-menu-item"
394
- onClick={_onBindWallet}
395
- aria-label={
396
- !isRawWalletAccount ? `${translation.bind}DID Wallet` : `${translation.bind}${translation.thirdParty}`
397
- }
398
- data-cy="sessionManager-bind-trigger">
399
- <SvgIcon component={BindWalletIcon} className="session-manager-menu-icon" />
400
- {!isRawWalletAccount ? `${translation.bind}DID Wallet` : `${translation.bind}${translation.thirdParty}`}
401
- </MenuItem>
402
- )}
294
+ )} */}
403
295
 
404
296
  <MenuItem
405
297
  className="session-manager-menu-item"
@@ -408,7 +300,7 @@ function SessionManager({
408
300
  aria-label="Logout account"
409
301
  data-cy="sessionManager-logout-trigger">
410
302
  <SvgIcon component={DisconnectIcon} className="session-manager-menu-icon" />
411
- {translation.disconnect}
303
+ {t('disconnect')}
412
304
  </MenuItem>
413
305
  </MenuList>
414
306
  </UserPopper>
@@ -0,0 +1,143 @@
1
+ /* eslint-disable react/prop-types */
2
+ /* eslint-disable react/jsx-no-bind */
3
+ import { useMemoizedFn, useUpdate } from 'ahooks';
4
+ import { MenuItem } from '@mui/material';
5
+ import { Icon } from '@iconify/react';
6
+ import AccountIcon from '@arcblock/icons/lib/Account';
7
+ import LinkIcon from '@iconify-icons/mdi/link';
8
+
9
+ import AccountItem from './account-item';
10
+ import MenuAccordion from './menu-accordion';
11
+ import { translations } from './translation';
12
+ import { translate } from '../Locale/util';
13
+ import { useConfirm } from '../Dialog/confirm';
14
+ import { getSourceProvider } from './utils';
15
+ import AddAccountItem from './add-account-item';
16
+ import useAccounts from './use-accounts';
17
+
18
+ export default function ManageAccounts({
19
+ session,
20
+ locale,
21
+ onBindWallet,
22
+ onSwitchDid,
23
+ connectAccount,
24
+ close,
25
+ hasBindAccount,
26
+ }) {
27
+ const { bindOAuth, configs: oauthConfigs } = session.useOAuth();
28
+ const t = useMemoizedFn((key, data = {}) => {
29
+ return translate(translations, key, locale, 'en', data);
30
+ });
31
+
32
+ const { confirmApi, confirmHolder } = useConfirm();
33
+ const { accounts, setAccounts } = useAccounts();
34
+ const update = useUpdate();
35
+
36
+ const onChoose = useMemoizedFn((account, { active }) => {
37
+ if (active) {
38
+ return;
39
+ }
40
+ close();
41
+ session.switchDid(
42
+ (...args) => {
43
+ connectAccount();
44
+ onSwitchDid(...args);
45
+ },
46
+ {
47
+ provider: account.provider,
48
+ providerMode: 'paramsFirst',
49
+ }
50
+ );
51
+ });
52
+
53
+ const oauthConfigList = Object.entries(oauthConfigs)
54
+ .map(([key, value]) => {
55
+ return { ...value, provider: key };
56
+ })
57
+ .filter((item) => item.enabled);
58
+
59
+ const isRawWalletAccount = getSourceProvider(session.user) === 'wallet';
60
+
61
+ const onDelete = useMemoizedFn((account, { active }) => {
62
+ if (active) {
63
+ return;
64
+ }
65
+ confirmApi.open({
66
+ title: t('deleteAccountTitle'),
67
+ content: t('deleteAccountContent'),
68
+ confirmButtonText: t('confirm'),
69
+ cancelButtonText: t('cancel'),
70
+ onConfirm(done) {
71
+ const findIndex = accounts.findIndex((item) => item.did === account.did);
72
+ if (findIndex >= 0) {
73
+ accounts.splice(findIndex, 1);
74
+ }
75
+ setAccounts(accounts);
76
+ update();
77
+ done();
78
+ },
79
+ });
80
+ });
81
+
82
+ const onAdd = useMemoizedFn((app) => {
83
+ close();
84
+ session.switchDid(
85
+ (...args) => {
86
+ connectAccount();
87
+ update();
88
+ onSwitchDid(...args);
89
+ },
90
+ {
91
+ provider: app.provider,
92
+ providerMode: 'paramsFirst',
93
+ }
94
+ );
95
+ });
96
+
97
+ function _onBindWallet() {
98
+ close();
99
+ // FIXME: @zhanghan 暂时切换回 isRawWalletAccount 的方式来判断,在 did-connect 改版时,简化这里的关系判断
100
+ if (!isRawWalletAccount) {
101
+ session.bindWallet(onBindWallet);
102
+ } else {
103
+ bindOAuth();
104
+ }
105
+ }
106
+
107
+ return (
108
+ <>
109
+ <MenuAccordion
110
+ locale={locale}
111
+ title={
112
+ <>
113
+ <AccountIcon className="session-manager-menu-icon" style={{ width: 24, height: 24 }} />
114
+ {t('manageAccounts')}
115
+ </>
116
+ }>
117
+ {accounts.map((item) => (
118
+ <AccountItem
119
+ key={item.did}
120
+ account={item}
121
+ locale={locale}
122
+ active={session.user.did === item.did}
123
+ onDelete={onDelete}
124
+ onChoose={onChoose}
125
+ />
126
+ ))}
127
+ <AddAccountItem locale={locale} onAdd={onAdd} />
128
+
129
+ {oauthConfigList.length > 0 && !hasBindAccount && session.provider !== 'federated' && (
130
+ <MenuItem
131
+ className="session-manager-menu-item"
132
+ onClick={_onBindWallet}
133
+ aria-label={!isRawWalletAccount ? `${t('bind')}DID Wallet` : `${t('bind')}${t('thirdParty')}`}
134
+ data-cy="sessionManager-bind-trigger">
135
+ <Icon icon={LinkIcon} width={24} height={24} className="session-manager-menu-icon" />
136
+ {!isRawWalletAccount ? `${t('bind')}DID Wallet` : `${t('bind')}${t('thirdParty')}`}
137
+ </MenuItem>
138
+ )}
139
+ </MenuAccordion>
140
+ {confirmHolder}
141
+ </>
142
+ );
143
+ }
@@ -0,0 +1,64 @@
1
+ /* eslint-disable react/no-array-index-key */
2
+ import PropTypes from 'prop-types';
3
+ import { useMemoizedFn } from 'ahooks';
4
+ import { Icon } from '@iconify/react';
5
+ import AppsIcon from '@iconify-icons/mdi/apps';
6
+ import { MenuItem, SvgIcon } from '@mui/material';
7
+
8
+ import MenuAccordion from './menu-accordion';
9
+ import { translate } from '../Locale/util';
10
+ import { translations } from './translation';
11
+
12
+ export default function ManageBlocklet({ menu, menuRender, locale }) {
13
+ const t = useMemoizedFn((key, data = {}) => {
14
+ return translate(translations, key, locale, 'en', data);
15
+ });
16
+
17
+ return (
18
+ <MenuAccordion
19
+ locale={locale}
20
+ title={
21
+ <>
22
+ <Icon icon={AppsIcon} width={24} height={24} className="session-manager-menu-icon" />
23
+ {t('manageBlocklet')}
24
+ </>
25
+ }>
26
+ {Array.isArray(menu) &&
27
+ menu.map((menuItem, index) => {
28
+ const { svgIcon, ...menuProps } = menuItem;
29
+ return (
30
+ <MenuItem
31
+ key={index}
32
+ className="session-manager-menu-item"
33
+ {...{
34
+ ...menuProps,
35
+ icon: undefined,
36
+ label: undefined,
37
+ }}>
38
+ {svgIcon
39
+ ? svgIcon && <SvgIcon component={svgIcon} className="session-manager-menu-icon" />
40
+ : menuItem.icon}
41
+ {menuItem.label}
42
+ </MenuItem>
43
+ );
44
+ })}
45
+ {menuRender({
46
+ classes: {
47
+ menuItem: 'session-manager-menu-item',
48
+ menuIcon: 'session-manager-menu-icon',
49
+ },
50
+ })}
51
+ </MenuAccordion>
52
+ );
53
+ }
54
+
55
+ ManageBlocklet.propTypes = {
56
+ menu: PropTypes.array,
57
+ menuRender: PropTypes.func,
58
+ locale: PropTypes.string.isRequired,
59
+ };
60
+
61
+ ManageBlocklet.defaultProps = {
62
+ menu: [],
63
+ menuRender: () => {},
64
+ };