@arcblock/did-connect-react 3.2.19 → 3.3.1

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 (54) hide show
  1. package/docs/assets/diagram/core-components-session-provider-01.ja.jpg +0 -0
  2. package/docs/assets/diagram/core-components-session-provider-01.jpg +0 -0
  3. package/docs/assets/diagram/core-components-session-provider-01.zh-TW.jpg +0 -0
  4. package/docs/assets/diagram/core-components-session-provider-01.zh.jpg +0 -0
  5. package/docs/assets/diagram/did-connect-diagram-0.ja.jpg +0 -0
  6. package/docs/assets/diagram/did-connect-diagram-0.jpg +0 -0
  7. package/docs/assets/diagram/did-connect-diagram-0.zh-TW.jpg +0 -0
  8. package/docs/assets/diagram/did-connect-diagram-0.zh.jpg +0 -0
  9. package/docs/assets/diagram/overview-01.ja.jpg +0 -0
  10. package/docs/assets/diagram/overview-01.jpg +0 -0
  11. package/docs/assets/diagram/overview-01.zh-TW.jpg +0 -0
  12. package/docs/assets/diagram/overview-01.zh.jpg +0 -0
  13. package/docs/assets/diagram/use-connect-diagram-0.ja.jpg +0 -0
  14. package/docs/assets/diagram/use-connect-diagram-0.jpg +0 -0
  15. package/docs/assets/diagram/use-connect-diagram-0.zh-TW.jpg +0 -0
  16. package/docs/assets/diagram/use-connect-diagram-0.zh.jpg +0 -0
  17. package/docs/core-components-did-connect.ja.md +3 -50
  18. package/docs/core-components-did-connect.md +5 -52
  19. package/docs/core-components-did-connect.zh-TW.md +3 -50
  20. package/docs/core-components-did-connect.zh.md +3 -50
  21. package/docs/core-components-session-provider.ja.md +3 -45
  22. package/docs/core-components-session-provider.md +3 -45
  23. package/docs/core-components-session-provider.zh-TW.md +3 -45
  24. package/docs/core-components-session-provider.zh.md +3 -45
  25. package/docs/hooks-use-connect.ja.md +3 -39
  26. package/docs/hooks-use-connect.md +4 -40
  27. package/docs/hooks-use-connect.zh-TW.md +3 -39
  28. package/docs/hooks-use-connect.zh.md +3 -39
  29. package/docs/overview.ja.md +3 -45
  30. package/docs/overview.md +3 -45
  31. package/docs/overview.zh-TW.md +3 -45
  32. package/docs/overview.zh.md +3 -45
  33. package/lib/Connect/assets/locale.js +4 -2
  34. package/lib/Connect/components/login-item/connect-choose-list.js +2 -2
  35. package/lib/Connect/components/login-item/connect-provider-list.js +299 -0
  36. package/lib/Connect/components/login-item/login-method-item.js +42 -41
  37. package/lib/Connect/hooks/provider-list.js +50 -0
  38. package/lib/Connect/index.js +180 -196
  39. package/lib/OAuth/context.js +33 -32
  40. package/lib/Passkey/context.js +64 -63
  41. package/lib/Session/hooks/use-verify.js +1 -1
  42. package/lib/Session/libs/locales.js +3 -3
  43. package/lib/package.json.js +1 -1
  44. package/package.json +9 -9
  45. package/src/Connect/assets/locale.js +2 -0
  46. package/src/Connect/components/login-item/connect-choose-list.jsx +5 -5
  47. package/src/Connect/components/login-item/connect-provider-list.jsx +392 -0
  48. package/src/Connect/components/login-item/login-method-item.jsx +31 -28
  49. package/src/Connect/hooks/provider-list.js +127 -0
  50. package/src/Connect/index.jsx +8 -27
  51. package/src/OAuth/context.jsx +10 -2
  52. package/src/Passkey/context.jsx +3 -0
  53. package/src/Session/hooks/use-verify.jsx +1 -1
  54. package/src/Session/libs/locales.js +3 -3
@@ -0,0 +1,392 @@
1
+ import PropTypes from 'prop-types';
2
+ import { Box } from '@mui/material';
3
+ import { LOGIN_PROVIDER, LOGIN_PROVIDER_NAME } from '@arcblock/ux/lib/Util/constant';
4
+ import { checkSameProtocol, getWebWalletUrl } from '@arcblock/ux/lib/Util/wallet';
5
+ import noop from 'lodash/noop';
6
+ import { useMemoizedFn } from 'ahooks';
7
+ import Cookie from 'js-cookie';
8
+ import { detectWalletExtension, getCookieOptions } from '@arcblock/ux/lib/Util';
9
+ import { useEffect, useRef } from 'react';
10
+ import { mergeSx } from '@arcblock/ux/lib/Util/style';
11
+ import ProviderIcon from '@arcblock/ux/lib/DIDConnect/provider-icon';
12
+ import { GA_LAST_LOGIN_METHOD } from '@arcblock/ux/lib/withTracker/constant';
13
+ import { translate } from '@arcblock/ux/lib/Locale/util';
14
+ import Empty from '@arcblock/ux/lib/Empty';
15
+ import { useBrowser } from '@arcblock/react-hooks';
16
+
17
+ import MobileLoginItem from './mobile-login-item';
18
+ import WebLoginItem from './web-login-item';
19
+ import LoginMethodItem from './login-method-item';
20
+ import { useOAuth } from '../../../OAuth';
21
+ import { useStateContext } from '../../contexts/state';
22
+ import { getApiErrorMessage, getAppId, logger } from '../../../utils';
23
+ import PasskeyLoginItem from './passkey-login-item';
24
+ import { usePasskey } from '../../../Passkey';
25
+ import { useEmailPlugin } from '../../plugins';
26
+ import translations from '../../assets/locale';
27
+
28
+ export default function ConnectProviderList({
29
+ onSuccess = noop,
30
+ onError = noop,
31
+ size = 'small',
32
+ tokenState,
33
+ webWalletUrl = getWebWalletUrl(),
34
+ tokenKey,
35
+ passkeyBehavior = 'none',
36
+ onReset = noop,
37
+ providerList = [],
38
+ slotProps = {},
39
+ disableSwitchApp = false,
40
+ forceUpdate = noop,
41
+ magicToken = undefined,
42
+ baseUrl = '/',
43
+ customItems = [],
44
+ }) {
45
+ const walletLoginRef = useRef(null);
46
+ const webLoginRef = useRef(null);
47
+ const passkeyLoginRef = useRef(null);
48
+
49
+ const browser = useBrowser();
50
+ const isSameProtocol = checkSameProtocol(webWalletUrl);
51
+ const extension = detectWalletExtension();
52
+
53
+ const { loginOAuth, logoutOAuth, t: oauthT, oauthState } = useOAuth();
54
+ const { passkeyState } = usePasskey();
55
+ const { extraParams, locale, connectState, plugins, setPlugins, setSelectedPlugin, getPlugin } = useStateContext();
56
+
57
+ const t = useMemoizedFn((key, data = {}) => {
58
+ return translate(translations, key, locale, 'en', data);
59
+ });
60
+
61
+ const handleLoginOAuth = useMemoizedFn(async (item) => {
62
+ localStorage.setItem(GA_LAST_LOGIN_METHOD, item.provider);
63
+ tokenState.reset();
64
+ oauthState.reset({
65
+ status: 'scanned',
66
+ });
67
+ passkeyState.reset();
68
+ connectState.chooseMethod = item.provider;
69
+
70
+ const sourceAppPid = extraParams?.sourceAppPid;
71
+ try {
72
+ oauthState.loading = true;
73
+ oauthState.status = 'scanned';
74
+ const loginResult = await loginOAuth(item, {
75
+ action: tokenState.action,
76
+ ...extraParams,
77
+ });
78
+ const cookieOptions = getCookieOptions({ returnDomain: false });
79
+ Cookie.remove('connected_did', cookieOptions);
80
+ Cookie.remove('connected_pk', cookieOptions);
81
+ Cookie.remove('connected_wallet_os', cookieOptions);
82
+
83
+ if (loginResult?.sessionToken) {
84
+ await onSuccess(
85
+ {
86
+ ...loginResult,
87
+ encrypted: false,
88
+ },
89
+ (val) => val,
90
+ {
91
+ sourceAppPid,
92
+ connected_app: getAppId(tokenState.appInfo, tokenState.memberAppInfo),
93
+ }
94
+ );
95
+ oauthState.loading = false;
96
+ oauthState.status = 'succeed';
97
+ }
98
+ } catch (e) {
99
+ logger.error(`Failed login OAuth: ${item.provider}`, e);
100
+ const errorMessage = getApiErrorMessage(e, oauthT('loginOAuthFailed'));
101
+ oauthState.loading = false;
102
+ oauthState.error = errorMessage;
103
+ oauthState.status = 'error';
104
+ await logoutOAuth({ provider: item.provider });
105
+ onError(new Error(errorMessage));
106
+ }
107
+ });
108
+
109
+ const defaultRetryConnect = useMemoizedFn(async () => {
110
+ tokenState.reset();
111
+ await onReset();
112
+ tokenState.status = 'created';
113
+ connectState.chooseMethod = 'wallet';
114
+ });
115
+
116
+ const showEmailLogin = providerList.some((p) => p.provider === LOGIN_PROVIDER.EMAIL);
117
+
118
+ const emailPlugin = useEmailPlugin({ baseUrl });
119
+
120
+ const setupMagicToken = useMemoizedFn(() => {
121
+ if (
122
+ magicToken &&
123
+ providerList.some((provider) => provider.name === LOGIN_PROVIDER.EMAIL) &&
124
+ plugins.some((plugin) => plugin.name === LOGIN_PROVIDER.EMAIL)
125
+ ) {
126
+ const plugin = getPlugin(LOGIN_PROVIDER.EMAIL);
127
+ if (plugin.state.status === 'idle') {
128
+ localStorage.setItem(GA_LAST_LOGIN_METHOD, 'email');
129
+ plugin.state.reset();
130
+ plugin.state.magicToken = magicToken;
131
+ connectState.chooseMethod = LOGIN_PROVIDER.EMAIL;
132
+ setSelectedPlugin(plugin);
133
+ forceUpdate();
134
+ }
135
+ }
136
+ });
137
+
138
+ // 考虑到切换账号的情况,此时 showEmailLogin 会根据当前上下文的 blocklet 发生变化,所以需要监听 showEmailLogin 的变化
139
+ useEffect(() => {
140
+ const finalList = [];
141
+ if (showEmailLogin) {
142
+ // 尽可能确保在 baseUrl 不变的情况下,不更改 email 插件的数据,以确保页面的展示不会出现闪烁
143
+ const prevEmailPlugin = getPlugin(LOGIN_PROVIDER.EMAIL);
144
+ if (prevEmailPlugin && prevEmailPlugin.baseUrl === emailPlugin.baseUrl) {
145
+ finalList.push(prevEmailPlugin);
146
+ } else {
147
+ finalList.push(emailPlugin);
148
+ }
149
+ }
150
+ setPlugins(finalList);
151
+ connectState.retryConnect = defaultRetryConnect;
152
+ // HACK: 必须要设置延迟,不然拿不到最新的 plugins 的值
153
+ setTimeout(() => {
154
+ setupMagicToken();
155
+ }, 100);
156
+ // eslint-disable-next-line react-hooks/exhaustive-deps
157
+ }, [showEmailLogin]);
158
+
159
+ const renderProviderList = providerList
160
+ .map((item) => {
161
+ if (item.provider === LOGIN_PROVIDER.WALLET) {
162
+ if (browser.mobile.any) {
163
+ return (
164
+ <MobileLoginItem
165
+ key={LOGIN_PROVIDER.WALLET}
166
+ ref={walletLoginRef}
167
+ tokenState={tokenState}
168
+ sx={[size === 'small' ? { p: 1 } : { p: 2 }]}
169
+ locale={locale}
170
+ tokenKey={tokenKey}
171
+ disableSwitchApp={disableSwitchApp}
172
+ onClick={async () => {
173
+ localStorage.setItem(GA_LAST_LOGIN_METHOD, 'wallet');
174
+ tokenState.reset();
175
+ await onReset();
176
+ tokenState.status = 'created';
177
+ connectState.chooseMethod = 'wallet';
178
+ const connectFn = walletLoginRef.current?.connect;
179
+ connectState.retryConnect = () => {
180
+ connectFn(defaultRetryConnect);
181
+ };
182
+ }}
183
+ />
184
+ );
185
+ }
186
+
187
+ if ((isSameProtocol || extension) && (!browser.mobile.any || extension)) {
188
+ return (
189
+ <WebLoginItem
190
+ key={LOGIN_PROVIDER.WALLET}
191
+ ref={webLoginRef}
192
+ tokenState={tokenState}
193
+ webWalletUrl={webWalletUrl}
194
+ sx={[size === 'small' ? { p: 1 } : { p: 2 }]}
195
+ disableSwitchApp={disableSwitchApp}
196
+ onClick={() => {
197
+ localStorage.setItem(GA_LAST_LOGIN_METHOD, 'wallet');
198
+ // HACK: 在点击插件登录时,直接将状态置为扫码中,避免插件登录时的状态切换
199
+ tokenState.status = 'scanned';
200
+ connectState.chooseMethod = 'wallet-web';
201
+ const connectFn = webLoginRef.current.connect;
202
+ connectState.retryConnect = async () => {
203
+ await onReset();
204
+ tokenState.error = '';
205
+ tokenState.status = 'scanned';
206
+ connectFn();
207
+ };
208
+ }}
209
+ />
210
+ );
211
+ }
212
+ }
213
+
214
+ if (item.provider === LOGIN_PROVIDER.PASSKEY) {
215
+ if (passkeyBehavior === 'none') {
216
+ return null;
217
+ }
218
+ return (
219
+ <PasskeyLoginItem
220
+ key={LOGIN_PROVIDER.PASSKEY}
221
+ ref={passkeyLoginRef}
222
+ onSuccess={onSuccess}
223
+ onError={onError}
224
+ tokenState={tokenState}
225
+ behavior={passkeyBehavior}
226
+ sx={[size === 'small' ? { p: 1 } : { p: 2 }]}
227
+ onClick={() => {
228
+ localStorage.setItem(GA_LAST_LOGIN_METHOD, 'passkey');
229
+ const connectFn = passkeyLoginRef.current.connect;
230
+ connectState.chooseMethod = 'passkey';
231
+ connectState.retryConnect = () => {
232
+ passkeyState.verifying = true;
233
+ connectState.chooseMethod = 'passkey';
234
+ connectFn();
235
+ };
236
+ }}
237
+ slotProps={{
238
+ icon: {
239
+ sx: {
240
+ fontSize: 24,
241
+ '& svg': {
242
+ fontSize: 24,
243
+ width: '1em',
244
+ height: '1em',
245
+ },
246
+ },
247
+ },
248
+ }}
249
+ />
250
+ );
251
+ }
252
+
253
+ if (item.provider === LOGIN_PROVIDER.EMAIL) {
254
+ const findEmailPlugin = plugins.find((p) => p.name === LOGIN_PROVIDER.EMAIL);
255
+ if (!findEmailPlugin) {
256
+ return null;
257
+ }
258
+ return findEmailPlugin?.renderListItem({
259
+ key: findEmailPlugin.name,
260
+ sx: [size === 'small' ? { p: 1 } : { p: 2 }],
261
+ // forceUpdate,
262
+ });
263
+ }
264
+
265
+ if (item.type === 'oauth') {
266
+ return (
267
+ <LoginMethodItem
268
+ key={item.provider}
269
+ title={LOGIN_PROVIDER_NAME[item.provider]}
270
+ icon={
271
+ <ProviderIcon
272
+ provider={item.provider}
273
+ sx={{
274
+ transform: 'scale(0.95)',
275
+ width: 24,
276
+ height: 24,
277
+ color: 'text.primary',
278
+ }}
279
+ />
280
+ }
281
+ onClick={() => {
282
+ handleLoginOAuth(item);
283
+ connectState.retryConnect = () => {
284
+ handleLoginOAuth(item);
285
+ };
286
+ }}
287
+ sx={[size === 'small' ? { p: 1 } : { p: 2 }]}
288
+ />
289
+ );
290
+ }
291
+
292
+ return null;
293
+ })
294
+ .filter(Boolean);
295
+
296
+ return (
297
+ <Box className="did-connect__choose" sx={mergeSx({ flex: 1 }, slotProps?.root?.sx)}>
298
+ <Box
299
+ sx={{
300
+ display: 'flex',
301
+ flexDirection: 'column',
302
+ gap: 2,
303
+ }}>
304
+ <Box
305
+ sx={[
306
+ {
307
+ display: 'flex',
308
+ flexDirection: 'column',
309
+ gap: 1.5,
310
+ },
311
+ ]}>
312
+ <Box
313
+ sx={{
314
+ display: 'grid',
315
+ gridTemplateColumns: 'repeat(12, 1fr)' /* 灵活的12列基础网格 */,
316
+ gap: 1.25,
317
+ '.arc-login-item:nth-child(-n+3)': {
318
+ gridColumn: 'span 12',
319
+ },
320
+ '.arc-login-item:nth-child(4):last-child': {
321
+ gridColumn: 'span 12',
322
+ },
323
+ '.arc-login-item:nth-child(4):nth-last-child(2), .arc-login-item:nth-child(4):nth-last-child(2), .arc-login-item:nth-child(4):nth-last-child(2) ~ .arc-login-item':
324
+ {
325
+ gridColumn: 'span 6',
326
+ justifyContent: 'center',
327
+ '.arc-login-item__body, .other-item-icon': {
328
+ display: 'none',
329
+ },
330
+ },
331
+ '.arc-login-item:nth-child(4):nth-last-child(3), .arc-login-item:nth-child(4):nth-last-child(3) ~ .arc-login-item':
332
+ {
333
+ justifyContent: 'center',
334
+ gridColumn: 'span 4',
335
+ '.arc-login-item__body, .other-item-icon': {
336
+ display: 'none',
337
+ },
338
+ },
339
+ '.arc-login-item:nth-child(4):nth-last-child(4), .arc-login-item:nth-child(4):nth-last-child(4) ~ .arc-login-item':
340
+ {
341
+ gridColumn: 'span 3',
342
+ justifyContent: 'center',
343
+ '.arc-login-item__body, .other-item-icon': {
344
+ display: 'none',
345
+ },
346
+ },
347
+ '&:has(.arc-login-item:nth-child(8)) .arc-login-item:nth-child(n+4)': {
348
+ gridColumn: 'span 3',
349
+ justifyContent: 'center',
350
+ '.arc-login-item__body, .other-item-icon': {
351
+ display: 'none',
352
+ },
353
+ },
354
+ }}>
355
+ {renderProviderList.length > 0 ? (
356
+ renderProviderList
357
+ ) : (
358
+ <Empty
359
+ className="arc-login-item"
360
+ sx={{
361
+ '.empty-content': {
362
+ textAlign: 'center',
363
+ },
364
+ }}>
365
+ {t('noAuthenticationProvider')}
366
+ </Empty>
367
+ )}
368
+ </Box>
369
+ {customItems.map((item) => (!item ? null : item))}
370
+ </Box>
371
+ </Box>
372
+ </Box>
373
+ );
374
+ }
375
+
376
+ ConnectProviderList.propTypes = {
377
+ onSuccess: PropTypes.func,
378
+ onError: PropTypes.func,
379
+ size: PropTypes.oneOf(['small', 'normal', 'large']),
380
+ tokenState: PropTypes.object.isRequired,
381
+ webWalletUrl: PropTypes.string,
382
+ tokenKey: PropTypes.string.isRequired,
383
+ passkeyBehavior: PropTypes.oneOf(['none', 'both', 'only-existing', 'only-new']),
384
+ onReset: PropTypes.func,
385
+ providerList: PropTypes.array,
386
+ slotProps: PropTypes.object,
387
+ disableSwitchApp: PropTypes.bool,
388
+ forceUpdate: PropTypes.func,
389
+ magicToken: PropTypes.string,
390
+ baseUrl: PropTypes.string,
391
+ customItems: PropTypes.arrayOf(PropTypes.node),
392
+ };
@@ -1,4 +1,4 @@
1
- import { Box, Typography, useTheme } from '@mui/material';
1
+ import { Box, Tooltip, Typography, useTheme } from '@mui/material';
2
2
  import { Icon } from '@iconify/react';
3
3
  import { isValidElement } from 'react';
4
4
  import PropTypes from 'prop-types';
@@ -19,6 +19,7 @@ export default function LoginMethodItem({
19
19
  return (
20
20
  <Box
21
21
  {...rest}
22
+ className="arc-login-item"
22
23
  sx={mergeSx(
23
24
  {
24
25
  display: 'flex',
@@ -48,34 +49,36 @@ export default function LoginMethodItem({
48
49
  },
49
50
  rest?.sx
50
51
  )}>
51
- <Box
52
- className="arc-login-item__icon"
53
- sx={mergeSx(
54
- {
55
- display: 'flex',
56
- justifyContent: 'center',
57
- alignItems: 'center',
58
- color: 'text.primary',
59
- },
60
- slotProps?.icon?.sx
61
- )}>
62
- {isValidElement(icon) ? (
63
- icon
64
- ) : (
65
- <Box
66
- component={Icon}
67
- icon={icon}
68
- sx={{
69
- transform: `scale(${iconScale})`,
70
- width: 24,
71
- height: 24,
72
- }}
73
- />
74
- )}
75
- </Box>
52
+ <Tooltip title={title}>
53
+ <Box
54
+ className="arc-login-item__icon"
55
+ sx={mergeSx(
56
+ {
57
+ display: 'flex',
58
+ justifyContent: 'center',
59
+ alignItems: 'center',
60
+ color: 'text.primary',
61
+ },
62
+ slotProps?.icon?.sx
63
+ )}>
64
+ {isValidElement(icon) ? (
65
+ icon
66
+ ) : (
67
+ <Box
68
+ component={Icon}
69
+ icon={icon}
70
+ sx={{
71
+ transform: `scale(${iconScale})`,
72
+ width: 24,
73
+ height: 24,
74
+ }}
75
+ />
76
+ )}
77
+ </Box>
78
+ </Tooltip>
76
79
  {mode === 'normal' ? (
77
80
  <>
78
- <Box sx={{ display: 'flex', flexDirection: 'column', flex: 1 }}>
81
+ <Box className="arc-login-item__body" sx={{ display: 'flex', flexDirection: 'column', flex: 1 }}>
79
82
  <Typography
80
83
  sx={{
81
84
  fontSize: 14,
@@ -114,5 +117,5 @@ LoginMethodItem.propTypes = {
114
117
  icon: PropTypes.any.isRequired,
115
118
  iconScale: PropTypes.number,
116
119
  slotProps: PropTypes.object,
117
- mode: PropTypes.oneOf(['simple', 'normal']),
120
+ mode: PropTypes.oneOf(['mini', 'simple', 'normal']),
118
121
  };
@@ -0,0 +1,127 @@
1
+ import { useBrowser } from '@arcblock/react-hooks';
2
+ import { useCreation, useRequest } from 'ahooks';
3
+ import isNil from 'lodash/isNil';
4
+ import { LOGIN_PROVIDER } from '@arcblock/ux/lib/Util/constant';
5
+ import { getBlockletData, getFederatedEnabled, getMaster } from '@arcblock/ux/lib/Util/federated';
6
+
7
+ const getAuthenticationConfig = async ({ sourceAppPid }) => {
8
+ const blocklet = globalThis?.blocklet;
9
+ if (!blocklet) {
10
+ return {
11
+ [LOGIN_PROVIDER.WALLET]: {
12
+ order: 0,
13
+ enabled: true,
14
+ showQrcode: true,
15
+ },
16
+ [LOGIN_PROVIDER.PASSKEY]: {
17
+ order: 1,
18
+ enabled: true,
19
+ },
20
+ };
21
+ }
22
+ const federatedEnabled = getFederatedEnabled(blocklet);
23
+ const master = getMaster(blocklet);
24
+ if (federatedEnabled && master?.appPid && sourceAppPid === master?.appPid) {
25
+ const masterBlocklet = await getBlockletData(master.appUrl);
26
+ return masterBlocklet?.settings?.authentication || {};
27
+ }
28
+ return blocklet?.settings?.authentication || {};
29
+ };
30
+
31
+ const getLoginProviderList = async ({ sourceAppPid } = {}) => {
32
+ const authenticationConfig = await getAuthenticationConfig({ sourceAppPid });
33
+ const loginProviderList = Object.entries(authenticationConfig)
34
+ .map(([key, value]) => {
35
+ return { ...value, provider: key };
36
+ })
37
+ .filter((item) => item.enabled)
38
+ .sort((a, b) => {
39
+ if (!isNil(a?.order) && !isNil(b?.order)) {
40
+ return a.order - b.order;
41
+ }
42
+ if (!isNil(a?.order)) {
43
+ return -1;
44
+ }
45
+ return 1;
46
+ });
47
+ return loginProviderList;
48
+ };
49
+
50
+ export default function useProviderList({
51
+ allowWallet = true,
52
+ passkeyBehavior = 'none',
53
+ action,
54
+ sourceAppPid,
55
+ mode = 'dialog',
56
+ blocklet = globalThis.blocklet,
57
+ isSmallView = false,
58
+ }) {
59
+ const actionList = ['login', 'invite', 'connect-to-did-space', 'connect-to-did-domain', 'destroy-self'];
60
+ const browser = useBrowser();
61
+
62
+ const { data: loginProviderList = [] } = useRequest(
63
+ async () => {
64
+ const data = await getLoginProviderList({ sourceAppPid });
65
+ return data;
66
+ },
67
+ { refreshDeps: [sourceAppPid] }
68
+ );
69
+
70
+ const showedLoginProviderList = useCreation(() => {
71
+ const result = loginProviderList.filter((item) => {
72
+ if (item.name === LOGIN_PROVIDER.WALLET) {
73
+ return allowWallet;
74
+ }
75
+ if (item.name === LOGIN_PROVIDER.PASSKEY) {
76
+ return passkeyBehavior !== 'none' && !browser.wallet && !browser.arcSphere;
77
+ }
78
+ if (item.name === LOGIN_PROVIDER.EMAIL) {
79
+ return blocklet?.settings?.notification?.email?.enabled ?? false;
80
+ }
81
+
82
+ if (item.type === 'oauth') {
83
+ if (!actionList.includes(action)) {
84
+ return false;
85
+ }
86
+ }
87
+ return true;
88
+ });
89
+ return result;
90
+ }, [loginProviderList]);
91
+
92
+ const hideQRCode = useCreation(() => {
93
+ const isMobileView = mode === 'drawer' || (isSmallView && browser.mobile.any);
94
+ if (!globalThis?.blocklet) {
95
+ if (!isMobileView) {
96
+ return false;
97
+ }
98
+ return true;
99
+ }
100
+
101
+ const walletProvider = showedLoginProviderList.find((item) => item.provider === LOGIN_PROVIDER.WALLET);
102
+ if (walletProvider?.showQrcode !== true) {
103
+ return true;
104
+ }
105
+ if (isMobileView) {
106
+ return true;
107
+ }
108
+ return false;
109
+ }, [mode, isSmallView, showedLoginProviderList]);
110
+
111
+ const hideChooseList = useCreation(() => {
112
+ return false;
113
+ // NOTICE: 先保留这部分逻辑,后续根据需求调整
114
+ // if (showOAuthLogin || showPasskeyLogin) {
115
+ // return false;
116
+ // }
117
+ // return true;
118
+ });
119
+
120
+ const result = {
121
+ hideChooseList,
122
+ hideQRCode,
123
+ providerList: showedLoginProviderList,
124
+ };
125
+
126
+ return result;
127
+ }
@@ -36,7 +36,7 @@ import useSecurity from './hooks/security';
36
36
 
37
37
  import { SessionContext } from '../Session/context';
38
38
  import { StateProvider, useStateContext } from './contexts/state';
39
- import ConnectChooseList from './components/login-item/connect-choose-list';
39
+ import ConnectProviderList from './components/login-item/connect-provider-list';
40
40
  import AutoHeight from './components/auto-height';
41
41
  import useToken from './hooks/token';
42
42
  import { useOAuth } from '../OAuth';
@@ -46,7 +46,7 @@ import { API_DID_PREFIX, DEFAULT_TIMEOUT, BUSY_STATUS, CHECK_STATUS_INTERVAL } f
46
46
  import { getWebWalletUrl } from '../utils';
47
47
  import DIDConnectTitle from './components/did-connect-title';
48
48
  import DownloadTips from './components/download-tips';
49
- import useMethodList from './hooks/method-list';
49
+ import useProviderList from './hooks/provider-list';
50
50
  import useAuthUrl from './hooks/auth-url';
51
51
  import { getWalletDid } from '../User/use-did';
52
52
 
@@ -213,19 +213,9 @@ function Connect({
213
213
  return LOGIN_PROVIDER_NAME[connectState.chooseMethod] || 'DID Wallet';
214
214
  }, [connectState.chooseMethod]);
215
215
 
216
- const {
217
- showMobileLogin,
218
- hideChooseList,
219
- oauthProviderList,
220
- showOAuthLogin,
221
- showPasskeyLogin,
222
- showWebLogin,
223
- showEmailLogin,
224
- hideQRCode,
225
- } = useMethodList({
216
+ const { providerList, hideQRCode, hideChooseList } = useProviderList({
226
217
  action: state.action,
227
218
  sourceAppPid: connectState?.sourceAppPid,
228
- enabledConnectTypes,
229
219
  allowWallet,
230
220
  passkeyBehavior,
231
221
  webWalletUrl,
@@ -301,7 +291,7 @@ function Connect({
301
291
 
302
292
  // 防止二维码抖动,使用 useCreation 进行缓存
303
293
  const qrcode = useCreation(() => {
304
- const backgroundColor = theme.mode === 'dark' ? theme.palette.grey[500] : 'white';
294
+ const backgroundColor = theme.mode === 'dark' ? theme.palette.grey[600] : 'white';
305
295
  return (
306
296
  <Box
307
297
  sx={{
@@ -437,7 +427,7 @@ function Connect({
437
427
  }}>
438
428
  {/* eslint-disable-next-line no-nested-ternary */}
439
429
  {content}
440
- <ConnectChooseList
430
+ <ConnectProviderList
441
431
  slotProps={{
442
432
  root: {
443
433
  sx: [showStatus ? { display: 'none' } : {}],
@@ -453,18 +443,13 @@ function Connect({
453
443
  webWalletUrl={webWalletUrl}
454
444
  extraContent={extraContent}
455
445
  enabledConnectTypes={enabledConnectTypes}
456
- onRest={handleReset}
457
- showMobileLogin={showMobileLogin && hideQRCode}
458
- showOAuthLogin={showOAuthLogin}
459
- showPasskeyLogin={showPasskeyLogin}
460
- showWebLogin={showWebLogin}
461
- showEmailLogin={showEmailLogin}
462
- oauthProviderList={oauthProviderList}
446
+ onReset={handleReset}
463
447
  disableSwitchApp={disableSwitchApp}
464
448
  forceUpdate={forceUpdate}
465
449
  magicToken={magicToken}
466
450
  baseUrl={baseUrl}
467
451
  customItems={customItems}
452
+ providerList={providerList}
468
453
  />
469
454
  </Box>
470
455
  </Box>
@@ -494,11 +479,7 @@ function Connect({
494
479
  maxWidth: '100%',
495
480
  width:
496
481
  // eslint-disable-next-line no-nested-ternary
497
- mode === 'drawer'
498
- ? '100%'
499
- : hideQRCode || showStatus || hideChooseList
500
- ? DID_CONNECT_SMALL_WIDTH
501
- : DID_CONNECT_MEDIUM_WIDTH,
482
+ mode === 'drawer' ? '100%' : hideQRCode || showStatus ? DID_CONNECT_SMALL_WIDTH : DID_CONNECT_MEDIUM_WIDTH,
502
483
  transition: 'width 0.2s ease-in-out',
503
484
  margin: 'auto',
504
485
  p: isSmallView ? 2 : 3,