@blocklet/ui-react 3.1.26 → 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.
- package/lib/@types/index.d.ts +1 -1
- package/lib/UserCenter/components/fallback.d.ts +8 -0
- package/lib/UserCenter/components/fallback.js +21 -0
- package/lib/UserCenter/components/user-center.js +205 -200
- package/lib/UserCenter/components/user-info/social-actions/chat.d.ts +5 -0
- package/lib/UserCenter/components/user-info/social-actions/chat.js +24 -0
- package/lib/UserCenter/components/user-info/social-actions/follow.d.ts +2 -0
- package/lib/UserCenter/components/user-info/social-actions/follow.js +19 -0
- package/lib/UserCenter/components/user-info/social-actions/index.d.ts +5 -0
- package/lib/UserCenter/components/user-info/social-actions/index.js +13 -0
- package/lib/UserCenter/components/user-info/user-basic-info.js +37 -35
- package/lib/UserCenter/libs/locales.d.ts +14 -0
- package/lib/UserCenter/libs/locales.js +16 -2
- package/lib/contexts/user-followers.d.ts +13 -0
- package/lib/contexts/user-followers.js +40 -0
- package/lib/hooks/use-follow.d.ts +12 -0
- package/lib/hooks/use-follow.js +47 -0
- package/package.json +6 -6
- package/src/@types/index.ts +1 -1
- package/src/UserCenter/components/fallback.tsx +51 -0
- package/src/UserCenter/components/user-center.tsx +22 -12
- package/src/UserCenter/components/user-info/social-actions/chat.tsx +42 -0
- package/src/UserCenter/components/user-info/social-actions/follow.tsx +30 -0
- package/src/UserCenter/components/user-info/social-actions/index.tsx +17 -0
- package/src/UserCenter/components/user-info/user-basic-info.tsx +6 -0
- package/src/UserCenter/libs/locales.ts +14 -0
- package/src/contexts/user-followers.tsx +54 -0
- 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
|
+
}
|