mirror of
https://github.com/danny-avila/LibreChat.git
synced 2025-12-17 17:00:15 +01:00
117 lines
4.3 KiB
TypeScript
117 lines
4.3 KiB
TypeScript
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, useAdaptiveSSE, useResumeOnLoad } 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 });
|
|
|
|
useAdaptiveSSE(rootSubmission, chatHelpers, false, index);
|
|
useAdaptiveSSE(addedSubmission, addedChatHelpers, true, index + 1);
|
|
|
|
// Auto-resume if navigating back to conversation with active job
|
|
useResumeOnLoad(conversationId, chatHelpers.getMessages, index);
|
|
|
|
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);
|