109 lines
		
	
	
	
		
			3.5 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
			
		
		
	
	
			109 lines
		
	
	
	
		
			3.5 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
| import React, { ForwardedRef, useState, useEffect, useRef } from 'react';
 | |
| 
 | |
| type Message = {
 | |
|   role: string
 | |
|   content: string
 | |
| }
 | |
| 
 | |
| interface ConversationProps {
 | |
|   messages: Message[];
 | |
|   onStopClick: () => void;
 | |
|   onResendClick: () => void;
 | |
|   onEditClick: () => void;
 | |
|   onCopyClick: () => void;
 | |
|   isClicked: boolean
 | |
| }
 | |
| 
 | |
| const ConversationFrontend = React.forwardRef<HTMLDivElement, ConversationProps>(
 | |
|   ({ messages, onStopClick, onResendClick, onEditClick, onCopyClick, isClicked }, ref: ForwardedRef<HTMLDivElement>) => {
 | |
|     const [isScrolling, setIsScrolling] = useState(true);
 | |
|     const messagesEndRef = useRef<HTMLDivElement | null>(null);
 | |
| 
 | |
|     useEffect(() => {
 | |
|       const observer = new IntersectionObserver(
 | |
|         (entries) => {
 | |
|           if (entries[0].isIntersecting) {
 | |
|             console.log('End of messages reached');
 | |
|             setIsScrolling(true);
 | |
|           } else {
 | |
|             console.log('End of messages not reached');
 | |
|             setIsScrolling(false);
 | |
|           }
 | |
|         },
 | |
|         {
 | |
|           root: document.querySelector('.output'),
 | |
|           threshold: 1.0, // Ensure the whole element is visible
 | |
|         }
 | |
|       );
 | |
|       
 | |
|       const endOfMessages = messagesEndRef.current;
 | |
|       if (endOfMessages) {
 | |
|         observer.observe(endOfMessages);
 | |
|       }
 | |
| 
 | |
|       return () => {
 | |
|         if (endOfMessages) {
 | |
|           observer.unobserve(endOfMessages);
 | |
|         }
 | |
|       };
 | |
|     }, [messages]);
 | |
| 
 | |
|     // Scroll to bottom when new messages arrive
 | |
|     useEffect(() => {
 | |
|       if (isScrolling) {
 | |
|         messagesEndRef.current?.scrollIntoView({ behavior: 'smooth' });
 | |
|       }
 | |
|     }, [messages, isScrolling]);
 | |
| 
 | |
|     return (
 | |
|       <div className="output" ref={ref}>
 | |
|         <div className="conversation resize" id="conversation">
 | |
|           {messages.map((message, index) => {
 | |
|             if (index >= 1) {
 | |
| 
 | |
|               return (
 | |
|                 <div
 | |
|                   key={index}
 | |
|                   className={message.role === "user" ? 'user-message' : 'ai-message'}
 | |
|                 >
 | |
|                   <p> {message.content}</p>
 | |
|                 </div>
 | |
|               );
 | |
|             }
 | |
|           })}
 | |
| 
 | |
|           <div className="button-container">
 | |
|             <div className="tooltip">
 | |
|               <button type="button" onClick={onStopClick}>
 | |
|                 <img src="/img/resend.svg" alt="stop" />
 | |
|               </button>
 | |
|               <span className="tooltiptext">Stop</span>
 | |
|             </div>
 | |
|             <div className="tooltip">
 | |
|               <button type="button" onClick={onResendClick}>
 | |
|                 <img src="/img/resend.svg" alt="resend" />
 | |
|               </button>
 | |
|               <span className="tooltiptext">Resend</span>
 | |
|             </div>
 | |
|             <div className="tooltip">
 | |
|               <button type="button" onClick={onEditClick}>
 | |
|                 <img src="/img/edit.svg" alt="edit" />
 | |
|               </button>
 | |
|               <span className="tooltiptext">Edit</span>
 | |
|             </div>
 | |
|             <div className="tooltip">
 | |
|               <button type="button" onClick={onCopyClick}>
 | |
|                 <img src="/img/copy.svg" alt="copy" />
 | |
|               </button>
 | |
|               <span className="tooltiptext">{isClicked?"Copied!": "Copy" }</span>
 | |
|             </div>
 | |
|           </div>
 | |
|           <div className={"endOfMessages"} ref={messagesEndRef} style={{height:"10px"}}/>
 | |
|         </div>
 | |
|         <button id="scrollToBottom" disabled={isScrolling?true:false} style={{visibility: isScrolling?"hidden":"visible"}} onClick={()=> setIsScrolling(true)}>Down</button>
 | |
|       </div>
 | |
|     );
 | |
|   } 
 | |
| );
 | |
| 
 | |
| export default ConversationFrontend;
 |