@arcblock/did-connect-react 3.4.0 → 3.4.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/Connect/assets/locale.js +4 -2
- package/lib/Connect/components/login-item/connect-choose-list.js +120 -114
- package/lib/Connect/components/login-item/connect-provider-list.js +187 -180
- package/lib/Connect/components/login-item/login-method-item.js +63 -47
- package/lib/Connect/components/login-item/passkey-login-item.js +17 -15
- package/lib/Connect/components/login-item/wallet-login-options.js +42 -40
- package/lib/Connect/connect.js +116 -117
- package/lib/Connect/contexts/state.js +73 -64
- package/lib/Connect/hooks/provider-list.js +43 -33
- package/lib/Connect/hooks/token.js +121 -122
- package/lib/Connect/plugins/email/index.js +15 -12
- package/lib/Connect/plugins/email/list-item.js +19 -18
- package/lib/Passkey/actions.js +80 -75
- package/lib/package.json.js +1 -1
- package/package.json +5 -5
- package/src/Connect/assets/locale.js +2 -0
- package/src/Connect/components/login-item/connect-choose-list.jsx +12 -5
- package/src/Connect/components/login-item/connect-provider-list.jsx +11 -4
- package/src/Connect/components/login-item/login-method-item.jsx +24 -7
- package/src/Connect/components/login-item/passkey-login-item.jsx +3 -1
- package/src/Connect/components/login-item/wallet-login-options.jsx +3 -2
- package/src/Connect/connect.jsx +36 -35
- package/src/Connect/contexts/state.jsx +10 -0
- package/src/Connect/hooks/provider-list.js +43 -17
- package/src/Connect/hooks/token.js +13 -13
- package/src/Connect/plugins/email/index.jsx +3 -0
- package/src/Connect/plugins/email/list-item.jsx +3 -2
- package/src/Passkey/actions.jsx +5 -0
|
@@ -9,6 +9,7 @@ import { translate } from '@arcblock/ux/lib/Locale/util';
|
|
|
9
9
|
import { getCurrentApp, getMaster } from '@arcblock/ux/lib/Util/federated';
|
|
10
10
|
import { getDIDMotifInfo } from '@arcblock/did-motif';
|
|
11
11
|
import { getDIDColor, isEthereumDid } from '@arcblock/ux/lib/Util';
|
|
12
|
+
import { GA_LAST_LOGIN_METHOD } from '@arcblock/ux/lib/withTracker/constant';
|
|
12
13
|
|
|
13
14
|
import useApps from '../hooks/use-apps';
|
|
14
15
|
import { SessionContext } from '../../Session/context';
|
|
@@ -68,6 +69,13 @@ function StateProvider({
|
|
|
68
69
|
sourceAppPid: extraParams?.sourceAppPid,
|
|
69
70
|
enableSwitchApp: extraParams?.forceSwitch || extraParams?.enableSwitchApp,
|
|
70
71
|
});
|
|
72
|
+
const lastLoginMethod = useCreation(() => {
|
|
73
|
+
try {
|
|
74
|
+
return localStorage.getItem(GA_LAST_LOGIN_METHOD);
|
|
75
|
+
} catch (error) {
|
|
76
|
+
return '';
|
|
77
|
+
}
|
|
78
|
+
}, []);
|
|
71
79
|
|
|
72
80
|
const rootRef = useRef(null);
|
|
73
81
|
const size = useSize(rootRef);
|
|
@@ -180,6 +188,8 @@ function StateProvider({
|
|
|
180
188
|
// 控制钱包登录的显示
|
|
181
189
|
showWalletOptions,
|
|
182
190
|
setShowWalletOptions,
|
|
191
|
+
// 用于记录上一次登录方式
|
|
192
|
+
lastLoginMethod,
|
|
183
193
|
};
|
|
184
194
|
}, [
|
|
185
195
|
browser.wallet,
|
|
@@ -56,6 +56,7 @@ export default function useProviderList({
|
|
|
56
56
|
mode = 'dialog',
|
|
57
57
|
blocklet = globalThis.blocklet,
|
|
58
58
|
isSmallView = false,
|
|
59
|
+
lastLoginMethod = '',
|
|
59
60
|
}) {
|
|
60
61
|
const [loadingProviderList, setLoadingProviderList] = useState(false);
|
|
61
62
|
const actionList = ['login', 'invite', 'connect-to-did-space', 'connect-to-did-domain', 'destroy-self'];
|
|
@@ -72,26 +73,51 @@ export default function useProviderList({
|
|
|
72
73
|
);
|
|
73
74
|
|
|
74
75
|
const showedLoginProviderList = useCreation(() => {
|
|
75
|
-
const result = loginProviderList
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
76
|
+
const result = loginProviderList
|
|
77
|
+
.filter((item) => {
|
|
78
|
+
if (item.name === LOGIN_PROVIDER.WALLET) {
|
|
79
|
+
return allowWallet;
|
|
80
|
+
}
|
|
81
|
+
if (item.name === LOGIN_PROVIDER.PASSKEY) {
|
|
82
|
+
return passkeyBehavior !== 'none' && !browser.wallet && !browser.arcSphere;
|
|
83
|
+
}
|
|
84
|
+
if (item.name === LOGIN_PROVIDER.EMAIL) {
|
|
85
|
+
return blocklet?.settings?.notification?.email?.enabled ?? false;
|
|
86
|
+
}
|
|
85
87
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
88
|
+
if (item.type === 'oauth') {
|
|
89
|
+
if (!actionList.includes(action)) {
|
|
90
|
+
return false;
|
|
91
|
+
}
|
|
89
92
|
}
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
+
return true;
|
|
94
|
+
})
|
|
95
|
+
.sort((a, b) => {
|
|
96
|
+
// 优先处理 lastLoginMethod:匹配的项目排在最前面
|
|
97
|
+
if (lastLoginMethod) {
|
|
98
|
+
const aIsLastMethod = a.provider === lastLoginMethod;
|
|
99
|
+
const bIsLastMethod = b.provider === lastLoginMethod;
|
|
100
|
+
if (aIsLastMethod && !bIsLastMethod) {
|
|
101
|
+
return -1;
|
|
102
|
+
}
|
|
103
|
+
if (!aIsLastMethod && bIsLastMethod) {
|
|
104
|
+
return 1;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
// 然后按照 order 属性排序
|
|
108
|
+
if (!isNil(a?.order) && !isNil(b?.order)) {
|
|
109
|
+
return a.order - b.order;
|
|
110
|
+
}
|
|
111
|
+
if (!isNil(a?.order)) {
|
|
112
|
+
return -1;
|
|
113
|
+
}
|
|
114
|
+
if (!isNil(b?.order)) {
|
|
115
|
+
return 1;
|
|
116
|
+
}
|
|
117
|
+
return 0;
|
|
118
|
+
});
|
|
93
119
|
return result;
|
|
94
|
-
}, [loginProviderList]);
|
|
120
|
+
}, [loginProviderList, lastLoginMethod]);
|
|
95
121
|
|
|
96
122
|
const hideQRCode = useCreation(() => {
|
|
97
123
|
const isMobileView = mode === 'drawer' || (isSmallView && browser.mobile.any);
|
|
@@ -119,7 +119,6 @@ export default function useToken({
|
|
|
119
119
|
store: null,
|
|
120
120
|
status: 'created',
|
|
121
121
|
error: '',
|
|
122
|
-
checkCount: 0,
|
|
123
122
|
mfaCode: 0,
|
|
124
123
|
appInfo: null,
|
|
125
124
|
memberAppInfo: null,
|
|
@@ -140,6 +139,8 @@ export default function useToken({
|
|
|
140
139
|
},
|
|
141
140
|
});
|
|
142
141
|
|
|
142
|
+
// 使用 ref 存储 checkCount,避免计数时触发不必要的渲染
|
|
143
|
+
const checkCountRef = useRef(0);
|
|
143
144
|
const statusExtraParams = useRef(null);
|
|
144
145
|
|
|
145
146
|
const translation = translations[locale] || translations.en;
|
|
@@ -264,7 +265,7 @@ export default function useToken({
|
|
|
264
265
|
state.url = data.url;
|
|
265
266
|
state.status = 'created';
|
|
266
267
|
state.error = '';
|
|
267
|
-
|
|
268
|
+
checkCountRef.current = 0;
|
|
268
269
|
state.appInfo = data.appInfo;
|
|
269
270
|
state.memberAppInfo = data.memberAppInfo;
|
|
270
271
|
state.connectedDid = extra.connectedDid;
|
|
@@ -363,7 +364,6 @@ export default function useToken({
|
|
|
363
364
|
}, []);
|
|
364
365
|
|
|
365
366
|
// Check auth token status
|
|
366
|
-
// FIXME: @zhanghan 这个函数会造成 connect 组件每秒重渲染一次,需要从 setState 入手,优化这个问题。优化的原则是,页面数据没有变更时,不应该触发重渲染
|
|
367
367
|
const checkStatus = useMemoizedFn(async (force = false) => {
|
|
368
368
|
if ((state.checking || document.hidden) && !force) {
|
|
369
369
|
return null;
|
|
@@ -371,7 +371,14 @@ export default function useToken({
|
|
|
371
371
|
|
|
372
372
|
// NOTICE: 仅当状态为 created 时才去计算次数统计
|
|
373
373
|
if (state.status === 'created') {
|
|
374
|
-
|
|
374
|
+
checkCountRef.current++;
|
|
375
|
+
|
|
376
|
+
// 超时判断:超过最大检查次数则标记为超时
|
|
377
|
+
if (state.status !== 'timeout' && checkCountRef.current > maxCheckCount) {
|
|
378
|
+
state.status = 'timeout';
|
|
379
|
+
unsubscribe();
|
|
380
|
+
return null;
|
|
381
|
+
}
|
|
375
382
|
}
|
|
376
383
|
|
|
377
384
|
if (currentState.isSocketAvailable && !force) {
|
|
@@ -467,13 +474,6 @@ export default function useToken({
|
|
|
467
474
|
}
|
|
468
475
|
}
|
|
469
476
|
|
|
470
|
-
// Mark token as expired if exceed max retry count
|
|
471
|
-
if (state.status !== 'timeout' && state.checkCount > maxCheckCount) {
|
|
472
|
-
state.status = 'timeout';
|
|
473
|
-
unsubscribe();
|
|
474
|
-
return;
|
|
475
|
-
}
|
|
476
|
-
|
|
477
477
|
// Trigger on success if we completed the process
|
|
478
478
|
if (state.status === 'succeed' && !currentState.onSuccessCalled) {
|
|
479
479
|
// save connected_did to cookie if only on same origin
|
|
@@ -499,7 +499,7 @@ export default function useToken({
|
|
|
499
499
|
state.url = '';
|
|
500
500
|
state.appInfo = null;
|
|
501
501
|
state.memberAppInfo = null;
|
|
502
|
-
|
|
502
|
+
checkCountRef.current = 0;
|
|
503
503
|
state.status = 'scanned';
|
|
504
504
|
state.results = {
|
|
505
505
|
...state.results,
|
|
@@ -547,7 +547,7 @@ export default function useToken({
|
|
|
547
547
|
state.url = '';
|
|
548
548
|
state.appInfo = null;
|
|
549
549
|
state.memberAppInfo = null;
|
|
550
|
-
|
|
550
|
+
checkCountRef.current = 0;
|
|
551
551
|
state.status = 'scanned';
|
|
552
552
|
state.results = {
|
|
553
553
|
...state.results,
|
|
@@ -5,6 +5,7 @@ import { translate } from '@arcblock/ux/lib/Locale/util';
|
|
|
5
5
|
|
|
6
6
|
import EmailListItem from './list-item';
|
|
7
7
|
import EmailPlaceholder from './placeholder';
|
|
8
|
+
import defaultTranslations from '../../assets/locale';
|
|
8
9
|
|
|
9
10
|
export default function useEmailPlugin({ baseUrl }) {
|
|
10
11
|
const state = useReactive({
|
|
@@ -38,6 +39,7 @@ export default function useEmailPlugin({ baseUrl }) {
|
|
|
38
39
|
const icon = mailOutlineRoundedIcon;
|
|
39
40
|
const translations = {
|
|
40
41
|
zh: {
|
|
42
|
+
...defaultTranslations.zh,
|
|
41
43
|
email: '邮箱地址',
|
|
42
44
|
emailPlaceholder: '请输入邮箱地址',
|
|
43
45
|
sendCode: '发送验证邮件',
|
|
@@ -50,6 +52,7 @@ export default function useEmailPlugin({ baseUrl }) {
|
|
|
50
52
|
emailRequired: '邮箱地址不能为空',
|
|
51
53
|
},
|
|
52
54
|
en: {
|
|
55
|
+
...defaultTranslations.en,
|
|
53
56
|
email: 'Email',
|
|
54
57
|
emailPlaceholder: 'Enter your email address',
|
|
55
58
|
sendCode: 'Send Verification Email',
|
|
@@ -8,9 +8,9 @@ import LoginMethodItem from '../../components/login-item/login-method-item';
|
|
|
8
8
|
import { useStateContext } from '../../contexts/state';
|
|
9
9
|
|
|
10
10
|
export default function EmailListItem({ ...rest }) {
|
|
11
|
-
const { setSelectedPlugin, getPlugin, connectState } = useStateContext();
|
|
11
|
+
const { setSelectedPlugin, getPlugin, connectState, lastLoginMethod } = useStateContext();
|
|
12
12
|
const handleConnect = useMemoizedFn(() => {
|
|
13
|
-
localStorage.setItem(GA_LAST_LOGIN_METHOD,
|
|
13
|
+
localStorage.setItem(GA_LAST_LOGIN_METHOD, LOGIN_PROVIDER.EMAIL);
|
|
14
14
|
const plugin = getPlugin(LOGIN_PROVIDER.EMAIL);
|
|
15
15
|
plugin.state.reset();
|
|
16
16
|
plugin.state.status = 'creating';
|
|
@@ -21,6 +21,7 @@ export default function EmailListItem({ ...rest }) {
|
|
|
21
21
|
return (
|
|
22
22
|
<LoginMethodItem
|
|
23
23
|
{...rest}
|
|
24
|
+
isLatest={lastLoginMethod && lastLoginMethod === LOGIN_PROVIDER.EMAIL}
|
|
24
25
|
title={LOGIN_PROVIDER_NAME[LOGIN_PROVIDER.EMAIL]}
|
|
25
26
|
icon={mailFilledIcon}
|
|
26
27
|
onClick={handleConnect}
|
package/src/Passkey/actions.jsx
CHANGED
|
@@ -67,6 +67,7 @@ export default function PasskeyActions({
|
|
|
67
67
|
sx = {},
|
|
68
68
|
mode = 'normal',
|
|
69
69
|
onClick = noop,
|
|
70
|
+
isLatest = false,
|
|
70
71
|
}) {
|
|
71
72
|
const currentAction = useRef('');
|
|
72
73
|
const passkeyDialogRef = useRef(null);
|
|
@@ -149,6 +150,8 @@ export default function PasskeyActions({
|
|
|
149
150
|
<>
|
|
150
151
|
{['both', 'only-existing'].includes(behavior) ? (
|
|
151
152
|
<PasskeyAction
|
|
153
|
+
isLatest={isLatest}
|
|
154
|
+
t={t}
|
|
152
155
|
action="verifying"
|
|
153
156
|
state={passkeyState}
|
|
154
157
|
title={t('usePasskey')}
|
|
@@ -167,6 +170,7 @@ export default function PasskeyActions({
|
|
|
167
170
|
{['both', 'only-new'].includes(behavior) ? (
|
|
168
171
|
<>
|
|
169
172
|
<PasskeyAction
|
|
173
|
+
t={t}
|
|
170
174
|
action="creating"
|
|
171
175
|
state={passkeyState}
|
|
172
176
|
title={createButtonText || t('createPasskey')}
|
|
@@ -209,4 +213,5 @@ PasskeyActions.propTypes = {
|
|
|
209
213
|
mode: PropTypes.oneOf(['simple', 'normal']),
|
|
210
214
|
onClick: PropTypes.func,
|
|
211
215
|
ref: PropTypes.any,
|
|
216
|
+
isLatest: PropTypes.bool,
|
|
212
217
|
};
|