@blocklet/ui-react 2.9.13 → 2.9.15

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 (163) 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 +31 -57
  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 +56 -101
  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 +18 -11
  143. package/src/@types/index.ts +70 -0
  144. package/src/@types/shims.d.ts +12 -0
  145. package/src/Footer/index.jsx +1 -1
  146. package/src/Header/index.jsx +1 -1
  147. package/src/UserCenter/assets/banner.png +0 -0
  148. package/src/UserCenter/components/notification.tsx +275 -0
  149. package/src/UserCenter/components/passport.tsx +83 -0
  150. package/src/UserCenter/components/privacy.tsx +107 -0
  151. package/src/UserCenter/components/settings.tsx +78 -0
  152. package/src/UserCenter/components/user-basic-info.tsx +70 -0
  153. package/src/UserCenter/components/user-center.tsx +410 -0
  154. package/src/UserCenter/components/user-info-item.tsx +50 -0
  155. package/src/UserCenter/components/user-info.tsx +85 -0
  156. package/src/UserCenter/components/webhook-item.tsx +243 -0
  157. package/src/UserCenter/index.tsx +1 -0
  158. package/src/UserCenter/libs/client.ts +3 -0
  159. package/src/UserCenter/libs/locales.ts +72 -0
  160. package/src/UserCenter/libs/utils.ts +21 -0
  161. package/src/blocklets.js +2 -0
  162. package/src/index.ts +9 -0
  163. /package/src/common/{link-blocker.js → link-blocker.jsx} +0 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@blocklet/ui-react",
3
- "version": "2.9.13",
3
+ "version": "2.9.15",
4
4
  "description": "Some useful front-end web components that can be used in Blocklets.",
5
5
  "keywords": [
6
6
  "react",
@@ -20,11 +20,8 @@
20
20
  "scripts": {
21
21
  "lint": "eslint src tests --ext js --ext jsx",
22
22
  "lint:fix": "npm run lint -- --fix",
23
- "build": "npm run build:lib && npm run build:es && npm run autoexports",
24
- "build:lib": "babel src --out-dir lib --copy-files --no-copy-ignored",
25
- "build:es": "babel --config-file ./babel.config.es.js src --out-dir es --copy-files --no-copy-ignored",
26
- "autoexports": "node tools/auto-exports.js",
27
- "watch": "babel src --out-dir lib -w --copy-files --no-copy-ignored",
23
+ "build": "unbuild && node tools/auto-exports.js",
24
+ "watch": "CONSOLA_LEVEL=1 nodemon -e .jsx,.js,.ts,.tsx -w src -x 'yalc publish --push'",
28
25
  "precommit": "CI=1 npm run lint",
29
26
  "prepush": "CI=1 npm run lint",
30
27
  "prepublish": "npm run build",
@@ -61,14 +58,23 @@
61
58
  }
62
59
  },
63
60
  "dependencies": {
64
- "@arcblock/did-connect": "^2.9.13",
65
- "@arcblock/ux": "^2.9.13",
61
+ "@abtnode/constant": "1.16.23-beta-aeb9f5bd",
62
+ "@arcblock/did-connect": "^2.9.15",
63
+ "@arcblock/ux": "^2.9.15",
64
+ "@blocklet/js-sdk": "1.16.23-beta-aeb9f5bd",
66
65
  "@emotion/react": "^11.10.4",
67
66
  "@emotion/styled": "^11.10.4",
67
+ "@iconify-icons/material-symbols": "^1.2.58",
68
+ "@iconify/react": "^4.1.1",
68
69
  "@mui/material": "^5.14.8",
70
+ "ahooks": "^3.7.8",
71
+ "axios": "^0.27.2",
69
72
  "core-js": "^3.25.5",
70
73
  "iconify-icon": "^1.0.8",
71
- "react-error-boundary": "^3.1.4"
74
+ "iconify-icons-material-symbols-400": "^0.0.1",
75
+ "is-url": "^1.2.4",
76
+ "react-error-boundary": "^3.1.4",
77
+ "ufo": "^1.3.2"
72
78
  },
73
79
  "peerDependencies": {
74
80
  "react": ">=18.1.0"
@@ -83,7 +89,8 @@
83
89
  "@babel/preset-react": "^7.18.6",
84
90
  "eslint-plugin-react-hooks": "^4.6.0",
85
91
  "glob": "^10.3.3",
86
- "jest": "^28.1.3"
92
+ "jest": "^28.1.3",
93
+ "unbuild": "^2.0.0"
87
94
  },
88
- "gitHead": "c32202066e023e3ca91905f3d3292ac480325cd4"
95
+ "gitHead": "2402b2d3888dcac685215c373afd7651e6907acc"
89
96
  }
@@ -0,0 +1,70 @@
1
+ import type { Axios } from 'axios';
2
+
3
+ export type SessionContext = {
4
+ session: Session;
5
+ api: Axios;
6
+ };
7
+
8
+ export type User = {
9
+ did: string;
10
+ fullName: string;
11
+ role: string;
12
+ avatar: string;
13
+ email?: string;
14
+ phone?: string;
15
+ sourceProvider?: string;
16
+ lastLoginAt?: string;
17
+ lastLoginIp?: string;
18
+ createdAt?: string;
19
+ passports?: any[];
20
+ };
21
+
22
+ export type UserCenterTab = {
23
+ value: string;
24
+ label: string;
25
+ url: string;
26
+ protected: boolean;
27
+ icon?: string;
28
+ };
29
+
30
+ export type Session = {
31
+ loading: boolean;
32
+ user: User;
33
+ login: any;
34
+ logout: any;
35
+ switch: any;
36
+ switchDid: any;
37
+ switchProfile: any;
38
+ switchPassport: any;
39
+ };
40
+
41
+ export type WebhookType = 'slack' | 'api';
42
+ export type WebhookItemData = {
43
+ type: WebhookType;
44
+ url: string;
45
+ };
46
+
47
+ export type WebhookItemProps = {
48
+ onTest: (params: WebhookItemData) => void;
49
+ onSave: (params: WebhookItemData) => void;
50
+ onDelete?: (params: WebhookItemData) => void;
51
+ onCancel?: () => void;
52
+ edit: boolean;
53
+ type?: WebhookType;
54
+ url?: string;
55
+ };
56
+
57
+ export type CreatePassportProps = {
58
+ issuer: string;
59
+ title: string;
60
+ issuerDid: string;
61
+ issuerAvatarUrl: string;
62
+ ownerDid: string;
63
+ ownerName: string;
64
+ ownerAvatarUrl: string;
65
+ preferredColor?: string;
66
+ revoked?: boolean;
67
+ isDataUrl?: boolean;
68
+ width?: string;
69
+ height?: string;
70
+ };
@@ -0,0 +1,12 @@
1
+ declare module '@arcblock/ux/*';
2
+ declare module '@arcblock/did-connect/*';
3
+
4
+ declare module '@abtnode/constant';
5
+ declare module 'is-url';
6
+ declare module 'url-join';
7
+
8
+ declare module '*.png';
9
+
10
+ declare interface Window {
11
+ blocklet: any;
12
+ }
@@ -80,7 +80,7 @@ const StyledInternalFooter = styled(InternalFooter)`
80
80
  border-top: 1px solid #eee;
81
81
  color: ${(props) => props.theme.palette.grey[600]};
82
82
  ${({ $bgcolor }) => $bgcolor && `background-color: ${$bgcolor};`}
83
- font-family: Lato, Avenir, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif,
83
+ font-family: Inter, Avenir, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif,
84
84
  'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol';
85
85
  `;
86
86
 
@@ -138,7 +138,7 @@ Header.defaultProps = {
138
138
 
139
139
  const StyledUxHeader = styled(ResponsiveHeader)`
140
140
  ${({ $bgcolor }) => `background-color: ${$bgcolor || '#fff'};`}
141
- font-family: Lato, Avenir, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif,
141
+ font-family: Inter, Avenir, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif,
142
142
  'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol';
143
143
  .header-logo {
144
144
  min-width: 44px;
Binary file
@@ -0,0 +1,275 @@
1
+ import { ChangeEvent } from 'react';
2
+ import { Alert, Box, CircularProgress, Divider, Stack, Typography } from '@mui/material';
3
+ import { useCreation, useMemoizedFn, useReactive, useRequest } from 'ahooks';
4
+ import { Icon } from '@iconify/react';
5
+ import AddRoundedIcon from '@iconify-icons/material-symbols/add-rounded';
6
+ import Switch from '@arcblock/ux/lib/Switch';
7
+ import Button from '@arcblock/ux/lib/Button';
8
+ import { temp as colors } from '@arcblock/ux/lib/Colors';
9
+ import Toast from '@arcblock/ux/lib/Toast';
10
+ import { getWalletDid } from '@arcblock/ux/lib/SessionUser/libs/utils';
11
+ import { translate } from '@arcblock/ux/lib/Locale/util';
12
+ import { useLocaleContext } from '@arcblock/ux/lib/Locale/context';
13
+
14
+ import { translations } from '../libs/locales';
15
+ import WebhookItem from './webhook-item';
16
+ import { User, WebhookItemData } from '../../@types';
17
+ import { formatAxiosError } from '../libs/utils';
18
+ import { client } from '../libs/client';
19
+ import { AxiosError } from 'axios';
20
+
21
+ export default function Notification({ user }: { user: User }) {
22
+ const { locale } = useLocaleContext();
23
+ const t = useMemoizedFn((key, data = {}) => {
24
+ return translate(translations, key, locale, 'en', data);
25
+ });
26
+ const currentState = useReactive({
27
+ showAdd: false,
28
+ });
29
+
30
+ const notificationConfigState = useRequest(
31
+ async () => {
32
+ const data = await client.user.getUserNotificationConfig();
33
+ return data;
34
+ },
35
+ {
36
+ refreshDeps: [user],
37
+ loadingDelay: 300,
38
+ }
39
+ );
40
+ const notifications = useCreation(() => {
41
+ return {
42
+ wallet: true,
43
+ email: true,
44
+ phone: false,
45
+ ...(notificationConfigState?.data?.notifications || {}),
46
+ };
47
+ }, [notificationConfigState?.data?.notifications]);
48
+
49
+ const webhooks = useCreation(() => {
50
+ return notificationConfigState?.data?.webhooks || [];
51
+ }, [notificationConfigState?.data?.webhooks]);
52
+
53
+ const onSaveChanges = useMemoizedFn(async (values) => {
54
+ try {
55
+ await client.user.saveUserNotificationConfig(values);
56
+ Toast.success(t('saveSuccess'));
57
+ notificationConfigState.run();
58
+ } catch (err) {
59
+ Toast.error(formatAxiosError(err as AxiosError));
60
+ }
61
+ });
62
+
63
+ const handleChangeSwitch = useMemoizedFn(async (channel, value) => {
64
+ await onSaveChanges({
65
+ notifications: {
66
+ [channel]: value,
67
+ },
68
+ });
69
+ });
70
+ const handleTestWebhook = async (data: WebhookItemData) => {
71
+ try {
72
+ await client.user.testNotificationWebhook(data);
73
+ Toast.success(t('webhookTested'));
74
+ } catch (err) {
75
+ Toast.error(formatAxiosError(err as AxiosError));
76
+ }
77
+ };
78
+ const handleDeleteWebhook = useMemoizedFn(async (index) => {
79
+ await onSaveChanges({
80
+ webhooks: webhooks.filter((_: WebhookItemData, i: number) => i !== index),
81
+ });
82
+ });
83
+ const handleEditWebhook = useMemoizedFn(async (index, webhook) => {
84
+ await onSaveChanges({
85
+ webhooks: webhooks.map((item: WebhookItemData, i: number) => (i === index ? webhook : item)),
86
+ });
87
+ });
88
+ const handleAddWebhook = useMemoizedFn(async (webhook) => {
89
+ await onSaveChanges({
90
+ webhooks: [...webhooks, webhook],
91
+ });
92
+ currentState.showAdd = false;
93
+ });
94
+
95
+ if (notificationConfigState.error) {
96
+ return <Alert severity="error">{notificationConfigState.error.message}</Alert>;
97
+ }
98
+
99
+ if (notificationConfigState.loading || !notificationConfigState.data) {
100
+ return (
101
+ <Box
102
+ sx={{
103
+ display: 'flex',
104
+ justifyContent: 'center',
105
+ alignItems: 'center',
106
+ height: '100px',
107
+ }}>
108
+ <CircularProgress />
109
+ </Box>
110
+ );
111
+ }
112
+
113
+ return (
114
+ <Box sx={{ display: 'flex', flexDirection: 'column', gap: 2 }}>
115
+ <Box
116
+ sx={{
117
+ display: 'flex',
118
+ flexDirection: 'column',
119
+ gap: 1,
120
+ alignItems: 'start',
121
+ '.MuiFormControlLabel-root': {
122
+ gap: 1,
123
+ m: 0,
124
+ flexDirection: {
125
+ xs: 'row-reverse',
126
+ md: 'row',
127
+ },
128
+ width: {
129
+ xs: '100%',
130
+ md: 'unset',
131
+ },
132
+ },
133
+
134
+ '.MuiSwitch-track': {
135
+ borderRadius: '100vw',
136
+ },
137
+ '.MuiSwitch-thumb': {
138
+ borderRadius: '100%',
139
+ },
140
+ '.MuiSwitch-root.MuiSwitch-sizeSmall': {
141
+ height: '20px',
142
+ width: '36px',
143
+ '.MuiSwitch-thumb': {
144
+ width: '16px',
145
+ height: '16px',
146
+ },
147
+ },
148
+ }}>
149
+ <Switch
150
+ checked={notifications.wallet}
151
+ labelProps={{
152
+ label: (
153
+ <Typography
154
+ color="text.primary"
155
+ sx={{
156
+ fontSize: 14,
157
+ display: 'flex',
158
+ flexFlow: 'wrap',
159
+ columnGap: 1,
160
+ flex: 1,
161
+ }}>
162
+ {t('walletNotification')}
163
+ {getWalletDid(user) && (
164
+ <Typography component="span" color="text.secondary" fontSize={13}>
165
+ {getWalletDid(user)}
166
+ </Typography>
167
+ )}
168
+ </Typography>
169
+ ),
170
+ }}
171
+ size="small"
172
+ onChange={(event: ChangeEvent<HTMLInputElement>) => handleChangeSwitch('wallet', event.target.checked)}
173
+ />
174
+ <Switch
175
+ checked={notifications.email}
176
+ labelProps={{
177
+ label: (
178
+ <Typography
179
+ color="text.primary"
180
+ sx={{
181
+ fontSize: 14,
182
+ display: 'flex',
183
+ flexFlow: 'wrap',
184
+ columnGap: 1,
185
+ flex: 1,
186
+ }}>
187
+ {t('emailNotification')}
188
+ {user?.email && (
189
+ <Typography component="span" color="text.secondary" fontSize={13}>
190
+ {user?.email}
191
+ </Typography>
192
+ )}
193
+ </Typography>
194
+ ),
195
+ }}
196
+ size="small"
197
+ onChange={(event: ChangeEvent<HTMLInputElement>) => handleChangeSwitch('email', event.target.checked)}
198
+ />
199
+ <Switch
200
+ disabled
201
+ checked={notifications.phone}
202
+ labelProps={{
203
+ label: (
204
+ <Typography
205
+ color="text.primary"
206
+ sx={{
207
+ fontSize: 14,
208
+ display: 'flex',
209
+ flexFlow: 'wrap',
210
+ columnGap: 1,
211
+ flex: 1,
212
+ }}>
213
+ {t('phoneNotification')}
214
+ {user?.phone && (
215
+ <Typography component="span" color="text.secondary" fontSize={13}>
216
+ {user?.phone}
217
+ </Typography>
218
+ )}
219
+ </Typography>
220
+ ),
221
+ }}
222
+ size="small"
223
+ onChange={(event: ChangeEvent<HTMLInputElement>) => handleChangeSwitch('phone', event.target.checked)}
224
+ />
225
+ </Box>
226
+ <Divider />
227
+ <Stack spacing={1.5} useFlexGap direction="column" alignItems="start">
228
+ {webhooks.map((item: WebhookItemData, index: number) => (
229
+ <WebhookItem
230
+ // eslint-disable-next-line react/no-array-index-key
231
+ key={`${index}_${item.url}`}
232
+ onTest={handleTestWebhook}
233
+ onDelete={() => handleDeleteWebhook(index)}
234
+ onSave={(...args) => handleEditWebhook(index, ...args)}
235
+ type={item.type}
236
+ url={item.url}
237
+ edit={false}
238
+ />
239
+ ))}
240
+ {currentState.showAdd && (
241
+ <WebhookItem
242
+ key="add"
243
+ onTest={handleTestWebhook}
244
+ onCancel={() => {
245
+ currentState.showAdd = false;
246
+ }}
247
+ onSave={(...args) => handleAddWebhook(...args)}
248
+ edit
249
+ />
250
+ )}
251
+
252
+ <Button
253
+ variant="outlined"
254
+ size="small"
255
+ sx={{
256
+ color: colors.foregroundsFgBase,
257
+ borderColor: colors.strokeBorderBase,
258
+ backgroundColor: colors.buttonsButtonNeutral,
259
+ '&:hover': {
260
+ borderColor: colors.strokeBorderBase,
261
+ backgroundColor: colors.buttonsButtonNeutralHover,
262
+ },
263
+ py: 0.5,
264
+ borderRadius: 2,
265
+ }}
266
+ startIcon={<Icon icon={AddRoundedIcon} />}
267
+ onClick={() => {
268
+ currentState.showAdd = true;
269
+ }}>
270
+ {t('addWebhook')}
271
+ </Button>
272
+ </Stack>
273
+ </Box>
274
+ );
275
+ }
@@ -0,0 +1,83 @@
1
+ import { Stack } from '@mui/material';
2
+ import type { StackProps } from '@mui/material';
3
+ import Empty from '@arcblock/ux/lib/Empty';
4
+ import { useTheme } from '@arcblock/ux/lib/Theme';
5
+ import { temp as colors } from '@arcblock/ux/lib/Colors';
6
+ import { useLocaleContext } from '@arcblock/ux/lib/Locale/context';
7
+ import PassportItem from '@arcblock/ux/lib/Passport';
8
+ import { PASSPORT_STATUS } from '@abtnode/constant';
9
+ import { useCreation } from 'ahooks';
10
+ import uniqBy from 'lodash/uniqBy';
11
+
12
+ import { createPassportSvg } from '../libs/utils';
13
+ import type { User } from '../../@types';
14
+
15
+ export default function Passport({ user, ...rest }: { user: User } & StackProps) {
16
+ const { t } = useLocaleContext();
17
+ const theme = useTheme();
18
+ const passports = useCreation(() => {
19
+ const passportList = (user?.passports || []).map((x) => ({
20
+ ...x,
21
+ revoked: x.status === PASSPORT_STATUS.REVOKED,
22
+ }));
23
+ passportList.sort((a, b) => {
24
+ if (a.revoked === b.revoked) {
25
+ return 0;
26
+ }
27
+ if (a.revoked) {
28
+ return 1;
29
+ } else {
30
+ return -1;
31
+ }
32
+ });
33
+
34
+ return uniqBy(passportList, 'role');
35
+ }, [user?.passports]);
36
+
37
+ const currentRole = useCreation(() => passports?.find((item) => item.name === user.role), [passports, user?.role]);
38
+
39
+ const activeColor = useCreation(() => {
40
+ return theme?.palette?.primary?.main || colors.textBase;
41
+ }, [theme?.palette?.primary?.main]);
42
+
43
+ if (passports.length === 0) {
44
+ return <Empty>{t('noPassport')}</Empty>;
45
+ }
46
+
47
+ return (
48
+ <Stack direction="row" spacing={3} flexWrap="wrap" useFlexGap {...rest}>
49
+ {passports.map((x) => (
50
+ <PassportItem
51
+ key={x.id}
52
+ passport={x}
53
+ user={user}
54
+ width={200}
55
+ color={window.blocklet.passportColor}
56
+ createPassportSvg={createPassportSvg}
57
+ title={currentRole && currentRole.role === x.role ? t('currentPassport') : ''}
58
+ sx={{
59
+ flexDirection: 'column',
60
+ alignItems: 'center',
61
+ gap: 1,
62
+ '.passport-item__display': {
63
+ width: 166,
64
+ height: 166,
65
+ borderRadius: 2,
66
+ px: 2,
67
+ display: 'flex',
68
+ justifyContent: 'center',
69
+ backgroundColor: 'white',
70
+ boxShadow:
71
+ currentRole && currentRole.role === x.role
72
+ ? `0px 2px 4px 0px ${activeColor}, 0px 1px 2px -1px ${activeColor}, 0px 0px 0px 1px ${activeColor} !important`
73
+ : '0px 2px 4px 0px rgba(2, 7, 19, 0.04), 0px 1px 2px -1px rgba(2, 7, 19, 0.08), 0px 0px 0px 1px rgba(2, 7, 19, 0.08) !important',
74
+ },
75
+ '.passport-item__body': {
76
+ marginLeft: '0 !important',
77
+ },
78
+ }}
79
+ />
80
+ ))}
81
+ </Stack>
82
+ );
83
+ }
@@ -0,0 +1,107 @@
1
+ import { Box, Typography } from '@mui/material';
2
+ import Switch from '@arcblock/ux/lib/Switch';
3
+ import { ChangeEvent, useState } from 'react';
4
+ import { useMemoizedFn } from 'ahooks';
5
+ import { translate } from '@arcblock/ux/lib/Locale/util';
6
+ import { useLocaleContext } from '@arcblock/ux/lib/Locale/context';
7
+ import Toast from '@arcblock/ux/lib/Toast';
8
+ import type { AxiosError } from 'axios';
9
+
10
+ import { translations } from '../libs/locales';
11
+ import { client } from '../libs/client';
12
+ import { formatAxiosError } from '../libs/utils';
13
+
14
+ type PrivacyConfig = {
15
+ key: string;
16
+ name: string;
17
+ value: boolean;
18
+ };
19
+
20
+ export default function Privacy({ configList, onSave }: { configList: PrivacyConfig[]; onSave: () => void }) {
21
+ const [dataList, setDataList] = useState(configList);
22
+ const { locale } = useLocaleContext();
23
+ const t = useMemoizedFn((key, data = {}) => {
24
+ return translate(translations, key, locale, 'en', data);
25
+ });
26
+ const handleChangeSwitch = useMemoizedFn(async (type: string, value: boolean) => {
27
+ try {
28
+ const result = await client.user.saveUserPrivacyConfig({
29
+ [type]: !value,
30
+ });
31
+
32
+ setDataList(
33
+ dataList.map((item) => {
34
+ return {
35
+ ...item,
36
+ value: result?.[item.key] ?? item.value,
37
+ };
38
+ })
39
+ );
40
+ Toast.success(t('saveSuccess'));
41
+ onSave();
42
+ } catch (err) {
43
+ Toast.error(formatAxiosError(err as AxiosError));
44
+ }
45
+ });
46
+
47
+ return (
48
+ <Box
49
+ sx={{
50
+ display: 'flex',
51
+ flexDirection: 'column',
52
+ gap: 1,
53
+ alignItems: 'start',
54
+ '.MuiFormControlLabel-root': {
55
+ gap: 1,
56
+ m: 0,
57
+ flexDirection: {
58
+ xs: 'row-reverse',
59
+ md: 'row',
60
+ },
61
+ width: {
62
+ xs: '100%',
63
+ md: 'unset',
64
+ },
65
+ },
66
+
67
+ '.MuiSwitch-track': {
68
+ borderRadius: '100vw',
69
+ },
70
+ '.MuiSwitch-thumb': {
71
+ borderRadius: '100%',
72
+ },
73
+ '.MuiSwitch-root.MuiSwitch-sizeSmall': {
74
+ height: '20px',
75
+ width: '36px',
76
+ '.MuiSwitch-thumb': {
77
+ width: '16px',
78
+ height: '16px',
79
+ },
80
+ },
81
+ }}>
82
+ {dataList.map((item) => (
83
+ <Switch
84
+ key={item.key}
85
+ checked={!item.value}
86
+ labelProps={{
87
+ label: (
88
+ <Typography
89
+ color="text.primary"
90
+ sx={{
91
+ fontSize: 14,
92
+ display: 'flex',
93
+ flexFlow: 'wrap',
94
+ columnGap: 1,
95
+ flex: 1,
96
+ }}>
97
+ {t('toPublic', { name: item.name })}
98
+ </Typography>
99
+ ),
100
+ }}
101
+ size="small"
102
+ onChange={(event: ChangeEvent<HTMLInputElement>) => handleChangeSwitch(item.key, event.target.checked)}
103
+ />
104
+ ))}
105
+ </Box>
106
+ );
107
+ }