@blocklet/ui-react 2.9.13 → 2.9.14

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 (161) hide show
  1. package/build.config.ts +29 -0
  2. package/es/@types/index.d.ts +63 -0
  3. package/es/@types/index.js +0 -0
  4. package/es/@types/shims.d.ts +12 -0
  5. package/es/Dashboard/index.d.ts +41 -0
  6. package/es/Dashboard/index.js +63 -97
  7. package/es/Footer/brand.d.ts +22 -0
  8. package/es/Footer/brand.js +20 -37
  9. package/es/Footer/copyright.d.ts +18 -0
  10. package/es/Footer/copyright.js +14 -16
  11. package/es/Footer/index.d.ts +6 -0
  12. package/es/Footer/index.js +30 -56
  13. package/es/Footer/internal-footer.d.ts +29 -0
  14. package/es/Footer/internal-footer.js +67 -94
  15. package/es/Footer/layout/plain.d.ts +15 -0
  16. package/es/Footer/layout/plain.js +19 -37
  17. package/es/Footer/layout/row.d.ts +18 -0
  18. package/es/Footer/layout/row.js +9 -19
  19. package/es/Footer/layout/standard.d.ts +15 -0
  20. package/es/Footer/layout/standard.js +29 -57
  21. package/es/Footer/links.d.ts +22 -0
  22. package/es/Footer/links.js +72 -104
  23. package/es/Footer/social-media.d.ts +14 -0
  24. package/es/Footer/social-media.js +35 -35
  25. package/es/Header/index.d.ts +9 -0
  26. package/es/Header/index.js +55 -100
  27. package/es/Icon/index.d.ts +23 -0
  28. package/es/Icon/index.js +23 -58
  29. package/es/UserCenter/assets/banner.png +0 -0
  30. package/es/UserCenter/components/notification.d.ts +5 -0
  31. package/es/UserCenter/components/notification.js +276 -0
  32. package/es/UserCenter/components/passport.d.ts +6 -0
  33. package/es/UserCenter/components/passport.js +69 -0
  34. package/es/UserCenter/components/privacy.d.ts +11 -0
  35. package/es/UserCenter/components/privacy.js +99 -0
  36. package/es/UserCenter/components/settings.d.ts +10 -0
  37. package/es/UserCenter/components/settings.js +68 -0
  38. package/es/UserCenter/components/user-basic-info.d.ts +8 -0
  39. package/es/UserCenter/components/user-basic-info.js +66 -0
  40. package/es/UserCenter/components/user-center.d.ts +9 -0
  41. package/es/UserCenter/components/user-center.js +397 -0
  42. package/es/UserCenter/components/user-info-item.d.ts +10 -0
  43. package/es/UserCenter/components/user-info-item.js +54 -0
  44. package/es/UserCenter/components/user-info.d.ts +6 -0
  45. package/es/UserCenter/components/user-info.js +68 -0
  46. package/es/UserCenter/components/webhook-item.d.ts +3 -0
  47. package/es/UserCenter/components/webhook-item.js +243 -0
  48. package/es/UserCenter/index.d.ts +1 -0
  49. package/es/UserCenter/index.js +1 -0
  50. package/es/UserCenter/libs/client.d.ts +2 -0
  51. package/es/UserCenter/libs/client.js +2 -0
  52. package/es/UserCenter/libs/locales.d.ts +72 -0
  53. package/es/UserCenter/libs/locales.js +72 -0
  54. package/es/UserCenter/libs/utils.d.ts +4 -0
  55. package/es/UserCenter/libs/utils.js +14 -0
  56. package/es/blocklets.d.ts +16 -0
  57. package/es/blocklets.js +56 -45
  58. package/es/common/header-addons.d.ts +22 -0
  59. package/es/common/header-addons.js +41 -59
  60. package/es/common/link-blocker.d.ts +7 -0
  61. package/es/common/link-blocker.js +10 -17
  62. package/es/common/overridable-theme-provider.d.ts +18 -0
  63. package/es/common/overridable-theme-provider.js +6 -16
  64. package/es/common/wallet-hidden-topbar.d.ts +1 -0
  65. package/es/common/wallet-hidden-topbar.js +12 -10
  66. package/es/index.d.ts +5 -0
  67. package/es/index.js +5 -0
  68. package/es/types.d.ts +2 -0
  69. package/es/types.js +17 -11
  70. package/es/utils.d.ts +8 -0
  71. package/es/utils.js +21 -26
  72. package/lib/@types/index.d.ts +63 -0
  73. package/lib/@types/index.js +1 -0
  74. package/lib/@types/shims.d.ts +12 -0
  75. package/lib/Dashboard/index.d.ts +41 -0
  76. package/lib/Dashboard/index.js +44 -71
  77. package/lib/Footer/brand.d.ts +22 -0
  78. package/lib/Footer/brand.js +65 -30
  79. package/lib/Footer/copyright.d.ts +18 -0
  80. package/lib/Footer/copyright.js +18 -23
  81. package/lib/Footer/index.d.ts +6 -0
  82. package/lib/Footer/index.js +33 -42
  83. package/lib/Footer/internal-footer.d.ts +29 -0
  84. package/lib/Footer/internal-footer.js +43 -59
  85. package/lib/Footer/layout/plain.d.ts +15 -0
  86. package/lib/Footer/layout/plain.js +25 -30
  87. package/lib/Footer/layout/row.d.ts +18 -0
  88. package/lib/Footer/layout/row.js +34 -23
  89. package/lib/Footer/layout/standard.d.ts +15 -0
  90. package/lib/Footer/layout/standard.js +35 -41
  91. package/lib/Footer/links.d.ts +22 -0
  92. package/lib/Footer/links.js +163 -60
  93. package/lib/Footer/social-media.d.ts +14 -0
  94. package/lib/Footer/social-media.js +31 -25
  95. package/lib/Header/index.d.ts +9 -0
  96. package/lib/Header/index.js +83 -76
  97. package/lib/Icon/index.d.ts +23 -0
  98. package/lib/Icon/index.js +37 -51
  99. package/lib/UserCenter/assets/banner.png +0 -0
  100. package/lib/UserCenter/components/notification.d.ts +5 -0
  101. package/lib/UserCenter/components/notification.js +261 -0
  102. package/lib/UserCenter/components/passport.d.ts +6 -0
  103. package/lib/UserCenter/components/passport.js +86 -0
  104. package/lib/UserCenter/components/privacy.d.ts +11 -0
  105. package/lib/UserCenter/components/privacy.js +101 -0
  106. package/lib/UserCenter/components/settings.d.ts +10 -0
  107. package/lib/UserCenter/components/settings.js +81 -0
  108. package/lib/UserCenter/components/user-basic-info.d.ts +8 -0
  109. package/lib/UserCenter/components/user-basic-info.js +67 -0
  110. package/lib/UserCenter/components/user-center.d.ts +9 -0
  111. package/lib/UserCenter/components/user-center.js +376 -0
  112. package/lib/UserCenter/components/user-info-item.d.ts +10 -0
  113. package/lib/UserCenter/components/user-info-item.js +46 -0
  114. package/lib/UserCenter/components/user-info.d.ts +6 -0
  115. package/lib/UserCenter/components/user-info.js +94 -0
  116. package/lib/UserCenter/components/webhook-item.d.ts +3 -0
  117. package/lib/UserCenter/components/webhook-item.js +236 -0
  118. package/lib/UserCenter/index.d.ts +1 -0
  119. package/lib/UserCenter/index.js +13 -0
  120. package/lib/UserCenter/libs/client.d.ts +2 -0
  121. package/lib/UserCenter/libs/client.js +8 -0
  122. package/lib/UserCenter/libs/locales.d.ts +72 -0
  123. package/lib/UserCenter/libs/locales.js +78 -0
  124. package/lib/UserCenter/libs/utils.d.ts +4 -0
  125. package/lib/UserCenter/libs/utils.js +25 -0
  126. package/lib/blocklets.d.ts +16 -0
  127. package/lib/blocklets.js +28 -36
  128. package/lib/common/header-addons.d.ts +22 -0
  129. package/lib/common/header-addons.js +24 -36
  130. package/lib/common/link-blocker.d.ts +7 -0
  131. package/lib/common/link-blocker.js +10 -18
  132. package/lib/common/overridable-theme-provider.d.ts +18 -0
  133. package/lib/common/overridable-theme-provider.js +9 -14
  134. package/lib/common/wallet-hidden-topbar.d.ts +1 -0
  135. package/lib/common/wallet-hidden-topbar.js +1 -3
  136. package/lib/index.d.ts +5 -0
  137. package/lib/index.js +52 -0
  138. package/lib/types.d.ts +2 -0
  139. package/lib/types.js +3 -5
  140. package/lib/utils.d.ts +8 -0
  141. package/lib/utils.js +16 -23
  142. package/package.json +17 -11
  143. package/src/@types/index.ts +70 -0
  144. package/src/@types/shims.d.ts +12 -0
  145. package/src/UserCenter/assets/banner.png +0 -0
  146. package/src/UserCenter/components/notification.tsx +275 -0
  147. package/src/UserCenter/components/passport.tsx +83 -0
  148. package/src/UserCenter/components/privacy.tsx +107 -0
  149. package/src/UserCenter/components/settings.tsx +78 -0
  150. package/src/UserCenter/components/user-basic-info.tsx +70 -0
  151. package/src/UserCenter/components/user-center.tsx +410 -0
  152. package/src/UserCenter/components/user-info-item.tsx +50 -0
  153. package/src/UserCenter/components/user-info.tsx +85 -0
  154. package/src/UserCenter/components/webhook-item.tsx +243 -0
  155. package/src/UserCenter/index.tsx +1 -0
  156. package/src/UserCenter/libs/client.ts +3 -0
  157. package/src/UserCenter/libs/locales.ts +72 -0
  158. package/src/UserCenter/libs/utils.ts +21 -0
  159. package/src/blocklets.js +2 -0
  160. package/src/index.ts +9 -0
  161. /package/src/common/{link-blocker.js → link-blocker.jsx} +0 -0
@@ -0,0 +1,70 @@
1
+ import { Box, Chip, Typography } from '@mui/material';
2
+ import type { BoxProps } from '@mui/material';
3
+ import { Icon } from '@iconify/react';
4
+ import SwapHorizRoundedIcon from '@iconify-icons/material-symbols/swap-horiz-rounded';
5
+ import { temp as colors } from '@arcblock/ux/lib/Colors';
6
+ import DID from '@arcblock/ux/lib/DID';
7
+ import { useCreation } from 'ahooks';
8
+
9
+ import type { User } from '../../@types';
10
+
11
+ export default function UserBasicInfo({
12
+ user,
13
+ isMyself = true,
14
+ switchPassport,
15
+ ...rest
16
+ }: {
17
+ user: User;
18
+ isMyself: boolean;
19
+ switchPassport: () => void;
20
+ } & BoxProps) {
21
+ const currentRole = useCreation(
22
+ () => (user?.passports || [])?.find((item) => item.name === user.role),
23
+ [user?.passports, user?.role]
24
+ );
25
+
26
+ return (
27
+ <Box {...rest}>
28
+ <Typography
29
+ variant="h4"
30
+ sx={{
31
+ fontWeight: 'bold',
32
+ display: 'flex',
33
+ alignItems: 'center',
34
+ gap: 1,
35
+ mb: 1,
36
+ }}>
37
+ {user?.fullName}
38
+ {isMyself ? (
39
+ <Chip
40
+ label={currentRole?.title || user?.role || 'Guest'}
41
+ size="small"
42
+ variant="outlined"
43
+ sx={{
44
+ flexShrink: 0,
45
+ fontWeight: 'bold',
46
+ fontSize: '12px',
47
+ color: colors.textBase,
48
+ borderColor: colors.strokeBorderStrong,
49
+ backgroundColor: 'white',
50
+ textTransform: 'capitalize',
51
+ pr: 1,
52
+ pl: 0.5,
53
+ '&:hover': {
54
+ backgroundColor: 'rgba(0, 0, 0, 0.04)',
55
+ },
56
+ '&:active': {
57
+ boxShadow: 'none',
58
+ },
59
+ }}
60
+ clickable
61
+ deleteIcon={<Icon icon={SwapHorizRoundedIcon} color={colors.textBase} />}
62
+ onDelete={switchPassport}
63
+ onClick={switchPassport}
64
+ />
65
+ ) : null}
66
+ </Typography>
67
+ <DID did={user.did} copyable={false} />
68
+ </Box>
69
+ );
70
+ }
@@ -0,0 +1,410 @@
1
+ import { useContext } from 'react';
2
+ import { Box, CircularProgress, IconButton, Paper, Typography } from '@mui/material';
3
+ import type { PaperProps } from '@mui/material';
4
+ import { useCreation, useMemoizedFn, useMount, useRequest } from 'ahooks';
5
+ import { Icon } from '@iconify/react';
6
+ import SettingsOutlineRoundedIcon from '@iconify-icons/material-symbols/settings-outline-rounded';
7
+ import { SessionContext } from '@arcblock/did-connect/lib/Session';
8
+ import Avatar from '@arcblock/ux/lib/Avatar';
9
+ import Tabs from '@arcblock/ux/lib/Tabs';
10
+ import Empty from '@arcblock/ux/lib/Empty';
11
+ import { temp as colors } from '@arcblock/ux/lib/Colors';
12
+ import { useConfirm } from '@arcblock/ux/lib/Dialog';
13
+ import { translate } from '@arcblock/ux/lib/Locale/util';
14
+ import { useLocaleContext } from '@arcblock/ux/lib/Locale/context';
15
+ import { ErrorFallback } from '@arcblock/ux/lib/ErrorBoundary';
16
+ import cloneDeep from 'lodash/cloneDeep';
17
+ import { getQuery, withQuery } from 'ufo';
18
+ import type { AxiosError } from 'axios';
19
+
20
+ // @ts-ignore
21
+ import Header from '../../Header';
22
+ import { translations } from '../libs/locales';
23
+ import banner from '../assets/banner.png';
24
+ import UserInfo from './user-info';
25
+ import UserBasicInfo from './user-basic-info';
26
+ import type { SessionContext as TSessionContext, UserCenterTab } from '../../@types';
27
+ // @ts-ignore
28
+ import { formatBlockletInfo, getLocalizedNavigation } from '../../blocklets';
29
+ import Passport from './passport';
30
+ import Settings from './settings';
31
+ import { client } from '../libs/client';
32
+
33
+ export default function UserCenter({
34
+ children,
35
+ currentTab,
36
+ contentProps = {},
37
+ disableAutoRedirect = false,
38
+ autoPopupSetting = false,
39
+ }: {
40
+ children: any;
41
+ currentTab: string;
42
+ contentProps?: PaperProps;
43
+ disableAutoRedirect?: boolean;
44
+ autoPopupSetting?: boolean;
45
+ }) {
46
+ const { locale } = useLocaleContext();
47
+ const t = useMemoizedFn((key, data = {}) => {
48
+ return translate(translations, key, locale, 'en', data);
49
+ });
50
+ const sessionCtx: TSessionContext = useContext(SessionContext);
51
+ const session = sessionCtx?.session;
52
+
53
+ const currentDid = useCreation(() => {
54
+ const currentUrl = window.location.href;
55
+ const query = getQuery(currentUrl);
56
+ if (query?.did) {
57
+ if (Array.isArray(query.did)) {
58
+ return query.did[0];
59
+ }
60
+ return query.did;
61
+ }
62
+ return session?.user?.did;
63
+ }, [session?.user?.did]);
64
+
65
+ const isMyself = useCreation(() => {
66
+ if (session?.user) {
67
+ return currentDid === session?.user?.did;
68
+ }
69
+ return false;
70
+ }, [currentDid, session?.user?.did]);
71
+
72
+ const userState = useRequest(
73
+ async () => {
74
+ if (isMyself) {
75
+ return session.user;
76
+ }
77
+ if (currentDid) {
78
+ return await client.user.getUserPublicInfo({ did: currentDid });
79
+ }
80
+
81
+ throw new Error(t('noUserFound'));
82
+ },
83
+ {
84
+ refreshDeps: [currentDid, isMyself],
85
+ }
86
+ );
87
+
88
+ const privacyState = useRequest(
89
+ async () => {
90
+ if (userState.data && currentTab) {
91
+ const config = await client.user.getUserPrivacyConfig({ did: currentDid });
92
+ return config;
93
+ }
94
+ return null;
95
+ },
96
+ {
97
+ refreshDeps: [currentDid, userState.data, currentTab],
98
+ loadingDelay: 300,
99
+ }
100
+ );
101
+
102
+ const { confirmHolder, confirmApi } = useConfirm({
103
+ sx: {
104
+ '.MuiDialog-paper': {
105
+ borderRadius: 2,
106
+ },
107
+ '.ux-dialog_title': {
108
+ fontWeight: 600,
109
+ },
110
+ '.ux-dialog_closeButton': {
111
+ p: 1,
112
+ },
113
+ '.MuiDialogActions-root': {
114
+ display: {
115
+ xs: 'none',
116
+ md: 'flex',
117
+ },
118
+ },
119
+ },
120
+ });
121
+
122
+ const formattedBlocklet = useCreation(() => {
123
+ const blocklet = cloneDeep(window.blocklet);
124
+ try {
125
+ return formatBlockletInfo(blocklet);
126
+ } catch (e) {
127
+ console.error('Failed to format blocklet info', e, blocklet);
128
+ return blocklet;
129
+ }
130
+ }, []);
131
+
132
+ const userCenterTabs = useCreation<UserCenterTab[]>(() => {
133
+ const menus = formattedBlocklet?.navigation?.userCenter || [];
134
+ const localizedMenus = getLocalizedNavigation(menus, locale) || [];
135
+ return localizedMenus.map((x: any) => {
136
+ const value = x._rawLink ?? x.link;
137
+
138
+ return {
139
+ value,
140
+ label: x.title,
141
+ url: x.link,
142
+ protected: privacyState?.data?.[value] ?? false,
143
+ // icon: x.icon,
144
+ };
145
+ });
146
+ }, [formattedBlocklet, userState.data, privacyState?.data]);
147
+
148
+ const currentActiveTab = useCreation(() => {
149
+ return userCenterTabs.find((x) => x.value === currentTab);
150
+ }, [userCenterTabs]);
151
+
152
+ const handleChangeTab = useMemoizedFn((value) => {
153
+ const findTab = userCenterTabs.find((x) => x.value === value);
154
+ if (findTab) {
155
+ window.location.href = withQuery(findTab.url, {
156
+ did: isMyself ? undefined : currentDid,
157
+ });
158
+ }
159
+ });
160
+ const xsGridTemplateAreas = useCreation(() => {
161
+ return [
162
+ '"avatar settings"',
163
+ '"basicInfo basicInfo"',
164
+ userCenterTabs.length > 0 || !isMyself ? '"tabs tabs"' : null,
165
+ isMyself ? '"passport passport"' : null,
166
+ isMyself ? '"extraInfo extraInfo"' : null,
167
+ ];
168
+ }, [userCenterTabs, isMyself]);
169
+
170
+ const mdGridTemplateAreas = useCreation(() => {
171
+ if (!isMyself) {
172
+ return ['"avatar"', '"basicInfo"', '"tabs"'];
173
+ }
174
+ return [
175
+ '"avatar settings"',
176
+ '"basicInfo extraInfo"',
177
+ userCenterTabs.length > 0 ? '"tabs extraInfo"' : null,
178
+ '"passport extraInfo"',
179
+ ];
180
+ }, [userCenterTabs, isMyself]);
181
+
182
+ const openSettings = useMemoizedFn(() => {
183
+ confirmApi.open({
184
+ title: t('settings'),
185
+ content: (
186
+ <Settings
187
+ user={userState.data}
188
+ settings={{
189
+ userCenterTabs,
190
+ }}
191
+ sx={{ mt: -2 }}
192
+ onSave={async () => {
193
+ await privacyState.runAsync();
194
+ return privacyState.data;
195
+ }}
196
+ />
197
+ ),
198
+ showCancelButton: false,
199
+ confirmButtonText: t('done'),
200
+ onConfirm: confirmApi.close,
201
+ });
202
+ });
203
+
204
+ useMount(() => {
205
+ if (autoPopupSetting) {
206
+ openSettings();
207
+ }
208
+ });
209
+
210
+ const content = useCreation(() => {
211
+ if (userState.loading || session.loading) {
212
+ return null;
213
+ }
214
+ if (userState.error) {
215
+ const errorMessage =
216
+ (userState.error as AxiosError<{ error: string }>).response?.data?.error ||
217
+ userState.error.message ||
218
+ 'error occurred';
219
+
220
+ const formatError = {
221
+ message: errorMessage,
222
+ };
223
+ return <ErrorFallback error={formatError} />;
224
+ }
225
+
226
+ return (
227
+ <Box
228
+ sx={{
229
+ maxWidth: 1200,
230
+ margin: '0 auto',
231
+ px: 3,
232
+ pb: 3,
233
+ display: 'grid',
234
+ gap: 2.5,
235
+ gridTemplateAreas: {
236
+ xs: xsGridTemplateAreas.filter(Boolean).join(' '),
237
+ md: mdGridTemplateAreas.filter(Boolean).join(' '),
238
+ },
239
+ gridTemplateRows: {
240
+ xs: '64px auto auto auto',
241
+ md: '64px auto 1fr',
242
+ },
243
+ gridTemplateColumns: {
244
+ xs: '1fr',
245
+ md: isMyself ? '1fr 300px' : '1fr',
246
+ },
247
+ }}>
248
+ <Box>
249
+ <Avatar
250
+ src={userState.data?.avatar}
251
+ did={userState.data?.did}
252
+ size={120}
253
+ variant="circle"
254
+ shape="circle"
255
+ style={{
256
+ border: '4px solid #fff',
257
+ transform: 'translateY(-50%)',
258
+ borderRadius: '100%',
259
+ gridArea: 'avatar',
260
+ backgroundColor: '#fff',
261
+ }}
262
+ />
263
+ </Box>
264
+ {isMyself ? (
265
+ <Box
266
+ sx={{
267
+ gridArea: 'settings',
268
+ display: 'flex',
269
+ justifyContent: 'flex-end',
270
+ alignItems: 'center',
271
+ }}>
272
+ <IconButton
273
+ sx={{
274
+ borderRadius: 2,
275
+ color: colors.textBase,
276
+ backgroundColor: 'white',
277
+ border: `1px solid ${colors.strokeBorderBase}`,
278
+ }}
279
+ disableFocusRipple
280
+ onClick={openSettings}>
281
+ <Icon icon={SettingsOutlineRoundedIcon} />
282
+ </IconButton>
283
+ </Box>
284
+ ) : null}
285
+ <UserBasicInfo
286
+ isMyself={isMyself}
287
+ switchPassport={session.switchPassport}
288
+ user={userState.data}
289
+ sx={{
290
+ gridArea: 'basicInfo',
291
+ }}
292
+ />
293
+ {userCenterTabs.length > 0 && currentTab ? (
294
+ <Box
295
+ sx={{
296
+ gridArea: 'tabs',
297
+ overflow: 'auto',
298
+ padding: '1px',
299
+ }}>
300
+ <Tabs variant="card" tabs={userCenterTabs} current={currentTab} onChange={handleChangeTab} />
301
+ {!privacyState.data || privacyState.loading ? (
302
+ <Box
303
+ sx={{
304
+ height: '100%',
305
+ minWidth: '160px',
306
+ minHeight: '160px',
307
+ display: 'flex',
308
+ justifyContent: 'center',
309
+ alignItems: 'center',
310
+ }}>
311
+ <CircularProgress sx={{ color: colors.primary100 }} />
312
+ </Box>
313
+ ) : (
314
+ <>
315
+ {currentActiveTab?.protected && !isMyself ? (
316
+ <Paper variant="outlined" sx={{ mt: 2, borderRadius: 2, p: 2 }}>
317
+ <Empty>{t('underProtected')}</Empty>
318
+ </Paper>
319
+ ) : (
320
+ <>
321
+ {children && (
322
+ <Paper
323
+ {...contentProps}
324
+ variant="outlined"
325
+ sx={{ mt: 2, borderRadius: 2, p: 2, ...contentProps?.sx }}>
326
+ {children}
327
+ </Paper>
328
+ )}
329
+ </>
330
+ )}
331
+ </>
332
+ )}
333
+ </Box>
334
+ ) : null}
335
+ {!isMyself && userCenterTabs.length === 0 ? (
336
+ <Box
337
+ sx={{
338
+ gridArea: 'tabs',
339
+ overflow: 'auto',
340
+ padding: '1px',
341
+ }}>
342
+ <Paper
343
+ variant="outlined"
344
+ sx={{
345
+ borderRadius: 2,
346
+ p: 2,
347
+ }}>
348
+ <Empty>{t('emptyContent')}</Empty>
349
+ </Paper>
350
+ </Box>
351
+ ) : null}
352
+ {isMyself ? (
353
+ <>
354
+ <Box
355
+ sx={{
356
+ gridArea: 'passport',
357
+ }}>
358
+ <Typography variant="h5" sx={{ fontWeight: 'bold', mb: 1.5 }}>
359
+ Passport
360
+ </Typography>
361
+ <Passport user={userState.data} />
362
+ </Box>
363
+ <Box
364
+ sx={{
365
+ gridArea: 'extraInfo',
366
+ }}>
367
+ <UserInfo
368
+ user={userState.data}
369
+ sx={{
370
+ padding: 3,
371
+ borderRadius: 3,
372
+ }}
373
+ />
374
+ </Box>
375
+ </>
376
+ ) : null}
377
+ </Box>
378
+ );
379
+ }, [userState, userCenterTabs, mdGridTemplateAreas, xsGridTemplateAreas]);
380
+
381
+ if (!disableAutoRedirect && !currentTab && formattedBlocklet?.navigation?.userCenter?.length > 0) {
382
+ window.location.replace(formattedBlocklet?.navigation?.userCenter[0]?.link);
383
+ return null;
384
+ }
385
+
386
+ return (
387
+ <Box
388
+ sx={{
389
+ backgroundColor: colors.backgroundsBgSubtitle,
390
+ minHeight: '100vh',
391
+ }}>
392
+ <Header />
393
+ <Box
394
+ sx={{
395
+ pt: {
396
+ xs: `${(400 / 1280) * 100}%`,
397
+ sm: `${(300 / 1280) * 100}%`,
398
+ md: `${(200 / 1280) * 100}%`,
399
+ },
400
+ backgroundImage: `url(${banner})`,
401
+ backgroundSize: 'cover',
402
+ minHeight: '60px',
403
+ }}
404
+ />
405
+ {}
406
+ {content}
407
+ {confirmHolder}
408
+ </Box>
409
+ );
410
+ }
@@ -0,0 +1,50 @@
1
+ import { Box, Typography } from '@mui/material';
2
+ import { temp as colors } from '@arcblock/ux/lib/Colors';
3
+
4
+ type TUserInfoItemProps = {
5
+ data: {
6
+ icon: any;
7
+ title: string;
8
+ content: any;
9
+ };
10
+ };
11
+
12
+ export default function UserInfoItem({ data }: TUserInfoItemProps) {
13
+ return (
14
+ <Box
15
+ sx={{
16
+ display: 'grid',
17
+ gridTemplateColumns: 'auto 1fr',
18
+ gridTemplateAreas: `"icon title" ". content"`,
19
+ alignItems: 'center',
20
+ rowGap: 0.75,
21
+ columnGap: 1,
22
+ }}>
23
+ <Box
24
+ sx={{
25
+ gridArea: 'icon',
26
+ display: 'flex',
27
+ alignItems: 'center',
28
+ }}>
29
+ {data.icon}
30
+ </Box>
31
+ <Typography
32
+ sx={{
33
+ color: colors.textBase,
34
+ gridArea: 'title',
35
+ fontSize: '14px',
36
+ }}>
37
+ {data.title}
38
+ </Typography>
39
+ <Typography
40
+ sx={{
41
+ color: colors.textSubtitle,
42
+ whiteSpace: 'pre-wrap',
43
+ gridArea: 'content',
44
+ fontSize: '14px',
45
+ }}>
46
+ {data.content}
47
+ </Typography>
48
+ </Box>
49
+ );
50
+ }
@@ -0,0 +1,85 @@
1
+ import { Paper } from '@mui/material';
2
+ import type { PaperProps } from '@mui/material';
3
+ import { Icon } from '@iconify/react';
4
+ import { useMemoizedFn, useCreation } from 'ahooks';
5
+ import MailOutlineRoundedIcon from '@iconify-icons/material-symbols/mail-outline-rounded';
6
+ import ScheduleOutlineRoundedIcon from '@iconify-icons/material-symbols/schedule-outline-rounded';
7
+ import MoreTimeRoundedIcon from '@iconify-icons/material-symbols/more-time-rounded';
8
+ import CaptivePortalRoundedIcon from '@iconify-icons/material-symbols/captive-portal-rounded';
9
+ import { translate } from '@arcblock/ux/lib/Locale/util';
10
+ import { useLocaleContext } from '@arcblock/ux/lib/Locale/context';
11
+ import RelativeTime from '@arcblock/ux/lib/RelativeTime';
12
+
13
+ import UserInfoItem from './user-info-item';
14
+ import type { User } from '../../@types';
15
+ import { translations } from '../libs/locales';
16
+
17
+ export default function UserInfo({
18
+ user,
19
+ ...rest
20
+ }: {
21
+ user: User;
22
+ } & PaperProps) {
23
+ const { locale } = useLocaleContext();
24
+ const t = useMemoizedFn((key, data = {}) => {
25
+ return translate(translations, key, locale, 'en', data);
26
+ });
27
+
28
+ const readableProvider = useCreation(() => {
29
+ const nameMap = {
30
+ wallet: 'DID Wallet',
31
+ auth0: 'Auth0',
32
+ };
33
+ return nameMap[user.sourceProvider as keyof typeof nameMap] || t('unknown');
34
+ }, [user?.sourceProvider]);
35
+
36
+ const userInfoListData = [];
37
+ userInfoListData.push({
38
+ icon: <Icon fontSize={16} icon={MailOutlineRoundedIcon} />,
39
+ title: t('email'),
40
+ content: user?.email || t('emptyField'),
41
+ });
42
+ userInfoListData.push({
43
+ icon: <Icon fontSize={16} icon={ScheduleOutlineRoundedIcon} />,
44
+ title: t('lastLogin'),
45
+ content: (
46
+ <>
47
+ {user?.lastLoginAt || user?.lastLoginIp ? (
48
+ <>
49
+ {user?.lastLoginAt ? <RelativeTime locale={locale} value={user?.lastLoginAt} /> : null}
50
+ {user?.lastLoginAt && user?.lastLoginIp ? <br /> : null}
51
+ {user?.lastLoginIp}
52
+ </>
53
+ ) : (
54
+ t('unknown')
55
+ )}
56
+ </>
57
+ ),
58
+ });
59
+ userInfoListData.push({
60
+ icon: <Icon fontSize={16} icon={MoreTimeRoundedIcon} />,
61
+ title: t('createdAt'),
62
+ content: user?.createdAt ? <RelativeTime locale={locale} value={user?.createdAt} /> : t('unknown'),
63
+ });
64
+ userInfoListData.push({
65
+ icon: <Icon fontSize={16} icon={CaptivePortalRoundedIcon} />,
66
+ title: t('registerFrom'),
67
+ content: readableProvider,
68
+ });
69
+
70
+ return (
71
+ <Paper
72
+ variant="outlined"
73
+ {...rest}
74
+ sx={{
75
+ display: 'flex',
76
+ flexDirection: 'column',
77
+ gap: 3,
78
+ ...rest?.sx,
79
+ }}>
80
+ {userInfoListData.map((item) => (
81
+ <UserInfoItem key={item.title} data={item} />
82
+ ))}
83
+ </Paper>
84
+ );
85
+ }