import { GetSessionDataManager, RoomObjectType } from '@nitrots/nitro-renderer'; import { FC, UIEvent, useCallback, useEffect, useMemo, useRef, useState } from 'react'; import { ChatEntryType, LocalizeText, SanitizeHtml } from '../../../../api'; import { DraggableWindowPosition, NitroCardContentView, NitroCardHeaderView, NitroCardView } from '../../../../common'; import { useChatHistory, useChatWindow, useOnClickChat } from '../../../../hooks'; import { useRoom } from '../../../../hooks/rooms'; const BOTTOM_SCROLL_THRESHOLD = 20; export const ChatWidgetWindowView: FC<{}> = () => { const contentRef = useRef(null); const lastScrollTop = useRef(0); const [ isAutoScrollEnabled, setIsAutoScrollEnabled ] = useState(true); const [ hidePets, setHidePets ] = useState(false); const [ hideAvatars, setHideAvatars ] = useState(false); const [ hideBalloons, setHideBalloons ] = useState(false); const [ search, setSearch ] = useState(''); const { chatHistory = [], clearChatHistory = null } = useChatHistory(); const [ , setChatWindowEnabled ] = useChatWindow(); const { roomSession = null } = useRoom(); const { onClickChat } = useOnClickChat(); const ownUserId = (GetSessionDataManager()?.userId || -1); const roomChatHistory = useMemo(() => { const normalizedSearch = search.trim().toLowerCase(); return chatHistory.filter(chat => { if(chat.type !== ChatEntryType.TYPE_CHAT) return false; if(chat.roomId !== roomSession?.roomId) return false; if(hidePets && chat.entityType === RoomObjectType.PET) return false; if(!normalizedSearch.length) return true; return (`${ chat.name } ${ chat.message || '' } ${ chat.originalMessage || '' } ${ chat.translatedMessage || '' }`.toLowerCase().includes(normalizedSearch)); }); }, [ chatHistory, roomSession?.roomId, hidePets, search ]); const isAtBottom = useCallback((element: HTMLDivElement) => { const distanceToBottom = (element.scrollHeight - element.clientHeight - element.scrollTop); return (distanceToBottom <= BOTTOM_SCROLL_THRESHOLD); }, []); const scrollToLatest = useCallback((smooth: boolean = true) => { if(!contentRef.current) return; const element = contentRef.current; element.scrollTo({ top: element.scrollHeight, behavior: smooth ? 'smooth' : 'auto' }); }, []); const onScroll = useCallback((event: UIEvent) => { const element = event.currentTarget; const atBottom = isAtBottom(element); const isScrollingUp = (element.scrollTop < lastScrollTop.current); lastScrollTop.current = element.scrollTop; if(atBottom) { if(!isAutoScrollEnabled) setIsAutoScrollEnabled(true); return; } if(isAutoScrollEnabled && isScrollingUp) setIsAutoScrollEnabled(false); }, [ isAtBottom, isAutoScrollEnabled ]); useEffect(() => { if(!contentRef.current || !isAutoScrollEnabled) return; scrollToLatest(); }, [ roomChatHistory.length, isAutoScrollEnabled, scrollToLatest ]); return ( { setChatWindowEnabled(false); if(clearChatHistory) clearChatHistory(); } } />
setSearch(event.target.value) } />
{ roomChatHistory.map(chat => { const isOwnMessage = (chat.webId === ownUserId); const rowClassName = `mb-1 flex items-start gap-1 break-words ${ isOwnMessage ? 'justify-end' : '' }`; const messageClassName = `message${ chat.chatType === 1 ? ' italic text-[#595959]' : '' }${ chat.chatType === 2 ? ' font-bold' : '' }`; return (
{ hideBalloons && !hideAvatars &&
} { hideBalloons && (
{ !chat.showTranslation && } { chat.showTranslation &&
original:
translate:
}
) } { !hideBalloons && (
{ chat.style === 0 && (
) }
{ !hideAvatars && chat.imageUrl && chat.imageUrl.length > 0 && (
) }
{ !chat.showTranslation && } { chat.showTranslation &&
original:
translate:
}
) }
); }) }
{ !isAutoScrollEnabled && ( ) } ); };