Newer
Older
cortex-hub / frontend / src / App.js
// App.js
import React, { useState, useEffect } from "react";
import Navbar from "./components/Navbar";
import HomePage from "./pages/HomePage";
import VoiceChatPage from "./pages/VoiceChatPage";
import SwarmControlPage from "./pages/SwarmControlPage";
import LoginPage from "./pages/LoginPage";
import SettingsPage from "./pages/SettingsPage";
import ProfilePage from "./pages/ProfilePage";
import NodesPage from "./pages/NodesPage";
import SkillsPage from "./pages/SkillsPage";
import { getUserStatus, logout, getUserProfile } from "./services/apiService";

const Icon = ({ path, onClick, className }) => (
  <svg
    xmlns="http://www.w3.org/2000/svg"
    viewBox="0 0 24 24"
    fill="none"
    stroke="currentColor"
    strokeWidth="2"
    strokeLinecap="round"
    strokeLinejoin="round"
    className={`w-6 h-6 cursor-pointer transition-colors duration-200 ${className}`}
    onClick={onClick}
  >
    <path d={path} />
  </svg>
);

export default function App() {
  const [currentPage, setCurrentPage] = useState("home");
  const [isSidebarOpen, setIsSidebarOpen] = useState(false);
  const [isLoggedIn, setIsLoggedIn] = useState(false);
  const [userId, setUserId] = useState(null);
  const [userProfile, setUserProfile] = useState(null);

  const authenticatedPages = ["voice-chat", "swarm-control", "settings", "profile", "nodes", "skills"];
  const pageToPath = {
    "home": "/",
    "voice-chat": "/voice",
    "swarm-control": "/swarm",
    "settings": "/settings",
    "profile": "/profile",
    "nodes": "/nodes",
    "skills": "/skills",
    "login": "/login"
  };
  const pathToPage = Object.fromEntries(Object.entries(pageToPath).map(([pk, pv]) => [pv, pk]));

  // Sync state with URL on mount and handle popstate
  useEffect(() => {
    const handlePopState = () => {
      const path = window.location.pathname;
      const page = pathToPage[path] || "home";
      setCurrentPage(page);
    };

    window.addEventListener("popstate", handlePopState);

    // Initial sync
    const initialPath = window.location.pathname;
    const initialPage = pathToPage[initialPath] || "home";
    if (initialPage !== currentPage) {
      setCurrentPage(initialPage);
    }

    return () => window.removeEventListener("popstate", handlePopState);
  }, []);


  useEffect(() => {
    const urlParams = new URLSearchParams(window.location.search);
    const userIdFromUrl = urlParams.get('user_id');

    if (userIdFromUrl && !localStorage.getItem('userId')) {
      localStorage.setItem('userId', userIdFromUrl);
      console.log('User ID from URL saved to localStorage:', userIdFromUrl);
      window.history.replaceState({}, document.title, window.location.pathname);
    }
  }, []);

  useEffect(() => {
    const checkLoginStatus = async () => {
      const storedUserId = localStorage.getItem("userId");

      if (storedUserId) {
        try {
          const status = await getUserStatus(storedUserId);
          if (status.is_logged_in) {
            setIsLoggedIn(true);
            setUserId(storedUserId);
            // Fetch profile on success
            const profile = await getUserProfile();
            setUserProfile(profile);

            if (currentPage === "login") {
              setCurrentPage("home");
            }
          } else {
            setIsLoggedIn(false);
            setUserId(null);
            setUserProfile(null);
            localStorage.removeItem("userId");
            if (authenticatedPages.includes(currentPage)) {
              setCurrentPage("login");
            }
          }
        } catch (error) {
          console.error("Failed to check user status:", error);
          setIsLoggedIn(false);
          setUserId(null);
          setUserProfile(null);
          localStorage.removeItem("userId");
          if (authenticatedPages.includes(currentPage)) {
            setCurrentPage("login");
          }
        }
      } else {
        setIsLoggedIn(false);
        setUserId(null);
        setUserProfile(null);
        if (authenticatedPages.includes(currentPage)) {
          setCurrentPage("login");
        }
      }
    };

    checkLoginStatus();
  }, [currentPage]);

  const handleLogout = async () => {
    try {
      await logout();
      setIsLoggedIn(false);
      setUserId(null);
      setUserProfile(null);
      localStorage.removeItem("userId");
      setCurrentPage("home");
    } catch (error) {
      console.error("Logout failed:", error);
    }
  };

  const handleNavigate = (page) => {
    if (authenticatedPages.includes(page) && !isLoggedIn) {
      setCurrentPage("login");
      window.history.pushState({}, "", pageToPath["login"]);
    } else {
      setCurrentPage(page);
      window.history.pushState({}, "", pageToPath[page] || "/");
    }
  };

  const toggleSidebar = () => {
    setIsSidebarOpen(!isSidebarOpen);
  };

  const renderPage = () => {
    switch (currentPage) {
      case "home":
        // Pass both isLoggedIn and handleLogout to HomePage
        return <HomePage onNavigate={handleNavigate} isLoggedIn={isLoggedIn} />;
      case "voice-chat":
        return <VoiceChatPage Icon={Icon} />;
      case "swarm-control":
        return <SwarmControlPage onNavigate={handleNavigate} Icon={Icon} />;
      case "settings":
        // Only admins can see global settings
        if (userProfile?.role !== "admin") {
          return <ProfilePage onLogout={handleLogout} />;
        }
        return <SettingsPage />;
      case "profile":
        return <ProfilePage onLogout={handleLogout} />;
      case "nodes":
        return <NodesPage user={userProfile} />;
      case "skills":
        return <SkillsPage user={userProfile} Icon={Icon} />;
      case "login":
        return <LoginPage />;
      default:
        return <HomePage onNavigate={handleNavigate} isLoggedIn={isLoggedIn} />;
    }
  };

  return (
    <div className="flex h-screen overflow-hidden bg-gray-100 dark:bg-gray-900 font-sans">
      {currentPage !== "login" && (
        <Navbar
          isOpen={isSidebarOpen}
          onToggle={toggleSidebar}
          onNavigate={handleNavigate}
          onLogout={handleLogout}
          isLoggedIn={isLoggedIn}
          user={userProfile}
          Icon={Icon}
        />
      )}
      <div className="flex-grow overflow-hidden">
        {renderPage()}
      </div>
    </div>
  );
}