@blocklet/ui-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 (256) hide show
  1. package/lib/common/org-switch/use-org.d.ts +4 -4
  2. package/lib/common/ws.d.ts +22 -1
  3. package/package.json +10 -7
  4. package/.aigne/doc-smith/.local/afs-storage.sqlite3 +0 -0
  5. package/.aigne/doc-smith/config.yaml +0 -78
  6. package/.aigne/doc-smith/history.yaml +0 -14
  7. package/.aigne/doc-smith/media-description.yaml +0 -11
  8. package/.aigne/doc-smith/output/structure-plan.json +0 -255
  9. package/.aigne/doc-smith/translation-cache.yaml +0 -11
  10. package/.aigne/doc-smith/upload-cache.yaml +0 -528
  11. package/build.config.ts +0 -24
  12. package/docs/_sidebar.md +0 -19
  13. package/docs/assets/diagram/component-installer-diagram-0.ja.jpg +0 -0
  14. package/docs/assets/diagram/component-installer-diagram-0.jpg +0 -0
  15. package/docs/assets/diagram/component-installer-diagram-0.zh-TW.jpg +0 -0
  16. package/docs/assets/diagram/component-installer-diagram-0.zh.jpg +0 -0
  17. package/docs/assets/diagram/component-management-diagram-0.ja.jpg +0 -0
  18. package/docs/assets/diagram/component-management-diagram-0.jpg +0 -0
  19. package/docs/assets/diagram/component-management-diagram-0.zh-TW.jpg +0 -0
  20. package/docs/assets/diagram/component-management-diagram-0.zh.jpg +0 -0
  21. package/docs/assets/diagram/core-concepts-diagram-0.ja.jpg +0 -0
  22. package/docs/assets/diagram/core-concepts-diagram-0.jpg +0 -0
  23. package/docs/assets/diagram/core-concepts-diagram-0.zh-TW.jpg +0 -0
  24. package/docs/assets/diagram/core-concepts-diagram-0.zh.jpg +0 -0
  25. package/docs/assets/diagram/dashboard-diagram-0.ja.jpg +0 -0
  26. package/docs/assets/diagram/dashboard-diagram-0.jpg +0 -0
  27. package/docs/assets/diagram/dashboard-diagram-0.zh-TW.jpg +0 -0
  28. package/docs/assets/diagram/dashboard-diagram-0.zh.jpg +0 -0
  29. package/docs/assets/diagram/header-diagram-0.ja.jpg +0 -0
  30. package/docs/assets/diagram/header-diagram-0.jpg +0 -0
  31. package/docs/assets/diagram/header-diagram-0.zh-TW.jpg +0 -0
  32. package/docs/assets/diagram/header-diagram-0.zh.jpg +0 -0
  33. package/docs/assets/diagram/layout-diagram-0.ja.jpg +0 -0
  34. package/docs/assets/diagram/layout-diagram-0.jpg +0 -0
  35. package/docs/assets/diagram/layout-diagram-0.zh-TW.jpg +0 -0
  36. package/docs/assets/diagram/layout-diagram-0.zh.jpg +0 -0
  37. package/docs/assets/diagram/notifications-diagram-0.ja.jpg +0 -0
  38. package/docs/assets/diagram/notifications-diagram-0.jpg +0 -0
  39. package/docs/assets/diagram/notifications-diagram-0.zh-TW.jpg +0 -0
  40. package/docs/assets/diagram/notifications-diagram-0.zh.jpg +0 -0
  41. package/docs/assets/diagram/overview-diagram-0.ja.jpg +0 -0
  42. package/docs/assets/diagram/overview-diagram-0.jpg +0 -0
  43. package/docs/assets/diagram/overview-diagram-0.zh-TW.jpg +0 -0
  44. package/docs/assets/diagram/overview-diagram-0.zh.jpg +0 -0
  45. package/docs/assets/diagram/user-center-diagram-0.ja.jpg +0 -0
  46. package/docs/assets/diagram/user-center-diagram-0.jpg +0 -0
  47. package/docs/assets/diagram/user-center-diagram-0.zh-TW.jpg +0 -0
  48. package/docs/assets/diagram/user-center-diagram-0.zh.jpg +0 -0
  49. package/docs/assets/diagram/user-management-diagram-0.ja.jpg +0 -0
  50. package/docs/assets/diagram/user-management-diagram-0.jpg +0 -0
  51. package/docs/assets/diagram/user-management-diagram-0.zh-TW.jpg +0 -0
  52. package/docs/assets/diagram/user-management-diagram-0.zh.jpg +0 -0
  53. package/docs/assets/diagram/user-sessions-diagram-0.ja.jpg +0 -0
  54. package/docs/assets/diagram/user-sessions-diagram-0.jpg +0 -0
  55. package/docs/assets/diagram/user-sessions-diagram-0.zh-TW.jpg +0 -0
  56. package/docs/assets/diagram/user-sessions-diagram-0.zh.jpg +0 -0
  57. package/docs/components-component-management-blocklet-studio.ja.md +0 -194
  58. package/docs/components-component-management-blocklet-studio.md +0 -194
  59. package/docs/components-component-management-blocklet-studio.zh-TW.md +0 -194
  60. package/docs/components-component-management-blocklet-studio.zh.md +0 -194
  61. package/docs/components-component-management-component-installer.ja.md +0 -182
  62. package/docs/components-component-management-component-installer.md +0 -182
  63. package/docs/components-component-management-component-installer.zh-TW.md +0 -182
  64. package/docs/components-component-management-component-installer.zh.md +0 -182
  65. package/docs/components-component-management.ja.md +0 -30
  66. package/docs/components-component-management.md +0 -30
  67. package/docs/components-component-management.zh-TW.md +0 -30
  68. package/docs/components-component-management.zh.md +0 -30
  69. package/docs/components-layout-dashboard.ja.md +0 -185
  70. package/docs/components-layout-dashboard.md +0 -187
  71. package/docs/components-layout-dashboard.zh-TW.md +0 -185
  72. package/docs/components-layout-dashboard.zh.md +0 -185
  73. package/docs/components-layout-footer.ja.md +0 -165
  74. package/docs/components-layout-footer.md +0 -165
  75. package/docs/components-layout-footer.zh-TW.md +0 -165
  76. package/docs/components-layout-footer.zh.md +0 -165
  77. package/docs/components-layout-header.ja.md +0 -183
  78. package/docs/components-layout-header.md +0 -183
  79. package/docs/components-layout-header.zh-TW.md +0 -183
  80. package/docs/components-layout-header.zh.md +0 -183
  81. package/docs/components-layout.ja.md +0 -31
  82. package/docs/components-layout.md +0 -31
  83. package/docs/components-layout.zh-TW.md +0 -31
  84. package/docs/components-layout.zh.md +0 -31
  85. package/docs/components-notifications.ja.md +0 -125
  86. package/docs/components-notifications.md +0 -125
  87. package/docs/components-notifications.zh-TW.md +0 -125
  88. package/docs/components-notifications.zh.md +0 -125
  89. package/docs/components-user-management-user-center.ja.md +0 -148
  90. package/docs/components-user-management-user-center.md +0 -147
  91. package/docs/components-user-management-user-center.zh-TW.md +0 -148
  92. package/docs/components-user-management-user-center.zh.md +0 -148
  93. package/docs/components-user-management-user-sessions.ja.md +0 -121
  94. package/docs/components-user-management-user-sessions.md +0 -123
  95. package/docs/components-user-management-user-sessions.zh-TW.md +0 -121
  96. package/docs/components-user-management-user-sessions.zh.md +0 -121
  97. package/docs/components-user-management.ja.md +0 -49
  98. package/docs/components-user-management.md +0 -51
  99. package/docs/components-user-management.zh-TW.md +0 -49
  100. package/docs/components-user-management.zh.md +0 -49
  101. package/docs/components-utilities-icon.ja.md +0 -106
  102. package/docs/components-utilities-icon.md +0 -106
  103. package/docs/components-utilities-icon.zh-TW.md +0 -106
  104. package/docs/components-utilities-icon.zh.md +0 -106
  105. package/docs/components-utilities.ja.md +0 -136
  106. package/docs/components-utilities.md +0 -136
  107. package/docs/components-utilities.zh-TW.md +0 -136
  108. package/docs/components-utilities.zh.md +0 -136
  109. package/docs/components.ja.md +0 -27
  110. package/docs/components.md +0 -27
  111. package/docs/components.zh-TW.md +0 -27
  112. package/docs/components.zh.md +0 -27
  113. package/docs/core-concepts.ja.md +0 -134
  114. package/docs/core-concepts.md +0 -135
  115. package/docs/core-concepts.zh-TW.md +0 -134
  116. package/docs/core-concepts.zh.md +0 -134
  117. package/docs/getting-started.ja.md +0 -132
  118. package/docs/getting-started.md +0 -132
  119. package/docs/getting-started.zh-TW.md +0 -132
  120. package/docs/getting-started.zh.md +0 -132
  121. package/docs/hooks-api.ja.md +0 -214
  122. package/docs/hooks-api.md +0 -214
  123. package/docs/hooks-api.zh-TW.md +0 -214
  124. package/docs/hooks-api.zh.md +0 -214
  125. package/docs/how-to-guides.ja.md +0 -413
  126. package/docs/how-to-guides.md +0 -413
  127. package/docs/how-to-guides.zh-TW.md +0 -413
  128. package/docs/how-to-guides.zh.md +0 -413
  129. package/docs/overview.ja.md +0 -51
  130. package/docs/overview.md +0 -51
  131. package/docs/overview.zh-TW.md +0 -51
  132. package/docs/overview.zh.md +0 -51
  133. package/glossary.md +0 -12
  134. package/src/@types/index.ts +0 -230
  135. package/src/@types/shims.d.ts +0 -18
  136. package/src/BlockletStudio/README.md +0 -116
  137. package/src/BlockletStudio/index.tsx +0 -145
  138. package/src/ComponentInstaller/ComponentInstaller.stories.jsx +0 -16
  139. package/src/ComponentInstaller/index.jsx +0 -207
  140. package/src/ComponentInstaller/installer-item.jsx +0 -129
  141. package/src/ComponentInstaller/locales.js +0 -22
  142. package/src/ComponentInstaller/use-component-installed.js +0 -88
  143. package/src/ComponentManager/components/add-component.tsx +0 -136
  144. package/src/ComponentManager/components/check-component.tsx +0 -3
  145. package/src/ComponentManager/components/publish-component.tsx +0 -90
  146. package/src/ComponentManager/components/resource-dialog.tsx +0 -91
  147. package/src/ComponentManager/index.tsx +0 -3
  148. package/src/ComponentManager/libs/locales.ts +0 -15
  149. package/src/Dashboard/Dashboard.stories.jsx +0 -20
  150. package/src/Dashboard/app-shell/app-badge.stories.tsx +0 -64
  151. package/src/Dashboard/app-shell/app-badge.tsx +0 -94
  152. package/src/Dashboard/app-shell/app-header.tsx +0 -104
  153. package/src/Dashboard/app-shell/app-info-context.tsx +0 -182
  154. package/src/Dashboard/app-shell/badges/app-badge-default.tsx +0 -130
  155. package/src/Dashboard/app-shell/badges/app-badge-did.tsx +0 -28
  156. package/src/Dashboard/app-shell/badges/app-badge-state.tsx +0 -40
  157. package/src/Dashboard/app-shell/badges/app-badge-switch.tsx +0 -72
  158. package/src/Dashboard/app-shell/badges/app-badge-version.tsx +0 -60
  159. package/src/Dashboard/app-shell/index.ts +0 -5
  160. package/src/Dashboard/index.jsx +0 -184
  161. package/src/Footer/Footer.stories.jsx +0 -33
  162. package/src/Footer/brand.jsx +0 -81
  163. package/src/Footer/copyright.jsx +0 -22
  164. package/src/Footer/index.jsx +0 -111
  165. package/src/Footer/internal-footer.jsx +0 -139
  166. package/src/Footer/layout/plain.jsx +0 -55
  167. package/src/Footer/layout/row.jsx +0 -43
  168. package/src/Footer/layout/standard.jsx +0 -114
  169. package/src/Footer/links.jsx +0 -321
  170. package/src/Footer/social-media.jsx +0 -55
  171. package/src/Header/Header.stories.jsx +0 -30
  172. package/src/Header/index.tsx +0 -259
  173. package/src/Icon/Icon.stories.jsx +0 -12
  174. package/src/Icon/index.tsx +0 -87
  175. package/src/Notifications/Snackbar.tsx +0 -261
  176. package/src/Notifications/hooks/use-title.tsx +0 -254
  177. package/src/Notifications/hooks/use-width.tsx +0 -16
  178. package/src/Notifications/utils.ts +0 -246
  179. package/src/UserCenter/assets/banner.png +0 -0
  180. package/src/UserCenter/components/config-inviter.tsx +0 -48
  181. package/src/UserCenter/components/config-profile.tsx +0 -99
  182. package/src/UserCenter/components/danger-zone.tsx +0 -82
  183. package/src/UserCenter/components/editable-field.tsx +0 -273
  184. package/src/UserCenter/components/fallback.tsx +0 -57
  185. package/src/UserCenter/components/nft-preview.tsx +0 -84
  186. package/src/UserCenter/components/nft.tsx +0 -279
  187. package/src/UserCenter/components/notification.tsx +0 -319
  188. package/src/UserCenter/components/passport.tsx +0 -107
  189. package/src/UserCenter/components/privacy.tsx +0 -120
  190. package/src/UserCenter/components/settings.tsx +0 -170
  191. package/src/UserCenter/components/status-dialog/date-picker.tsx +0 -77
  192. package/src/UserCenter/components/status-dialog/index.tsx +0 -293
  193. package/src/UserCenter/components/status-selector/duration-menu.tsx +0 -90
  194. package/src/UserCenter/components/status-selector/index.tsx +0 -58
  195. package/src/UserCenter/components/status-selector/menu-item.tsx +0 -56
  196. package/src/UserCenter/components/storage/action.tsx +0 -49
  197. package/src/UserCenter/components/storage/connected.tsx +0 -61
  198. package/src/UserCenter/components/storage/delete.tsx +0 -72
  199. package/src/UserCenter/components/storage/disconnect.tsx +0 -40
  200. package/src/UserCenter/components/storage/icons/empty-spaces-nft.svg +0 -1
  201. package/src/UserCenter/components/storage/icons/long-arrow.svg +0 -5
  202. package/src/UserCenter/components/storage/icons/space-connected.svg +0 -3
  203. package/src/UserCenter/components/storage/icons/space-disconnect.svg +0 -3
  204. package/src/UserCenter/components/storage/index.tsx +0 -41
  205. package/src/UserCenter/components/storage/preview-nft.tsx +0 -72
  206. package/src/UserCenter/components/third-party-login/index.tsx +0 -199
  207. package/src/UserCenter/components/third-party-login/third-party-item.tsx +0 -296
  208. package/src/UserCenter/components/user-center.tsx +0 -787
  209. package/src/UserCenter/components/user-info/address.tsx +0 -143
  210. package/src/UserCenter/components/user-info/index.tsx +0 -4
  211. package/src/UserCenter/components/user-info/link-preview-input.tsx +0 -274
  212. package/src/UserCenter/components/user-info/metadata.tsx +0 -658
  213. package/src/UserCenter/components/user-info/social-actions/chat.tsx +0 -43
  214. package/src/UserCenter/components/user-info/social-actions/follow.tsx +0 -23
  215. package/src/UserCenter/components/user-info/social-actions/index.tsx +0 -17
  216. package/src/UserCenter/components/user-info/switch-role.tsx +0 -42
  217. package/src/UserCenter/components/user-info/timezone-select.tsx +0 -119
  218. package/src/UserCenter/components/user-info/user-basic-info.tsx +0 -292
  219. package/src/UserCenter/components/user-info/user-info-item.tsx +0 -54
  220. package/src/UserCenter/components/user-info/user-info.tsx +0 -91
  221. package/src/UserCenter/components/user-info/user-status.tsx +0 -234
  222. package/src/UserCenter/components/user-info/utils.ts +0 -320
  223. package/src/UserCenter/components/webhook-item.tsx +0 -248
  224. package/src/UserCenter/index.tsx +0 -1
  225. package/src/UserCenter/libs/locales.ts +0 -378
  226. package/src/UserCenter/libs/utils.ts +0 -30
  227. package/src/UserSessions/components/user-session-info.tsx +0 -78
  228. package/src/UserSessions/components/user-sessions.tsx +0 -545
  229. package/src/UserSessions/index.tsx +0 -1
  230. package/src/UserSessions/libs/locales.ts +0 -60
  231. package/src/UserSessions/libs/utils.ts +0 -82
  232. package/src/blocklets.js +0 -195
  233. package/src/common/domain-warning.jsx +0 -178
  234. package/src/common/header-addons.jsx +0 -119
  235. package/src/common/link-blocker.jsx +0 -20
  236. package/src/common/notification-addon.jsx +0 -135
  237. package/src/common/org-switch/avatar-uploader.jsx +0 -271
  238. package/src/common/org-switch/create.jsx +0 -267
  239. package/src/common/org-switch/index.jsx +0 -407
  240. package/src/common/org-switch/locales.js +0 -52
  241. package/src/common/org-switch/use-org.jsx +0 -79
  242. package/src/common/overridable-theme-provider.jsx +0 -17
  243. package/src/common/wallet-hidden-topbar.js +0 -14
  244. package/src/common/wizard-modal.jsx +0 -200
  245. package/src/common/ws.js +0 -68
  246. package/src/contexts/config-user-space.tsx +0 -88
  247. package/src/contexts/user-followers.tsx +0 -54
  248. package/src/hooks/use-follow.tsx +0 -75
  249. package/src/hooks/use-mobile.tsx +0 -6
  250. package/src/index.ts +0 -16
  251. package/src/libs/constant.ts +0 -1
  252. package/src/libs/spaces.tsx +0 -18
  253. package/src/libs/with-hide-when-embed.tsx +0 -24
  254. package/src/types.js +0 -45
  255. package/src/utils.js +0 -161
  256. package/vite.config.mjs +0 -34
@@ -1,658 +0,0 @@
1
- import { Icon } from '@iconify/react';
2
- import { Box, Backdrop, useMediaQuery, SwipeableDrawer, Typography, Tooltip } from '@mui/material';
3
- import type { BackdropProps } from '@mui/material';
4
-
5
- import styled from '@emotion/styled';
6
- import Button from '@arcblock/ux/lib/Button';
7
- import PhoneInput, {
8
- PhoneValue,
9
- validatePhoneNumber,
10
- getDialCodeByCountry,
11
- getCountryNameByCountry,
12
- detectCountryFromPhone,
13
- } from '@arcblock/ux/lib/PhoneInput';
14
- import cloneDeep from 'lodash/cloneDeep';
15
- import omit from 'lodash/omit';
16
- import { mergeSx } from '@arcblock/ux/lib/Util/style';
17
- import { LOGIN_PROVIDER } from '@arcblock/ux/lib/Util/constant';
18
- import { useCreation, useMemoizedFn, useReactive } from 'ahooks';
19
- import { useMemo, useRef, useState, memo, useEffect } from 'react';
20
- import { translate } from '@arcblock/ux/lib/Locale/util';
21
- import isEmail from 'validator/lib/isEmail';
22
- import isPostalCode from 'validator/lib/isPostalCode';
23
- import { useLocaleContext } from '@arcblock/ux/lib/Locale/context';
24
- import { useBrowser } from '@arcblock/react-hooks';
25
- import Clock from '@arcblock/ux/lib/UserCard/Content/clock';
26
-
27
- import EmailIcon from '@arcblock/icons/lib/Email';
28
- import PhoneIcon from '@arcblock/icons/lib/Phone';
29
- import TimezoneIcon from '@arcblock/icons/lib/Timezone';
30
- import LocationIcon from '@arcblock/icons/lib/Location';
31
-
32
- import { translations } from '../../libs/locales';
33
- import type { User, UserAddress, UserMetadata, UserPhoneProps } from '../../../@types';
34
- import EditableField, { commonInputStyle, inputFieldStyle } from '../editable-field';
35
- import { LinkPreviewInput } from './link-preview-input';
36
- import { defaultButtonStyle, primaryButtonStyle } from './utils';
37
- import { TimezoneSelect } from './timezone-select';
38
- import AddressEditor from './address';
39
-
40
- const iconSize = {
41
- width: 20,
42
- height: 20,
43
- };
44
-
45
- const bioMaxLength = 200;
46
-
47
- const BackdropWrap = memo(function BackdropWrap({
48
- ref,
49
- ...backdropProps
50
- }: BackdropProps & {
51
- // eslint-disable-next-line react/require-default-props
52
- ref?: React.Ref<unknown>;
53
- }) {
54
- return (
55
- <Backdrop
56
- ref={ref}
57
- component="div"
58
- style={{
59
- backgroundColor: 'rgba(0, 0, 0, 0.6)',
60
- backdropFilter: 'blur(3px)',
61
- touchAction: 'none',
62
- }}
63
- {...backdropProps}
64
- key="background"
65
- />
66
- );
67
- });
68
-
69
- // 添加 displayName
70
- BackdropWrap.displayName = 'BackdropWrap';
71
-
72
- export default function UserMetadataComponent({
73
- isMyself,
74
- user,
75
- onSave,
76
- isMobile,
77
- }: {
78
- isMobile: boolean;
79
- isMyself: boolean;
80
- user: User;
81
- onSave: (v: { metadata: UserMetadata; address: UserAddress }) => void;
82
- }) {
83
- const [editable, setEditable] = useState(false);
84
- const [visible, setVisible] = useState(false);
85
- const drawerDragger = useRef(null);
86
- const browser = useBrowser();
87
- const isMobileView = useMediaQuery('(max-width:640px)') || browser.mobile.any;
88
- const validateMsg = useReactive<Record<string, string>>({
89
- email: '',
90
- phone: '',
91
- });
92
- const addressValidateMsg = useReactive<Record<string, string>>({
93
- country: '',
94
- province: '',
95
- city: '',
96
- line1: '',
97
- line2: '',
98
- postalCode: '',
99
- });
100
-
101
- useEffect(() => {
102
- if (!isMobileView) {
103
- setVisible(false);
104
- }
105
- }, [isMobileView]);
106
-
107
- const phoneVerified = useCreation(() => {
108
- return user?.phoneVerified ?? false;
109
- }, [user?.phoneVerified]);
110
-
111
- const emailVerified = useCreation(() => {
112
- return user?.emailVerified ?? false;
113
- }, [user?.emailVerified]);
114
-
115
- const { locale } = useLocaleContext();
116
- const t = useMemoizedFn((key, data = {}) => {
117
- return translate(translations, key, locale, 'en', data);
118
- });
119
-
120
- const metadata: UserMetadata = useReactive(
121
- user?.metadata
122
- ? cloneDeep(user.metadata)
123
- : {
124
- joinedAt: user?.createdAt,
125
- email: user?.email,
126
- phone: {
127
- country: 'cn',
128
- phoneNumber: user?.phone ?? '',
129
- },
130
- }
131
- );
132
-
133
- const address: UserAddress = useReactive(
134
- user?.address
135
- ? cloneDeep(user.address)
136
- : {
137
- country: '',
138
- province: '',
139
- city: '',
140
- line1: '',
141
- line2: '',
142
- postalCode: '',
143
- }
144
- );
145
-
146
- // 判断是否支持地址, 如果已经支持则返回 {}, 否则返回为 undefined
147
- const isSupportAddress = useCreation(() => {
148
- return !!user?.address;
149
- }, [user?.address?.country]);
150
-
151
- /**
152
- * 获取默认的国家
153
- * 如果 address 中存储有 country 信息就使用 address 中的信息
154
- * 如果没有根据 locale 获取,如果是中文环境,默认 country 是中国,如果是其他就选择美国
155
- */
156
- const defaultCountry = useMemo(() => {
157
- if (user?.address?.country) {
158
- return user.address.country;
159
- }
160
-
161
- return locale === 'zh' ? 'cn' : 'us';
162
- }, [user?.address?.country, locale]);
163
-
164
- const phoneValue = useCreation((): PhoneValue => {
165
- const phone = metadata.phone ??
166
- user?.phone ?? {
167
- country: defaultCountry,
168
- phone: '',
169
- };
170
-
171
- if (phone && typeof phone === 'string') {
172
- const detectedCountry = detectCountryFromPhone(phone);
173
- return {
174
- country: detectedCountry || defaultCountry,
175
- phone,
176
- };
177
- }
178
- if (phone && typeof phone === 'object') {
179
- const { country: phoneCountry = '', phoneNumber = '' } = phone as UserPhoneProps;
180
- const detectedCountry = !phoneCountry ? detectCountryFromPhone(phoneNumber) || '' : phoneCountry;
181
-
182
- return {
183
- country: detectedCountry,
184
- phone: phoneNumber || '',
185
- };
186
- }
187
-
188
- return {
189
- country: defaultCountry,
190
- phone: '',
191
- };
192
- }, [metadata.phone, user?.phone, defaultCountry]);
193
-
194
- const onChange = (v: any, field: keyof UserMetadata | 'email' | 'phone') => {
195
- metadata[field] = v;
196
- };
197
-
198
- const onAddressChange = (field: keyof UserAddress, value: string) => {
199
- address[field] = value;
200
-
201
- if (field === 'city') {
202
- onChange(value, 'location');
203
- }
204
-
205
- if (field === 'postalCode') {
206
- addressValidateMsg.postalCode =
207
- value && !isPostalCode(value, 'any') ? t('profile.address.invalidPostalCode') : '';
208
- } else {
209
- addressValidateMsg[field] = '';
210
- }
211
- };
212
-
213
- const onEdit = () => {
214
- if (!isMobileView) {
215
- setEditable(true);
216
- } else {
217
- setVisible(true);
218
- }
219
- };
220
-
221
- const onCancel = () => {
222
- const defaultMetadata: UserMetadata = cloneDeep(user?.metadata) ?? {};
223
- if (defaultMetadata) {
224
- Object.keys(metadata).forEach((key) => {
225
- const k = key as keyof UserMetadata;
226
- (metadata[k] as any) = defaultMetadata[k];
227
- });
228
- }
229
-
230
- const defaultAddress: UserAddress = cloneDeep(user?.address) ?? {};
231
- if (defaultAddress) {
232
- Object.keys(address).forEach((key) => {
233
- const k = key as keyof UserAddress;
234
- (address[k] as any) = defaultAddress[k];
235
- });
236
- }
237
-
238
- // 清空校验状态
239
- [validateMsg, addressValidateMsg].forEach((o) => {
240
- Object.keys(o).forEach((key) => {
241
- o[key] = '';
242
- });
243
- });
244
-
245
- if (!isMobileView) {
246
- setEditable(false);
247
- } else {
248
- setVisible(false);
249
- }
250
- };
251
-
252
- const links = useMemo(() => {
253
- const defaultLinks = metadata?.links?.map((link) => link.url) || [''];
254
- return defaultLinks.length > 0 ? defaultLinks : [''];
255
- }, [metadata.links]);
256
-
257
- const handleLinksChange = (values: string[]) => {
258
- const newLinks = values.map((link) => {
259
- if (!link) {
260
- return {
261
- url: link,
262
- };
263
- }
264
- const targetLink = metadata.links?.find((l) => l.url === link);
265
- if (targetLink) {
266
- return {
267
- ...targetLink,
268
- url: link,
269
- };
270
- }
271
- return {
272
- url: link,
273
- favicon: link,
274
- };
275
- });
276
- onChange(newLinks, 'links');
277
- };
278
-
279
- const handleSave = () => {
280
- Object.keys(metadata).forEach((key) => {
281
- const k = key as keyof UserMetadata;
282
- const value = metadata[k];
283
- if (value && typeof value === 'string') {
284
- (metadata[k] as string) = value.trim();
285
- }
286
- if (k === 'bio') {
287
- metadata[k] = metadata[k]?.slice(0, bioMaxLength);
288
- }
289
- if (k === 'timezone') {
290
- metadata[k] = (value as string) || '';
291
- }
292
- if (k === 'phone' && value && typeof value === 'object') {
293
- const phoneInput = value as UserPhoneProps;
294
- const dialCode = getDialCodeByCountry(phoneInput.country);
295
- // 去除电话号码中的区号部分
296
- const phoneWithoutCode = phoneInput.phoneNumber?.replace(new RegExp(`^\\+${dialCode}`), '') || '';
297
-
298
- const hasActualPhoneNumber = phoneWithoutCode?.trim().length > 0;
299
-
300
- metadata[k] = {
301
- country: phoneInput.country,
302
- ...(hasActualPhoneNumber ? { phoneNumber: phoneInput.phoneNumber } : {}),
303
- };
304
- }
305
- });
306
-
307
- // 单独处理邮政编码验证,避免嵌套三元表达式
308
- if (address.postalCode && !isPostalCode(address.postalCode, 'any')) {
309
- addressValidateMsg.postalCode = t('profile.address.invalidPostalCode');
310
- }
311
-
312
- // 检查是否有错误
313
- if ([validateMsg, addressValidateMsg].some((o) => Object.values(o).some((e) => e))) {
314
- return;
315
- }
316
-
317
- // 兼容代码。移除之前的 detailedAddress 字段
318
- const newAddress = omit(address, 'detailedAddress');
319
- // 添加默认值
320
- if (!newAddress.country) {
321
- newAddress.country = defaultCountry;
322
- }
323
-
324
- onSave({ metadata, address: newAddress });
325
- setEditable(false);
326
- setVisible(false);
327
- };
328
-
329
- const renderEdit = (editing: boolean, mode: 'drawer' | 'self' = 'self') => {
330
- return (
331
- <MetadataInfo
332
- pt={2}
333
- display="flex"
334
- flexDirection="column"
335
- justifyContent="space-between"
336
- alignItems="flex-start"
337
- gap={!isMobile ? '16px' : '4px'}>
338
- <EditableField
339
- value={metadata.bio ?? ''}
340
- onChange={(value) => onChange(value, 'bio')}
341
- editable={editing}
342
- placeholder="Bio"
343
- component="textarea"
344
- inline={false}
345
- rows={3}
346
- label={t('profile.bio')}
347
- maxLength={bioMaxLength}
348
- style={{
349
- ...(editing ? { marginBottom: 8 } : {}),
350
- }}
351
- />
352
- {!editing && isMyself ? (
353
- <Button
354
- size={isMobile ? 'small' : 'large'}
355
- variant="outlined"
356
- sx={{
357
- ...defaultButtonStyle,
358
- mb: !isMobile ? 2 : '4px',
359
- mt: !isMobile ? 2 : '4px',
360
- height: !isMobile ? '40px' : '32px',
361
- }}
362
- onClick={onEdit}
363
- fullWidth>
364
- {t('profile.editProfile')}
365
- </Button>
366
- ) : null}
367
- {editing && isMyself && isSupportAddress ? (
368
- <AddressEditor
369
- address={address}
370
- errors={addressValidateMsg}
371
- handleChange={onAddressChange}
372
- defaultCountry={defaultCountry}
373
- />
374
- ) : (
375
- <EditableField
376
- value={metadata.location ?? user?.address?.city ?? ''}
377
- onChange={(value) => onChange(value, 'location')}
378
- editable={editing}
379
- placeholder="Location"
380
- label={t('profile.location')}
381
- tooltip={
382
- isMyself && (address.line1 || address.line2) ? (
383
- <>
384
- {['line1', 'line2'].map((k) => {
385
- const value = address[k as keyof UserAddress];
386
- if (!value) {
387
- return null;
388
- }
389
- return (
390
- <Box key={k}>
391
- <Typography
392
- variant="caption"
393
- component="p"
394
- sx={{
395
- fontWeight: 600,
396
- mb: 0,
397
- }}>
398
- {t(`profile.address.${k}`)}
399
- </Typography>
400
- <Typography variant="caption" component="span">
401
- {address[k as keyof UserAddress]}
402
- </Typography>
403
- </Box>
404
- );
405
- })}
406
- </>
407
- ) : null
408
- }
409
- renderValue={() => {
410
- const countryName = address?.country ? getCountryNameByCountry(address?.country) : '';
411
- const fullLocation = [countryName, address.province, address.city || metadata.location || '']
412
- .filter(Boolean)
413
- .join(' ');
414
- return <Typography component="span">{fullLocation}</Typography>;
415
- }}
416
- icon={<LocationIcon {...iconSize} />}
417
- />
418
- )}
419
- <EditableField
420
- value={metadata.timezone || ''}
421
- onChange={(value) => onChange(value, 'timezone')}
422
- editable={editing}
423
- placeholder="timezone"
424
- icon={<TimezoneIcon {...iconSize} />}
425
- label={t('profile.timezone')}
426
- renderValue={(value) => {
427
- return <Clock value={value} />;
428
- }}>
429
- <TimezoneSelect
430
- value={metadata.timezone ?? ''}
431
- onChange={(value) => onChange(value, 'timezone')}
432
- disabled={!editing}
433
- mode={mode}
434
- />
435
- </EditableField>
436
- <EditableField
437
- value={metadata.email ?? user?.email ?? ''}
438
- editable={editing}
439
- hidePreview={!isMyself}
440
- disabled={user?.sourceProvider === LOGIN_PROVIDER.EMAIL}
441
- canEdit={!emailVerified}
442
- verified={emailVerified}
443
- placeholder="Email"
444
- icon={<EmailIcon {...iconSize} />}
445
- label={
446
- <>
447
- {t('profile.email')}
448
- {user?.sourceProvider === LOGIN_PROVIDER.EMAIL ? (
449
- <Tooltip title={t('profile.emailSourceProviderNotAllowEdit')}>
450
- <Box
451
- component={Icon}
452
- icon="mdi:info-outline"
453
- sx={{
454
- verticalAlign: 'middle',
455
- ml: 0.25,
456
- }}
457
- />
458
- </Tooltip>
459
- ) : null}
460
- </>
461
- }
462
- onChange={(value) => onChange(value, 'email')}
463
- errorMsg={validateMsg.email}
464
- renderValue={(value) =>
465
- isMyself ? (
466
- <a
467
- href={`mailto:${value}`}
468
- style={{
469
- color: 'inherit',
470
- textDecoration: 'none',
471
- }}>
472
- {value}
473
- </a>
474
- ) : null
475
- }
476
- onValueValidate={(value) => {
477
- let msg = '';
478
- if (!!value && !isEmail(value)) {
479
- msg = t('profile.emailInvalid');
480
- }
481
- validateMsg.email = msg;
482
- }}
483
- />
484
- <EditableField
485
- value={phoneValue.phone}
486
- editable={editing}
487
- hidePreview={!isMyself}
488
- canEdit={!phoneVerified}
489
- verified={phoneVerified}
490
- placeholder="Phone"
491
- icon={<PhoneIcon {...iconSize} />}
492
- onChange={(value) => onChange(value, 'phone')}
493
- label={t('profile.phone')}
494
- renderValue={() => {
495
- return isMyself ? <PhoneInput value={phoneValue} preview /> : null;
496
- }}>
497
- <PhoneInput
498
- variant="outlined"
499
- className="editable-field"
500
- slotProps={{
501
- input: {
502
- sx: { backgroundColor: 'transparent' },
503
- placeholder: 'Phone',
504
- },
505
- }}
506
- value={phoneValue}
507
- error={!!validateMsg.phone}
508
- helperText={validateMsg.phone}
509
- sx={mergeSx(inputFieldStyle, !validateMsg.phone ? commonInputStyle : {})}
510
- onChange={(value: any) => {
511
- const isValid = validatePhoneNumber(value.phone, value.country);
512
- if (!isValid) {
513
- validateMsg.phone = t('profile.phoneInvalid');
514
- } else {
515
- validateMsg.phone = '';
516
- }
517
- onChange(
518
- {
519
- country: value.country,
520
- phoneNumber: value.phone,
521
- },
522
- 'phone'
523
- );
524
- }}
525
- />
526
- </EditableField>
527
- <LinkPreviewInput editable={editing} links={links} onChange={handleLinksChange} />
528
- {editing && isMyself ? (
529
- <Box
530
- style={{ width: '100%' }}
531
- sx={{
532
- display: 'flex',
533
- gap: 1,
534
- justifyContent: 'flex-end',
535
- flexDirection: mode === 'drawer' ? 'column' : 'row',
536
- }}>
537
- <Button
538
- fullWidth={mode === 'drawer'}
539
- size="small"
540
- variant="outlined"
541
- sx={{ ...defaultButtonStyle, minWidth: '54px' }}
542
- onClick={onCancel}>
543
- {t('common.cancel')}
544
- </Button>
545
- <Button
546
- fullWidth={mode === 'drawer'}
547
- size="small"
548
- disabled={!!validateMsg.email || !!validateMsg.phone}
549
- variant="outlined"
550
- sx={{
551
- ...primaryButtonStyle,
552
- minWidth: '54px',
553
- '&.Mui-disabled': {
554
- backgroundColor: 'rgba(0, 0, 0, 0.12)',
555
- },
556
- }}
557
- onClick={handleSave}>
558
- {t('common.save')}
559
- </Button>
560
- </Box>
561
- ) : null}
562
- </MetadataInfo>
563
- );
564
- };
565
-
566
- return (
567
- <>
568
- {renderEdit(editable)}
569
- {isMobileView && (
570
- <SwipeableDrawer
571
- sx={{
572
- zIndex: 9999,
573
- }}
574
- disableSwipeToOpen
575
- onOpen={onEdit}
576
- open={visible}
577
- anchor="bottom"
578
- onClose={onCancel}
579
- slots={{
580
- backdrop: BackdropWrap,
581
- }}
582
- slotProps={{
583
- paper: {
584
- sx: {
585
- boxShadow: '0px -2px 16px 0px rgba(0, 0, 0, 0.08)',
586
- borderRadius: 1.5, // 保持跟 DID Wallet 一致
587
- borderBottomLeftRadius: 0,
588
- borderBottomRightRadius: 0,
589
- },
590
- },
591
- }}>
592
- <Box
593
- ref={drawerDragger}
594
- sx={{
595
- padding: '16px 32px',
596
- margin: '-8px auto -16px',
597
- zIndex: 1,
598
- }}>
599
- <Box
600
- sx={{
601
- width: '48px',
602
- height: '4px',
603
- borderRadius: '100vw',
604
- backgroundColor: 'rgba(0, 0, 0, 0.2)',
605
- }}
606
- />
607
- </Box>
608
- <Box
609
- sx={{
610
- p: 2,
611
- maxHeight: '500px',
612
- overflowY: 'auto',
613
- }}>
614
- {renderEdit(true, 'drawer')}
615
- </Box>
616
- </SwipeableDrawer>
617
- )}
618
- </>
619
- );
620
- }
621
- const MetadataInfo = styled(Box)`
622
- width: 100%;
623
-
624
- .MuiOutlinedInput-root {
625
- padding: 8px;
626
- .MuiOutlinedInput-input {
627
- padding: 0;
628
- }
629
- }
630
- .timezone-select {
631
- min-width: 150px;
632
- &.disabled {
633
- padding: 4px 8px;
634
- fieldset {
635
- border: unset;
636
- }
637
- svg {
638
- display: none;
639
- }
640
- }
641
- }
642
- .info-row {
643
- display: flex;
644
- flex-direction: row;
645
- align-items: center;
646
- justify-content: center;
647
- gap: 4px;
648
- margin: 0;
649
- p {
650
- display: flex;
651
- align-items: center;
652
- margin: 0;
653
- font-size: 16px;
654
- font-weight: 400;
655
- color: #666;
656
- }
657
- }
658
- `;
@@ -1,43 +0,0 @@
1
- import { useMemo } from 'react';
2
- import { Button } from '@mui/material';
3
- import { useMemoizedFn } from 'ahooks';
4
- import { Icon } from '@iconify/react';
5
- import { translate } from '@arcblock/ux/lib/Locale/util';
6
- import { useLocaleContext } from '@arcblock/ux/lib/Locale/context';
7
-
8
- import { joinURL } from 'ufo';
9
- import { User } from '../../../../@types';
10
-
11
- import { translations } from '../../../libs/locales';
12
-
13
- const getDiscussKitMountPoint = () => {
14
- const { componentMountPoints = [] } = window.blocklet || {};
15
- const component = componentMountPoints.find((c: any) => c.name === 'did-comments');
16
- return component?.mountPoint;
17
- };
18
-
19
- function Chat({ user }: { user: User }) {
20
- const { locale } = useLocaleContext();
21
- const t = useMemoizedFn((key, data = {}) => {
22
- return translate(translations, key, locale, 'en', data);
23
- });
24
- // 获取 discuss kit 的挂载点
25
- const discussKitMountPoint = useMemo(() => getDiscussKitMountPoint(), []);
26
-
27
- const onNavigateToChat = useMemoizedFn(() => {
28
- window.open(joinURL(discussKitMountPoint, `/chat/dm/${user?.did}`), '_blank');
29
- });
30
-
31
- if (!discussKitMountPoint) {
32
- return null;
33
- }
34
-
35
- return (
36
- <Button fullWidth variant="outlined" color="inherit" onClick={onNavigateToChat} sx={{ borderColor: 'divider' }}>
37
- <Icon icon="tabler:message-dots" style={{ marginRight: 4 }} />
38
- {t('profile.chat')}
39
- </Button>
40
- );
41
- }
42
-
43
- export default Chat;