Spaces:
Running
Running
File size: 3,236 Bytes
edd2230 4af6326 bc1cf4e 4af6326 3ba9c0c 4af6326 db06845 3ba9c0c 4af6326 db06845 bc1cf4e 4af6326 db06845 4af6326 f80b091 4af6326 db06845 bc1cf4e db06845 4af6326 db06845 4af6326 f80b091 4af6326 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 |
'use client';
// import { ChatList } from '@/components/chat/ChatList';
import Composer from '@/components/chat/Composer';
import useVisionAgent from '@/lib/hooks/useVisionAgent';
import { useScrollAnchor } from '@/lib/hooks/useScrollAnchor';
import { useEffect } from 'react';
import { ChatWithMessages } from '@/lib/types';
import { ChatMessage } from './ChatMessage';
import { Button } from '../ui/Button';
import { cn } from '@/lib/utils';
import { IconArrowDown } from '../ui/Icons';
import { dbPostCreateMessage } from '@/lib/db/functions';
import { Card } from '../ui/Card';
import { useSetAtom } from 'jotai';
import { selectedMessageId } from '@/state/chat';
export interface ChatListProps {
chat: ChatWithMessages;
userId?: string | null;
}
export const SCROLL_BOTTOM = 120;
const ChatList: React.FC<ChatListProps> = ({ chat, userId }) => {
const { id, messages: dbMessages, userId: chatUserId } = chat;
const { append, isLoading, data } = useVisionAgent(chat);
// Only login and chat owner can compose
const canCompose = !chatUserId || userId === chatUserId;
const lastDbMessage = dbMessages[dbMessages.length - 1];
const setMessageId = useSetAtom(selectedMessageId);
const { messagesRef, scrollRef, visibilityRef, isVisible, scrollToBottom } =
useScrollAnchor(SCROLL_BOTTOM);
// Scroll to bottom on init and highlight last message
useEffect(() => {
scrollToBottom();
if (lastDbMessage.result) {
setMessageId(lastDbMessage.id);
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
return (
<Card
className="size-full max-w-5xl overflow-auto relative"
ref={scrollRef}
>
<div className="overflow-auto h-full p-4 z-10" ref={messagesRef}>
{dbMessages.map((message, index) => {
const isLastMessage = index === dbMessages.length - 1;
return (
<ChatMessage
key={message.id}
message={message}
loading={isLastMessage && isLoading}
wipAssistantMessage={data}
/>
);
})}
<div
className="w-full"
style={{ height: SCROLL_BOTTOM }}
ref={visibilityRef}
/>
</div>
{canCompose && (
<div className="absolute bottom-4 w-full">
<Composer
// Use the last message mediaUrl as the initial mediaUrl
initMediaUrl={dbMessages[dbMessages.length - 1]?.mediaUrl}
disabled={isLoading}
onSubmit={async ({ input, mediaUrl: newMediaUrl }) => {
const messageInput = {
prompt: input,
mediaUrl: newMediaUrl,
};
const resp = await dbPostCreateMessage(id, messageInput);
append(resp);
}}
/>
</div>
)}
{/* Scroll to bottom Icon */}
<Button
size="icon"
className={cn(
'absolute bottom-3 right-3 transition-opacity duration-300 size-6',
isVisible ? 'opacity-0' : 'opacity-100',
)}
onClick={() => scrollToBottom()}
>
<IconArrowDown className="size-3" />
</Button>
</Card>
);
};
export default ChatList;
|