wuyiqunLu
feat: encode uri for s3 url when loading (#104)
c7e97b5 unverified
raw
history blame contribute delete
No virus
2.92 kB
'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';
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 { isLoading, data } = useVisionAgent(chat);
// Only login and chat owner can compose
const canCompose = !chatUserId || userId === chatUserId;
const { messagesRef, scrollRef, visibilityRef, isVisible, scrollToBottom } =
useScrollAnchor(SCROLL_BOTTOM);
// Scroll to bottom on init
useEffect(() => {
scrollToBottom();
}, [scrollToBottom]);
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={
isLastMessage && data.length > 0 ? data : undefined
}
/>
);
})}
<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,
};
await dbPostCreateMessage(id, messageInput);
}}
/>
</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;