import React, { lazy, Suspense, useEffect, useState } from 'react' import { useTranslation } from 'react-i18next' import MessageInput from './message-input' import InfiniteScroll from './infinite-scroll' import ChatFallbackError from './chat-fallback-error' import Icon from '../../../shared/components/icon' import { useLayoutContext } from '../../../shared/context/layout-context' import { useUserContext } from '../../../shared/context/user-context' import withErrorBoundary from '../../../infrastructure/error-boundary' import { FetchError } from '../../../infrastructure/fetch-json' import { useChatContext } from '../context/chat-context' import LoadingSpinner from '../../../shared/components/loading-spinner' const MessageList = lazy(() => import('./message-list')) const ChatPane = React.memo(function ChatPane() { const { t } = useTranslation() const { chatIsOpen } = useLayoutContext() const user = useUserContext() const { status, messages, initialMessagesLoaded, atEnd, loadInitialMessages, loadMoreMessages, reset, sendMessage, markMessagesAsRead, error, } = useChatContext() useEffect(() => { if (chatIsOpen && !initialMessagesLoaded) { loadInitialMessages() } }, [chatIsOpen, loadInitialMessages, initialMessagesLoaded]) const shouldDisplayPlaceholder = status !== 'pending' && messages.length === 0 const messageContentCount = messages.reduce( (acc, { contents }) => acc + contents.length, 0 ) // Keep the chat pane in the DOM to avoid resetting the form input and re-rendering MathJax content. const [chatOpenedOnce, setChatOpenedOnce] = useState(chatIsOpen) useEffect(() => { if (chatIsOpen) { setChatOpenedOnce(true) } }, [chatIsOpen]) if (error) { // let user try recover from fetch errors if (error instanceof FetchError) { return } throw error } if (!user) { return null } if (!chatOpenedOnce) { return null } return ( ) }) function Placeholder() { const { t } = useTranslation() return ( <>
{t('no_messages')}
{t('send_first_message')}
) } export default withErrorBoundary(ChatPane, ChatFallbackError)