Path: blob/master/cloud/ai-service-apps/nextjs-carbon-react-ui/src/components/QAPanel/QAPanel.js
6408 views
"use client";12import { useState, useRef, useCallback, useMemo, useEffect } from "react";3import { Button } from "@carbon/react";4import { StopOutline, Send } from "@carbon/react/icons";5import { TextNode } from "lexical";6import { LexicalComposer } from "@lexical/react/LexicalComposer";7import { LexicalErrorBoundary } from "@lexical/react/LexicalErrorBoundary";8import { HistoryPlugin } from "@lexical/react/LexicalHistoryPlugin";9import { ClearEditorPlugin } from "@lexical/react/LexicalClearEditorPlugin";10import { ContentEditable } from "@lexical/react/LexicalContentEditable";11import { PlainTextPlugin } from "@lexical/react/LexicalPlainTextPlugin";12import { AutoFocusPlugin } from "@lexical/react/LexicalAutoFocusPlugin";13import InitialMessage from "../InitialMessage/InitialMessage";14import InputPlugin from "../InputPlugin/InputPlugin";15import ChatItem from "../ChatItem/ChatItem";16import { MESSAGE_ROLE, MESSAGE_STATUS } from "@/utils/constants";1718const QAPanel = ({ messages, onInput, onAbort, intersectorRef, isRunning }) => {19const [questionText, setQuestionText] = useState("");20const hasMessages = messages.length > 0;21const chatMessagesRef = useRef(null);2223const handleOnSubmit = useCallback(() => {24onInput(questionText);25setQuestionText("");26}, [onInput, questionText]);2728const handleOnAbort = useCallback(() => {29onAbort();30}, [onAbort]);3132const textareaElement = (33<LexicalComposer34initialConfig={{35namespace: "chat-input",36editable: true,37onError: (err) => logger.error(err),38editorState: () => {},39nodes: [TextNode],40}}41>42<div className="qa-panel__editorContainer">43<div className="qa-panel__inputWrapper">44<PlainTextPlugin45contentEditable={<ContentEditable className="qa-panel__input" />}46placeholder={<div className="qa-panel__inputPlaceholder">Type something...</div>}47ErrorBoundary={LexicalErrorBoundary}48/>49</div>50<InputPlugin51onChange={(text) => setQuestionText(text)}52input={questionText}53onSubmit={handleOnSubmit}54/>55<AutoFocusPlugin />56<HistoryPlugin />57<ClearEditorPlugin />58</div>59</LexicalComposer>60);6162const _renderInitialMessage = useMemo(63() => (64<div className="qa-panel__chatHistory qa-panel__initialMessageDisplayed">65<ChatItem66message={{67status: MESSAGE_STATUS.READY,68content: <InitialMessage onQuestion={onInput} />,69role: MESSAGE_ROLE.ASSISTANT,70initial: true,71}}72/>73</div>74),75[onInput]76);7778const submitButton = useMemo(79() => (80<Button81id="question-enter"82className="qa-panel__submitBtn"83onClick={isRunning ? handleOnAbort : handleOnSubmit}84kind={isRunning ? "danger--ghost" : "ghost"}85hasIconOnly86renderIcon={isRunning ? StopOutline : Send}87iconDescription={isRunning ? "Abort" : "Submit"}88size="sm"89disabled={!questionText && !isRunning}90/>91),92[isRunning, handleOnAbort, handleOnSubmit, questionText]93);9495useEffect(() => {96if (!messages.length) {97setQuestionText("");98}99}, [messages]);100101return (102<div className="qa-panel__container">103<div className="qa-panel__innerPanel">104{!hasMessages ? (105_renderInitialMessage106) : (107<div id="chat-messages" ref={chatMessagesRef} className="qa-panel__chatHistory">108<div id="auto-scroll" ref={intersectorRef} />109{messages.map((message, index) => (110<ChatItem111key={`${message.role}:${message.timestamp}`}112message={message}113last={!index}114/>115))}116</div>117)}118<div className="qa-panel__questionSection">119<div className="qa-panel__questionInputContainer">120{textareaElement}121{submitButton}122</div>123</div>124</div>125</div>126);127};128129export default QAPanel;130131132