HEX
Server: LiteSpeed
System: Linux houston.panomity.com 6.8.0-100-generic #100-Ubuntu SMP PREEMPT_DYNAMIC Tue Jan 13 16:40:06 UTC 2026 x86_64
User: nudepix (1011)
PHP: 7.4.33
Disabled: pcntl_alarm,pcntl_fork,pcntl_waitpid,pcntl_wait,pcntl_wifexited,pcntl_wifstopped,pcntl_wifsignaled,pcntl_wifcontinued,pcntl_wexitstatus,pcntl_wtermsig,pcntl_wstopsig,pcntl_signal,pcntl_signal_get_handler,pcntl_signal_dispatch,pcntl_get_last_error,pcntl_strerror,pcntl_sigprocmask,pcntl_sigwaitinfo,pcntl_sigtimedwait,pcntl_exec,pcntl_getpriority,pcntl_setpriority,pcntl_async_signals,pcntl_unshare,
Upload Files
File: //tmp/AppLayout.jsx
import React, { useEffect, useState } from 'react';
import { Link, Outlet, useLocation, useNavigate } from 'react-router-dom';
import { Matomo } from './Matomo.jsx';
import { Adsense } from './Adsense.jsx';
import 'preline';
import { apiFetch } from './api.js';
import { AuthModal } from '../auth/AuthModal.jsx';
import { ChatWidget } from '../chat/ChatWidget.jsx';
import { featuredSeoLinks, seoHub } from '../seo/catalog.js';
import { buildUploadPath } from '../../utils/tracking.js';

export const AppLayout = () => {
    const location = useLocation();
    const navigate = useNavigate();
    const [me, setMe] = useState(null);
    const [authOpen, setAuthOpen] = useState(false);

    useEffect(() => {
        // Auto-init Preline components after navigation
        try { window.HSStaticMethods?.autoInit?.(); } catch {}
    }, [location.pathname]);

    useEffect(() => {
        let cancelled = false;
        const loadMe = async () => {
            try {
                const res = await apiFetch('/api/auth/me');
                if (!cancelled && res.ok) {
                    const data = await res.json().catch(() => ({}));
                    setMe(data.user || null);
                } else if (!cancelled) {
                    setMe(null);
                }
            } catch {
                if (!cancelled) setMe(null);
            }
        };
        loadMe();
        const onAuthChanged = () => loadMe();
        const onAuthOpen = () => setAuthOpen(true);
        window.addEventListener('auth:changed', onAuthChanged);
        window.addEventListener('auth:open', onAuthOpen);
        return () => {
            cancelled = true;
            window.removeEventListener('auth:changed', onAuthChanged);
            window.removeEventListener('auth:open', onAuthOpen);
        };
    }, [location.pathname]);

    const onLogout = async () => {
        try {
            await apiFetch('/api/auth/logout', { method: 'POST' });
        } finally {
            try { window.dispatchEvent(new Event('auth:changed')); } catch {}
            navigate('/');
        }
    };

    return (
        <div className="min-h-screen flex flex-col">
            <Matomo />
            <Adsense />
            <header className="sticky top-0 z-40 bg-white/80 backdrop-blur border-b">
                <div className="mx-auto max-w-6xl px-4 py-3 flex items-center justify-between">
                    <Link to="/" className="text-2xl font-black tracking-tight text-coral-500" aria-label="bewertemich.de Startseite">
                        bewertemich.de
                    </Link>
                    <nav className="flex items-center gap-4 text-sm">
                        <Link to={buildUploadPath('header_nav')} className="btn border-0 bg-coral-500 text-white hover:bg-coral-600">Upload</Link>
                        <Link to="/top10" className="btn btn-ghost hidden sm:inline-flex">Top 10</Link>
                        <a href={`/${seoHub.slug}/`} className="btn btn-ghost hidden md:inline-flex">Ratgeber</a>
                        {me && <Link to="/messages" className="btn btn-ghost">Nachrichten</Link>}
                        {me && <Link to="/wallet" className="btn btn-ghost">Credits</Link>}
                        {me?.is_admin ? (<Link to="/admin" className="btn btn-ghost">Admin</Link>) : null}

                        {!me ? (
                            <button className="btn btn-ghost hidden md:inline-flex" onClick={() => setAuthOpen(true)}>Login / Registrieren</button>
                        ) : (
                            <div className="dropdown dropdown-end">
                                <div tabIndex={0} role="button" className="btn btn-ghost btn-circle avatar">
                                    <div className="w-9 rounded-full">
                                        {me?.avatar_photo_id ? (
                                            <img alt="Avatar" src={`/api/photos/file/${me.avatar_photo_id}`} />
                                        ) : (
                                            <div className="w-full h-full bg-gray-200 flex items-center justify-center text-xs font-semibold rounded-full">{(me.username||'?').slice(0,2).toUpperCase()}</div>
                                        )}
                                    </div>
                                </div>
                                <ul tabIndex={0} className="menu menu-sm dropdown-content bg-base-100 rounded-box z-[1] mt-3 w-52 p-2 shadow">
                                    <li><Link to={`/u/${me.username}`}>Profil ansehen</Link></li>
                                    <li><Link to="/settings">Einstellungen</Link></li>
                                    <li><button onClick={onLogout}>Abmelden</button></li>
                                </ul>
                            </div>
                        )}
                    </nav>
                </div>
            </header>
            <main className="flex-1">
                <Outlet />
            </main>
            <footer className="border-t py-10 text-sm text-gray-600">
                <div className="mx-auto max-w-6xl px-4 flex flex-wrap items-center justify-between gap-4">
                    <p>&copy; {new Date().getFullYear()} bewertemich.de</p>
                    <nav className="flex items-center gap-4 flex-wrap">
                        <a href={`/${seoHub.slug}/`} className="link">#profilbild ratgeber</a>
                        {featuredSeoLinks.map((item) => (
                            <a key={item.slug} href={`/${item.slug}/`} className="link">#{item.slug.replace(/-/g, ' ')}</a>
                        ))}
                        <a href="https://panomity.de/rechtliches/impressum/" target="_blank" rel="noreferrer">Impressum</a>
                        <a href="https://panomity.de/rechtliches/datenschutz/" target="_blank" rel="noreferrer">Datenschutz</a>
                    </nav>
                </div>
            </footer>
            <AuthModal open={authOpen} onClose={() => setAuthOpen(false)} onSuccess={() => setAuthOpen(false)} />
            <ChatWidget />
        </div>
    );
};