"use client" import clsx from "clsx" import React, { useCallback, useEffect, useRef, useState } from "react" import { useAiAssistant, useIsBrowser } from "../../../providers" import { AiAssistantChatWindowHeader } from "./Header" import { useAiAssistantChat } from "../../../providers/AiAssistant/Chat" import { AiAssistantSuggestions } from "../Suggestions" import { AiAssistantThreadItem } from "../ThreadItem" import { AiAssistantChatWindowInput } from "./Input" import { useAiAssistantChatNavigation, useKeyboardShortcut } from "../../.." import { AiAssistantChatWindowFooter } from "./Footer" const DEFAULT_HEIGHT = "calc(100% - 8px)" export const AiAssistantChatWindow = () => { const { chatOpened, setChatOpened, chatType: type } = useAiAssistant() const [height, setHeight] = useState(DEFAULT_HEIGHT) const [showFade, setShowFade] = useState(false) const { isBrowser } = useIsBrowser() const { inputRef, thread, getThreadItems: getChatThreadItems, answer, loading, contentRef, } = useAiAssistantChat() const chatWindowRef = useRef(null) useEffect(() => { if (chatOpened) { inputRef.current?.focus({ preventScroll: true, }) } else { inputRef.current?.blur() } }, [chatOpened]) const getThreadItems = useCallback(() => { const sortedThread = getChatThreadItems() return sortedThread.map((item, index) => ( )) }, [getChatThreadItems]) useAiAssistantChatNavigation({ getChatWindowElm: () => chatWindowRef.current as HTMLElement | null, getInputElm: () => inputRef.current as HTMLTextAreaElement | null, focusInput: () => inputRef.current?.focus({ preventScroll: true, }), }) useKeyboardShortcut({ metakey: false, shortcutKeys: ["escape"], checkEditing: false, action: () => { if (!chatWindowRef.current?.contains(document.activeElement)) { return } setChatOpened(false) }, }) const checkShowFade = () => { const parentElm = contentRef.current?.parentElement if (!parentElm) { return } setShowFade( !loading && parentElm.offsetHeight + parentElm.scrollTop < parentElm.scrollHeight ) } useEffect(() => { if (!contentRef.current?.parentElement) { return } contentRef.current.parentElement.addEventListener("scroll", checkShowFade) return () => { contentRef.current?.parentElement?.removeEventListener( "scroll", checkShowFade ) } }, [contentRef.current]) useEffect(() => { if (loading) { setShowFade(false) } else { checkShowFade() } }, [loading]) const changeHeightForViewport = () => { if (!window.visualViewport?.height) { setHeight(DEFAULT_HEIGHT) return } setHeight(`${window.visualViewport.height - 8}px`) } useEffect(() => { if (!isBrowser) { return } window.visualViewport?.addEventListener("resize", changeHeightForViewport) return () => { window.visualViewport?.removeEventListener( "resize", changeHeightForViewport ) } }, [isBrowser]) useEffect(() => { checkShowFade() }, [height]) return ( <>
setChatOpened(false)} />
{!thread.length && } {getThreadItems()} {(answer.length || loading) && ( )}
) }