import { useState, useEffect, useCallback } 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, StorageNavIcon, UsersNavIcon, SettingsNavIcon, HelpNavIcon, LogOutIcon, ChevronLeftIcon, CinemaNavIcon, MenuIcon, CloseIcon, } from "../../components/Icons"; import Home from "../home/Home"; import Storage from "../storage/Storage"; import Users from "../users/Users"; import Settings from "../settings/Settings"; import Help from "../help/Help"; import Profile from "../profile/Profile"; import Cinema from "../cinema/Cinema"; import "./Dashboard.css"; interface DashboardProps { user: UserDto; dbInfo: SafeDbInfo | null; dbStatus: DbStatus | null; onLogout: () => void; } type NavTab = "home" | "storage" | "cinema" | "users" | "settings" | "profile" | "help"; // Helper for Smart TV / Android TV detection const detectTvEnvironment = (): boolean => { if (typeof window === "undefined") return false; const saved = localStorage.getItem("has_tv_mode"); if (saved !== null) return saved === "true"; 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; return false; }; export default function Dashboard({ user, dbInfo, dbStatus, onLogout, }: DashboardProps) { const [currentUser, setCurrentUser] = useState(user); useEffect(() => { setCurrentUser(user); }, [user]); const [isTvEnvironment, setIsTvEnvironment] = useState(detectTvEnvironment); const [activeTab, setActiveTab] = useState(() => { return detectTvEnvironment() ? "cinema" : "home"; }); 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); // Dynamic D-Pad Remote Control Key Listener (Auto-detects TV when user presses remote buttons) useEffect(() => { const handleRemoteDpadKey = (e: KeyboardEvent) => { const isRemoteKey = [19, 20, 21, 22, 23, 4, 82, 85, 179].includes(e.keyCode) || ["ArrowUp", "ArrowDown", "ArrowLeft", "ArrowRight"].includes(e.key); if (isRemoteKey && !isTvEnvironment) { setIsTvEnvironment(true); localStorage.setItem("has_tv_mode", "true"); } }; window.addEventListener("keydown", handleRemoteDpadKey); return () => window.removeEventListener("keydown", handleRemoteDpadKey); }, [isTvEnvironment]); 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 separate cinema tabs are reserved for admin useEffect(() => { if (!isUserAdmin && (activeTab === "users" || activeTab === "cinema")) { setActiveTab("home"); } }, [isUserAdmin, activeTab]); const isCinemaView = activeTab === "cinema" || (!isUserAdmin && activeTab === "home"); 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 === "storage" && "Файловое хранилище"} {activeTab === "users" && "Пользователи системы"} {activeTab === "settings" && "Настройки системы"} {activeTab === "help" && "Помощь и поддержка"}

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

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