Newer
Older
cortex-hub / ui / client-app / src / components / ChatWindow.js
import React, { useState } from "react";
import ReactMarkdown from 'react-markdown';
import './ChatWindow.css';
import FileListComponent from "./FileList";
import DiffViewer from "./DiffViewer";

// Individual message component for better modularity
const ChatMessage = ({ message }) => {
  const [selectedFile, setSelectedFile] = useState(null);
  const [isReasoningExpanded, setIsReasoningExpanded] = useState(false);

  const toggleReasoning = () => {
    setIsReasoningExpanded(!isReasoningExpanded);
  };

    // A simple handler to close the diff viewer
    const handleCloseDiff = () => {
      setSelectedFile(null);
    };
  
    const handleFileClick = (file) => {
      setSelectedFile(file);
    };

  const messageClasses = `max-w-md p-4 rounded-lg shadow-md ${
    message.isUser 
      ? "bg-indigo-500 text-white ml-auto" 
      : "bg-gray-200 dark:bg-gray-700 text-gray-900 dark:text-gray-100 mr-auto"
  }`;

  return (
    <div className={messageClasses}>
      {message.reasoning && (
        <div className="mb-2">
          <button 
            onClick={toggleReasoning} 
            className="text-sm font-semibold text-indigo-700 hover:text-indigo-800 dark:text-gray-300 dark:hover:text-gray-100 focus:outline-none"
          >
            {isReasoningExpanded ? "Hide Reasoning ▲" : "Show Reasoning ▼"}
          </button>
          <div 
            className={`mt-2 text-xs transition-max-h duration-500 ease-in-out overflow-hidden ${
              isReasoningExpanded ? "max-h-96" : "max-h-0"
            } 
            text-gray-700 dark:text-gray-300`} 
          >
            <ReactMarkdown>{message.reasoning}</ReactMarkdown>
          </div>
        </div>
      )}
      <ReactMarkdown>{message.text}</ReactMarkdown>
      {message.code_diff && (
                <FileListComponent files={message.code_diff} onFileClick={handleFileClick} />
            )}
      {selectedFile && <DiffViewer diff={selectedFile.diff} onClose={handleCloseDiff} />}
    </div>
  );
};

// Main ChatWindow component remains the same
const ChatWindow = ({ chatHistory }) => {
  return (
    <div className="space-y-4">
      {chatHistory.map((message, index) => (
        <div
          key={index}
          className={`flex ${
            message.isUser ? "justify-end" : "justify-start"
          }`}
        >
          <ChatMessage message={message} />
        </div>
      ))}
    </div>
  );
};

export default ChatWindow;