"use client"; import { useState, useEffect } from "react"; import PropTypes from "prop-types"; import Link from "next/link"; import { usePathname } from "next/navigation"; import { cn } from "@/shared/utils/cn"; import { APP_CONFIG, UPDATER_CONFIG } from "@/shared/constants/config"; import { MEDIA_PROVIDER_KINDS } from "@/shared/constants/providers"; import { useCopyToClipboard } from "@/shared/hooks/useCopyToClipboard"; import Button from "./Button"; import { ConfirmModal } from "./Modal"; // const VISIBLE_MEDIA_KINDS = ["embedding", "image", "imageToText", "tts", "stt", "webSearch", "webFetch", "video", "music"]; const VISIBLE_MEDIA_KINDS = ["embedding", "image", "tts"]; const navItems = [ { href: "/dashboard/endpoint", label: "Endpoint", icon: "api" }, { href: "/dashboard/providers", label: "Providers", icon: "dns" }, // { href: "/dashboard/basic-chat", label: "Basic Chat", icon: "chat" }, // Hidden { href: "/dashboard/combos", label: "Combos", icon: "layers" }, { href: "/dashboard/usage", label: "Usage", icon: "bar_chart" }, { href: "/dashboard/quota", label: "Quota Tracker", icon: "data_usage" }, { href: "/dashboard/mitm", label: "MITM", icon: "security" }, { href: "/dashboard/cli-tools", label: "CLI Tools", icon: "terminal" }, ]; const debugItems = [ { href: "/dashboard/console-log", label: "Console Log", icon: "terminal" }, { href: "/dashboard/translator", label: "Translator", icon: "translate" }, ]; const systemItems = [ { href: "/dashboard/proxy-pools", label: "Proxy Pools", icon: "lan" }, ]; export default function Sidebar({ onClose }) { const pathname = usePathname(); const [mediaOpen, setMediaOpen] = useState(false); const [showShutdownModal, setShowShutdownModal] = useState(false); const [isShuttingDown, setIsShuttingDown] = useState(false); const [isDisconnected, setIsDisconnected] = useState(false); const [updateInfo, setUpdateInfo] = useState(null); const [showUpdateModal, setShowUpdateModal] = useState(false); const [isUpdating, setIsUpdating] = useState(false); const [enableTranslator, setEnableTranslator] = useState(false); const { copied, copy } = useCopyToClipboard(2000); const INSTALL_CMD = UPDATER_CONFIG.installCmd; useEffect(() => { fetch("/api/settings") .then(res => res.json()) .then(data => { if (data.enableTranslator) setEnableTranslator(true); }) .catch(() => {}); }, []); // Lazy check for new npm version on mount useEffect(() => { fetch("/api/version") .then(res => res.json()) .then(data => { if (data.hasUpdate) setUpdateInfo(data); }) .catch(() => {}); }, []); const isActive = (href) => { if (href === "/dashboard/endpoint") { return pathname === "/dashboard" || pathname.startsWith("/dashboard/endpoint"); } return pathname.startsWith(href); }; const handleUpdate = async () => { setIsUpdating(true); setShowUpdateModal(false); try { const res = await fetch("/api/version/update", { method: "POST" }); if (!res.ok) { const data = await res.json().catch(() => ({})); alert(data.message || "Update failed. Please run the install command manually."); setIsUpdating(false); return; } // Server will exit shortly; show disconnected overlay setIsDisconnected(true); } catch (e) { // Expected once the server exits; treat as disconnected setIsDisconnected(true); } }; const handleShutdown = async () => { setIsShuttingDown(true); try { await fetch("/api/shutdown", { method: "POST" }); } catch (e) { // Expected to fail as server shuts down; ignore error } setIsShuttingDown(false); setShowShutdownModal(false); setIsDisconnected(true); }; return ( <> {/* Shutdown Confirmation Modal */} setShowShutdownModal(false)} onConfirm={handleShutdown} title="Close Proxy" message="Are you sure you want to close the proxy server?" confirmText="Close" cancelText="Cancel" variant="danger" loading={isShuttingDown} /> {/* Update Confirmation Modal */} setShowUpdateModal(false)} onConfirm={handleUpdate} title="Update 9Router" message={`This will close 9Router and install v${updateInfo?.latestVersion || ""} in a separate window. Continue?`} confirmText="Update" cancelText="Cancel" variant="primary" loading={isUpdating} /> {/* Disconnected Overlay */} {isDisconnected && (
{isUpdating ? ( <>
download

Updating 9Router

A new terminal window is installing the update. Once finished, run 9router again.

) : ( <>
power_off

Server Disconnected

The proxy server has been stopped.

)}
)} ); } Sidebar.propTypes = { onClose: PropTypes.func, };