// Layout.tsx import { useEffect, useState, ReactNode } from "react"; import { useTranslation } from "react-i18next"; import { Menu, X, Home, User, Briefcase, BookOpen, Phone, LayoutDashboard, } from "lucide-react"; // Supabase wird lazy geladen um Initial Bundle zu reduzieren import { ContactInfo } from "./ContactInfo"; import { NavLink } from "./NavLink"; import LanguageSwitcher from "./LanguageSwitcher"; import { Link, useLocation } from "react-router-dom"; import Footer from "./Footer"; import { useScrollContext } from "./ScrollContext"; import { PerformanceMonitor } from "./PerformanceMonitor"; import GlobalBackground from "./GlobalBackground"; interface LayoutProps { children: ReactNode; } const Layout = ({ children }: LayoutProps) => { const { t } = useTranslation(); const [isAdmin, setIsAdmin] = useState(false); const [scrolled, setScrolled] = useState(false); const [isMounted, setIsMounted] = useState(false); const location = useLocation(); const { isMenuOpen, setIsMenuOpen } = useScrollContext(); // Initial mount with immediate execution useEffect(() => { // Use requestAnimationFrame to ensure smooth initial render requestAnimationFrame(() => { setIsMounted(true); }); }, []); // Schließe das Menü beim Routenwechsel useEffect(() => { setIsMenuOpen(false); }, [location.pathname, setIsMenuOpen]); // Toggle Menu const toggleMenu = () => { setIsMenuOpen(!isMenuOpen); }; // Scroll-Handler useEffect(() => { const handleScroll = () => { setScrolled(window.scrollY > 0); }; window.addEventListener("scroll", handleScroll); return () => window.removeEventListener("scroll", handleScroll); }, []); // Prüfe Admin-Status verzögert und lazy (nach Initial Render) useEffect(() => { const checkAdmin = async () => { // Dynamischer Import von Supabase - wird erst geladen wenn benötigt const { supabase } = await import("../utils/supabaseClient"); const { data, error } = await supabase.auth.getSession(); if (error) { console.error("Error checking admin status:", error); return; } if (data.session) { const { user } = data.session; const { data: adminData, error: adminError } = await supabase .from("profiles") .select("isAdmin") .eq("id", user.id) .single(); if (adminError) { console.error("Error checking admin role:", adminError); return; } setIsAdmin(adminData.isAdmin); } }; // Verzögere Admin-Check deutlich (5s) um kritischen Pfad nicht zu blockieren const timeoutId = setTimeout(checkAdmin, 5000); return () => clearTimeout(timeoutId); }, []); const navigationLinks = [ { path: "/", label: t("navigation.main.home"), icon: , }, { path: "/about", label: t("navigation.main.about"), icon: , }, { path: "/portfolio", label: t("navigation.main.portfolio"), icon: , }, { path: "/blog", label: t("navigation.main.blog"), icon: , }, { path: "/contact", label: t("navigation.main.contact"), icon: , }, ...(isAdmin ? [ { path: "/dashboard", label: t("navigation.admin.dashboard"), icon: , }, ] : []), ]; // Render with opacity 0 on initial mount to prevent flicker if (!isMounted) { return (
{children}
); } return (
{/* Global Background */} {/* Navigation – oberste Ebene */} {/* Mobile Menu - CSS-only Animationen */} {/* Backdrop */}
{/* Sidebar */}
{/* Sidebar Header mit Close-Button */}
Menu
{/* Scrollbarer Sidebar-Inhalt */}
{/* Contact Info */} {/* Navigation Links */}
{navigationLinks.map(({ path, label, icon }) => ( setIsMenuOpen(false)} className="flex items-center w-full mb-1" /> ))}
{/* Language Switcher */}
Sprache ändern
{/* Hauptinhalt */}
{children}
{/* Footer */}
); }; export default Layout;