@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.
@@ -1,15 +1,18 @@
1
- const S = {
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
- S as EVENTS
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
+ };
@@ -1,4 +1,4 @@
1
- const o = "3.1.28", s = {
1
+ const o = "3.1.31", s = {
2
2
  version: o
3
3
  };
4
4
  export {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@arcblock/did-connect-react",
3
- "version": "3.1.28",
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.28",
35
+ "@arcblock/bridge": "3.1.31",
36
36
  "@arcblock/did": "^1.21.3",
37
- "@arcblock/icons": "3.1.28",
38
- "@arcblock/react-hooks": "3.1.28",
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": "8a62be8796c0ab9129b24a08ecc051d1ac23e0de"
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';
@@ -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 './passport-switcher';
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({ children, locale = 'en', onBindOAuth = noop, onUnbindOAuth = noop, onSwitchPassport = noop }) {
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 = session;
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 = session?.user?.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
- /* eslint-disable react/prop-types */
2
- import pick from 'lodash/pick';
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';
@@ -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 '../OAuth/passport-switcher';
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 = 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: session?.user?.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 api={api} locale={locale} switchState={switchState} onSwitchPassport={handleSwitchPassport} />
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();