@arcblock/did-connect-react 3.4.14 → 3.5.0

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 (208) hide show
  1. package/dist/standalone/did-connect-react.css +1 -0
  2. package/dist/standalone/index.js +133700 -0
  3. package/lib/Connect/components/login-item/connect-choose-list.js +111 -111
  4. package/lib/Connect/components/login-item/connect-provider-list.js +180 -180
  5. package/lib/Connect/components/login-item/mobile-login-item.js +56 -56
  6. package/lib/Connect/components/login-item/passkey-login-item.js +27 -29
  7. package/lib/Connect/components/login-item/web-login-item.js +31 -29
  8. package/lib/Connect/connect.js +202 -197
  9. package/lib/Connect/contexts/state.js +19 -17
  10. package/lib/Connect/hooks/provider-list.js +33 -33
  11. package/lib/Connect/plugins/email/list-item.js +14 -14
  12. package/lib/Connect/plugins/email/placeholder.js +77 -76
  13. package/lib/package.json.js +1 -1
  14. package/package.json +14 -9
  15. package/.aigne/doc-smith/config.yaml +0 -85
  16. package/.aigne/doc-smith/history.yaml +0 -6
  17. package/.aigne/doc-smith/output/structure-plan.json +0 -204
  18. package/.aigne/doc-smith/translation-cache.yaml +0 -11
  19. package/.aigne/doc-smith/upload-cache.yaml +0 -213
  20. package/docs/_sidebar.md +0 -18
  21. package/docs/advanced-authentication-methods.ja.md +0 -261
  22. package/docs/advanced-authentication-methods.md +0 -261
  23. package/docs/advanced-authentication-methods.zh-TW.md +0 -261
  24. package/docs/advanced-authentication-methods.zh.md +0 -261
  25. package/docs/advanced-utilities.ja.md +0 -132
  26. package/docs/advanced-utilities.md +0 -132
  27. package/docs/advanced-utilities.zh-TW.md +0 -132
  28. package/docs/advanced-utilities.zh.md +0 -132
  29. package/docs/advanced.ja.md +0 -95
  30. package/docs/advanced.md +0 -95
  31. package/docs/advanced.zh-TW.md +0 -95
  32. package/docs/advanced.zh.md +0 -95
  33. package/docs/api-reference.ja.md +0 -178
  34. package/docs/api-reference.md +0 -178
  35. package/docs/api-reference.zh-TW.md +0 -178
  36. package/docs/api-reference.zh.md +0 -178
  37. package/docs/assets/diagram/core-components-session-provider-01.ja.jpg +0 -0
  38. package/docs/assets/diagram/core-components-session-provider-01.jpg +0 -0
  39. package/docs/assets/diagram/core-components-session-provider-01.zh-TW.jpg +0 -0
  40. package/docs/assets/diagram/core-components-session-provider-01.zh.jpg +0 -0
  41. package/docs/assets/diagram/did-connect-diagram-0.ja.jpg +0 -0
  42. package/docs/assets/diagram/did-connect-diagram-0.jpg +0 -0
  43. package/docs/assets/diagram/did-connect-diagram-0.zh-TW.jpg +0 -0
  44. package/docs/assets/diagram/did-connect-diagram-0.zh.jpg +0 -0
  45. package/docs/assets/diagram/overview-01.ja.jpg +0 -0
  46. package/docs/assets/diagram/overview-01.jpg +0 -0
  47. package/docs/assets/diagram/overview-01.zh-TW.jpg +0 -0
  48. package/docs/assets/diagram/overview-01.zh.jpg +0 -0
  49. package/docs/assets/diagram/use-connect-diagram-0.ja.jpg +0 -0
  50. package/docs/assets/diagram/use-connect-diagram-0.jpg +0 -0
  51. package/docs/assets/diagram/use-connect-diagram-0.zh-TW.jpg +0 -0
  52. package/docs/assets/diagram/use-connect-diagram-0.zh.jpg +0 -0
  53. package/docs/core-components-did-connect.ja.md +0 -166
  54. package/docs/core-components-did-connect.md +0 -166
  55. package/docs/core-components-did-connect.zh-TW.md +0 -166
  56. package/docs/core-components-did-connect.zh.md +0 -166
  57. package/docs/core-components-session-provider.ja.md +0 -197
  58. package/docs/core-components-session-provider.md +0 -197
  59. package/docs/core-components-session-provider.zh-TW.md +0 -197
  60. package/docs/core-components-session-provider.zh.md +0 -197
  61. package/docs/core-components.ja.md +0 -16
  62. package/docs/core-components.md +0 -16
  63. package/docs/core-components.zh-TW.md +0 -16
  64. package/docs/core-components.zh.md +0 -16
  65. package/docs/getting-started.ja.md +0 -138
  66. package/docs/getting-started.md +0 -138
  67. package/docs/getting-started.zh-TW.md +0 -138
  68. package/docs/getting-started.zh.md +0 -138
  69. package/docs/hooks-use-connect.ja.md +0 -178
  70. package/docs/hooks-use-connect.md +0 -178
  71. package/docs/hooks-use-connect.zh-TW.md +0 -178
  72. package/docs/hooks-use-connect.zh.md +0 -178
  73. package/docs/hooks-use-did.ja.md +0 -107
  74. package/docs/hooks-use-did.md +0 -107
  75. package/docs/hooks-use-did.zh-TW.md +0 -107
  76. package/docs/hooks-use-did.zh.md +0 -107
  77. package/docs/hooks-use-oauth-passkey.ja.md +0 -188
  78. package/docs/hooks-use-oauth-passkey.md +0 -188
  79. package/docs/hooks-use-oauth-passkey.zh-TW.md +0 -188
  80. package/docs/hooks-use-oauth-passkey.zh.md +0 -188
  81. package/docs/hooks.ja.md +0 -23
  82. package/docs/hooks.md +0 -23
  83. package/docs/hooks.zh-TW.md +0 -23
  84. package/docs/hooks.zh.md +0 -23
  85. package/docs/overview.ja.md +0 -119
  86. package/docs/overview.md +0 -119
  87. package/docs/overview.zh-TW.md +0 -119
  88. package/docs/overview.zh.md +0 -119
  89. package/docs/ui-components-address.ja.md +0 -121
  90. package/docs/ui-components-address.md +0 -121
  91. package/docs/ui-components-address.zh-TW.md +0 -121
  92. package/docs/ui-components-address.zh.md +0 -121
  93. package/docs/ui-components-avatar.ja.md +0 -65
  94. package/docs/ui-components-avatar.md +0 -65
  95. package/docs/ui-components-avatar.zh-TW.md +0 -65
  96. package/docs/ui-components-avatar.zh.md +0 -65
  97. package/docs/ui-components-button.ja.md +0 -99
  98. package/docs/ui-components-button.md +0 -99
  99. package/docs/ui-components-button.zh-TW.md +0 -99
  100. package/docs/ui-components-button.zh.md +0 -99
  101. package/docs/ui-components-logo.ja.md +0 -52
  102. package/docs/ui-components-logo.md +0 -52
  103. package/docs/ui-components-logo.zh-TW.md +0 -52
  104. package/docs/ui-components-logo.zh.md +0 -52
  105. package/docs/ui-components.ja.md +0 -57
  106. package/docs/ui-components.md +0 -57
  107. package/docs/ui-components.zh-TW.md +0 -57
  108. package/docs/ui-components.zh.md +0 -57
  109. package/glossary.md +0 -1
  110. package/src/Address/index.jsx +0 -2
  111. package/src/Avatar/index.jsx +0 -2
  112. package/src/Button/Button.stories.jsx +0 -7
  113. package/src/Button/index.jsx +0 -21
  114. package/src/Connect/Connect.stories.jsx +0 -34
  115. package/src/Connect/assets/locale.js +0 -149
  116. package/src/Connect/assets/login-bg.png +0 -0
  117. package/src/Connect/assets/login-slogan.js +0 -7
  118. package/src/Connect/components/action-button.jsx +0 -22
  119. package/src/Connect/components/app-tips.jsx +0 -156
  120. package/src/Connect/components/auto-height.jsx +0 -38
  121. package/src/Connect/components/back-button.jsx +0 -24
  122. package/src/Connect/components/connect-status.jsx +0 -259
  123. package/src/Connect/components/did-connect-title.jsx +0 -107
  124. package/src/Connect/components/download-tips.jsx +0 -55
  125. package/src/Connect/components/loading.jsx +0 -25
  126. package/src/Connect/components/login-item/connect-choose-list.jsx +0 -317
  127. package/src/Connect/components/login-item/connect-provider-list.jsx +0 -462
  128. package/src/Connect/components/login-item/login-method-item.jsx +0 -139
  129. package/src/Connect/components/login-item/mobile-login-item.jsx +0 -181
  130. package/src/Connect/components/login-item/passkey-login-item.jsx +0 -54
  131. package/src/Connect/components/login-item/wallet-login-options.jsx +0 -129
  132. package/src/Connect/components/login-item/web-login-item.jsx +0 -157
  133. package/src/Connect/components/mask-overlay.jsx +0 -32
  134. package/src/Connect/components/refresh-overlay.jsx +0 -52
  135. package/src/Connect/components/switch-app.jsx +0 -69
  136. package/src/Connect/connect.jsx +0 -617
  137. package/src/Connect/contexts/state.jsx +0 -234
  138. package/src/Connect/fallback-connect.jsx +0 -47
  139. package/src/Connect/fullpage.jsx +0 -3
  140. package/src/Connect/hooks/auth-url.js +0 -31
  141. package/src/Connect/hooks/method-list.js +0 -121
  142. package/src/Connect/hooks/page-show.js +0 -24
  143. package/src/Connect/hooks/provider-list.js +0 -165
  144. package/src/Connect/hooks/security.js +0 -40
  145. package/src/Connect/hooks/token.js +0 -627
  146. package/src/Connect/hooks/use-apps.js +0 -69
  147. package/src/Connect/hooks/use-quick-connect.js +0 -119
  148. package/src/Connect/index.jsx +0 -21
  149. package/src/Connect/landing-page.jsx +0 -3
  150. package/src/Connect/plugins/email/index.jsx +0 -85
  151. package/src/Connect/plugins/email/list-item.jsx +0 -34
  152. package/src/Connect/plugins/email/placeholder.jsx +0 -365
  153. package/src/Connect/plugins/index.js +0 -2
  154. package/src/Connect/use-connect.jsx +0 -321
  155. package/src/Connect/with-blocklet.jsx +0 -26
  156. package/src/Connect/with-bridge-call.jsx +0 -138
  157. package/src/Federated/context.jsx +0 -93
  158. package/src/Federated/index.jsx +0 -1
  159. package/src/Logo/index.jsx +0 -2
  160. package/src/OAuth/bind-conflict-alert.jsx +0 -37
  161. package/src/OAuth/context.jsx +0 -407
  162. package/src/OAuth/guest.svg +0 -20
  163. package/src/OAuth/index.jsx +0 -1
  164. package/src/OAuth/passport-switcher.jsx +0 -2
  165. package/src/Passkey/actions.jsx +0 -217
  166. package/src/Passkey/constants.js +0 -2
  167. package/src/Passkey/context.jsx +0 -395
  168. package/src/Passkey/dialog.jsx +0 -401
  169. package/src/Passkey/icon.jsx +0 -10
  170. package/src/Passkey/index.jsx +0 -2
  171. package/src/Service/index.jsx +0 -96
  172. package/src/Session/assets/did-spaces-guide-cover.svg +0 -1
  173. package/src/Session/assets/did-spaces-guide-icon.svg +0 -7
  174. package/src/Session/context.jsx +0 -7
  175. package/src/Session/did-spaces-guide.jsx +0 -173
  176. package/src/Session/handler.jsx +0 -98
  177. package/src/Session/hooks/use-federated.js +0 -91
  178. package/src/Session/hooks/use-mobile.jsx +0 -6
  179. package/src/Session/hooks/use-protected-routes.js +0 -16
  180. package/src/Session/hooks/use-session-token.js +0 -400
  181. package/src/Session/hooks/use-verify.jsx +0 -76
  182. package/src/Session/index.jsx +0 -1789
  183. package/src/Session/libs/constants.js +0 -17
  184. package/src/Session/libs/did-spaces.js +0 -38
  185. package/src/Session/libs/federated.js +0 -82
  186. package/src/Session/libs/index.js +0 -5
  187. package/src/Session/libs/locales.js +0 -160
  188. package/src/Session/libs/login-mobile.js +0 -80
  189. package/src/Session/window-focus-aware.jsx +0 -28
  190. package/src/SessionManager/index.jsx +0 -2
  191. package/src/Storage/engine/cookie.js +0 -25
  192. package/src/Storage/engine/local-storage.js +0 -57
  193. package/src/Storage/index.js +0 -25
  194. package/src/User/index.js +0 -4
  195. package/src/User/use-did.js +0 -80
  196. package/src/User/wrap-did.jsx +0 -18
  197. package/src/WebWalletSWKeeper/index.jsx +0 -3
  198. package/src/components/PassportSwitcher.jsx +0 -160
  199. package/src/constant.js +0 -27
  200. package/src/error.js +0 -6
  201. package/src/hooks/use-locale.jsx +0 -6
  202. package/src/index.js +0 -32
  203. package/src/locales/en.jsx +0 -15
  204. package/src/locales/index.jsx +0 -13
  205. package/src/locales/zh.jsx +0 -15
  206. package/src/types.d.ts +0 -355
  207. package/src/utils.js +0 -413
  208. package/vite.config.mjs +0 -29
@@ -1,119 +0,0 @@
1
- import { useCreation, useMemoizedFn, useReactive, useRequest } from 'ahooks';
2
- import { joinURL } from 'ufo';
3
- import pick from 'lodash/pick';
4
- import unionBy from 'lodash/unionBy';
5
- import sortBy from 'lodash/sortBy';
6
- import Toast from '@arcblock/ux/lib/Toast';
7
-
8
- import { BLOCKLET_SERVICE_PATH_PREFIX } from '../../constant';
9
- import { createAxios, logger } from '../../utils';
10
-
11
- const prefix = joinURL(BLOCKLET_SERVICE_PATH_PREFIX, '/api/user-session');
12
-
13
- export default function useQuickConnect({
14
- appPid,
15
- sourceAppPid,
16
- loginAppPid,
17
- autoFetch = true,
18
- baseUrl = '/',
19
- fetchAll = false,
20
- } = {}) {
21
- const api = useCreation(() => {
22
- return createAxios(
23
- {
24
- baseURL: joinURL(baseUrl, prefix),
25
- },
26
- { lazy: true, lazyTime: 500 }
27
- );
28
- }, [baseUrl]);
29
-
30
- const getUserSessions = useMemoizedFn(async () => {
31
- if (!window.blocklet) {
32
- return [];
33
- }
34
-
35
- let userSessions = [];
36
- try {
37
- ({ data: userSessions = [] } = await api.get(''));
38
- } catch (err) {
39
- logger.error('Failed to get user-sessions', err);
40
- }
41
- // NOTICE: 已经包含了 federated master userSessions
42
- const result = userSessions
43
- .filter((x) => {
44
- if (!fetchAll) {
45
- return !x.appUrl;
46
- }
47
- return true;
48
- })
49
- .map((x) => ({
50
- appUrl: baseUrl,
51
- ...x,
52
- }));
53
- return result;
54
- });
55
- const currentState = useReactive({
56
- loaded: false,
57
- loadingId: null,
58
- });
59
- const userSessionsState = useRequest(getUserSessions, {
60
- manual: !autoFetch,
61
- onFinally() {
62
- currentState.loaded = true;
63
- },
64
- refreshDeps: [baseUrl],
65
- });
66
-
67
- const loginUserSession = async (userSession) => {
68
- const params = pick(userSession, ['userDid', 'visitorId', 'passportId', 'id']);
69
- try {
70
- currentState.loadingId = userSession.id;
71
- const { data } = await api.post(
72
- 'login',
73
- { ...params, appPid: loginAppPid },
74
- {
75
- baseURL: joinURL(userSession.appUrl || '/', prefix),
76
- }
77
- );
78
- return data;
79
- } catch (err) {
80
- const errorMsg = err.response ? err.response?.data?.error || err.response?.data : err.message;
81
- Toast.error(errorMsg);
82
- logger.error('Quick login error', err);
83
- throw err;
84
- } finally {
85
- currentState.loadingId = null;
86
- }
87
- };
88
-
89
- const onlineUserSessions = useCreation(() => {
90
- if (!userSessionsState.data) return [];
91
- return userSessionsState.data.filter((x) => x.status !== 'expired');
92
- }, [userSessionsState.data]);
93
-
94
- const uniqueUserSessions = useCreation(() => {
95
- const now = new Date().getTime();
96
- const sortedUserSessions = sortBy(onlineUserSessions, (x) => now - new Date(x.updatedAt).getTime());
97
- return unionBy(sortedUserSessions, (x) =>
98
- [
99
- x.userDid,
100
- // 暂不以用户角色来做去重的因子
101
- // x.user.role
102
- ].join('_')
103
- );
104
- }, [onlineUserSessions, sourceAppPid, appPid]);
105
-
106
- const quickLoginEnabled = useCreation(() => {
107
- return Boolean(uniqueUserSessions && uniqueUserSessions.length > 0);
108
- }, [uniqueUserSessions]);
109
-
110
- return {
111
- loadingId: currentState.loadingId,
112
- userSessions: uniqueUserSessions,
113
- quickLoginEnabled,
114
- loginUserSession,
115
- loading: userSessionsState.loading,
116
- loaded: userSessionsState.loaded,
117
- refresh: userSessionsState.refreshAsync,
118
- };
119
- }
@@ -1,21 +0,0 @@
1
- import { lazy, Suspense } from 'react';
2
- import { withContainer, withUxTheme } from '@arcblock/ux/lib/DIDConnect';
3
-
4
- import withBlocklet from './with-blocklet';
5
- import withBridgeCall from './with-bridge-call';
6
- import useSecurity from './hooks/security';
7
- import FallbackConnect from './fallback-connect';
8
-
9
- const LazyConnect = lazy(() => import('./connect'));
10
-
11
- function WrapConnect(props) {
12
- return (
13
- <Suspense fallback={<FallbackConnect />}>
14
- <LazyConnect {...props} />
15
- </Suspense>
16
- );
17
- }
18
-
19
- export default withUxTheme(withBridgeCall(withBlocklet(withContainer(WrapConnect))));
20
-
21
- export { useSecurity };
@@ -1,3 +0,0 @@
1
- import LandingPage from '@arcblock/ux/lib/DIDConnect/landing-page';
2
-
3
- export default LandingPage;
@@ -1,85 +0,0 @@
1
- import { useMemoizedFn, useReactive } from 'ahooks';
2
- import mailOutlineRoundedIcon from '@iconify-icons/material-symbols/mail-outline-rounded';
3
- import { LOGIN_PROVIDER } from '@arcblock/ux/lib/Util/constant';
4
- import { translate } from '@arcblock/ux/lib/Locale/util';
5
-
6
- import EmailListItem from './list-item';
7
- import EmailPlaceholder from './placeholder';
8
- import defaultTranslations from '../../assets/locale';
9
-
10
- export default function useEmailPlugin({ baseUrl }) {
11
- const state = useReactive({
12
- baseUrl,
13
- status: 'idle',
14
- get computedStatus() {
15
- if (this.status === 'idle') {
16
- return 'creating';
17
- }
18
- if (this.status === 'creating') {
19
- return 'scanned';
20
- }
21
- if (this.status === 'sending') {
22
- return 'scanned';
23
- }
24
- if (this.status === 'verifying') {
25
- return 'scanned';
26
- }
27
- return this.status;
28
- },
29
- error: '',
30
- magicToken: '',
31
- reset() {
32
- this.status = 'idle';
33
- this.error = '';
34
- this.magicToken = '';
35
- },
36
- });
37
- const name = LOGIN_PROVIDER.EMAIL;
38
- const title = 'Email';
39
- const icon = mailOutlineRoundedIcon;
40
- const translations = {
41
- zh: {
42
- ...defaultTranslations.zh,
43
- email: '邮箱地址',
44
- emailPlaceholder: '请输入邮箱地址',
45
- sendCode: '发送验证邮件',
46
- confirm: '确认',
47
- verifyEmail: '登录链接已发送至邮箱,请登录邮箱查看',
48
- useCode: '使用验证码',
49
- codePlaceholder: '请输入验证码',
50
- orUseCodePlaceholder: '或使用验证码',
51
- emailInvalid: '邮箱格式不正确',
52
- emailRequired: '邮箱地址不能为空',
53
- },
54
- en: {
55
- ...defaultTranslations.en,
56
- email: 'Email',
57
- emailPlaceholder: 'Enter your email address',
58
- sendCode: 'Send Verification Email',
59
- confirm: 'Confirm',
60
- verifyEmail: 'Login link sent! Please check your email.',
61
- useCode: 'Use Verification Code',
62
- codePlaceholder: 'Enter your verification code.',
63
- orUseCodePlaceholder: 'Or use verification code.',
64
- emailInvalid: 'Email format is incorrect',
65
- emailRequired: 'Email is required',
66
- },
67
- };
68
- const t = useMemoizedFn((key, data = {}, locale = 'en') => {
69
- return translate(translations, key, locale, 'en', data);
70
- });
71
-
72
- return {
73
- name,
74
- title,
75
- icon,
76
- renderListItem(props) {
77
- return <EmailListItem {...props} state={state} name={name} title={title} icon={icon} t={t} />;
78
- },
79
- renderPlaceholder(props) {
80
- return <EmailPlaceholder {...props} state={state} name={name} title={title} icon={icon} t={t} />;
81
- },
82
- order: 100,
83
- state,
84
- };
85
- }
@@ -1,34 +0,0 @@
1
- import PropTypes from 'prop-types';
2
- import { useMemoizedFn } from 'ahooks';
3
- import mailFilledIcon from '@iconify-icons/tabler/mail-filled';
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';
6
-
7
- import LoginMethodItem from '../../components/login-item/login-method-item';
8
- import { useStateContext } from '../../contexts/state';
9
-
10
- export default function EmailListItem({ ...rest }) {
11
- const { setSelectedPlugin, getPlugin, connectState, lastLoginMethod } = useStateContext();
12
- const handleConnect = useMemoizedFn(() => {
13
- localStorage.setItem(GA_LAST_LOGIN_METHOD, LOGIN_PROVIDER.EMAIL);
14
- const plugin = getPlugin(LOGIN_PROVIDER.EMAIL);
15
- plugin.state.reset();
16
- plugin.state.status = 'creating';
17
- connectState.chooseMethod = LOGIN_PROVIDER.EMAIL;
18
- setSelectedPlugin(plugin);
19
- });
20
-
21
- return (
22
- <LoginMethodItem
23
- {...rest}
24
- isLatest={lastLoginMethod && lastLoginMethod === LOGIN_PROVIDER.EMAIL}
25
- title={LOGIN_PROVIDER_NAME[LOGIN_PROVIDER.EMAIL]}
26
- icon={mailFilledIcon}
27
- onClick={handleConnect}
28
- />
29
- );
30
- }
31
-
32
- EmailListItem.propTypes = {
33
- onClick: PropTypes.func,
34
- };
@@ -1,365 +0,0 @@
1
- import LoadingMask from '@arcblock/ux/lib/LoadingMask';
2
- import { Box, CircularProgress, TextField, Typography } from '@mui/material';
3
- import { useCreation, useInterval, useMemoizedFn, useReactive } from 'ahooks';
4
- import PropTypes from 'prop-types';
5
- import { joinURL, withQuery } from 'ufo';
6
- import Toast from '@arcblock/ux/lib/Toast';
7
- import VerificationCode from '@arcblock/ux/lib/VerificationCode';
8
- import { useEffect } from 'react';
9
- import noop from 'lodash/noop';
10
- import ProviderIcon from '@arcblock/ux/lib/DIDConnect/provider-icon';
11
-
12
- import BackButton from '../../components/back-button';
13
- import ActionButton from '../../components/action-button';
14
- import { useStateContext } from '../../contexts/state';
15
- import { BLOCKLET_SERVICE_PATH_PREFIX, CHECK_STATUS_INTERVAL, VERIFY_CODE_LENGTH } from '../../../constant';
16
- import { createAxios, debug } from '../../../utils';
17
-
18
- export default function EmailPlaceholder({
19
- fallback = null,
20
- state,
21
- forceUpdate = noop,
22
- onSuccess = noop,
23
- t: rawT = noop,
24
- }) {
25
- const { setSelectedPlugin, locale, connectState, action, extraParams } = useStateContext();
26
- const t = useMemoizedFn((key, data = {}) => {
27
- return rawT(key, data, locale);
28
- });
29
- const api = useCreation(() => {
30
- return createAxios({
31
- baseURL: joinURL(state.baseUrl, BLOCKLET_SERVICE_PATH_PREFIX, '/api/user'),
32
- });
33
- }, [state.baseUrl]);
34
-
35
- const currentState = useReactive({
36
- email: '',
37
- code: '',
38
- codeId: '',
39
- defaultVerifyMode: 'magicLink',
40
- verifyMode: 'magicLink', // magicLink, code
41
- loadingSendCode: false,
42
- loadingVerifyCode: false,
43
- error: '',
44
- });
45
-
46
- const reset = useMemoizedFn(() => {
47
- currentState.email = '';
48
- currentState.code = '';
49
- currentState.codeId = '';
50
- currentState.verifyMode = currentState.defaultVerifyMode;
51
- currentState.loadingSendCode = false;
52
- currentState.loadingVerifyCode = false;
53
- currentState.error = '';
54
- });
55
-
56
- const sendCode = useMemoizedFn(async () => {
57
- if (!currentState.email || !currentState.email.trim()) {
58
- currentState.error = t('emailRequired');
59
- return;
60
- }
61
-
62
- // 检查邮箱格式
63
- const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
64
- if (!emailRegex.test(currentState.email)) {
65
- currentState.error = t('emailInvalid');
66
- return;
67
- }
68
- currentState.error = '';
69
-
70
- try {
71
- currentState.loadingSendCode = true;
72
- let useMagicLink = false;
73
- // FIXME: @zhanghan 暂时只允许登录时使用 magicLink,否则其他的事件无法调用正确的回调
74
- if (['login'].includes(action)) {
75
- // FIXME: @zhanghan 如果 sourceAppPid 存在,则不使用 magicLink,暂无法获得正确的 magicLink 地址
76
- if (!connectState.sourceAppPid) {
77
- useMagicLink = true;
78
- }
79
- }
80
- const { data } = await api.post(withQuery('/email/sendCode', { locale }), {
81
- email: currentState.email,
82
- sourceAppPid: connectState.sourceAppPid,
83
- useMagicLink,
84
- });
85
- currentState.verifyMode = currentState.defaultVerifyMode;
86
- currentState.codeId = data.id;
87
- state.status = 'sending';
88
- } catch (error) {
89
- const errorMessage = error?.response?.data?.error || error?.message;
90
- state.status = 'error';
91
- state.error = errorMessage;
92
- } finally {
93
- currentState.loadingSendCode = false;
94
- forceUpdate();
95
- }
96
- });
97
- const verifyCode = useMemoizedFn(async () => {
98
- if (currentState.code.length !== VERIFY_CODE_LENGTH) {
99
- return;
100
- }
101
-
102
- try {
103
- currentState.loadingVerifyCode = true;
104
- const { data: loginResult } = await api.post(withQuery('/email/login', { locale }), {
105
- ...extraParams,
106
- action,
107
- code: currentState.code,
108
- sourceAppPid: connectState.sourceAppPid,
109
- });
110
- debug('Email login succeed (use code)', { loginResult });
111
- await onSuccess(
112
- {
113
- ...loginResult,
114
- encrypted: false,
115
- },
116
- (val) => val
117
- );
118
- state.status = 'succeed';
119
- } catch (error) {
120
- const errorMessage = error?.response?.data || error?.message;
121
- Toast.error(errorMessage);
122
- debug('Email login failed (use code)', { error });
123
- } finally {
124
- currentState.loadingVerifyCode = false;
125
- forceUpdate();
126
- }
127
- });
128
- const verifyMagicToken = useMemoizedFn(async () => {
129
- state.status = 'verifying';
130
- forceUpdate();
131
- try {
132
- const { data: loginResult } = await api.post(withQuery('/email/login', { locale }), {
133
- ...extraParams,
134
- action,
135
- magicToken: state.magicToken,
136
- });
137
- debug('Email login succeed (use magic link)', { loginResult });
138
- await onSuccess(
139
- {
140
- ...loginResult,
141
- encrypted: false,
142
- },
143
- (val) => val
144
- );
145
- state.status = 'succeed';
146
- } catch (error) {
147
- const errorMessage = error?.response?.data || error?.message;
148
- state.status = 'error';
149
- state.error = errorMessage;
150
- debug('Email login failed (use magic link)', { error });
151
- }
152
- forceUpdate();
153
- });
154
-
155
- const shouldPoll =
156
- currentState.verifyMode === 'magicLink' &&
157
- state.status === 'sending' &&
158
- // 如果正在校验验证码,则不轮询状态
159
- !currentState.loadingVerifyCode &&
160
- currentState.codeId;
161
-
162
- const checkStatus = useMemoizedFn(async () => {
163
- if (!shouldPoll) {
164
- return;
165
- }
166
- try {
167
- const { data } = await api.get('/email/status', {
168
- params: {
169
- codeId: currentState.codeId,
170
- },
171
- });
172
- if (data.verified) {
173
- state.status = 'succeed';
174
- reset();
175
- await onSuccess({ encrypted: false }, (val) => val);
176
- }
177
- } catch (error) {
178
- // 只做记录
179
- console.error('check status error', error);
180
- }
181
- forceUpdate();
182
- });
183
-
184
- useInterval(checkStatus, shouldPoll ? CHECK_STATUS_INTERVAL : undefined);
185
-
186
- useEffect(() => {
187
- reset();
188
- // FIXME: @zhanghan 暂不支持子站进行统一登录时使用 magicLink 登录
189
- if (connectState.sourceAppPid || !['login'].includes(action)) {
190
- currentState.defaultVerifyMode = 'code';
191
- }
192
- if (state.magicToken) {
193
- verifyMagicToken();
194
- }
195
- // 由于存在 email 插件被重置的情况,所以需要监听 state 是否被重新赋值来执行 init 操作
196
- // eslint-disable-next-line react-hooks/exhaustive-deps
197
- }, [state]);
198
-
199
- let content = null;
200
- if (state.status === 'creating') {
201
- content = (
202
- <>
203
- <Typography
204
- variant="body2"
205
- sx={{
206
- textAlign: 'center',
207
- color: 'text.secondary',
208
- }}>
209
- {t('emailPlaceholder')}
210
- </Typography>
211
- <TextField
212
- name="email"
213
- fullWidth
214
- type="email"
215
- variant="outlined"
216
- label={t('email')}
217
- placeholder={t('emailPlaceholder')}
218
- size="small"
219
- value={currentState.email}
220
- onChange={(e) => {
221
- currentState.email = e.target.value;
222
- }}
223
- onKeyDown={(e) => {
224
- if (e.key === 'Enter') {
225
- sendCode(currentState.email);
226
- }
227
- }}
228
- sx={{
229
- maxWidth: 320,
230
- '& .MuiOutlinedInput-root': {
231
- borderRadius: 1,
232
- },
233
- }}
234
- error={!!currentState.error}
235
- helperText={currentState.error}
236
- slotProps={{
237
- htmlInput: {
238
- sx: {
239
- boxSizing: 'content-box !important',
240
- },
241
- },
242
- }}
243
- />
244
- <Box sx={{ display: 'flex', gap: 1 }}>
245
- <BackButton
246
- onClick={() => {
247
- state.reset();
248
- setSelectedPlugin();
249
- }}
250
- />
251
- <ActionButton
252
- sx={{
253
- color: 'primary.main',
254
- borderColor: 'primary.light',
255
- }}
256
- disabled={currentState.loadingSendCode}
257
- onClick={() => {
258
- sendCode(currentState.email);
259
- }}>
260
- {currentState.loadingSendCode ? <CircularProgress color="inherit" size={14} sx={{ mr: 1 }} /> : null}
261
- {t('sendCode')}
262
- </ActionButton>
263
- </Box>
264
- </>
265
- );
266
- } else if (state.status === 'sending') {
267
- content = (
268
- <>
269
- <Box sx={{ display: 'flex', flexDirection: 'column', alignItems: 'center' }}>
270
- <Typography variant="body2" sx={{ textAlign: 'center', color: 'text.secondary' }}>
271
- {currentState.verifyMode === 'magicLink' ? (
272
- <>
273
- {t('verifyEmail')}
274
- <br />
275
- {t('orUseCodePlaceholder')}
276
- </>
277
- ) : (
278
- t('codePlaceholder')
279
- )}
280
- </Typography>
281
- <>
282
- {/* eslint-disable-next-line jsx-a11y/anchor-is-valid */}
283
- {/* 暂时保留代码,防止后期需要再使用 */}
284
- {/* <Link
285
- underline="none"
286
- variant="caption"
287
- component="button"
288
- sx={{ mb: 2 }}
289
- onClick={() => {
290
- currentState.verifyMode = 'code';
291
- forceUpdate();
292
- }}>
293
- {t('useCode')}
294
- </Link>
295
- <BackButton
296
- onClick={() => {
297
- state.status = 'creating';
298
- forceUpdate();
299
- }}
300
- /> */}
301
- </>
302
- </Box>
303
- <>
304
- <VerificationCode
305
- code={currentState.code}
306
- onChange={(code) => {
307
- currentState.code = code;
308
- }}
309
- onComplete={() => {
310
- verifyCode();
311
- }}
312
- />
313
- <Box sx={{ display: 'flex', gap: 1 }}>
314
- <BackButton
315
- onClick={() => {
316
- currentState.code = '';
317
- state.status = 'creating';
318
- forceUpdate();
319
- }}
320
- />
321
- <ActionButton
322
- sx={{
323
- color: 'primary.main',
324
- borderColor: 'primary.light',
325
- }}
326
- disabled={currentState.loadingVerifyCode}
327
- onClick={() => {
328
- verifyCode();
329
- }}>
330
- {currentState.loadingVerifyCode ? <CircularProgress color="inherit" size={14} sx={{ mr: 1 }} /> : null}
331
- {t('confirm')}
332
- </ActionButton>
333
- </Box>
334
- </>
335
- </>
336
- );
337
- } else {
338
- return fallback;
339
- }
340
-
341
- return (
342
- <Box
343
- sx={{
344
- display: 'flex',
345
- flexDirection: 'column',
346
- alignItems: 'center',
347
- justifyContent: 'center',
348
- gap: 2,
349
- pb: 1,
350
- }}>
351
- <LoadingMask size={52} borderRadius={12}>
352
- <ProviderIcon provider="email" />
353
- </LoadingMask>
354
- {content}
355
- </Box>
356
- );
357
- }
358
-
359
- EmailPlaceholder.propTypes = {
360
- fallback: PropTypes.any,
361
- state: PropTypes.object.isRequired,
362
- forceUpdate: PropTypes.func,
363
- onSuccess: PropTypes.func,
364
- t: PropTypes.func,
365
- };
@@ -1,2 +0,0 @@
1
- /* eslint-disable import/prefer-default-export */
2
- export { default as useEmailPlugin } from './email';