import { HTMLAttributes, useRef, useEffect, useState } from 'react' import cx from 'classnames' import Box from '@mui/material/Box' import { Message as IMessage, InlineMedia } from 'models/chat' import { Message } from 'components/Message' export interface ChatTranscriptProps extends HTMLAttributes { messageLog: Array userId: string } export const ChatTranscript = ({ className, messageLog, userId, }: ChatTranscriptProps) => { const boxRef = useRef(null) const [previousMessageLogLength, setPreviousMessageLogLength] = useState(0) useEffect(() => { const { current: boxEl } = boxRef if (!boxEl) return const { scrollHeight, clientHeight, scrollTop, children } = boxEl const scrollTopMax = scrollHeight - clientHeight if (children.length === 0) return const lastChild = children[children.length - 1] const lastChildHeight = lastChild.clientHeight const previousScrollTopMax = scrollTopMax - lastChildHeight const wasPreviouslyScrolledToBottom = Math.ceil(scrollTop) >= Math.ceil(previousScrollTopMax) const wasMessageLogPreviouslyEmpty = previousMessageLogLength === 0 const shouldScrollToLatestMessage = wasPreviouslyScrolledToBottom || wasMessageLogPreviouslyEmpty if ( shouldScrollToLatestMessage && // scrollTo is not defined in the unit test environment 'scrollTo' in boxEl ) { boxEl.scrollTo({ top: scrollTopMax }) } }, [messageLog, previousMessageLogLength]) useEffect(() => { setPreviousMessageLogLength(messageLog.length) }, [messageLog.length]) return ( ({ display: 'flex', flexDirection: 'column', mx: 'auto', paddingY: theme.spacing(1), width: '100%', maxWidth: theme.breakpoints.values.md, })} > {messageLog.map((message, idx) => { const previousMessage = messageLog[idx - 1] const isFirstMessageInGroup = previousMessage?.authorId !== message.authorId return ( // This wrapper div is necessary for accurate layout calculations // when new messages cause the transcript to scroll to the bottom.
) })}
) }