refactor: 抽象与整理部分聊天代码

pull/13/head
moonrailgun 4 years ago
parent 41afc64cce
commit 3757c7804f

@ -2,6 +2,8 @@ import React, { useMemo } from 'react';
import { import {
ChatMessage, ChatMessage,
formatShortTime, formatShortTime,
getMessageTimeDiff,
shouldShowMessageTime,
SYSTEM_USERID, SYSTEM_USERID,
t, t,
useCachedUserInfo, useCachedUserInfo,
@ -11,7 +13,7 @@ import { Avatar } from '@/components/Avatar';
import { useRenderPluginMessageInterpreter } from './useRenderPluginMessageInterpreter'; import { useRenderPluginMessageInterpreter } from './useRenderPluginMessageInterpreter';
import { getMessageRender } from '@/plugin/common'; import { getMessageRender } from '@/plugin/common';
import { Icon } from '@iconify/react'; import { Icon } from '@iconify/react';
import { Dropdown, Menu } from 'antd'; import { Divider, Dropdown, Menu } from 'antd';
import { MessageHelper } from 'tailchat-shared'; import { MessageHelper } from 'tailchat-shared';
import { UserName } from '@/components/UserName'; import { UserName } from '@/components/UserName';
import './item.less'; import './item.less';
@ -128,13 +130,64 @@ interface ChatMessageItemProps {
showAvatar: boolean; showAvatar: boolean;
payload: ChatMessage; payload: ChatMessage;
} }
export const ChatMessageItem: React.FC<ChatMessageItemProps> = React.memo( const ChatMessageItem: React.FC<ChatMessageItemProps> = React.memo((props) => {
(props) => { if (props.payload.author === SYSTEM_USERID) {
if (props.payload.author === SYSTEM_USERID) { return <SystemMessage {...props} />;
return <SystemMessage {...props} />; }
return <NormalMessage {...props} />;
});
ChatMessageItem.displayName = 'ChatMessageItem';
function findMessageIndexWithId(
messages: ChatMessage[],
messageId: string
): number {
return messages.findIndex((m) => m._id === messageId);
}
/**
*
*/
export function buildItemRow(messages: ChatMessage[], messageId: string) {
const index = findMessageIndexWithId(messages, messageId); // TODO: 这里是因为mattermost的动态列表传的id因此只能这边再用id找回可以看看是否可以优化
if (index === -1) {
return <div />;
}
const message = messages[index];
let showDate = true;
let showAvatar = true;
const messageCreatedAt = new Date(message.createdAt ?? '');
if (index > 0) {
// 当不是第一条数据时
// 进行时间合并
const prevMessage = messages[index - 1];
if (
!shouldShowMessageTime(
new Date(prevMessage.createdAt ?? ''),
messageCreatedAt
)
) {
showDate = false;
} }
return <NormalMessage {...props} />; // 进行头像合并(在同一时间块下 且发送者为同一人)
if (showDate === false) {
showAvatar = prevMessage.author !== message.author;
}
} }
);
ChatMessageItem.displayName = 'ChatMessageItem'; return (
<div key={message._id} data-debug={JSON.stringify(index)}>
{showDate && (
<Divider className="text-sm opacity-40 px-6 font-normal select-none">
{getMessageTimeDiff(messageCreatedAt)}
</Divider>
)}
<ChatMessageItem showAvatar={showAvatar} payload={message} />
</div>
);
}

@ -3,7 +3,6 @@ import {
DynamicSizeRenderInfo, DynamicSizeRenderInfo,
OnScrollInfo, OnScrollInfo,
} from '@/components/DynamicVirtualizedList/DynamicSizeList'; } from '@/components/DynamicVirtualizedList/DynamicSizeList';
import { Divider } from 'antd';
import React, { import React, {
useEffect, useEffect,
useLayoutEffect, useLayoutEffect,
@ -12,16 +11,10 @@ import React, {
useState, useState,
} from 'react'; } from 'react';
import AutoSizer from 'react-virtualized-auto-sizer'; import AutoSizer from 'react-virtualized-auto-sizer';
import { import { ChatMessage, t, usePrevious, useUpdateRef } from 'tailchat-shared';
ChatMessage,
getMessageTimeDiff,
shouldShowMessageTime,
t,
usePrevious,
useUpdateRef,
} from 'tailchat-shared';
import { messageReverseItemId } from './const'; import { messageReverseItemId } from './const';
import { ChatMessageItem } from './Item'; import { buildItemRow } from './Item';
import type { MessageListProps } from './types';
// Reference: https://github.com/mattermost/mattermost-webapp/blob/master/components/post_view/post_list_virtualized/post_list_virtualized.jsx // Reference: https://github.com/mattermost/mattermost-webapp/blob/master/components/post_view/post_list_virtualized/post_list_virtualized.jsx
@ -41,22 +34,8 @@ const virtListStyles: React.CSSProperties = {
const dynamicListStyle: React.CSSProperties = {}; // TODO const dynamicListStyle: React.CSSProperties = {}; // TODO
function findMessageIndexWithId( export const VirtualizedMessageList: React.FC<MessageListProps> = React.memo(
messages: ChatMessage[], (props) => {
messageId: string
): number {
return messages.findIndex((m) => m._id === messageId);
}
export interface VirtualizedMessageListProps {
messages: ChatMessage[];
isLoadingMore: boolean;
hasMoreMessage: boolean;
onUpdateReadedMessage: (lastMessageId: string) => void;
onLoadMore: () => void;
}
export const VirtualizedMessageList: React.FC<VirtualizedMessageListProps> =
React.memo((props) => {
const listRef = useRef<DynamicSizeList>(null); const listRef = useRef<DynamicSizeList>(null);
const postListRef = useRef<HTMLDivElement>(null); const postListRef = useRef<HTMLDivElement>(null);
const [isBottom, setIsBottom] = useState(true); const [isBottom, setIsBottom] = useState(true);
@ -135,47 +114,7 @@ export const VirtualizedMessageList: React.FC<VirtualizedMessageListProps> =
); );
} }
const messages = props.messages; return buildItemRow(props.messages, itemId);
const index = findMessageIndexWithId(messages, itemId); // TODO: 这里是因为mattermost的动态列表传的id因此只能这边再用id找回可以看看是否可以优化
if (index === -1) {
return <div />;
}
const message = messages[index];
let showDate = true;
let showAvatar = true;
const messageCreatedAt = new Date(message.createdAt ?? '');
if (index > 0) {
// 当不是第一条数据时
// 进行时间合并
const prevMessage = messages[index - 1];
if (
!shouldShowMessageTime(
new Date(prevMessage.createdAt ?? ''),
messageCreatedAt
)
) {
showDate = false;
}
// 进行头像合并(在同一时间块下 且发送者为同一人)
if (showDate === false) {
showAvatar = prevMessage.author !== message.author;
}
}
return (
<div key={message._id} data-debug={JSON.stringify(index)}>
{showDate && (
<Divider className="text-sm opacity-40 px-6 font-normal select-none">
{getMessageTimeDiff(messageCreatedAt)}
</Divider>
)}
<ChatMessageItem showAvatar={showAvatar} payload={message} />
</div>
);
}; };
// 初始渲染范围 // 初始渲染范围
@ -215,7 +154,8 @@ export const VirtualizedMessageList: React.FC<VirtualizedMessageListProps> =
)} )}
</AutoSizer> </AutoSizer>
); );
}); }
);
VirtualizedMessageList.displayName = 'VirtualizedMessageList'; VirtualizedMessageList.displayName = 'VirtualizedMessageList';
/** /**

@ -1,15 +1,14 @@
import React from 'react'; import React from 'react';
import { import type { MessageListProps } from './types';
VirtualizedMessageList, import { VirtualizedMessageList } from './VirtualizedList';
VirtualizedMessageListProps,
} from './VirtualizedList';
export const ChatMessageList: React.FC<VirtualizedMessageListProps> = export const ChatMessageList: React.FC<MessageListProps> = React.memo(
React.memo((props) => { (props) => {
return ( return (
<div className="flex-1"> <div className="flex-1">
<VirtualizedMessageList {...props} /> <VirtualizedMessageList {...props} />
</div> </div>
); );
}); }
);
ChatMessageList.displayName = 'ChatMessageList'; ChatMessageList.displayName = 'ChatMessageList';

@ -0,0 +1,9 @@
import type { ChatMessage } from 'tailchat-shared';
export interface MessageListProps {
messages: ChatMessage[];
isLoadingMore: boolean;
hasMoreMessage: boolean;
onUpdateReadedMessage: (lastMessageId: string) => void;
onLoadMore: () => void;
}
Loading…
Cancel
Save