"use client"; import { useEffect, useState } from "react"; import dynamic from "next/dynamic"; import { useQueryClient } from "@tanstack/react-query"; import { toast } from "sonner"; import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; import { ServerControls } from "@/components/ServerControls"; import { Analytics } from "@/components/Analytics"; import { Skeleton } from "@/components/ui/skeleton"; const TabFallback = () => (
); const PlayerManager = dynamic( () => import("@/components/PlayerManager").then((m) => ({ default: m.PlayerManager })), { loading: TabFallback, ssr: false } ); const ChatBridge = dynamic( () => import("@/components/ChatBridge").then((m) => ({ default: m.ChatBridge })), { loading: TabFallback, ssr: false } ); const ModManager = dynamic( () => import("@/components/ModManager").then((m) => ({ default: m.ModManager })), { loading: TabFallback, ssr: false } ); const BackupManager = dynamic( () => import("@/components/BackupManager").then((m) => ({ default: m.BackupManager })), { loading: TabFallback, ssr: false } ); const LogViewer = dynamic( () => import("@/components/LogViewer").then((m) => ({ default: m.LogViewer })), { loading: TabFallback, ssr: false } ); const TABS = [ { value: "server", label: "Server" }, { value: "players", label: "Players" }, { value: "chat", label: "Chat" }, { value: "mods", label: "Mods" }, { value: "backups", label: "Backups" }, { value: "logs", label: "Logs" }, ]; const TAB_QUERIES: Record = { server: "status analytics schedule schedule-tasks".split(" "), players: ["players"], chat: ["chat"], mods: "mods mod-updates snapshots".split(" "), backups: ["backups"], logs: ["logs"], }; export function AdminTabs() { const queryClient = useQueryClient(); const [mounted, setMounted] = useState(false); const [value, setValue] = useState("server"); useEffect(() => { const isEditable = (el: Element | null) => { if (!el) return false; const tag = (el as HTMLElement).tagName; if (tag === "INPUT" || tag === "TEXTAREA" || tag === "SELECT") return true; return (el as HTMLElement).isContentEditable; }; const onKey = (e: KeyboardEvent) => { if (e.metaKey || e.ctrlKey || e.altKey) return; if (isEditable(document.activeElement)) return; if (e.key === "r") { e.preventDefault(); const keys = TAB_QUERIES[value] || []; keys.forEach((k) => { queryClient.refetchQueries({ queryKey: [k] }); }); toast.success(`Refreshing ${value}...`, { duration: 1500 }); } else if (e.key === "/") { const panel = document.querySelector( '[data-slot="tabs-content"] input, [data-slot="tabs-content"] [contenteditable="true"]' ) as HTMLElement | null; if (panel) { e.preventDefault(); panel.focus(); } } else if (e.key === "?") { e.preventDefault(); toast.message("Keyboard shortcuts", { description: "⌘K palette · r refresh · / focus search · Esc close · hash links jump tabs", duration: 5000, }); } }; window.addEventListener("keydown", onKey); return () => window.removeEventListener("keydown", onKey); }, [value, queryClient]); useEffect(() => { setMounted(true); const hash = window.location.hash.replace("#", ""); if (hash && TABS.some((t) => t.value === hash)) { setValue(hash); return; } const saved = localStorage.getItem("admin-tab"); if (saved && TABS.some((t) => t.value === saved)) setValue(saved); }, []); useEffect(() => { const onHash = () => { const h = window.location.hash.replace("#", ""); if (h && TABS.some((t) => t.value === h)) setValue(h); }; window.addEventListener("hashchange", onHash); return () => window.removeEventListener("hashchange", onHash); }, []); useEffect(() => { if (!mounted) return; localStorage.setItem("admin-tab", value); history.replaceState(null, "", `#${value}`); }, [value, mounted]); if (!mounted) return null; return ( setValue(v as string)} className="w-full" > {TABS.map((t) => ( {t.label} ))} ); }