crush-level-web/src/app/(main)/chat/MessageList.tsx

59 lines
1.6 KiB
TypeScript
Raw Normal View History

'use client';
import CharacterHeader from './CharacterHeader';
import AIMessage from './AIMessage';
import UserMessage from './UserMessage';
import VirtualList from '@/components/ui/virtual-list';
import { useStreamChatStore } from '@/app/(main)/chat/stream-chat';
import React, { useCallback, useEffect, useMemo } from 'react';
import { useChatParams } from './page';
const MessageList = React.memo(() => {
const { id } = useChatParams();
const messages = useStreamChatStore((s) => s.messages);
const itemList = useMemo(() => {
return [
{
type: 'header',
},
...messages.map((i) => {
return {
type: i.role === 'user' ? 'user-message' : 'assistant-message',
data: i,
};
}),
];
}, [messages]);
const itemContent = useCallback((index: number, item: { type: string; data: any }) => {
switch (item.type) {
case 'user-message':
return <UserMessage data={item.data} />;
case 'assistant-message':
return <AIMessage data={item.data} />;
case 'header':
return <CharacterHeader />;
default:
return null;
}
}, []);
return (
<div className="flex-1 min-h-0 relative z-10">
<VirtualList
className="h-full"
data={itemList}
autoScrollToBottom
cacheKey={id || 'empty'}
getItemKey={(index, item) => {
if (item.type === 'header') return 'header';
return item.data?.key ?? `${item.type}-${index}`;
}}
itemContent={itemContent}
/>
</div>
);
});
export default MessageList;