docs: use Kapa React SDK (#12792)

This commit is contained in:
Shahed Nasser
2025-06-20 18:24:14 +03:00
committed by GitHub
parent 77d0f00929
commit ab21ac57ca
27 changed files with 462 additions and 875 deletions
@@ -1,33 +1,33 @@
import React, { useEffect, useRef } from "react"
import clsx from "clsx"
import { useAiAssistantChat } from "../../../../providers/AiAssistant/Chat"
import { ArrowUpCircleSolid } from "@medusajs/icons"
import { useAiAssistant } from "../../../../providers"
import { useChat } from "@kapaai/react-sdk"
import { useAiAssistantChatNavigation } from "../../../../hooks"
export const AiAssistantChatWindowInput = () => {
const {
inputRef,
question,
setQuestion,
handleSubmit: submitQuestion,
loading,
getThreadItems,
} = useAiAssistantChat()
const { chatOpened } = useAiAssistant()
type AiAssistantChatWindowInputProps = {
chatWindowRef: React.RefObject<HTMLDivElement | null>
}
export const AiAssistantChatWindowInput = ({
chatWindowRef,
}: AiAssistantChatWindowInputProps) => {
const { chatOpened, inputRef, loading } = useAiAssistant()
const { submitQuery, conversation } = useChat()
const [question, setQuestion] = React.useState("")
const formRef = useRef<HTMLFormElement | null>(null)
const onSubmit = (e?: React.FormEvent<HTMLFormElement>) => {
e?.preventDefault()
submitQuestion()
submitQuery(question)
setQuestion("")
}
const handleKeyboardDown = (e: React.KeyboardEvent<HTMLTextAreaElement>) => {
if (e.key === "ArrowUp" && !question) {
const lastQuestion = getThreadItems()
.reverse()
.find((item) => item.type === "question")
const lastQuestion = conversation.getLatest()?.question
if (lastQuestion) {
setQuestion(lastQuestion.content)
setQuestion(lastQuestion)
}
return
}
@@ -87,6 +87,16 @@ export const AiAssistantChatWindowInput = () => {
}
}, [chatOpened, inputRef.current])
useAiAssistantChatNavigation({
getChatWindowElm: () => chatWindowRef.current as HTMLElement | null,
getInputElm: () => inputRef.current as HTMLTextAreaElement | null,
focusInput: () =>
inputRef.current?.focus({
preventScroll: true,
}),
question,
})
return (
<div
className={clsx(
@@ -103,7 +113,7 @@ export const AiAssistantChatWindowInput = () => {
"appearance-none text-base md:text-small placeholder:text-medusa-fg-muted",
"text-medusa-fg-base max-h-[210px] overflow-auto resize-none bg-transparent",
"focus:outline-none focus:ring-0 disabled:cursor-not-allowed max-h-[210px]",
"disabled:!bg-transparent disabled:text-medusa-fg-disabled"
"disabled:!bg-transparent disabled:text-medusa-fg-disabled disabled:placeholder:text-medusa-fg-disabled"
)}
value={question}
onChange={(e) => setQuestion(e.target.value)}
@@ -1,31 +1,37 @@
"use client"
import clsx from "clsx"
import React, { useCallback, useEffect, useRef, useState } from "react"
import React, {
Fragment,
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 { useKeyboardShortcut } from "../../.."
import { AiAssistantChatWindowFooter } from "./Footer"
import { useChat } from "@kapaai/react-sdk"
const DEFAULT_HEIGHT = "calc(100% - 8px)"
export const AiAssistantChatWindow = () => {
const { chatOpened, setChatOpened, chatType: type } = useAiAssistant()
const {
chatOpened,
setChatOpened,
chatType: type,
inputRef,
contentRef,
loading,
} = useAiAssistant()
const { conversation, error } = useChat()
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<HTMLDivElement | null>(null)
useEffect(() => {
@@ -39,21 +45,27 @@ export const AiAssistantChatWindow = () => {
}, [chatOpened])
const getThreadItems = useCallback(() => {
const sortedThread = getChatThreadItems()
return sortedThread.map((item, index) => (
<AiAssistantThreadItem item={item} key={index} />
return conversation.map((item, index) => (
<Fragment key={index}>
<AiAssistantThreadItem
item={{
type: "question",
content: item.question,
sources: item.sources,
question_id: item.id,
}}
/>
<AiAssistantThreadItem
item={{
type: "answer",
content: item.answer,
sources: item.sources,
question_id: item.id,
}}
/>
</Fragment>
))
}, [getChatThreadItems])
useAiAssistantChatNavigation({
getChatWindowElm: () => chatWindowRef.current as HTMLElement | null,
getInputElm: () => inputRef.current as HTMLTextAreaElement | null,
focusInput: () =>
inputRef.current?.focus({
preventScroll: true,
}),
})
}, [conversation])
useKeyboardShortcut({
metakey: false,
@@ -75,7 +87,8 @@ export const AiAssistantChatWindow = () => {
}
setShowFade(
!loading &&
parentElm.offsetHeight + parentElm.scrollTop < parentElm.scrollHeight
parentElm.offsetHeight + parentElm.scrollTop <
parentElm.scrollHeight - 1
)
}
@@ -168,14 +181,13 @@ export const AiAssistantChatWindow = () => {
)}
>
<div ref={contentRef}>
{!thread.length && <AiAssistantSuggestions />}
{!conversation.length && <AiAssistantSuggestions />}
{getThreadItems()}
{(answer.length || loading) && (
{error?.length && (
<AiAssistantThreadItem
item={{
type: "answer",
content: answer,
order: 0,
type: "error",
content: error,
}}
/>
)}
@@ -189,7 +201,7 @@ export const AiAssistantChatWindow = () => {
)}
></span>
</div>
<AiAssistantChatWindowInput />
<AiAssistantChatWindowInput chatWindowRef={chatWindowRef} />
<AiAssistantChatWindowFooter />
</div>
</>