@blocklet/ui-react 2.10.5 → 2.10.7

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.
@@ -51,6 +51,7 @@ export type User = UserPublicInfo & {
51
51
  didSpace?: Record<string, any>;
52
52
  connectedAccounts?: any[];
53
53
  locale?: string;
54
+ url: string;
54
55
  };
55
56
  export type UserCenterTab = {
56
57
  value: string;
@@ -67,6 +68,7 @@ export type Session = {
67
68
  logout: any;
68
69
  switch: any;
69
70
  switchDid: any;
71
+ refreshProfile: () => Promise<void>;
70
72
  switchProfile: any;
71
73
  switchPassport: any;
72
74
  refresh: Function;
@@ -1,11 +1,22 @@
1
+ import { LiteralUnion } from 'type-fest';
2
+ import type { BoxProps } from '@mui/material';
1
3
  import { BlockletMetaProps, SessionManagerProps } from '../@types';
2
- declare const _default: import("react").ComponentType<{
3
- meta: BlockletMetaProps;
4
- addons: Function | JSX.Element;
5
- sessionManagerProps: SessionManagerProps;
6
- homeLink: string;
7
- theme: object;
8
- hideNavMenu: boolean;
4
+ type HeaderProps = {
5
+ meta?: BlockletMetaProps;
6
+ addons?: Function | React.ReactNode;
7
+ sessionManagerProps?: SessionManagerProps;
8
+ homeLink?: string | Function;
9
+ theme?: object;
10
+ hideNavMenu?: boolean;
9
11
  bordered?: boolean;
10
- }>;
12
+ logo?: React.ReactNode;
13
+ brand?: React.ReactNode;
14
+ brandAddon?: React.ReactNode;
15
+ description?: React.ReactNode;
16
+ children?: React.ReactNode;
17
+ prepend?: React.ReactNode;
18
+ align?: 'left' | 'right';
19
+ maxWidth?: false | LiteralUnion<'xs' | 'sm' | 'md' | 'lg' | 'xl', string>;
20
+ };
21
+ declare const _default: import("react").ComponentType<HeaderProps & Omit<BoxProps, keyof HeaderProps>>;
11
22
  export default _default;
@@ -1,5 +1,5 @@
1
- import { jsx, jsxs } from "react/jsx-runtime";
2
- import { Box, Chip, IconButton, Typography } from "@mui/material";
1
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
2
+ import { Box, Chip, CircularProgress, IconButton, Tooltip, Typography } from "@mui/material";
3
3
  import { Icon } from "@iconify/react";
4
4
  import SwapHorizRoundedIcon from "@iconify-icons/material-symbols/swap-horiz-rounded";
5
5
  import SettingsOutlineRoundedIcon from "@iconify-icons/material-symbols/settings-outline-rounded";
@@ -11,7 +11,13 @@ import { useCreation, useMemoizedFn } from "ahooks";
11
11
  import { translate } from "@arcblock/ux/lib/Locale/util";
12
12
  import { useLocaleContext } from "@arcblock/ux/lib/Locale/context";
13
13
  import noop from "lodash/noop";
14
+ import RefreshOutlinedIcon from "@mui/icons-material/RefreshOutlined";
15
+ import { SessionContext } from "@arcblock/did-connect/lib/Session";
16
+ import { useContext, useState } from "react";
17
+ import Toast from "@arcblock/ux/lib/Toast";
18
+ import isEmpty from "lodash/isEmpty";
14
19
  import { translations } from "../../libs/locales.js";
20
+ import { formatAxiosError } from "../../libs/utils.js";
15
21
  export default function UserBasicInfo({
16
22
  user,
17
23
  isMyself = true,
@@ -22,6 +28,8 @@ export default function UserBasicInfo({
22
28
  ...rest
23
29
  }) {
24
30
  const { locale } = useLocaleContext();
31
+ const { session } = useContext(SessionContext);
32
+ const [loading, setLoading] = useState(false);
25
33
  const t = useMemoizedFn((key, data = {}) => {
26
34
  return translate(translations, key, locale, "en", data);
27
35
  });
@@ -34,6 +42,19 @@ export default function UserBasicInfo({
34
42
  if (!user) {
35
43
  return null;
36
44
  }
45
+ const refreshProfile = async () => {
46
+ try {
47
+ setLoading(true);
48
+ await session.refreshProfile();
49
+ session.refresh();
50
+ Toast.success(translate(translations, "refreshProfile.successfully", locale));
51
+ } catch (err) {
52
+ console.error(err);
53
+ Toast.error(formatAxiosError(err));
54
+ } finally {
55
+ setLoading(false);
56
+ }
57
+ };
37
58
  return /* @__PURE__ */ jsxs(
38
59
  Box,
39
60
  {
@@ -95,35 +116,48 @@ export default function UserBasicInfo({
95
116
  },
96
117
  children: [
97
118
  user?.fullName,
98
- isMyself ? /* @__PURE__ */ jsx(
99
- Chip,
100
- {
101
- label: currentRole?.title || user?.role || "Guest",
102
- size: "small",
103
- variant: "outlined",
104
- sx: {
105
- flexShrink: 0,
106
- fontWeight: "bold",
107
- fontSize: "12px",
108
- color: colors.textBase,
109
- borderColor: colors.strokeBorderStrong,
110
- backgroundColor: "transparent",
111
- textTransform: "capitalize",
112
- pr: 1,
113
- pl: 0.5,
114
- "&:hover": {
115
- backgroundColor: "rgba(0, 0, 0, 0.04)"
119
+ isMyself ? /* @__PURE__ */ jsxs(Fragment, { children: [
120
+ /* @__PURE__ */ jsx(
121
+ Chip,
122
+ {
123
+ label: currentRole?.title || user?.role || "Guest",
124
+ size: "small",
125
+ variant: "outlined",
126
+ sx: {
127
+ flexShrink: 0,
128
+ fontWeight: "bold",
129
+ fontSize: "12px",
130
+ color: colors.textBase,
131
+ borderColor: colors.strokeBorderStrong,
132
+ backgroundColor: "transparent",
133
+ textTransform: "capitalize",
134
+ pr: 1,
135
+ pl: 0.5,
136
+ "&:hover": {
137
+ backgroundColor: "rgba(0, 0, 0, 0.04)"
138
+ },
139
+ "&:active": {
140
+ boxShadow: "none"
141
+ }
116
142
  },
117
- "&:active": {
118
- boxShadow: "none"
119
- }
120
- },
121
- clickable: true,
122
- deleteIcon: /* @__PURE__ */ jsx(Icon, { icon: SwapHorizRoundedIcon, color: colors.textBase }),
123
- onDelete: switchPassport,
124
- onClick: switchPassport
125
- }
126
- ) : null
143
+ clickable: true,
144
+ deleteIcon: /* @__PURE__ */ jsx(Icon, { icon: SwapHorizRoundedIcon, color: colors.textBase }),
145
+ onDelete: switchPassport,
146
+ onClick: switchPassport
147
+ }
148
+ ),
149
+ !isEmpty(user.url) && /* @__PURE__ */ jsx(
150
+ Tooltip,
151
+ {
152
+ title: !loading && translate(translations, "refreshProfile.title", locale),
153
+ sx: { display: "flex", alignItems: "center" },
154
+ children: loading ? (
155
+ // @ts-expect-error
156
+ /* @__PURE__ */ jsx(CircularProgress, { size: "16px", sx: { color: theme?.colors?.primary, ml: 0.5 } })
157
+ ) : /* @__PURE__ */ jsx(RefreshOutlinedIcon, { onClick: refreshProfile })
158
+ }
159
+ )
160
+ ] }) : null
127
161
  ]
128
162
  }
129
163
  ),
@@ -39,6 +39,10 @@ export declare const translations: {
39
39
  };
40
40
  toPublic: string;
41
41
  currentPassport: string;
42
+ refreshProfile: {
43
+ title: string;
44
+ successfully: string;
45
+ };
42
46
  switchProfile: string;
43
47
  userInfo: string;
44
48
  myInfo: string;
@@ -125,6 +129,10 @@ export declare const translations: {
125
129
  };
126
130
  toPublic: string;
127
131
  currentPassport: string;
132
+ refreshProfile: {
133
+ title: string;
134
+ successfully: string;
135
+ };
128
136
  switchProfile: string;
129
137
  userInfo: string;
130
138
  myInfo: string;
@@ -39,6 +39,10 @@ export const translations = {
39
39
  },
40
40
  toPublic: "\u516C\u5F00 \u201C{name}\u201D \u9875\u9762",
41
41
  currentPassport: "\u5F53\u524D\u4F7F\u7528\u7684\u901A\u884C\u8BC1",
42
+ refreshProfile: {
43
+ title: "\u5237\u65B0\u4E2A\u4EBA\u4FE1\u606F",
44
+ successfully: "\u5237\u65B0\u4E2A\u4EBA\u4FE1\u606F\u6210\u529F"
45
+ },
42
46
  switchProfile: "\u5207\u6362",
43
47
  userInfo: "\u4E2A\u4EBA\u4FE1\u606F",
44
48
  myInfo: "\u6211\u7684\u4FE1\u606F",
@@ -125,6 +129,10 @@ export const translations = {
125
129
  },
126
130
  toPublic: 'Public "{name}" page',
127
131
  currentPassport: "Passport currently in use",
132
+ refreshProfile: {
133
+ title: "Refresh profile",
134
+ successfully: "Refresh profile successfully"
135
+ },
128
136
  switchProfile: "Switch",
129
137
  userInfo: "User Info",
130
138
  myInfo: "My Info",
@@ -187,7 +187,10 @@ export default function UserSessions({
187
187
  options: {
188
188
  customBodyRenderLite: (rawIndex) => {
189
189
  const x = safeData[rawIndex];
190
- return x.createdAt ? /* @__PURE__ */ jsx(RelativeTime, { value: x.createdAt, relativeRange: 3 * 86400 * 1e3, locale }) : t("unknown");
190
+ return x.createdAt ? (
191
+ // @ts-expect-error
192
+ /* @__PURE__ */ jsx(RelativeTime, { value: x.createdAt, relativeRange: 3 * 86400 * 1e3, locale })
193
+ ) : t("unknown");
191
194
  }
192
195
  }
193
196
  },
@@ -197,7 +200,10 @@ export default function UserSessions({
197
200
  options: {
198
201
  customBodyRenderLite: (rawIndex) => {
199
202
  const x = safeData[rawIndex];
200
- return x.status === "expired" ? t("expired") : /* @__PURE__ */ jsx(RelativeTime, { value: x.updatedAt, relativeRange: 3 * 86400 * 1e3, locale });
203
+ return x.status === "expired" ? t("expired") : (
204
+ // @ts-expect-error
205
+ /* @__PURE__ */ jsx(RelativeTime, { value: x.updatedAt, relativeRange: 3 * 86400 * 1e3, locale })
206
+ );
201
207
  }
202
208
  }
203
209
  },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@blocklet/ui-react",
3
- "version": "2.10.5",
3
+ "version": "2.10.7",
4
4
  "description": "Some useful front-end web components that can be used in Blocklets.",
5
5
  "keywords": [
6
6
  "react",
@@ -32,8 +32,8 @@
32
32
  "url": "https://github.com/ArcBlock/ux/issues"
33
33
  },
34
34
  "dependencies": {
35
- "@arcblock/bridge": "^2.10.5",
36
- "@arcblock/react-hooks": "^2.10.5",
35
+ "@arcblock/bridge": "^2.10.7",
36
+ "@arcblock/react-hooks": "^2.10.7",
37
37
  "@iconify-icons/logos": "^1.2.36",
38
38
  "@iconify-icons/material-symbols": "^1.2.58",
39
39
  "@iconify/react": "^4.1.1",
@@ -50,6 +50,7 @@
50
50
  "prop-types": "^15.8.1",
51
51
  "react-error-boundary": "^3.1.4",
52
52
  "react-placeholder": "^4.1.0",
53
+ "type-fest": "^4.22.0",
53
54
  "ua-parser-js": "^1.0.37",
54
55
  "ufo": "^1.5.3"
55
56
  },
@@ -78,5 +79,5 @@
78
79
  "jest": "^28.1.3",
79
80
  "unbuild": "^2.0.0"
80
81
  },
81
- "gitHead": "b5740a02ed3bae848a586abe9cd8b35d507f0152"
82
+ "gitHead": "865d3f490c7148b8ef706768add621409198a3c1"
82
83
  }
@@ -57,6 +57,7 @@ export type User = UserPublicInfo & {
57
57
  didSpace?: Record<string, any>;
58
58
  connectedAccounts?: any[];
59
59
  locale?: string;
60
+ url: string;
60
61
  };
61
62
 
62
63
  export type UserCenterTab = {
@@ -75,6 +76,8 @@ export type Session = {
75
76
  logout: any;
76
77
  switch: any;
77
78
  switchDid: any;
79
+
80
+ refreshProfile: () => Promise<void>;
78
81
  switchProfile: any;
79
82
  switchPassport: any;
80
83
 
@@ -7,6 +7,8 @@ import NavMenu from '@arcblock/ux/lib/NavMenu';
7
7
  import { useLocaleContext } from '@arcblock/ux/lib/Locale/context';
8
8
  import { temp as colors } from '@arcblock/ux/lib/Colors';
9
9
  import omit from 'lodash/omit';
10
+ import { LiteralUnion } from 'type-fest';
11
+ import type { BoxProps } from '@mui/material';
10
12
 
11
13
  import Icon from '../Icon';
12
14
  import OverridableThemeProvider from '../common/overridable-theme-provider';
@@ -56,6 +58,24 @@ const parseNavigation = (navigation: any) => {
56
58
  return { navItems, activeId: matchedIndex >= 0 ? flattened[matchedIndex].id : null };
57
59
  };
58
60
 
61
+ type HeaderProps = {
62
+ meta?: BlockletMetaProps;
63
+ addons?: Function | React.ReactNode;
64
+ sessionManagerProps?: SessionManagerProps;
65
+ homeLink?: string | Function;
66
+ theme?: object;
67
+ hideNavMenu?: boolean;
68
+ bordered?: boolean;
69
+ logo?: React.ReactNode;
70
+ brand?: React.ReactNode;
71
+ brandAddon?: React.ReactNode;
72
+ description?: React.ReactNode;
73
+ children?: React.ReactNode;
74
+ prepend?: React.ReactNode;
75
+ align?: 'left' | 'right';
76
+ maxWidth?: false | LiteralUnion<'xs' | 'sm' | 'md' | 'lg' | 'xl', string>;
77
+ };
78
+
59
79
  /**
60
80
  * 专门用于 (composable) blocklet 的 Header 组件, 解析 blocklet meta 中的数据, 通过组合 UX 中的 Header & NavMenu 组件来渲染
61
81
  */
@@ -71,15 +91,7 @@ function Header({
71
91
  theme: themeOverrides,
72
92
  hideNavMenu = false,
73
93
  ...rest
74
- }: {
75
- meta: BlockletMetaProps;
76
- addons: Function | JSX.Element;
77
- sessionManagerProps: SessionManagerProps;
78
- homeLink: string;
79
- theme: object;
80
- hideNavMenu: boolean;
81
- bordered?: boolean;
82
- }) {
94
+ }: HeaderProps & Omit<BoxProps, keyof HeaderProps>) {
83
95
  useWalletHiddenTopbar();
84
96
  const { locale } = useLocaleContext() || {};
85
97
  const formattedBlocklet = useMemo(() => {
@@ -1,4 +1,4 @@
1
- import { Box, Chip, IconButton, Typography } from '@mui/material';
1
+ import { Box, Chip, CircularProgress, IconButton, Tooltip, Typography } from '@mui/material';
2
2
  import type { BoxProps } from '@mui/material';
3
3
  import { Icon } from '@iconify/react';
4
4
  import SwapHorizRoundedIcon from '@iconify-icons/material-symbols/swap-horiz-rounded';
@@ -11,9 +11,17 @@ import { useCreation, useMemoizedFn } from 'ahooks';
11
11
  import { translate } from '@arcblock/ux/lib/Locale/util';
12
12
  import { useLocaleContext } from '@arcblock/ux/lib/Locale/context';
13
13
  import noop from 'lodash/noop';
14
+ import RefreshOutlinedIcon from '@mui/icons-material/RefreshOutlined';
15
+ import { SessionContext } from '@arcblock/did-connect/lib/Session';
16
+ import { useContext, useState } from 'react';
17
+ import Toast from '@arcblock/ux/lib/Toast';
18
+ import type { AxiosError } from 'axios';
19
+ import isEmpty from 'lodash/isEmpty';
20
+ import { SessionContext as TSessionContext } from '../../../@types';
14
21
 
15
22
  import { translations } from '../../libs/locales';
16
23
  import type { User } from '../../../@types';
24
+ import { formatAxiosError } from '../../libs/utils';
17
25
 
18
26
  export default function UserBasicInfo({
19
27
  user,
@@ -32,6 +40,9 @@ export default function UserBasicInfo({
32
40
  openSettings: () => void;
33
41
  } & BoxProps) {
34
42
  const { locale } = useLocaleContext();
43
+ const { session } = useContext<TSessionContext>(SessionContext);
44
+ const [loading, setLoading] = useState(false);
45
+
35
46
  const t = useMemoizedFn((key, data = {}) => {
36
47
  return translate(translations, key, locale, 'en', data);
37
48
  });
@@ -47,6 +58,20 @@ export default function UserBasicInfo({
47
58
  return null;
48
59
  }
49
60
 
61
+ const refreshProfile = async () => {
62
+ try {
63
+ setLoading(true);
64
+ await session.refreshProfile();
65
+ session.refresh();
66
+ Toast.success(translate(translations, 'refreshProfile.successfully', locale));
67
+ } catch (err) {
68
+ console.error(err);
69
+ Toast.error(formatAxiosError(err as AxiosError));
70
+ } finally {
71
+ setLoading(false);
72
+ }
73
+ };
74
+
50
75
  return (
51
76
  <Box
52
77
  {...rest}
@@ -55,6 +80,7 @@ export default function UserBasicInfo({
55
80
  ...rest.sx,
56
81
  }}>
57
82
  <Avatar
83
+ // @ts-ignore
58
84
  src={user?.avatar}
59
85
  did={user?.did}
60
86
  size={isSmallView ? 64 : 80}
@@ -103,32 +129,46 @@ export default function UserBasicInfo({
103
129
  }}>
104
130
  {user?.fullName}
105
131
  {isMyself ? (
106
- <Chip
107
- label={currentRole?.title || user?.role || 'Guest'}
108
- size="small"
109
- variant="outlined"
110
- sx={{
111
- flexShrink: 0,
112
- fontWeight: 'bold',
113
- fontSize: '12px',
114
- color: colors.textBase,
115
- borderColor: colors.strokeBorderStrong,
116
- backgroundColor: 'transparent',
117
- textTransform: 'capitalize',
118
- pr: 1,
119
- pl: 0.5,
120
- '&:hover': {
121
- backgroundColor: 'rgba(0, 0, 0, 0.04)',
122
- },
123
- '&:active': {
124
- boxShadow: 'none',
125
- },
126
- }}
127
- clickable
128
- deleteIcon={<Icon icon={SwapHorizRoundedIcon} color={colors.textBase} />}
129
- onDelete={switchPassport}
130
- onClick={switchPassport}
131
- />
132
+ <>
133
+ <Chip
134
+ label={currentRole?.title || user?.role || 'Guest'}
135
+ size="small"
136
+ variant="outlined"
137
+ sx={{
138
+ flexShrink: 0,
139
+ fontWeight: 'bold',
140
+ fontSize: '12px',
141
+ color: colors.textBase,
142
+ borderColor: colors.strokeBorderStrong,
143
+ backgroundColor: 'transparent',
144
+ textTransform: 'capitalize',
145
+ pr: 1,
146
+ pl: 0.5,
147
+ '&:hover': {
148
+ backgroundColor: 'rgba(0, 0, 0, 0.04)',
149
+ },
150
+ '&:active': {
151
+ boxShadow: 'none',
152
+ },
153
+ }}
154
+ clickable
155
+ deleteIcon={<Icon icon={SwapHorizRoundedIcon} color={colors.textBase} />}
156
+ onDelete={switchPassport}
157
+ onClick={switchPassport}
158
+ />
159
+ {!isEmpty(user.url) && (
160
+ <Tooltip
161
+ title={!loading && translate(translations, 'refreshProfile.title', locale)}
162
+ sx={{ display: 'flex', alignItems: 'center' }}>
163
+ {loading ? (
164
+ // @ts-expect-error
165
+ <CircularProgress size="16px" sx={{ color: theme?.colors?.primary, ml: 0.5 }} />
166
+ ) : (
167
+ <RefreshOutlinedIcon onClick={refreshProfile} />
168
+ )}
169
+ </Tooltip>
170
+ )}
171
+ </>
132
172
  ) : null}
133
173
  </Typography>
134
174
  <DID did={user.did} showQrcode copyable compact={!showFullDid} responsive={!showFullDid} locale={locale} />
@@ -39,6 +39,10 @@ export const translations = {
39
39
  },
40
40
  toPublic: '公开 “{name}” 页面',
41
41
  currentPassport: '当前使用的通行证',
42
+ refreshProfile: {
43
+ title: '刷新个人信息',
44
+ successfully: '刷新个人信息成功',
45
+ },
42
46
  switchProfile: '切换',
43
47
  userInfo: '个人信息',
44
48
  myInfo: '我的信息',
@@ -126,6 +130,10 @@ export const translations = {
126
130
  },
127
131
  toPublic: 'Public "{name}" page',
128
132
  currentPassport: 'Passport currently in use',
133
+ refreshProfile: {
134
+ title: 'Refresh profile',
135
+ successfully: 'Refresh profile successfully',
136
+ },
129
137
  switchProfile: 'Switch',
130
138
  userInfo: 'User Info',
131
139
  myInfo: 'My Info',
@@ -21,6 +21,7 @@ export default function UserSessionInfo({ user, sessionUser }: { readonly user:
21
21
  size={40}
22
22
  variant="circle"
23
23
  shape="circle"
24
+ // @ts-expect-error
24
25
  src={sessionUser.avatar}
25
26
  did={sessionUser.did}
26
27
  sx={{ flexShrink: 0 }}
@@ -209,6 +209,7 @@ export default function UserSessions({
209
209
  customBodyRenderLite: (rawIndex: number) => {
210
210
  const x = safeData[rawIndex];
211
211
  return x.createdAt ? (
212
+ // @ts-expect-error
212
213
  <RelativeTime value={x.createdAt} relativeRange={3 * 86400 * 1000} locale={locale} />
213
214
  ) : (
214
215
  t('unknown')
@@ -225,6 +226,7 @@ export default function UserSessions({
225
226
  return x.status === 'expired' ? (
226
227
  t('expired')
227
228
  ) : (
229
+ // @ts-expect-error
228
230
  <RelativeTime value={x.updatedAt} relativeRange={3 * 86400 * 1000} locale={locale} />
229
231
  );
230
232
  },