59 lines
1.6 KiB
TypeScript
59 lines
1.6 KiB
TypeScript
'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;
|