The following code is the App.js for a React app of a chatbot interface. I have a sidebar for keeping chats and being able to go back to any past chat, but the actual functionality is not working yet. I want to switch to using Redux for this. Incorporate it into my project.

App.js:
<code>
import React, { useState } from "react";
import axios from "axios";
import Sidebar from "./components/Sidebar";
import Header from "./components/Header";
import ChatWindow from "./components/ChatWindow";
import CodeSidebar from "./components/CodeSidebar";
import { FaSearch } from "react-icons/fa";

function App() {
  const [input, setInput] = useState("");
  const [chats, setChats] = useState([]);
  const [activeChat, setActiveChat] = useState(null);
  const [codeSnippet, setCodeSnippet] = useState(null);
  const [commonQueries] = useState([
    "What's the weather today?",
    "Tell me a joke",
    "Show me a React example",
  ]);

  const sendMessage = async () => {
    if (input.trim() === "") return;

    const updatedChats = [...chats];
    if (activeChat === null) {
      // Starting a new chat
      updatedChats.push([]);
      setActiveChat(updatedChats.length - 1);
    }

    const chatIndex = activeChat !== null ? activeChat : updatedChats.length - 1;

    // Add user message
    const userMessage = { sender: "user", text: input };
    updatedChats[chatIndex] = [...(updatedChats[chatIndex] || []), userMessage];
    setChats(updatedChats);

    try {
      const response = await axios.post("http://localhost:8000/api/chat", {
        text: input,
      });

      // Check if the response contains code
      const botText = response.data.response;
      let botMessage = { sender: "bot", text: botText };

      // Simple check for code block (you might want to implement a better logic)
      const codeMatch = botText.match(/```(?:\w+)?\n([\s\S]*?)```/);
      if (codeMatch) {
        const code = codeMatch[1];
        botMessage = { sender: "bot", text: botText, isCode: true, code };
      }

      updatedChats[chatIndex] = [...updatedChats[chatIndex], botMessage];
      setChats([...updatedChats]);
    } catch (error) {
      console.error("Error sending message:", error);
      const errorMessage = {
        sender: "bot",
        text: "Sorry, something went wrong.",
      };
      updatedChats[chatIndex] = [...updatedChats[chatIndex], errorMessage];
      setChats([...updatedChats]);
    }

    setInput("");
  };

  const startNewChat = () => {
    setActiveChat(null);
    setCodeSnippet(null);
  };

  const handleCodeClick = (code) => {
    setCodeSnippet(code);
  };

  return (
    <div className="flex h-screen">
      {/* Sidebar */}
      <Sidebar
        chats={chats}
        setActiveChat={setActiveChat}
        activeChat={activeChat}
        onNewChat={startNewChat}
      />

      {/* Main Content */}
      <div className="flex-1 flex flex-col">
        {/* Header */}
        <Header />

        {/* Search Box and Common Queries (Visible when no active chat) */}
        {activeChat === null && (
          <div className="p-4 bg-gray-100">
            {/* Search Box */}
            <div className="flex mb-4">
              <input
                type="text"
                className="flex-grow border rounded-l px-4 py-2 focus:outline-none"
                placeholder="Enter your query..."
                value={input}
                onChange={(e) => setInput(e.target.value)}
                onKeyPress={(e) => {
                  if (e.key === "Enter") sendMessage();
                }}
              />
              <button
                className="bg-blue-500 text-white px-4 py-2 rounded-r hover:bg-blue-600"
                onClick={sendMessage}
              >
                <FaSearch />
              </button>
            </div>

            {/* Common Queries */}
            <div>
              <h3 className="text-lg font-semibold mb-2">Common Queries:</h3>
              <div className="flex flex-wrap gap-2">
                {commonQueries.map((query, index) => (
                  <button
                    key={index}
                    className="bg-gray-200 text-gray-800 px-3 py-1 rounded hover:bg-gray-300"
                    onClick={() => setInput(query)}
                  >
                    {query}
                  </button>
                ))}
              </div>
            </div>
          </div>
        )}

        {/* Chat Window (Visible when a chat is active) */}
        {activeChat !== null && (
          <ChatWindow
            messages={chats[activeChat]}
            onSend={sendMessage}
            input={input}
            setInput={setInput}
            onCodeClick={handleCodeClick}
          />
        )}
      </div>

      {/* Code Sidebar */}
      {codeSnippet && (
        <CodeSidebar code={codeSnippet} onClose={() => setCodeSnippet(null)} />
      )}
    </div>
  );
}

export default App;
</code>

Sidebar.js:
<code>
import React from "react";
import { FaPlus, FaHistory } from "react-icons/fa";

function Sidebar({ chats, setActiveChat, activeChat, onNewChat }) {
  return (
    <div className="w-64 bg-white shadow-md h-screen flex flex-col">
      <div className="flex items-center justify-between p-4 border-b">
        <h2 className="text-xl font-semibold">Chats</h2>
        <button
          onClick={onNewChat}
          className="text-blue-500 hover:text-blue-700"
          title="New Chat"
        >
          <FaPlus size={20} />
        </button>
      </div>
      <div className="flex-1 overflow-y-auto">
        {chats.length === 0 ? (
          <p className="p-4 text-gray-500">No chats yet. Start a new chat!</p>
        ) : (
          chats.map((chat, index) => (
            <div
              key={index}
              onClick={() => setActiveChat(index)}
              className={`p-4 cursor-pointer hover:bg-gray-100 ${activeChat === index ? "bg-gray-200" : ""} flex items-center justify-between`}
            >
              <span>Chat {index + 1}</span>
              <FaHistory size={14} className="text-gray-500" />
            </div>
          ))
        )}
      </div>
    </div>
  );
}

export default Sidebar;
</code>

ChatWindow.js:
<code>
import React, { useRef, useEffect } from "react";
import { FaCopy } from "react-icons/fa";

function ChatWindow({ messages, onSend, input, setInput, onCodeClick }) {
  const messagesEndRef = useRef(null);

  const scrollToBottom = () => {
    messagesEndRef.current?.scrollIntoView({ behavior: "smooth" });
  };

  useEffect(scrollToBottom, [messages]);

  return (
    <div className="flex flex-col flex-1">
      <div className="flex-1 overflow-y-auto p-4 bg-gray-50">
        {messages.map((msg, index) => (
          <div
            key={index}
            className={`mb-4 flex ${
              msg.sender === "user" ? "justify-end" : "justify-start"
            }`}
          >
            <div
              className={`px-4 py-2 rounded-lg max-w-xs ${
                msg.sender === "user"
                  ? "bg-blue-500 text-white"
                  : "bg-white text-gray-800 shadow"
              }`}
              onClick={() => {
                if (msg.isCode && onCodeClick) onCodeClick(msg.code);
              }}
            >
              {msg.isCode ? (
                <pre className="whitespace-pre-wrap cursor-pointer">
                  {msg.code.length > 100
                    ? `${msg.code.substring(0, 100)}...`
                    : msg.code}
                  {msg.code.length > 100 && (
                    <span className="text-blue-300"> Click to expand</span>
                  )}
                </pre>
              ) : (
                msg.text
              )}
            </div>
          </div>
        ))}
        <div ref={messagesEndRef} />
      </div>
      <div className="flex p-4 bg-white border-t">
        <input
          type="text"
          className="flex-grow border rounded-l px-4 py-2 focus:outline-none"
          placeholder="Type your message..."
          value={input}
          onChange={(e) => setInput(e.target.value)}
          onKeyPress={(e) => {
            if (e.key === "Enter") onSend();
          }}
        />
        <button
          className="bg-blue-500 text-white px-4 py-2 rounded-r hover:bg-blue-600"
          onClick={onSend}
        >
          Send
        </button>
      </div>
    </div>
  );
}

export default ChatWindow;
</code>

main.py (backend):
<code>
import logging
import ast
from fastapi import FastAPI, HTTPException
from fastapi.middleware.cors import CORSMiddleware
from pydantic import BaseModel
from gradio_client import Client

# Configure logging
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger()

app = FastAPI()

# Configure CORS
app.add_middleware(
       CORSMiddleware,
       allow_origins=["*"],  # Allows all origins
       allow_credentials=True,
       allow_methods=["*"],  # Allows all methods
       allow_headers=["*"],  # Allows all headers
   )

# Initialize the Gradio Client
client = Client("yuntian-deng/o1mini")

class Message(BaseModel):
    text: str

def extract_response(data):
    parsed_data = ast.literal_eval(data)
    response = parsed_data[0][0][1]
    return response

@app.post("/api/chat")
async def chat(message: Message):
    try:
        logger.info(f"Received message: {message.text}")
        # Send the message to the Hugging Face Space
        response = client.predict(message.text, api_name="/predict")
        logger.info(f"Raw response from Gradio Client: {response}")
        
        # Adjust the response extraction based on actual response structure
        # For illustration, assuming response is a string
        chatbot_response = response if isinstance(response, str) else str(response)
        logging.info(f"Chatbot response type: {type(chatbot_response)}")
        
        logger.info(f"Chatbot response: {chatbot_response}")
        return {"response": extract_response(chatbot_response)}
    except Exception as e:
        logger.error("Error processing chat request", exc_info=True)
        raise HTTPException(status_code=500, detail=str(e))
</code>