@blocklet/ui-react 3.1.25 → 3.1.27

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 (28) hide show
  1. package/lib/@types/index.d.ts +1 -1
  2. package/lib/UserCenter/components/fallback.d.ts +8 -0
  3. package/lib/UserCenter/components/fallback.js +21 -0
  4. package/lib/UserCenter/components/user-center.js +205 -200
  5. package/lib/UserCenter/components/user-info/social-actions/chat.d.ts +5 -0
  6. package/lib/UserCenter/components/user-info/social-actions/chat.js +24 -0
  7. package/lib/UserCenter/components/user-info/social-actions/follow.d.ts +2 -0
  8. package/lib/UserCenter/components/user-info/social-actions/follow.js +19 -0
  9. package/lib/UserCenter/components/user-info/social-actions/index.d.ts +5 -0
  10. package/lib/UserCenter/components/user-info/social-actions/index.js +13 -0
  11. package/lib/UserCenter/components/user-info/user-basic-info.js +37 -35
  12. package/lib/UserCenter/libs/locales.d.ts +14 -0
  13. package/lib/UserCenter/libs/locales.js +16 -2
  14. package/lib/contexts/user-followers.d.ts +13 -0
  15. package/lib/contexts/user-followers.js +40 -0
  16. package/lib/hooks/use-follow.d.ts +12 -0
  17. package/lib/hooks/use-follow.js +47 -0
  18. package/package.json +6 -6
  19. package/src/@types/index.ts +1 -1
  20. package/src/UserCenter/components/fallback.tsx +51 -0
  21. package/src/UserCenter/components/user-center.tsx +22 -12
  22. package/src/UserCenter/components/user-info/social-actions/chat.tsx +42 -0
  23. package/src/UserCenter/components/user-info/social-actions/follow.tsx +30 -0
  24. package/src/UserCenter/components/user-info/social-actions/index.tsx +17 -0
  25. package/src/UserCenter/components/user-info/user-basic-info.tsx +6 -0
  26. package/src/UserCenter/libs/locales.ts +14 -0
  27. package/src/contexts/user-followers.tsx +54 -0
  28. package/src/hooks/use-follow.tsx +74 -0
@@ -0,0 +1,42 @@
1
+ import { useMemo } from 'react';
2
+ import { Button } from '@mui/material';
3
+ import { useMemoizedFn } from 'ahooks';
4
+ import { translate } from '@arcblock/ux/lib/Locale/util';
5
+ import { useLocaleContext } from '@arcblock/ux/lib/Locale/context';
6
+
7
+ import { joinURL } from 'ufo';
8
+ import { User } from '../../../../@types';
9
+
10
+ import { translations } from '../../../libs/locales';
11
+
12
+ const getDiscussKitMountPoint = () => {
13
+ const { componentMountPoints = [] } = window.blocklet || {};
14
+ const component = componentMountPoints.find((c: any) => c.name === 'did-comments');
15
+ return component?.mountPoint;
16
+ };
17
+
18
+ function Chat({ user }: { user: User }) {
19
+ const { locale } = useLocaleContext();
20
+ const t = useMemoizedFn((key, data = {}) => {
21
+ return translate(translations, key, locale, 'en', data);
22
+ });
23
+ // 获取 discuss kit 的挂载点
24
+ const discussKitMountPoint = useMemo(() => getDiscussKitMountPoint(), []);
25
+
26
+ const onNavigateToChat = useMemoizedFn(() => {
27
+ window.open(joinURL(discussKitMountPoint, `/chat/dm/${user?.did}`), '_blank');
28
+ });
29
+
30
+ if (!discussKitMountPoint) {
31
+ return null;
32
+ }
33
+
34
+ return (
35
+ <Button fullWidth variant="outlined" color="inherit" onClick={onNavigateToChat}>
36
+ <i className="iconify" data-icon="mi:message-alt" style={{ fontSize: '15px', marginRight: '4px' }} />
37
+ {t('profile.chat')}
38
+ </Button>
39
+ );
40
+ }
41
+
42
+ export default Chat;
@@ -0,0 +1,30 @@
1
+ import { Button } from '@mui/material';
2
+ import { useMemoizedFn } from 'ahooks';
3
+ import { translate } from '@arcblock/ux/lib/Locale/util';
4
+ import { useLocaleContext } from '@arcblock/ux/lib/Locale/context';
5
+ import NotificationsIcon from '@mui/icons-material/Notifications';
6
+ import NotificationsOffIcon from '@mui/icons-material/NotificationsOff';
7
+
8
+ import { translations } from '../../../libs/locales';
9
+ import { useUserFollowersContext } from '../../../../contexts/user-followers';
10
+
11
+ function Follow() {
12
+ const { locale } = useLocaleContext();
13
+ const t = useMemoizedFn((key, data = {}) => {
14
+ return translate(translations, key, locale, 'en', data);
15
+ });
16
+ const { followed, followUser, unfollowUser } = useUserFollowersContext();
17
+
18
+ return (
19
+ <Button variant="contained" onClick={() => (followed ? unfollowUser() : followUser())} fullWidth>
20
+ {followed ? (
21
+ <NotificationsOffIcon sx={{ fontSize: '14px', marginRight: '4px' }} />
22
+ ) : (
23
+ <NotificationsIcon sx={{ fontSize: '14px', marginRight: '4px' }} />
24
+ )}
25
+ {followed ? t('profile.unfollow') : t('profile.follow')}
26
+ </Button>
27
+ );
28
+ }
29
+
30
+ export default Follow;
@@ -0,0 +1,17 @@
1
+ import { Box } from '@mui/material';
2
+ import Chat from './chat';
3
+ import Follow from './follow';
4
+
5
+ import { User } from '../../../../@types';
6
+
7
+ // 进入这里肯定是他人的个人中心
8
+ function SocialActions({ user }: { user: User }) {
9
+ return (
10
+ <Box sx={{ display: 'flex', gap: 1 }}>
11
+ <Chat user={user} />
12
+ <Follow />
13
+ </Box>
14
+ );
15
+ }
16
+
17
+ export default SocialActions;
@@ -24,6 +24,7 @@ import UserMetadataComponent from './metadata';
24
24
  import UserStatus from './user-status';
25
25
  import UserInfo from './user-info';
26
26
  import { client } from '../../../libs/client';
27
+ import SocialActions from './social-actions';
27
28
 
28
29
  export default function UserBasicInfo({
29
30
  user,
@@ -225,6 +226,11 @@ export default function UserBasicInfo({
225
226
  <DID did={user.did} showQrcode copyable compact={!showFullDid} responsive={!showFullDid} locale={locale} />
226
227
  </Box>
227
228
  </Box>
229
+ {!isMyself ? (
230
+ <Box sx={{ mt: 2 }}>
231
+ <SocialActions user={user} />
232
+ </Box>
233
+ ) : null}
228
234
  <UserMetadataComponent isMobile={isMobile} isMyself={isMyself} user={user} onSave={onSave} />
229
235
  {isMyself ? (
230
236
  <>
@@ -25,10 +25,12 @@ export const translations = {
25
25
  emptyField: '未填写',
26
26
  emptyContent: '暂无内容',
27
27
  underProtected: '用户已设置隐私保护',
28
+ followersOnly: '用户已设置仅粉丝可见,关注用户后可查看',
28
29
  noUserFound: '未找到指定的用户',
29
30
  notificationManagement: '通知管理',
30
31
  privacyManagement: '隐私管理',
31
32
  storageManagement: 'DID Spaces',
33
+ userFollowers: '关注 & 粉丝',
32
34
  webhook: {
33
35
  url: '自定义URL',
34
36
  slack: 'Slack',
@@ -161,6 +163,11 @@ export const translations = {
161
163
  invalidPostalCode: '邮政编码格式不正确',
162
164
  },
163
165
  maxLinkCount: '最多可添加 {count} 个社交链接',
166
+ chat: '聊天',
167
+ follow: '关注',
168
+ unfollow: '取消关注',
169
+ follow_success: '关注成功',
170
+ unfollow_success: '取消关注成功',
164
171
  },
165
172
  destroyMyself: {
166
173
  title: '删除账户',
@@ -203,8 +210,10 @@ export const translations = {
203
210
  notificationManagement: 'Notifications',
204
211
  privacyManagement: 'Privacy',
205
212
  storageManagement: 'DID Spaces',
213
+ userFollowers: 'Following & Followers',
206
214
  emptyContent: 'Empty',
207
215
  underProtected: 'This page has protected privacy',
216
+ followersOnly: 'This page is only visible to followers, follow the user to view',
208
217
  noUserFound: 'No user found',
209
218
  webhook: {
210
219
  url: 'Custom url',
@@ -340,6 +349,11 @@ export const translations = {
340
349
  invalidPostalCode: 'Postal code is invalid',
341
350
  },
342
351
  maxLinkCount: 'Up to {count} social links can be added',
352
+ chat: 'Chat',
353
+ follow: 'Follow',
354
+ unfollow: 'Unfollow',
355
+ follow_success: 'Follow successfully',
356
+ unfollow_success: 'Unfollow successfully',
343
357
  },
344
358
  destroyMyself: {
345
359
  title: 'Delete Account',
@@ -0,0 +1,54 @@
1
+ import { createContext, useContext } from 'react';
2
+ import { translate } from '@arcblock/ux/lib/Locale/util';
3
+ import { useMemoizedFn } from 'ahooks';
4
+ import { useLocaleContext } from '@arcblock/ux/lib/Locale/context';
5
+
6
+ import useFollow from '../hooks/use-follow';
7
+ import { translations } from '../UserCenter/libs/locales';
8
+
9
+ const UserFollowersContext = createContext<UserFollowersContextType>({
10
+ followed: false,
11
+ followUser: () => {},
12
+ unfollowUser: () => {},
13
+ });
14
+ const { Provider } = UserFollowersContext;
15
+
16
+ type UserFollowersContextType = {
17
+ followed: boolean;
18
+ followUser: () => void;
19
+ unfollowUser: () => void;
20
+ };
21
+
22
+ function UserFollowersProvider({
23
+ isMySelf,
24
+ userDid,
25
+ children,
26
+ }: {
27
+ children: React.ReactNode;
28
+ isMySelf: boolean;
29
+ userDid: string;
30
+ }) {
31
+ const { locale } = useLocaleContext();
32
+ const t = useMemoizedFn((key, data = {}) => {
33
+ return translate(translations, key, locale, 'en', data);
34
+ });
35
+ const { followed, followUser, unfollowUser } = useFollow({ userDid, t, isMySelf });
36
+
37
+ return (
38
+ <Provider
39
+ value={{
40
+ followed,
41
+ followUser,
42
+ unfollowUser,
43
+ }}>
44
+ {children}
45
+ </Provider>
46
+ );
47
+ }
48
+
49
+ function useUserFollowersContext() {
50
+ const res = useContext(UserFollowersContext);
51
+ return res;
52
+ }
53
+
54
+ export { UserFollowersContext, useUserFollowersContext, UserFollowersProvider };
@@ -0,0 +1,74 @@
1
+ import { useEffect, useState } from 'react';
2
+ import { useMemoizedFn } from 'ahooks';
3
+ import Toast from '@arcblock/ux/lib/Toast';
4
+
5
+ import type { AxiosError } from 'axios';
6
+ import { client } from '../libs/client';
7
+ import { formatAxiosError } from '../UserCenter/libs/utils';
8
+
9
+ /**
10
+ * 登录用户与当前用户(userDid)的关注关系
11
+ */
12
+ export default function useFollow({
13
+ userDid,
14
+ t,
15
+ isMySelf,
16
+ }: {
17
+ userDid: string;
18
+ t: (k: string) => string;
19
+ isMySelf: boolean;
20
+ }) {
21
+ const [followed, setFollowed] = useState(false);
22
+
23
+ const isFollowingUser = useMemoizedFn(async () => {
24
+ try {
25
+ if (isMySelf) {
26
+ setFollowed(true);
27
+ return;
28
+ }
29
+ const res = await client.user.isFollowingUser({ userDid });
30
+ setFollowed(res);
31
+ } catch (error) {
32
+ console.error(error);
33
+ }
34
+ });
35
+
36
+ const followUser = useMemoizedFn(async (followUserDid: string = userDid) => {
37
+ if (isMySelf && followUserDid === userDid) {
38
+ return;
39
+ }
40
+ try {
41
+ await client.user.followUser({ userDid: followUserDid });
42
+ Toast.success(t('profile.follow_success'));
43
+ isFollowingUser();
44
+ } catch (error) {
45
+ console.error(error);
46
+ Toast.error(formatAxiosError(error as AxiosError));
47
+ }
48
+ });
49
+ const unfollowUser = useMemoizedFn(async (unfollowUserDid: string = userDid) => {
50
+ if (isMySelf && unfollowUserDid === userDid) {
51
+ return;
52
+ }
53
+ try {
54
+ await client.user.unfollowUser({ userDid: unfollowUserDid });
55
+ Toast.success(t('profile.unfollow_success'));
56
+ isFollowingUser();
57
+ } catch (error) {
58
+ console.error(error);
59
+ Toast.error(formatAxiosError(error as AxiosError));
60
+ }
61
+ });
62
+
63
+ useEffect(() => {
64
+ if (userDid && !isMySelf) {
65
+ isFollowingUser();
66
+ }
67
+ }, [isFollowingUser, userDid, isMySelf]);
68
+
69
+ return {
70
+ followed,
71
+ followUser,
72
+ unfollowUser,
73
+ };
74
+ }