import { useState, useEffect, useCallback, lazy, Suspense } from "react"; import { invoke } from "@tauri-apps/api/core"; import type { UserDto, DbStatus, SafeDbInfo, ServerUserDto, UserProfileDto } from "../../types"; import logoUrl from "../../assets/logo.png"; import { HomeNavIcon, UsersNavIcon, SettingsNavIcon, HelpNavIcon, LogOutIcon, ChevronLeftIcon, CinemaNavIcon, MenuIcon, CloseIcon, } from "../../components/Icons"; import Home from "../home/Home"; import Users from "../users/Users"; import Settings from "../settings/Settings"; import Help from "../help/Help"; import Profile from "../profile/Profile"; import "./Dashboard.css"; const Cinema = lazy(() => import("../cinema/Cinema")); function CinemaLoadingFallback() { return (
Загрузка Кинотеатра...
); } interface DashboardProps { user: UserDto; dbInfo: SafeDbInfo | null; dbStatus: DbStatus | null; onLogout: () => void; isTvEnvironment?: boolean; } type NavTab = "cinema" | "home" | "users" | "settings" | "profile" | "help"; // Helper for Smart TV / Android TV detection const detectTvEnvironment = (): boolean => { if (typeof window === "undefined") return false; const ua = (navigator.userAgent || "").toLowerCase(); const isTvUa = ua.includes("android tv") || ua.includes("smarttv") || ua.includes("googletv") || ua.includes("tizen") || ua.includes("webos") || ua.includes("appletv") || ua.includes("crkey") || ua.includes("bravia") || ua.includes("aftt") || ua.includes("aftm") || ua.includes("mibox") || ua.includes("mi box") || ua.includes("shield") || ua.includes("dtv") || ua.includes("smart-tv") || ua.includes("hbbtv") || ua.includes("netcast") || ua.includes("viera") || ua.includes("roku") || ua.includes("firetv"); if (isTvUa) return true; const isAndroid = ua.includes("android"); const noTouch = !("ontouchstart" in window) && navigator.maxTouchPoints === 0; if (isAndroid && noTouch) return true; // On pure desktop (macOS / Windows / Desktop Linux), default to desktop PC mode const isDesktop = (ua.includes("windows nt") || ua.includes("macintosh") || (ua.includes("linux") && !ua.includes("android"))) && !isTvUa; if (isDesktop) { return localStorage.getItem("has_tv_mode_manual") === "true"; } const saved = localStorage.getItem("has_tv_mode"); if (saved !== null) return saved === "true"; return false; }; export default function Dashboard({ user, dbInfo, dbStatus, onLogout, isTvEnvironment: propIsTv, }: DashboardProps) { const [currentUser, setCurrentUser] = useState(user); useEffect(() => { setCurrentUser(user); }, [user]); const [isTvEnvironment, setIsTvEnvironment] = useState(() => { return propIsTv !== undefined ? propIsTv : detectTvEnvironment(); }); useEffect(() => { if (propIsTv !== undefined && propIsTv !== isTvEnvironment) { setIsTvEnvironment(propIsTv); } }, [propIsTv, isTvEnvironment]); const [activeTab, setActiveTab] = useState("cinema"); const [serverUsers, setServerUsers] = useState([]); const [loadingUsers, setLoadingUsers] = useState(false); const [isCollapsed, setIsCollapsed] = useState(() => { return localStorage.getItem("has_sidebar_collapsed") === "true"; }); const [mobileMenuOpen, setMobileMenuOpen] = useState(false); const handleNavClick = (tab: NavTab) => { setActiveTab(tab); setMobileMenuOpen(false); }; const toggleSidebar = () => { setIsCollapsed((prev) => { const next = !prev; localStorage.setItem("has_sidebar_collapsed", String(next)); return next; }); }; const displayName = currentUser.username?.trim() || currentUser.email.split("@")[0]; const isTauri = typeof window !== "undefined" && "__TAURI_INTERNALS__" in window; useEffect(() => { if (isTauri && currentUser.email) { invoke("get_user_profile", { userEmail: currentUser.email }) .then((profile) => { if (profile) { setCurrentUser((prev) => ({ ...prev, username: profile.username || prev.username, avatar: profile.avatar !== undefined ? profile.avatar : prev.avatar, role: profile.role || prev.role, })); } }) .catch((err) => { console.warn("Could not preload user avatar for sidebar:", err); }); } }, [currentUser.email, isTauri]); // Periodic heartbeat to keep user online status updated in database useEffect(() => { if (!isTauri || !currentUser.email) return; const sendHeartbeat = () => { invoke("update_user_heartbeat", { userEmail: currentUser.email }).catch(() => {}); }; sendHeartbeat(); const interval = setInterval(sendHeartbeat, 30000); window.addEventListener("focus", sendHeartbeat); return () => { clearInterval(interval); window.removeEventListener("focus", sendHeartbeat); }; }, [currentUser.email, isTauri]); const isUserAdmin = (currentUser.role || "").toLowerCase() === "admin" || (currentUser.role || "").toLowerCase() === "администратор" || currentUser.email.toLowerCase() === "ne60201@gmail.com" || serverUsers.some( (u) => u.email.toLowerCase() === currentUser.email.toLowerCase() && (u.role?.toLowerCase() === "admin" || u.role?.toLowerCase() === "администратор" || u.id === 1) ); // Non-admin redirection: users and home (server stats) tabs are reserved for admin useEffect(() => { if (!isUserAdmin && (activeTab === "users" || activeTab === "home")) { setActiveTab("cinema"); } }, [isUserAdmin, activeTab]); const isCinemaView = activeTab === "cinema"; const loadServerUsers = useCallback(async () => { if (!isTauri) return; setLoadingUsers(true); try { const res = await invoke("list_server_users"); if (Array.isArray(res)) { setServerUsers(res); } } catch (err) { console.error("Ошибка загрузки пользователей:", err); } finally { setLoadingUsers(false); } }, [isTauri]); useEffect(() => { loadServerUsers(); }, [loadServerUsers]); useEffect(() => { if (activeTab === "users") { loadServerUsers(); } }, [activeTab, loadServerUsers]); return (
{/* Mobile Top Header (Visible on Mobile / Small screens) */}
handleNavClick("home")} role="button" tabIndex={0} > HAS Logo HAS
{/* Backdrop for mobile drawer */} {mobileMenuOpen && (
setMobileMenuOpen(false)} /> )} {/* ======================================================== LEFT SIDEBAR NAVIGATION (Desktop Sidebar / Mobile Drawer) ======================================================== */} {/* ======================================================== MAIN CONTENT VIEW AREA ======================================================== */}
{/* Top Header Row (Hidden on Profile and Cinema views) */} {!isCinemaView && activeTab !== "profile" && (

{activeTab === "home" && "Обзор сервера"} {activeTab === "users" && "Пользователи системы"} {activeTab === "settings" && "Настройки системы"} {activeTab === "help" && "Помощь и поддержка"}

Сервер Home Autli • Защищенный шлюз

{dbStatus?.connected ? "Система активна" : "Проверка связи..."}
{isTvEnvironment && ( )}
)} {/* Content Body Rendering Separate Page Components */}
{activeTab === "cinema" && ( }> handleNavClick(tab as NavTab)} onLogout={onLogout} isTvEnvironment={isTvEnvironment} /> )} {activeTab === "home" && isUserAdmin && ( )} {activeTab === "users" && isUserAdmin && ( )} {activeTab === "settings" && } {activeTab === "profile" && ( setCurrentUser(updated)} serverUsers={serverUsers} onRefreshUsers={loadServerUsers} onNavigateToUsers={() => handleNavClick("users")} /> )} {activeTab === "help" && }
); }