@blocklet/ui-react 2.9.67 → 2.9.69

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 (54) hide show
  1. package/es/@types/index.d.ts +38 -1
  2. package/es/@types/shims.d.ts +6 -0
  3. package/es/Dashboard/index.js +0 -1
  4. package/es/UserCenter/components/settings.js +7 -1
  5. package/es/UserCenter/components/third-party-login/index.d.ts +5 -0
  6. package/es/UserCenter/components/third-party-login/index.js +111 -0
  7. package/es/UserCenter/components/third-party-login/third-party-item.d.ts +13 -0
  8. package/es/UserCenter/components/third-party-login/third-party-item.js +227 -0
  9. package/es/UserCenter/components/user-center.js +22 -17
  10. package/es/UserCenter/components/user-info/index.d.ts +3 -0
  11. package/es/UserCenter/components/user-info/index.js +3 -0
  12. package/es/UserCenter/components/{user-basic-info.d.ts → user-info/user-basic-info.d.ts} +1 -1
  13. package/es/UserCenter/components/{user-basic-info.js → user-info/user-basic-info.js} +1 -1
  14. package/es/UserCenter/components/{user-info.d.ts → user-info/user-info.d.ts} +1 -1
  15. package/es/UserCenter/components/{user-info.js → user-info/user-info.js} +3 -6
  16. package/es/UserCenter/libs/locales.d.ts +20 -0
  17. package/es/UserCenter/libs/locales.js +20 -0
  18. package/es/UserSessions/components/user-sessions.js +1 -4
  19. package/lib/@types/index.d.ts +38 -1
  20. package/lib/@types/shims.d.ts +6 -0
  21. package/lib/Dashboard/index.js +1 -3
  22. package/lib/UserCenter/components/settings.js +8 -1
  23. package/lib/UserCenter/components/third-party-login/index.d.ts +5 -0
  24. package/lib/UserCenter/components/third-party-login/index.js +123 -0
  25. package/lib/UserCenter/components/third-party-login/third-party-item.d.ts +13 -0
  26. package/lib/UserCenter/components/third-party-login/third-party-item.js +235 -0
  27. package/lib/UserCenter/components/user-center.js +23 -16
  28. package/lib/UserCenter/components/user-info/index.d.ts +3 -0
  29. package/lib/UserCenter/components/user-info/index.js +27 -0
  30. package/lib/UserCenter/components/{user-basic-info.d.ts → user-info/user-basic-info.d.ts} +1 -1
  31. package/lib/UserCenter/components/{user-basic-info.js → user-info/user-basic-info.js} +1 -1
  32. package/lib/UserCenter/components/{user-info.d.ts → user-info/user-info.d.ts} +1 -1
  33. package/lib/UserCenter/components/{user-info.js → user-info/user-info.js} +3 -6
  34. package/lib/UserCenter/libs/locales.d.ts +20 -0
  35. package/lib/UserCenter/libs/locales.js +20 -0
  36. package/lib/UserSessions/components/user-sessions.js +1 -4
  37. package/package.json +10 -9
  38. package/src/@types/index.ts +42 -1
  39. package/src/@types/shims.d.ts +6 -0
  40. package/src/Dashboard/index.jsx +2 -1
  41. package/src/UserCenter/components/settings.tsx +7 -1
  42. package/src/UserCenter/components/third-party-login/index.tsx +133 -0
  43. package/src/UserCenter/components/third-party-login/third-party-item.tsx +239 -0
  44. package/src/UserCenter/components/user-center.tsx +24 -17
  45. package/src/UserCenter/components/user-info/index.tsx +3 -0
  46. package/src/UserCenter/components/{user-basic-info.tsx → user-info/user-basic-info.tsx} +2 -2
  47. package/src/UserCenter/components/{user-info.tsx → user-info/user-info.tsx} +4 -7
  48. package/src/UserCenter/libs/locales.ts +22 -0
  49. package/src/UserSessions/components/user-sessions.tsx +0 -3
  50. /package/es/UserCenter/components/{user-info-item.d.ts → user-info/user-info-item.d.ts} +0 -0
  51. /package/es/UserCenter/components/{user-info-item.js → user-info/user-info-item.js} +0 -0
  52. /package/lib/UserCenter/components/{user-info-item.d.ts → user-info/user-info-item.d.ts} +0 -0
  53. /package/lib/UserCenter/components/{user-info-item.js → user-info/user-info-item.js} +0 -0
  54. /package/src/UserCenter/components/{user-info-item.tsx → user-info/user-info-item.tsx} +0 -0
@@ -0,0 +1,239 @@
1
+ import { Icon } from '@iconify/react';
2
+ import { Box, ListItem, Tooltip, Typography } from '@mui/material';
3
+ import LinkRoundedIcon from '@iconify-icons/material-symbols/link-rounded';
4
+ import { temp as colors } from '@arcblock/ux/lib/Colors';
5
+ import Button from '@arcblock/ux/lib/Button';
6
+ import Avatar from '@arcblock/ux/lib/Avatar';
7
+ import { useCreation, useMemoizedFn, useReactive } from 'ahooks';
8
+ import { translate } from '@arcblock/ux/lib/Locale/util';
9
+ import { useConfirm } from '@arcblock/ux/lib/Dialog';
10
+ import { useLocaleContext } from '@arcblock/ux/lib/Locale/context';
11
+ import MailOutlineRoundedIcon from '@iconify-icons/material-symbols/mail-outline-rounded';
12
+ import InfoOutlineRoundedIcon from '@iconify-icons/material-symbols/info-outline-rounded';
13
+ import AppleIcon from '@iconify-icons/logos/apple';
14
+ import GithubIcon from '@iconify-icons/logos/github-icon';
15
+ import GoogleIcon from '@iconify-icons/logos/google-icon';
16
+ // import Auth0Icon from '@iconify-icons/logos/auth0-icon';
17
+ import { SessionContext } from '@arcblock/did-connect/lib/Session';
18
+ import { useContext } from 'react';
19
+ import pick from 'lodash/pick';
20
+ import { getFederatedEnabled, getMaster } from '@arcblock/ux/lib/Util/federated';
21
+ import { LOGIN_PROVIDER, OAUTH_PROVIDER } from '@arcblock/ux/lib/Util/constant';
22
+
23
+ import { translations } from '../../libs/locales';
24
+ import type { OAuthAccount, SessionContext as TSessionContext } from '../../../@types';
25
+
26
+ export default function ThirdPartyItem({
27
+ item,
28
+ }: {
29
+ item: {
30
+ provider: string;
31
+ did: string;
32
+ pk: string;
33
+ userInfo?: OAuthAccount['userInfo'];
34
+ _bind?: boolean;
35
+ _rawProvider?: string;
36
+ _mainProvider?: boolean;
37
+ };
38
+ }) {
39
+ const { confirmApi, confirmHolder } = useConfirm();
40
+ const currentState = useReactive({
41
+ loading: false,
42
+ });
43
+ const { locale } = useLocaleContext();
44
+ const t = useMemoizedFn((key, data = {}) => {
45
+ return translate(translations, key, locale, 'en', data);
46
+ });
47
+ const { session } = useContext<TSessionContext>(SessionContext);
48
+ const { bindOAuth, unbindOAuth, setBaseUrl, baseUrl: oauthBaseUrl } = session.useOAuth();
49
+
50
+ const iconMap = {
51
+ // email: MailOutlineRoundedIcon,
52
+ [LOGIN_PROVIDER.AUTH0]: MailOutlineRoundedIcon,
53
+ [LOGIN_PROVIDER.APPLE]: AppleIcon,
54
+ [LOGIN_PROVIDER.GITHUB]: GithubIcon,
55
+ [LOGIN_PROVIDER.GOOGLE]: GoogleIcon,
56
+ };
57
+
58
+ const icon = useCreation(() => {
59
+ return iconMap[item?.provider];
60
+ }, [item?.provider]);
61
+ const title = useCreation(() => {
62
+ return OAUTH_PROVIDER[item?.provider as keyof typeof OAUTH_PROVIDER] || 'unknown';
63
+ }, [item?.provider]);
64
+
65
+ const toggleBind = useMemoizedFn(async () => {
66
+ try {
67
+ currentState.loading = true;
68
+ await new Promise((resolve, reject) => {
69
+ if (item?._bind) {
70
+ confirmApi.open({
71
+ title: t('thirdPartyLogin.confirmUnbind', { name: title }),
72
+ content: t('thirdPartyLogin.confirmUnbindDescription', { name: title }),
73
+ confirmButtonText: t('common.confirm'),
74
+ cancelButtonText: t('common.cancel'),
75
+ onConfirm(close: () => void) {
76
+ unbindOAuth({
77
+ session,
78
+ connectedAccount: {
79
+ ...pick(item, ['did', 'pk']),
80
+ showProvider: item.provider,
81
+ provider: item._rawProvider,
82
+ },
83
+ })
84
+ .then(resolve)
85
+ .catch(reject);
86
+ close();
87
+ },
88
+ onCancel: resolve,
89
+ });
90
+ } else {
91
+ const backupBaseUrl = oauthBaseUrl;
92
+ const blocklet = window?.blocklet;
93
+ let baseUrl = '/';
94
+ const federatedEnabled = getFederatedEnabled(blocklet);
95
+ const master = getMaster(blocklet);
96
+ if (federatedEnabled && master?.appPid && session?.user?.sourceAppPid) {
97
+ baseUrl = master.appUrl;
98
+ }
99
+ setBaseUrl(baseUrl);
100
+ bindOAuth({
101
+ session,
102
+ oauthItem: {
103
+ ...item,
104
+ provider: item._rawProvider,
105
+ },
106
+ })
107
+ .then(resolve)
108
+ .catch(reject)
109
+ .finally(() => {
110
+ setBaseUrl(backupBaseUrl);
111
+ });
112
+ }
113
+ });
114
+ } catch (err) {
115
+ console.error(`Failed to ${item?._bind ? 'unbind' : 'bind'} oauth account`, err);
116
+ } finally {
117
+ currentState.loading = false;
118
+ }
119
+ });
120
+
121
+ return (
122
+ <>
123
+ <ListItem
124
+ disablePadding
125
+ sx={{
126
+ display: 'flex',
127
+ alignItems: 'center',
128
+ gap: 1,
129
+ }}>
130
+ <Box
131
+ sx={{
132
+ flex: 1,
133
+ borderRadius: 2,
134
+ border: `1px solid ${colors.strokeBorderBase}`,
135
+ background: colors.backgroundsBgField,
136
+ display: 'flex',
137
+ alignItems: 'center',
138
+ py: 1,
139
+ px: 1.5,
140
+ gap: 0.75,
141
+ fontSize: '14px',
142
+ lineHeight: 1,
143
+ }}>
144
+ <Icon icon={icon} fontSize={16} />
145
+ <Box
146
+ sx={{
147
+ display: 'flex',
148
+ alignItems: 'center',
149
+ justifyContent: 'space-between',
150
+ flex: 1,
151
+ gap: 1,
152
+ }}>
153
+ {title}
154
+ </Box>
155
+ <Box
156
+ sx={{
157
+ display: 'flex',
158
+ alignItems: 'center',
159
+ gap: 0.5,
160
+ }}>
161
+ {item.userInfo?.email || item.did}
162
+ {item.userInfo?.email ? (
163
+ <Tooltip
164
+ title={
165
+ <>
166
+ <Box sx={{ display: 'flex', alignItems: 'center', gap: 1 }}>
167
+ <Avatar size={36} variant="circle" shape="circle" src={item.userInfo?.picture} did={item.did} />
168
+ <Box>
169
+ <Typography
170
+ sx={{
171
+ whiteSpace: 'normal',
172
+ wordBreak: 'break-all',
173
+ fontSize: '0.9rem',
174
+ }}>
175
+ {item.userInfo?.name}
176
+ </Typography>
177
+ <Typography
178
+ sx={{
179
+ whiteSpace: 'normal',
180
+ wordBreak: 'break-all',
181
+ fontSize: '0.9rem',
182
+ }}>
183
+ {item.userInfo?.email}
184
+ </Typography>
185
+ </Box>
186
+ </Box>
187
+ {/* 暂不显示 oauth 账户的 did */}
188
+ {/* <Box
189
+ component={DID}
190
+ did={item.did}
191
+ sx={{
192
+ '& .did-address-text': {
193
+ color: 'white',
194
+ },
195
+ }}
196
+ /> */}
197
+ </>
198
+ }>
199
+ <Icon
200
+ icon={InfoOutlineRoundedIcon}
201
+ color={colors.textSubtitle}
202
+ fontSize={16}
203
+ style={{ cursor: 'pointer' }}
204
+ />
205
+ </Tooltip>
206
+ ) : null}
207
+ </Box>
208
+ </Box>
209
+ <Tooltip title={item._mainProvider ? t('thirdPartyLogin.mainProviderCantRemove') : ''}>
210
+ {/* HACK: 结合下面的 button disable 使用,必须增加这一层 */}
211
+ <Box>
212
+ <Button
213
+ variant="outlined"
214
+ size="small"
215
+ sx={{
216
+ color: item?._bind ? colors.red : colors.foregroundsFgBase,
217
+ borderColor: item?._bind ? colors.red : colors.strokeBorderBase,
218
+ backgroundColor: colors.buttonsButtonNeutral,
219
+ '&:hover': {
220
+ borderColor: item?._bind ? colors.red : colors.strokeBorderBase,
221
+ backgroundColor: colors.buttonsButtonNeutralHover,
222
+ },
223
+ py: 0.5,
224
+ borderRadius: 2,
225
+ fontWeight: 500,
226
+ }}
227
+ startIcon={currentState.loading ? null : <Icon icon={LinkRoundedIcon} />}
228
+ onClick={toggleBind}
229
+ disabled={item._mainProvider}
230
+ loading={currentState.loading}>
231
+ {item?._bind ? t('thirdPartyLogin.disconnect') : t('thirdPartyLogin.connect')}
232
+ </Button>
233
+ </Box>
234
+ </Tooltip>
235
+ </ListItem>
236
+ {confirmHolder}
237
+ </>
238
+ );
239
+ }
@@ -1,7 +1,7 @@
1
1
  import { useContext } from 'react';
2
2
  import { Box, CircularProgress, Typography } from '@mui/material';
3
3
  import type { BoxProps } from '@mui/material';
4
- import { useCreation, useMemoizedFn, useMount, useRequest } from 'ahooks';
4
+ import { useCreation, useMemoizedFn, useMount, useRequest, useUpdateEffect } from 'ahooks';
5
5
  import pWaitFor from 'p-wait-for';
6
6
 
7
7
  import { SessionContext } from '@arcblock/did-connect/lib/Session';
@@ -21,8 +21,7 @@ import type { UserPublicInfo } from '@blocklet/js-sdk';
21
21
  import Footer from '../../Footer';
22
22
  import Header from '../../Header';
23
23
  import { translations } from '../libs/locales';
24
- import UserInfo from './user-info';
25
- import UserBasicInfo from './user-basic-info';
24
+ import { UserInfo, UserBasicInfo } from './user-info';
26
25
  import type { SessionContext as TSessionContext, User, UserCenterTab } from '../../@types';
27
26
  // @ts-ignore
28
27
  import { formatBlockletInfo, getLocalizedNavigation } from '../../blocklets';
@@ -96,14 +95,14 @@ export default function UserCenter({
96
95
  }
97
96
  },
98
97
  {
99
- refreshDeps: [currentDid, isMyself, session?.initialized],
98
+ refreshDeps: [currentDid, isMyself, session?.initialized, session?.user],
100
99
  }
101
100
  );
102
101
 
103
102
  const privacyState = useRequest(
104
103
  async () => {
105
104
  if (userState.data && currentTab) {
106
- const config = await client.user.getUserPrivacyConfig({ did: currentDid });
105
+ const config = await client.user.getUserPrivacyConfig({ did: currentDid as string });
107
106
  return config;
108
107
  }
109
108
  return null;
@@ -174,27 +173,35 @@ export default function UserCenter({
174
173
  }
175
174
  });
176
175
 
176
+ const settingContent = useCreation(() => {
177
+ return (
178
+ <Settings
179
+ user={userState.data as User}
180
+ settings={{ userCenterTabs }}
181
+ onSave={async () => {
182
+ await privacyState.runAsync();
183
+ return privacyState.data;
184
+ }}
185
+ />
186
+ );
187
+ }, [userState.data]);
188
+
177
189
  const openSettings = useMemoizedFn(() => {
178
190
  confirmApi.open({
179
191
  title: t('settings'),
180
- content: (
181
- <Settings
182
- user={userState.data as User}
183
- settings={{
184
- userCenterTabs,
185
- }}
186
- onSave={async () => {
187
- await privacyState.runAsync();
188
- return privacyState.data;
189
- }}
190
- />
191
- ),
192
+ content: settingContent,
192
193
  showCancelButton: false,
193
194
  confirmButtonText: t('done'),
194
195
  onConfirm: confirmApi.close,
195
196
  });
196
197
  });
197
198
 
199
+ useUpdateEffect(() => {
200
+ confirmApi.update({
201
+ content: settingContent,
202
+ });
203
+ }, [settingContent]);
204
+
198
205
  useMount(() => {
199
206
  if (autoPopupSetting) {
200
207
  openSettings();
@@ -0,0 +1,3 @@
1
+ export { default as UserBasicInfo } from './user-basic-info';
2
+ export { default as UserInfoItem } from './user-info-item';
3
+ export { default as UserInfo } from './user-info';
@@ -12,8 +12,8 @@ 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
14
 
15
- import { translations } from '../libs/locales';
16
- import type { User } from '../../@types';
15
+ import { translations } from '../../libs/locales';
16
+ import type { User } from '../../../@types';
17
17
 
18
18
  export default function UserBasicInfo({
19
19
  user,
@@ -10,10 +10,11 @@ import SettingsInputAntennaRoundedIcon from '@iconify-icons/material-symbols/set
10
10
  import RelativeTime from '@arcblock/ux/lib/RelativeTime';
11
11
  import { translate } from '@arcblock/ux/lib/Locale/util';
12
12
  import { useLocaleContext } from '@arcblock/ux/lib/Locale/context';
13
+ import { LOGIN_PROVIDER_NAME } from '@arcblock/ux/lib/Util/constant';
13
14
 
14
- import { translations } from '../libs/locales';
15
+ import { translations } from '../../libs/locales';
15
16
  import UserInfoItem from './user-info-item';
16
- import type { User } from '../../@types';
17
+ import type { User } from '../../../@types';
17
18
 
18
19
  export default function UserInfo({
19
20
  user,
@@ -27,11 +28,7 @@ export default function UserInfo({
27
28
  });
28
29
 
29
30
  const readableProvider = useCreation(() => {
30
- const nameMap = {
31
- wallet: 'DID Wallet',
32
- auth0: 'Auth0',
33
- };
34
- return (user?.sourceProvider && nameMap[user.sourceProvider as keyof typeof nameMap]) || t('unknown');
31
+ return (user?.sourceProvider && LOGIN_PROVIDER_NAME[user.sourceProvider]) || t('unknown');
35
32
  }, [user?.sourceProvider]);
36
33
 
37
34
  const userInfoListData = [];
@@ -31,6 +31,8 @@ export const translations = {
31
31
  slack: 'Slack',
32
32
  },
33
33
  common: {
34
+ confirm: '确认',
35
+ cancel: '取消',
34
36
  required: '必填的',
35
37
  invalid: '无效',
36
38
  },
@@ -68,6 +70,15 @@ export const translations = {
68
70
  },
69
71
  },
70
72
  },
73
+ thirdPartyLogin: {
74
+ title: '第三方登录',
75
+ connect: '绑定',
76
+ disconnect: '解绑',
77
+ mainProviderCantRemove: '主账号不允许解绑',
78
+ confirmUnbind: '确定要解绑 {name} 吗?',
79
+ confirmUnbindDescription:
80
+ '解绑后您将无法使用 {name} 登录至该账户。如果解绑后,您仍使用 {name} 登录,会自动创建一个新账户',
81
+ },
71
82
  },
72
83
  en: {
73
84
  settings: 'Settings',
@@ -101,6 +112,8 @@ export const translations = {
101
112
  slack: 'Slack',
102
113
  },
103
114
  common: {
115
+ confirm: 'Confirm',
116
+ cancel: 'Cancel',
104
117
  required: 'Required',
105
118
  invalid: 'Invalid',
106
119
  },
@@ -138,5 +151,14 @@ export const translations = {
138
151
  },
139
152
  },
140
153
  },
154
+ thirdPartyLogin: {
155
+ title: 'Third Party Login',
156
+ connect: 'Connect',
157
+ disconnect: 'Disconnect',
158
+ mainProviderCantRemove: 'Main account not allowed to remove',
159
+ confirmUnbind: 'Are you sure to unbind {name}?',
160
+ confirmUnbindDescription:
161
+ 'You will not be able to log in to this account using {name} after unbundling. If you are still logged in with {name} after unbundling, a new account will be created automatically!',
162
+ },
141
163
  },
142
164
  };
@@ -201,9 +201,7 @@ export default function UserSessions({
201
201
  options: {
202
202
  customBodyRenderLite: (rawIndex: number) => {
203
203
  const x = safeData[rawIndex];
204
- // @ts-ignore FIXME: @zhanghan 新版 js-sdk 会提供这个属性的提示
205
204
  return x.createdAt ? (
206
- // @ts-ignore FIXME: @zhanghan 新版 js-sdk 会提供这个属性的提示
207
205
  <RelativeTime value={x.createdAt} relativeRange={3 * 86400 * 1000} locale={locale} />
208
206
  ) : (
209
207
  t('unknown')
@@ -217,7 +215,6 @@ export default function UserSessions({
217
215
  options: {
218
216
  customBodyRenderLite: (rawIndex: number) => {
219
217
  const x = safeData[rawIndex];
220
- // @ts-ignore FIXME: @zhanghan 新版 js-sdk 会提供这个属性的提示
221
218
  return x.status === 'expired' ? (
222
219
  t('expired')
223
220
  ) : (