| import { memo, useCallback } from 'react'; | |
| import { useRecoilValue } from 'recoil'; | |
| import { useForm } from 'react-hook-form'; | |
| import { Spinner } from '@librechat/client'; | |
| import { useParams } from 'react-router-dom'; | |
| import { Constants, buildTree } from 'librechat-data-provider'; | |
| import type { TMessage } from 'librechat-data-provider'; | |
| import type { ChatFormValues } from '~/common'; | |
| import { ChatContext, AddedChatContext, useFileMapContext, ChatFormProvider } from '~/Providers'; | |
| import { useChatHelpers, useAddedResponse, useSSE } from '~/hooks'; | |
| import ConversationStarters from './Input/ConversationStarters'; | |
| import { useGetMessagesByConvoId } from '~/data-provider'; | |
| import MessagesView from './Messages/MessagesView'; | |
| import Presentation from './Presentation'; | |
| import ChatForm from './Input/ChatForm'; | |
| import Landing from './Landing'; | |
| import Header from './Header'; | |
| import Footer from './Footer'; | |
| import { cn } from '~/utils'; | |
| import store from '~/store'; | |
| function LoadingSpinner() { | |
| return ( | |
| <div className="relative flex-1 overflow-hidden overflow-y-auto"> | |
| <div className="relative flex h-full items-center justify-center"> | |
| <Spinner className="text-text-primary" /> | |
| </div> | |
| </div> | |
| ); | |
| } | |
| function ChatView({ index = 0 }: { index?: number }) { | |
| const { conversationId } = useParams(); | |
| const rootSubmission = useRecoilValue(store.submissionByIndex(index)); | |
| const addedSubmission = useRecoilValue(store.submissionByIndex(index + 1)); | |
| const centerFormOnLanding = useRecoilValue(store.centerFormOnLanding); | |
| const fileMap = useFileMapContext(); | |
| const { data: messagesTree = null, isLoading } = useGetMessagesByConvoId(conversationId ?? '', { | |
| select: useCallback( | |
| (data: TMessage[]) => { | |
| const dataTree = buildTree({ messages: data, fileMap }); | |
| return dataTree?.length === 0 ? null : (dataTree ?? null); | |
| }, | |
| [fileMap], | |
| ), | |
| enabled: !!fileMap, | |
| }); | |
| const chatHelpers = useChatHelpers(index, conversationId); | |
| const addedChatHelpers = useAddedResponse({ rootIndex: index }); | |
| useSSE(rootSubmission, chatHelpers, false); | |
| useSSE(addedSubmission, addedChatHelpers, true); | |
| const methods = useForm<ChatFormValues>({ | |
| defaultValues: { text: '' }, | |
| }); | |
| let content: JSX.Element | null | undefined; | |
| const isLandingPage = | |
| (!messagesTree || messagesTree.length === 0) && | |
| (conversationId === Constants.NEW_CONVO || !conversationId); | |
| const isNavigating = (!messagesTree || messagesTree.length === 0) && conversationId != null; | |
| if (isLoading && conversationId !== Constants.NEW_CONVO) { | |
| content = <LoadingSpinner />; | |
| } else if ((isLoading || isNavigating) && !isLandingPage) { | |
| content = <LoadingSpinner />; | |
| } else if (!isLandingPage) { | |
| content = <MessagesView messagesTree={messagesTree} />; | |
| } else { | |
| content = <Landing centerFormOnLanding={centerFormOnLanding} />; | |
| } | |
| return ( | |
| <ChatFormProvider {...methods}> | |
| <ChatContext.Provider value={chatHelpers}> | |
| <AddedChatContext.Provider value={addedChatHelpers}> | |
| <Presentation> | |
| <div className="flex h-full w-full flex-col"> | |
| {!isLoading && <Header />} | |
| <> | |
| <div | |
| className={cn( | |
| 'flex flex-col', | |
| isLandingPage | |
| ? 'flex-1 items-center justify-end sm:justify-center' | |
| : 'h-full overflow-y-auto', | |
| )} | |
| > | |
| {content} | |
| <div | |
| className={cn( | |
| 'w-full', | |
| isLandingPage && 'max-w-3xl transition-all duration-200 xl:max-w-4xl', | |
| )} | |
| > | |
| <ChatForm index={index} /> | |
| {isLandingPage ? <ConversationStarters /> : <Footer />} | |
| </div> | |
| </div> | |
| {isLandingPage && <Footer />} | |
| </> | |
| </div> | |
| </Presentation> | |
| </AddedChatContext.Provider> | |
| </ChatContext.Provider> | |
| </ChatFormProvider> | |
| ); | |
| } | |
| export default memo(ChatView); | |