@arcblock/did-connect-react 3.1.28 → 3.1.31
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/components/login-item/connect-choose-list.js +104 -102
- package/lib/Connect/plugins/email/list-item.js +13 -11
- package/lib/OAuth/context.js +98 -89
- package/lib/OAuth/passport-switcher.js +3 -112
- package/lib/Passkey/context.js +65 -54
- package/lib/Session/handler.js +55 -0
- package/lib/Session/hooks/use-session-token.js +109 -105
- package/lib/Session/index.js +455 -425
- package/lib/Session/libs/constants.js +5 -2
- package/lib/components/PassportSwitcher.js +128 -0
- package/lib/package.json.js +1 -1
- package/package.json +5 -5
- package/src/Connect/components/login-item/connect-choose-list.jsx +6 -0
- package/src/Connect/plugins/email/list-item.jsx +2 -0
- package/src/OAuth/context.jsx +15 -6
- package/src/OAuth/passport-switcher.jsx +2 -133
- package/src/Passkey/context.jsx +13 -5
- package/src/Session/handler.jsx +98 -0
- package/src/Session/hooks/use-session-token.js +12 -0
- package/src/Session/index.jsx +103 -31
- package/src/Session/libs/constants.js +3 -0
- package/src/components/PassportSwitcher.jsx +160 -0
|
@@ -1,15 +1,18 @@
|
|
|
1
|
-
const
|
|
1
|
+
const l = {
|
|
2
2
|
LOGIN: Symbol("login"),
|
|
3
|
+
LOGIN_FAILED: Symbol("loginFailed"),
|
|
3
4
|
CANCEL_LOGIN: Symbol("cancelLogin"),
|
|
4
5
|
LOGOUT: Symbol("logout"),
|
|
5
6
|
SWITCH_PROFILE: Symbol("switchProfile"),
|
|
6
7
|
CANCEL_SWITCH_PROFILE: Symbol("cancelSwitchProfile"),
|
|
7
8
|
SWITCH_PASSPORT: Symbol("switchPassport"),
|
|
9
|
+
SWITCH_PASSPORT_FAILED: Symbol("switchPassportFailed"),
|
|
8
10
|
CANCEL_SWITCH_PASSPORT: Symbol("cancelSwitchPassport"),
|
|
9
11
|
BIND_WALLET: Symbol("bindWallet"),
|
|
12
|
+
BIND_WALLET_FAILED: Symbol("bindWalletFailed"),
|
|
10
13
|
CANCEL_BIND_WALLET: Symbol("cancelBindWallet"),
|
|
11
14
|
DID_SPACE_CONNECTED: Symbol("didSpaceConnected")
|
|
12
15
|
};
|
|
13
16
|
export {
|
|
14
|
-
|
|
17
|
+
l as EVENTS
|
|
15
18
|
};
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import { jsxs as m, jsx as p } from "react/jsx-runtime";
|
|
2
|
+
import y from "lodash/pick";
|
|
3
|
+
import { Confirm as F } from "@arcblock/ux/lib/Dialog";
|
|
4
|
+
import { Box as h } from "@mui/material";
|
|
5
|
+
import f from "@arcblock/ux/lib/Toast";
|
|
6
|
+
import C from "@arcblock/ux/lib/CardSelector";
|
|
7
|
+
import { translate as R } from "@arcblock/ux/lib/Locale/util";
|
|
8
|
+
import { useMemoizedFn as T, useCreation as k } from "ahooks";
|
|
9
|
+
import { createPassportSvg as I } from "@arcblock/ux/lib/Util/passport";
|
|
10
|
+
import { ReactGA as P } from "@arcblock/ux/lib/withTracker";
|
|
11
|
+
import x from "../OAuth/guest.svg.js";
|
|
12
|
+
const B = (e) => e ? typeof e == "string" ? { sessionToken: e } : y(e, ["sessionToken", "refreshToken", "visitorId", "destroySessionId"]) : {}, G = {
|
|
13
|
+
zh: {
|
|
14
|
+
switchPassport: "切换通行证",
|
|
15
|
+
switchPassportFailed: "切换通行证失败",
|
|
16
|
+
switchPassportSucceed: "切换通行证成功",
|
|
17
|
+
selectedPassport: "请选择一个通行证",
|
|
18
|
+
switch: "切换",
|
|
19
|
+
cancel: "取消",
|
|
20
|
+
currentRole: "当前角色:",
|
|
21
|
+
passport: "通行证",
|
|
22
|
+
getPassportFailed: "获取通行证失败"
|
|
23
|
+
},
|
|
24
|
+
en: {
|
|
25
|
+
switchPassport: "Switch passport",
|
|
26
|
+
switchPassportFailed: "Switch passport failed",
|
|
27
|
+
switchPassportSucceed: "Switch passport succeed",
|
|
28
|
+
selectedPassport: "Select a passport to switch",
|
|
29
|
+
switch: "Switch",
|
|
30
|
+
cancel: "Cancel",
|
|
31
|
+
currentRole: "Current role: ",
|
|
32
|
+
passport: "Passport",
|
|
33
|
+
getPassportFailed: "Get passports failed"
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
function q({ api: e, locale: w, switchState: r, onSwitchPassport: g, session: a }) {
|
|
37
|
+
const t = T((s, i = {}) => R(G, s, w, "en", i)), l = k(() => r.passports.filter((s) => s.role !== r.currentUser?.role), [r.passports, r.currentUser?.role]), S = async () => {
|
|
38
|
+
const s = r.selectedPassport, i = a?.user?.role, v = a?.user?.passports?.find((o) => o.id === s)?.role ?? "guest", d = `${i} -> ${v}`;
|
|
39
|
+
try {
|
|
40
|
+
const { data: o } = await e.post("/switch", { passportId: s }), { sessionToken: c, refreshToken: n } = B(o);
|
|
41
|
+
g({ sessionToken: c, refreshToken: n }), f.success(t("switchPassportSucceed"));
|
|
42
|
+
const u = {
|
|
43
|
+
action: "switchPassportSuccess",
|
|
44
|
+
change: d,
|
|
45
|
+
success: !0
|
|
46
|
+
};
|
|
47
|
+
P.event(u.action, u);
|
|
48
|
+
} catch (o) {
|
|
49
|
+
const c = o.message || t("switchPassportFailed"), n = {
|
|
50
|
+
action: "switchPassportFailed",
|
|
51
|
+
success: !1,
|
|
52
|
+
change: d,
|
|
53
|
+
errorMessage: c
|
|
54
|
+
};
|
|
55
|
+
P.event(n.action, n), f.error(c);
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
return /* @__PURE__ */ m(
|
|
59
|
+
F,
|
|
60
|
+
{
|
|
61
|
+
open: r.open,
|
|
62
|
+
title: t("switchPassport"),
|
|
63
|
+
onConfirm: S,
|
|
64
|
+
onCancel: r.reset,
|
|
65
|
+
confirmButton: {
|
|
66
|
+
text: t("switch"),
|
|
67
|
+
props: {
|
|
68
|
+
variant: "contained",
|
|
69
|
+
color: "primary"
|
|
70
|
+
}
|
|
71
|
+
},
|
|
72
|
+
cancelButton: {
|
|
73
|
+
text: t("cancel"),
|
|
74
|
+
props: {
|
|
75
|
+
color: "inherit"
|
|
76
|
+
}
|
|
77
|
+
},
|
|
78
|
+
PaperProps: { style: { width: 600 } },
|
|
79
|
+
children: [
|
|
80
|
+
/* @__PURE__ */ m(
|
|
81
|
+
h,
|
|
82
|
+
{
|
|
83
|
+
sx: {
|
|
84
|
+
mb: 2
|
|
85
|
+
},
|
|
86
|
+
children: [
|
|
87
|
+
t("currentRole"),
|
|
88
|
+
r.currentUser?.role
|
|
89
|
+
]
|
|
90
|
+
}
|
|
91
|
+
),
|
|
92
|
+
/* @__PURE__ */ p(
|
|
93
|
+
C,
|
|
94
|
+
{
|
|
95
|
+
width: 160,
|
|
96
|
+
height: 240,
|
|
97
|
+
cardSpace: 24,
|
|
98
|
+
list: [
|
|
99
|
+
// eslint-disable-next-line react/no-unstable-nested-components
|
|
100
|
+
() => /* @__PURE__ */ p(x, {}),
|
|
101
|
+
...l.map((s) => s.display ? {
|
|
102
|
+
src: s.display,
|
|
103
|
+
name: s.title
|
|
104
|
+
} : () => /* @__PURE__ */ p(
|
|
105
|
+
h,
|
|
106
|
+
{
|
|
107
|
+
sx: { width: "100%" },
|
|
108
|
+
dangerouslySetInnerHTML: {
|
|
109
|
+
__html: I(s)
|
|
110
|
+
}
|
|
111
|
+
},
|
|
112
|
+
s.id
|
|
113
|
+
))
|
|
114
|
+
],
|
|
115
|
+
onSelect: (s) => {
|
|
116
|
+
r.selectedPassport = s > 0 ? l[s - 1].id : void 0;
|
|
117
|
+
},
|
|
118
|
+
defaultIndex: 0
|
|
119
|
+
}
|
|
120
|
+
)
|
|
121
|
+
]
|
|
122
|
+
}
|
|
123
|
+
);
|
|
124
|
+
}
|
|
125
|
+
export {
|
|
126
|
+
q as PassportSwitcher,
|
|
127
|
+
B as parseResponse
|
|
128
|
+
};
|
package/lib/package.json.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@arcblock/did-connect-react",
|
|
3
|
-
"version": "3.1.
|
|
3
|
+
"version": "3.1.31",
|
|
4
4
|
"description": "Client side library to work with DID Connect by ArcBlock.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"react",
|
|
@@ -32,10 +32,10 @@
|
|
|
32
32
|
"url": "https://github.com/ArcBlock/ux/issues"
|
|
33
33
|
},
|
|
34
34
|
"dependencies": {
|
|
35
|
-
"@arcblock/bridge": "3.1.
|
|
35
|
+
"@arcblock/bridge": "3.1.31",
|
|
36
36
|
"@arcblock/did": "^1.21.3",
|
|
37
|
-
"@arcblock/icons": "3.1.
|
|
38
|
-
"@arcblock/react-hooks": "3.1.
|
|
37
|
+
"@arcblock/icons": "3.1.31",
|
|
38
|
+
"@arcblock/react-hooks": "3.1.31",
|
|
39
39
|
"@arcblock/ws": "^1.21.3",
|
|
40
40
|
"@fontsource/lexend": "^5.2.9",
|
|
41
41
|
"@iconify-icons/logos": "^1.2.36",
|
|
@@ -80,5 +80,5 @@
|
|
|
80
80
|
"eslint-plugin-react-hooks": "^4.6.2",
|
|
81
81
|
"jest": "^29.7.0"
|
|
82
82
|
},
|
|
83
|
-
"gitHead": "
|
|
83
|
+
"gitHead": "a904bcfb38156f7cdff5b2134c126b19d528f4b2"
|
|
84
84
|
}
|
|
@@ -9,6 +9,7 @@ import { getCookieOptions } from '@arcblock/ux/lib/Util';
|
|
|
9
9
|
import { useEffect, useRef } from 'react';
|
|
10
10
|
import { mergeSx } from '@arcblock/ux/lib/Util/style';
|
|
11
11
|
import ProviderIcon from '@arcblock/ux/lib/DIDConnect/provider-icon';
|
|
12
|
+
import { GA_LAST_LOGIN_METHOD } from '@arcblock/ux/lib/withTracker/constant';
|
|
12
13
|
|
|
13
14
|
import MobileLoginItem from './mobile-login-item';
|
|
14
15
|
import WebLoginItem from './web-login-item';
|
|
@@ -50,6 +51,7 @@ export default function ConnectChooseList({
|
|
|
50
51
|
const { extraParams, locale, connectState, plugins, setPlugins, setSelectedPlugin, getPlugin } = useStateContext();
|
|
51
52
|
|
|
52
53
|
const handleLoginOAuth = useMemoizedFn(async (item) => {
|
|
54
|
+
localStorage.setItem(GA_LAST_LOGIN_METHOD, item.provider);
|
|
53
55
|
tokenState.reset();
|
|
54
56
|
oauthState.reset({
|
|
55
57
|
status: 'scanned',
|
|
@@ -109,6 +111,7 @@ export default function ConnectChooseList({
|
|
|
109
111
|
if (magicToken && showEmailLogin && plugins.some((plugin) => plugin.name === LOGIN_PROVIDER.EMAIL)) {
|
|
110
112
|
const plugin = getPlugin(LOGIN_PROVIDER.EMAIL);
|
|
111
113
|
if (plugin.state.status === 'idle') {
|
|
114
|
+
localStorage.setItem(GA_LAST_LOGIN_METHOD, 'email');
|
|
112
115
|
plugin.state.reset();
|
|
113
116
|
plugin.state.magicToken = magicToken;
|
|
114
117
|
connectState.chooseMethod = LOGIN_PROVIDER.EMAIL;
|
|
@@ -164,6 +167,7 @@ export default function ConnectChooseList({
|
|
|
164
167
|
tokenKey={tokenKey}
|
|
165
168
|
disableSwitchApp={disableSwitchApp}
|
|
166
169
|
onClick={async () => {
|
|
170
|
+
localStorage.setItem(GA_LAST_LOGIN_METHOD, 'wallet');
|
|
167
171
|
tokenState.reset();
|
|
168
172
|
await onRest();
|
|
169
173
|
tokenState.status = 'created';
|
|
@@ -183,6 +187,7 @@ export default function ConnectChooseList({
|
|
|
183
187
|
sx={[size === 'small' ? { p: 1 } : { p: 2 }]}
|
|
184
188
|
disableSwitchApp={disableSwitchApp}
|
|
185
189
|
onClick={() => {
|
|
190
|
+
localStorage.setItem(GA_LAST_LOGIN_METHOD, 'wallet');
|
|
186
191
|
// HACK: 在点击插件登录时,直接将状态置为扫码中,避免插件登录时的状态切换
|
|
187
192
|
tokenState.status = 'scanned';
|
|
188
193
|
connectState.chooseMethod = 'wallet-web';
|
|
@@ -249,6 +254,7 @@ export default function ConnectChooseList({
|
|
|
249
254
|
behavior={passkeyBehavior}
|
|
250
255
|
sx={[size === 'small' ? { p: 1 } : { p: 2 }]}
|
|
251
256
|
onClick={() => {
|
|
257
|
+
localStorage.setItem(GA_LAST_LOGIN_METHOD, 'passkey');
|
|
252
258
|
const connectFn = passkeyLoginRef.current.connect;
|
|
253
259
|
connectState.chooseMethod = 'passkey';
|
|
254
260
|
connectState.retryConnect = () => {
|
|
@@ -2,6 +2,7 @@ import PropTypes from 'prop-types';
|
|
|
2
2
|
import { useMemoizedFn } from 'ahooks';
|
|
3
3
|
import mailOutlineRoundedIcon from '@iconify-icons/material-symbols/mail-outline-rounded';
|
|
4
4
|
import { LOGIN_PROVIDER, LOGIN_PROVIDER_NAME } from '@arcblock/ux/lib/Util/constant';
|
|
5
|
+
import { GA_LAST_LOGIN_METHOD } from '@arcblock/ux/lib/withTracker/constant';
|
|
5
6
|
|
|
6
7
|
import LoginMethodItem from '../../components/login-item/login-method-item';
|
|
7
8
|
import { useStateContext } from '../../contexts/state';
|
|
@@ -9,6 +10,7 @@ import { useStateContext } from '../../contexts/state';
|
|
|
9
10
|
export default function EmailListItem({ ...rest }) {
|
|
10
11
|
const { setSelectedPlugin, getPlugin, connectState } = useStateContext();
|
|
11
12
|
const handleConnect = useMemoizedFn(() => {
|
|
13
|
+
localStorage.setItem(GA_LAST_LOGIN_METHOD, 'email');
|
|
12
14
|
const plugin = getPlugin(LOGIN_PROVIDER.EMAIL);
|
|
13
15
|
plugin.state.reset();
|
|
14
16
|
plugin.state.status = 'creating';
|
package/src/OAuth/context.jsx
CHANGED
|
@@ -12,7 +12,7 @@ import { LOGIN_PROVIDER_NAME, BLOCKLET_SERVICE_PATH_PREFIX } from '@arcblock/ux/
|
|
|
12
12
|
|
|
13
13
|
// eslint-disable-next-line import/no-unresolved
|
|
14
14
|
import { getApiErrorMessage, createAxios, openPopup, runPopup, sleep } from '../utils';
|
|
15
|
-
import { PassportSwitcher, parseResponse } from '
|
|
15
|
+
import { PassportSwitcher, parseResponse } from '../components/PassportSwitcher';
|
|
16
16
|
|
|
17
17
|
const OAuthContext = createContext({});
|
|
18
18
|
const { Provider, Consumer: OAuthConsumer } = OAuthContext;
|
|
@@ -48,7 +48,14 @@ const translations = {
|
|
|
48
48
|
},
|
|
49
49
|
};
|
|
50
50
|
|
|
51
|
-
function OAuthProvider({
|
|
51
|
+
function OAuthProvider({
|
|
52
|
+
children,
|
|
53
|
+
locale = 'en',
|
|
54
|
+
onBindOAuth = noop,
|
|
55
|
+
onUnbindOAuth = noop,
|
|
56
|
+
onSwitchPassport = noop,
|
|
57
|
+
session = null,
|
|
58
|
+
}) {
|
|
52
59
|
const state = useReactive({
|
|
53
60
|
baseUrl: '/',
|
|
54
61
|
bindFnSession: undefined,
|
|
@@ -165,8 +172,8 @@ function OAuthProvider({ children, locale = 'en', onBindOAuth = noop, onUnbindOA
|
|
|
165
172
|
}
|
|
166
173
|
});
|
|
167
174
|
|
|
168
|
-
const bindOAuth = async ({ session, oauthItem } = {}) => {
|
|
169
|
-
state.bindFnSession =
|
|
175
|
+
const bindOAuth = async ({ session: userSession, oauthItem } = {}) => {
|
|
176
|
+
state.bindFnSession = userSession;
|
|
170
177
|
state.bindAuthLoading = true;
|
|
171
178
|
|
|
172
179
|
try {
|
|
@@ -188,10 +195,10 @@ function OAuthProvider({ children, locale = 'en', onBindOAuth = noop, onUnbindOA
|
|
|
188
195
|
}
|
|
189
196
|
};
|
|
190
197
|
|
|
191
|
-
const unbindOAuth = async ({ session, connectedAccount }) => {
|
|
198
|
+
const unbindOAuth = async ({ session: userSession, connectedAccount }) => {
|
|
192
199
|
state.unbindAuthLoading = true;
|
|
193
200
|
try {
|
|
194
|
-
const sourceAppPid =
|
|
201
|
+
const sourceAppPid = userSession?.user?.sourceAppPid;
|
|
195
202
|
await api.current.post('/unbind', {
|
|
196
203
|
locale,
|
|
197
204
|
connectedAccount: omit(connectedAccount, ['showProvider']),
|
|
@@ -324,6 +331,7 @@ function OAuthProvider({ children, locale = 'en', onBindOAuth = noop, onUnbindOA
|
|
|
324
331
|
locale={locale}
|
|
325
332
|
switchState={switchState}
|
|
326
333
|
onSwitchPassport={handleSwitchPassport}
|
|
334
|
+
session={session}
|
|
327
335
|
/>
|
|
328
336
|
</Provider>
|
|
329
337
|
);
|
|
@@ -341,6 +349,7 @@ OAuthProvider.propTypes = {
|
|
|
341
349
|
onBindOAuth: PropTypes.func,
|
|
342
350
|
onUnbindOAuth: PropTypes.func,
|
|
343
351
|
onSwitchPassport: PropTypes.func,
|
|
352
|
+
session: PropTypes.object,
|
|
344
353
|
};
|
|
345
354
|
|
|
346
355
|
export { OAuthContext, OAuthConsumer, OAuthProvider, useOAuth };
|
|
@@ -1,133 +1,2 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
import { Confirm } from '@arcblock/ux/lib/Dialog';
|
|
4
|
-
import { Box } from '@mui/material';
|
|
5
|
-
import Toast from '@arcblock/ux/lib/Toast';
|
|
6
|
-
import CardSelector from '@arcblock/ux/lib/CardSelector';
|
|
7
|
-
import { translate } from '@arcblock/ux/lib/Locale/util';
|
|
8
|
-
import { useCreation, useMemoizedFn } from 'ahooks';
|
|
9
|
-
import { createPassportSvg } from '@arcblock/ux/lib/Util/passport';
|
|
10
|
-
|
|
11
|
-
// eslint-disable-next-line import/no-unresolved
|
|
12
|
-
import Guest from './guest.svg?react';
|
|
13
|
-
|
|
14
|
-
export const parseResponse = (data) => {
|
|
15
|
-
if (!data) {
|
|
16
|
-
return {};
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
// for backward compatibility
|
|
20
|
-
if (typeof data === 'string') {
|
|
21
|
-
return { sessionToken: data };
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
return pick(data, ['sessionToken', 'refreshToken', 'visitorId', 'destroySessionId']);
|
|
25
|
-
};
|
|
26
|
-
|
|
27
|
-
const translations = {
|
|
28
|
-
zh: {
|
|
29
|
-
switchPassport: '切换通行证',
|
|
30
|
-
switchPassportFailed: '切换通行证失败',
|
|
31
|
-
switchPassportSucceed: '切换通行证成功',
|
|
32
|
-
selectedPassport: '请选择一个通行证',
|
|
33
|
-
switch: '切换',
|
|
34
|
-
cancel: '取消',
|
|
35
|
-
currentRole: '当前角色:',
|
|
36
|
-
passport: '通行证',
|
|
37
|
-
getPassportFailed: '获取通行证失败',
|
|
38
|
-
},
|
|
39
|
-
en: {
|
|
40
|
-
switchPassport: 'Switch passport',
|
|
41
|
-
switchPassportFailed: 'Switch passport failed',
|
|
42
|
-
switchPassportSucceed: 'Switch passport succeed',
|
|
43
|
-
selectedPassport: 'Select a passport to switch',
|
|
44
|
-
switch: 'Switch',
|
|
45
|
-
cancel: 'Cancel',
|
|
46
|
-
currentRole: 'Current role: ',
|
|
47
|
-
passport: 'Passport',
|
|
48
|
-
getPassportFailed: 'Get passports failed',
|
|
49
|
-
},
|
|
50
|
-
};
|
|
51
|
-
|
|
52
|
-
export function PassportSwitcher({ api, locale, switchState, onSwitchPassport }) {
|
|
53
|
-
const t = useMemoizedFn((key, data = {}) => {
|
|
54
|
-
return translate(translations, key, locale, 'en', data);
|
|
55
|
-
});
|
|
56
|
-
|
|
57
|
-
const visiblePassports = useCreation(() => {
|
|
58
|
-
return switchState.passports.filter((x) => x.role !== switchState.currentUser?.role);
|
|
59
|
-
}, [switchState.passports, switchState.currentUser?.role]);
|
|
60
|
-
|
|
61
|
-
const onSwitch = async () => {
|
|
62
|
-
try {
|
|
63
|
-
const { data } = await api.post('/switch', { passportId: switchState.selectedPassport });
|
|
64
|
-
const { sessionToken, refreshToken } = parseResponse(data);
|
|
65
|
-
onSwitchPassport({ sessionToken, refreshToken });
|
|
66
|
-
Toast.success(t('switchPassportSucceed'));
|
|
67
|
-
} catch (err) {
|
|
68
|
-
Toast.error(err.message || t('switchPassportFailed'));
|
|
69
|
-
}
|
|
70
|
-
};
|
|
71
|
-
|
|
72
|
-
return (
|
|
73
|
-
<Confirm
|
|
74
|
-
open={switchState.open}
|
|
75
|
-
title={t('switchPassport')}
|
|
76
|
-
onConfirm={onSwitch}
|
|
77
|
-
onCancel={switchState.reset}
|
|
78
|
-
confirmButton={{
|
|
79
|
-
text: t('switch'),
|
|
80
|
-
props: {
|
|
81
|
-
variant: 'contained',
|
|
82
|
-
color: 'primary',
|
|
83
|
-
},
|
|
84
|
-
}}
|
|
85
|
-
cancelButton={{
|
|
86
|
-
text: t('cancel'),
|
|
87
|
-
props: {
|
|
88
|
-
color: 'inherit',
|
|
89
|
-
},
|
|
90
|
-
}}
|
|
91
|
-
PaperProps={{ style: { width: 600 } }}>
|
|
92
|
-
<Box
|
|
93
|
-
sx={{
|
|
94
|
-
mb: 2,
|
|
95
|
-
}}>
|
|
96
|
-
{t('currentRole')}
|
|
97
|
-
{switchState.currentUser?.role}
|
|
98
|
-
</Box>
|
|
99
|
-
<CardSelector
|
|
100
|
-
width={160}
|
|
101
|
-
height={240}
|
|
102
|
-
cardSpace={24}
|
|
103
|
-
list={[
|
|
104
|
-
// eslint-disable-next-line react/no-unstable-nested-components
|
|
105
|
-
() => <Guest />,
|
|
106
|
-
...visiblePassports.map((x) => {
|
|
107
|
-
if (x.display) {
|
|
108
|
-
return {
|
|
109
|
-
src: x.display,
|
|
110
|
-
name: x.title,
|
|
111
|
-
};
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
// eslint-disable-next-line react/no-unstable-nested-components, react/function-component-definition
|
|
115
|
-
return () => (
|
|
116
|
-
<Box
|
|
117
|
-
key={x.id}
|
|
118
|
-
sx={{ width: '100%' }}
|
|
119
|
-
dangerouslySetInnerHTML={{
|
|
120
|
-
__html: createPassportSvg(x),
|
|
121
|
-
}}
|
|
122
|
-
/>
|
|
123
|
-
);
|
|
124
|
-
}),
|
|
125
|
-
]}
|
|
126
|
-
onSelect={(index) => {
|
|
127
|
-
switchState.selectedPassport = index > 0 ? visiblePassports[index - 1].id : undefined;
|
|
128
|
-
}}
|
|
129
|
-
defaultIndex={0}
|
|
130
|
-
/>
|
|
131
|
-
</Confirm>
|
|
132
|
-
);
|
|
133
|
-
}
|
|
1
|
+
// Re-export from the shared component
|
|
2
|
+
export { PassportSwitcher, parseResponse } from '../components/PassportSwitcher';
|
package/src/Passkey/context.jsx
CHANGED
|
@@ -11,7 +11,7 @@ import { getFederatedEnabled, getMaster, getBlockletData } from '@arcblock/ux/li
|
|
|
11
11
|
import { startAuthentication, startRegistration } from '@simplewebauthn/browser';
|
|
12
12
|
|
|
13
13
|
import { getApiErrorMessage, getWebAuthnErrorMessage, createAxios, logger } from '../utils';
|
|
14
|
-
import { PassportSwitcher, parseResponse } from '../
|
|
14
|
+
import { PassportSwitcher, parseResponse } from '../components/PassportSwitcher';
|
|
15
15
|
|
|
16
16
|
const PasskeyContext = createContext({});
|
|
17
17
|
const { Provider, Consumer: PasskeyConsumer } = PasskeyContext;
|
|
@@ -90,6 +90,7 @@ function PasskeyProvider({
|
|
|
90
90
|
onAddPasskey = noop,
|
|
91
91
|
onRemovePasskey = noop,
|
|
92
92
|
onSwitchPassport = noop,
|
|
93
|
+
session = null,
|
|
93
94
|
}) {
|
|
94
95
|
const prefix = joinURL(window.env?.apiPrefix || BLOCKLET_SERVICE_PATH_PREFIX, '/api/passkey');
|
|
95
96
|
|
|
@@ -259,8 +260,8 @@ function PasskeyProvider({
|
|
|
259
260
|
}
|
|
260
261
|
};
|
|
261
262
|
|
|
262
|
-
const disconnectPasskey = async ({ session, connectedAccount }) => {
|
|
263
|
-
state.session =
|
|
263
|
+
const disconnectPasskey = async ({ session: userSession, connectedAccount }) => {
|
|
264
|
+
state.session = userSession;
|
|
264
265
|
state.disconnecting = true;
|
|
265
266
|
|
|
266
267
|
try {
|
|
@@ -268,7 +269,7 @@ function PasskeyProvider({
|
|
|
268
269
|
action: 'disconnect',
|
|
269
270
|
locale,
|
|
270
271
|
componentId,
|
|
271
|
-
sourceAppPid:
|
|
272
|
+
sourceAppPid: userSession?.user?.sourceAppPid,
|
|
272
273
|
credentialId: connectedAccount.id,
|
|
273
274
|
});
|
|
274
275
|
|
|
@@ -360,7 +361,13 @@ function PasskeyProvider({
|
|
|
360
361
|
t,
|
|
361
362
|
}}>
|
|
362
363
|
{children}
|
|
363
|
-
<PassportSwitcher
|
|
364
|
+
<PassportSwitcher
|
|
365
|
+
api={api}
|
|
366
|
+
locale={locale}
|
|
367
|
+
switchState={switchState}
|
|
368
|
+
onSwitchPassport={handleSwitchPassport}
|
|
369
|
+
session={session}
|
|
370
|
+
/>
|
|
364
371
|
</Provider>
|
|
365
372
|
);
|
|
366
373
|
}
|
|
@@ -376,6 +383,7 @@ PasskeyProvider.propTypes = {
|
|
|
376
383
|
onAddPasskey: PropTypes.func,
|
|
377
384
|
onRemovePasskey: PropTypes.func,
|
|
378
385
|
onSwitchPassport: PropTypes.func,
|
|
386
|
+
session: PropTypes.object,
|
|
379
387
|
};
|
|
380
388
|
|
|
381
389
|
export { PasskeyContext, PasskeyConsumer, PasskeyProvider, usePasskey };
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { ReactGA } from '@arcblock/ux/lib/withTracker';
|
|
2
|
+
import { GA_LAST_LOGIN_METHOD, GA_LAST_ROLE, GA_LAST_SOURCE_PROVIDER } from '@arcblock/ux/lib/withTracker/constant';
|
|
3
|
+
|
|
4
|
+
// 监听用户登录事件
|
|
5
|
+
export const gaLoginSuccessHandler = () => {
|
|
6
|
+
/**
|
|
7
|
+
* @type {import('@arcblock/ux/lib/withTracker/action/login').LoginSuccessEvent}
|
|
8
|
+
*/
|
|
9
|
+
const loginSuccessEvent = {
|
|
10
|
+
action: 'loginSuccess',
|
|
11
|
+
provider: localStorage.getItem(GA_LAST_LOGIN_METHOD),
|
|
12
|
+
success: true,
|
|
13
|
+
};
|
|
14
|
+
ReactGA.event(loginSuccessEvent.action, loginSuccessEvent);
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
*
|
|
19
|
+
* @param {Error} error
|
|
20
|
+
*/
|
|
21
|
+
export const gaLoginFailedHandler = (error) => {
|
|
22
|
+
/**
|
|
23
|
+
* @type {import('@arcblock/ux/lib/withTracker/action/login').LoginFailedEvent}
|
|
24
|
+
*/
|
|
25
|
+
const loginFailedEvent = {
|
|
26
|
+
action: 'loginFailed',
|
|
27
|
+
provider: localStorage.getItem(GA_LAST_LOGIN_METHOD),
|
|
28
|
+
success: false,
|
|
29
|
+
errorMessage: error.message,
|
|
30
|
+
};
|
|
31
|
+
ReactGA.event(loginFailedEvent.action, loginFailedEvent);
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
export const gaSwitchPassportSuccessHandler = (_result, _decrypt, session) => {
|
|
35
|
+
const fromRole = localStorage.getItem(GA_LAST_ROLE);
|
|
36
|
+
const toRole = session?.user?.role;
|
|
37
|
+
const change = `${fromRole} -> ${toRole}`;
|
|
38
|
+
/** @type {import('@arcblock/ux/lib/withTracker/action/switch-passport').SwitchPassportSuccessEvent} */
|
|
39
|
+
const switchPassportSuccessEvent = {
|
|
40
|
+
action: 'switchPassportSuccess',
|
|
41
|
+
change,
|
|
42
|
+
success: true,
|
|
43
|
+
};
|
|
44
|
+
ReactGA.event(switchPassportSuccessEvent.action, switchPassportSuccessEvent);
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
*
|
|
49
|
+
* @param {Error} error
|
|
50
|
+
*/
|
|
51
|
+
export const gaSwitchPassportFailedHandler = (error) => {
|
|
52
|
+
/** @type {import('@arcblock/ux/lib/withTracker/action/switch-passport').SwitchPassportFailedEvent} */
|
|
53
|
+
const switchPassportFailedEvent = {
|
|
54
|
+
action: 'switchPassportFailed',
|
|
55
|
+
success: false,
|
|
56
|
+
errorMessage: error.message,
|
|
57
|
+
};
|
|
58
|
+
ReactGA.event(switchPassportFailedEvent.action, switchPassportFailedEvent);
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
*
|
|
63
|
+
* @param {any} _result
|
|
64
|
+
* @param {Function} _decrypt
|
|
65
|
+
* @param {import('../types').SessionProps} session
|
|
66
|
+
*/
|
|
67
|
+
/**
|
|
68
|
+
*
|
|
69
|
+
* @param {any} _result
|
|
70
|
+
* @param {Function} _decrypt
|
|
71
|
+
* @param {import('../types').SessionProps} session
|
|
72
|
+
*/
|
|
73
|
+
export const gaBindWalletSuccessHandler = (_result, _decrypt, session) => {
|
|
74
|
+
/**
|
|
75
|
+
* @type {import('@arcblock/ux/lib/withTracker/action/bind-wallet').BindWalletSuccessEvent} */
|
|
76
|
+
const bindWalletEvent = {
|
|
77
|
+
action: 'bindWalletSuccess',
|
|
78
|
+
provider: session?.user?.sourceProvider,
|
|
79
|
+
success: true,
|
|
80
|
+
};
|
|
81
|
+
ReactGA.event(bindWalletEvent.action, bindWalletEvent);
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* @param {Error} error
|
|
86
|
+
* @param {import('../types').User} user
|
|
87
|
+
*/
|
|
88
|
+
export const gaBindWalletFailedHandler = (error) => {
|
|
89
|
+
/** @type {import('@arcblock/ux/lib/withTracker/action/bind-wallet').BindWalletFailedEvent} */
|
|
90
|
+
const bindWalletFailedEvent = {
|
|
91
|
+
action: 'bindWalletFailed',
|
|
92
|
+
provider: localStorage.getItem(GA_LAST_SOURCE_PROVIDER),
|
|
93
|
+
success: false,
|
|
94
|
+
errorMessage: error.message,
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
ReactGA.event(bindWalletFailedEvent.action, bindWalletFailedEvent);
|
|
98
|
+
};
|
|
@@ -8,6 +8,8 @@ import Toast from '@arcblock/ux/lib/Toast';
|
|
|
8
8
|
import pRetry from 'p-retry';
|
|
9
9
|
import noop from 'lodash/noop';
|
|
10
10
|
|
|
11
|
+
import { ReactGA } from '@arcblock/ux/lib/withTracker';
|
|
12
|
+
import { GA_LAST_SOURCE_PROVIDER } from '@arcblock/ux/lib/withTracker/constant';
|
|
11
13
|
import createService from '../../Service';
|
|
12
14
|
import { createAxios, getBrowserLang, decrypt as _decrypt, sleep, logger, debug } from '../../utils';
|
|
13
15
|
import { CHECK_INTERVAL_TIME, LANG_COOKIE_NAME } from '../../constant';
|
|
@@ -103,6 +105,16 @@ export default function useSessionToken({
|
|
|
103
105
|
}
|
|
104
106
|
const { data, status } = await requestFn();
|
|
105
107
|
|
|
108
|
+
const userId = data?.user?.did;
|
|
109
|
+
if (userId) {
|
|
110
|
+
ReactGA.set({
|
|
111
|
+
user_id: userId,
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
if (data?.user?.sourceProvider) {
|
|
115
|
+
localStorage.setItem(GA_LAST_SOURCE_PROVIDER, data.user.sourceProvider);
|
|
116
|
+
}
|
|
117
|
+
|
|
106
118
|
if (status === 400) {
|
|
107
119
|
// NOTE: 如果通过多种方式传递了 token,服务端会报 400 的错误,需要移除现有的 token
|
|
108
120
|
removeToken();
|