feat: 在线状态监测与处理用户信息缓存

pull/13/head
moonrailgun 4 years ago
parent ce149bdaa8
commit 2a12916428

@ -1,17 +1,36 @@
import { useQuery } from 'react-query';
import { fetchUserInfo, UserBaseInfo } from '../model/user';
import {
fetchUserInfo,
getUserOnlineStatus,
UserBaseInfo,
} from '../model/user';
function buildUseCacheFactory<T>(
scope: string,
fetcher: (id: string) => Promise<T>
) {
return (id: string): T | Record<string, never> => {
const { data } = useQuery([scope, id], () => fetcher(id));
return data ?? {};
};
/**
*
*/
export function useCachedUserInfo(
userId: string,
refetch = false
): UserBaseInfo | Record<string, never> {
const { data } = useQuery(['user', userId], () => fetchUserInfo(userId), {
staleTime: 2 * 60 * 60 * 1000, // 缓存2小时
refetchOnMount: refetch ? 'always' : true,
});
return data ?? {};
}
export const useCachedUserInfo = buildUseCacheFactory<UserBaseInfo>(
'user',
fetchUserInfo
);
/**
*
*/
export function useCachedOnlineStatus(ids: string[]): boolean[] {
const { data } = useQuery(
['onlineStatus', ids.join(',')],
() => getUserOnlineStatus(ids),
{
staleTime: 10 * 1000, // 缓存10s
}
);
return data ?? ids.map(() => false);
}

@ -86,3 +86,21 @@ export async function fetchUserInfo(userId: string): Promise<UserBaseInfo> {
return data;
}
/**
* 线
*/
export async function getUserOnlineStatus(
userIds: string[]
): Promise<boolean[]> {
const { data } = await request.get<boolean[]>(
'/api/gateway/checkUserOnline',
{
params: {
userIds,
},
}
);
return data;
}

@ -1,5 +1,5 @@
import React, { useMemo } from 'react';
import { Avatar as AntdAvatar } from 'antd';
import { Avatar as AntdAvatar, Badge } from 'antd';
import _head from 'lodash/head';
import _upperCase from 'lodash/upperCase';
import _isNil from 'lodash/isNil';
@ -10,6 +10,7 @@ import { getTextColorHex } from 'pawchat-shared';
interface AvatarProps extends AntdAvatarProps {
name?: string;
isOnline?: boolean;
}
export const Avatar: React.FC<AvatarProps> = React.memo((props) => {
const src = typeof props.src !== 'string' ? props.src : undefined;
@ -41,10 +42,33 @@ export const Avatar: React.FC<AvatarProps> = React.memo((props) => {
style.fontSize = props.size * 0.4;
}
return (
const inner = (
<AntdAvatar {...props} src={src} style={style}>
{name}
</AntdAvatar>
);
if (typeof props.isOnline === 'boolean') {
const style = {
bottom: 0,
top: 'auto',
};
if (props.isOnline === true) {
return (
<Badge dot={true} color="green" style={style}>
{inner}
</Badge>
);
} else {
return (
<Badge dot={true} color="#999" style={style}>
{inner}
</Badge>
);
}
}
return inner;
});
Avatar.displayName = 'Avatar';

@ -1,9 +1,10 @@
import React, { useCallback } from 'react';
import { Avatar } from './Avatar';
import _isNil from 'lodash/isNil';
import _isEmpty from 'lodash/isEmpty';
import { Skeleton, Space } from 'antd';
// import { openUserProfile } from './modals/UserProfile';
import { useCachedUserInfo } from 'pawchat-shared';
import { useCachedOnlineStatus } from '../../../shared/cache/useCache';
// const UserAvatar = styled(Avatar)`
// cursor: pointer !important;
@ -22,6 +23,7 @@ interface UserListItemProps {
export const UserListItem: React.FC<UserListItemProps> = React.memo((props) => {
const { actions = [] } = props;
const userInfo = useCachedUserInfo(props.userId);
const [isOnline] = useCachedOnlineStatus([props.userId]);
const userName = userInfo.nickname;
const handleClick = useCallback(() => {
@ -31,13 +33,13 @@ export const UserListItem: React.FC<UserListItemProps> = React.memo((props) => {
return (
<div className="flex items-center h-14 px-2.5 rounded group bg-white bg-opacity-0 hover:bg-opacity-20">
<Skeleton
loading={_isNil(userInfo)}
loading={_isEmpty(userInfo)}
avatar={true}
title={false}
active={true}
>
<div className="mr-2" onClick={handleClick}>
<Avatar src={userInfo.avatar} name={userName} />
<Avatar src={userInfo.avatar} name={userName} isOnline={isOnline} />
</div>
<div className="flex-1 text-white">
<span>{userName}</span>

Loading…
Cancel
Save