import React, { useEffect, useMemo, useState } from 'react'; import { Box, Heading, Text, List, ListItem, Link, Divider, Code, OrderedList, HStack, IconButton, useColorModeValue, useToast } from '@chakra-ui/react'; import { FaLink, FaArrowUp } from 'react-icons/fa'; import AdminLayout from '../../layouts/AdminLayout'; const AdminDocsPage: React.FC = () => { const sections = useMemo(() => [ { id: 'nastaveni', label: 'Nastavení (branding + SMTP)' }, { id: 'clanky', label: 'Články a kategorie' }, { id: 'zapasy', label: 'Zápasy (FAČR)' }, { id: 'hraci-tymy', label: 'Hráči a týmy' }, { id: 'media', label: 'Média' }, { id: 'sponzori-bannery', label: 'Sponzoři a bannery' }, { id: 'newsletter', label: 'Newsletter' }, { id: 'aliasy', label: 'Alias soutěží' }, { id: 'prefetch', label: 'Prefetch' }, { id: 'videa', label: 'Videa' }, { id: 'aktivity', label: 'Aktivity' }, { id: 'merch', label: 'Oblečení' }, { id: 'zpravy', label: 'Zprávy' }, { id: 'reset-admin', label: 'Reset hesla' }, { id: 'uzivatele', label: 'Uživatelé' }, { id: 'seo-analytics', label: 'SEO a Analytics' }, { id: 'troubleshooting', label: 'Troubleshooting' }, ], []); const [activeId, setActiveId] = useState(''); const toast = useToast(); useEffect(() => { const observer = new IntersectionObserver( (entries) => { // Pick the entry closest to the top that is intersecting const visible = entries .filter((e) => e.isIntersecting) .sort((a, b) => (a.boundingClientRect.top > b.boundingClientRect.top ? 1 : -1)); if (visible[0]) { setActiveId(visible[0].target.id); } }, { rootMargin: '-40% 0px -50% 0px', threshold: [0, 0.25, 0.5, 0.75, 1] } ); const els = sections.map((s) => document.getElementById(s.id)).filter(Boolean) as Element[]; els.forEach((el) => observer.observe(el)); return () => observer.disconnect(); }, [sections]); // Persist active section and restore on reload useEffect(() => { if (activeId) { try { localStorage.setItem('adminDocs:lastAnchor', activeId); } catch {} } }, [activeId]); useEffect(() => { // Run after paint so layout is ready const t = setTimeout(() => { const hash = (window.location.hash || '').replace('#', '').trim(); let targetId = hash; if (!targetId) { try { targetId = localStorage.getItem('adminDocs:lastAnchor') || ''; } catch {} } if (targetId) { const el = document.getElementById(targetId); if (el) { el.scrollIntoView({ behavior: 'smooth', block: 'start' }); setActiveId(targetId); } } }, 50); return () => clearTimeout(t); }, []); const copyDeepLink = async (id: string) => { try { const url = `${window.location.origin}${window.location.pathname}#${id}`; await navigator.clipboard.writeText(url); toast({ title: 'Odkaz zkopírován', status: 'success', duration: 1500, isClosable: true }); } catch { toast({ title: 'Nelze zkopírovat odkaz', status: 'error', duration: 2000, isClosable: true }); } }; const tocActiveColor = useColorModeValue('blue.700', 'blue.300'); const tocActiveBg = useColorModeValue('blue.50', 'blue.900'); return ( {/* Sticky TOC */} Rychlá navigace {sections.map((s) => ( { try { localStorage.setItem('adminDocs:lastAnchor', s.id); } catch {} }} > {s.label} ))} {/* Main content */} Dokumentace Přehled funkcí, postupů a řešení problémů Začínáme Tato stránka shrnuje hlavní možnosti administrace webu. Pro rychlý start doporučujeme nejprve vyplnit Nastavení, poté vytvořit první článek a ověřit funkčnost e‑mailů. Obsah Nastavení klubu, branding a SMTP Články a kategorie Zápasy a výsledky (FAČR) Hráči a týmy Média (soubory a obrázky) Sponzoři a bannery Newsletter Alias názvů soutěží Prefetch (YouTube a další data) Uživatelé a přístupy SEO a Analytics Troubleshooting (řešení problémů) Nastavení klubu, branding a SMTP } onClick={() => copyDeepLink('nastaveni')} /> Branding: Nastavte název klubu, logo a barvy. Tyto hodnoty se propsají do e‑mailů i vzhledu webu. SMTP: Vyplňte host, port, uživatele a heslo. U portu 465 se používá implicitní SSL, jinak STARTTLS. Test: V sekci Newsletter → Test odešlete zkušební e‑mail a ověřte doručení. Na začátek Články a kategorie } onClick={() => copyDeepLink('clanky')} /> Vytvořte kategorii (pokud ještě neexistuje) a poté nový článek. Vyplňte SEO název a popis — zlepší to výsledky ve vyhledávání. Obrázek nahrávejte do Média a vložte URL do článku. Další správa kategorií je v sekci Kategorie. Na začátek Zápasy a výsledky (FAČR) } onClick={() => copyDeepLink('zapasy')} /> Napojení na FAČR umožňuje zobrazit soutěže, tabulky a nadcházející utkání. Přes Alias názvů soutěží si můžete upravit názvy pro front‑end. Pokud FAČR data nevidíte, spusťte Prefetch pro načtení cache. Na začátek Hráči a týmy } onClick={() => copyDeepLink('hraci-tymy')} /> Přidávejte týmy a hráče, udržujte je aktuální pro přehled na webu. Loga týmů lze přepsat v sekci Alias/Overrides, pokud se nenačtou správně. Na začátek Média (soubory a obrázky) } onClick={() => copyDeepLink('media')} /> Nahrajte soubor v sekci Média, zkopírujte URL a použijte ji v článcích nebo bannerech. Podporované formáty: JPEG/PNG/SVG/… dle konfigurace serveru. Na začátek Sponzoři a bannery } onClick={() => copyDeepLink('sponzori-bannery')} /> Přidávejte sponzory s logem a odkazem. Můžete je zobrazit na vybraných sekcích webu. Pro reklamní plochy používejte sekci Bannery a nastavte cílové URL. Na začátek Newsletter } onClick={() => copyDeepLink('newsletter')} /> Nastavte SMTP a identitu odesílatele (jméno + adresa). Odešlete test na svou adresu, ověřte zobrazení a doručení. Hromadné rozesílky plánujte s ohledem na limity poskytovatele SMTP. Postup: konfigurace SMTP (krok za krokem) Otevřete Nastavení a vyplňte Host, Port, Uživatelské jméno, Heslo a „From“ adresu. Pro port 465 použijte SSL. Pro port 587 použijte STARTTLS (Use TLS ano). Uložte změny. Přejděte do Newsletter a odešlete testovací e‑mail na vaši adresu. Zkontrolujte doručení v inboxu a případně složku spam. Pokud nedorazí, viz Troubleshooting níže. Alias názvů soutěží } onClick={() => copyDeepLink('aliasy')} /> Upravit zobrazení soutěží (přejmenování, sjednocení názvů) můžete v sekci Alias. Změny se projeví na front‑endu. Na začátek Prefetch (YouTube a další data) } onClick={() => copyDeepLink('prefetch')} /> Prefetch vytváří rychlou cache pro veřejné části webu (YouTube, články…). Při problémech s rychlostí načtení spusťte ručně Prefetch a zkontrolujte stav. Na začátek Videa } onClick={() => copyDeepLink('videa')} /> Správa videí a playlistů zobrazovaných na webu. Pro rychlé načítání videí použijte Prefetch (YouTube cache). Na začátek Aktivity } onClick={() => copyDeepLink('aktivity')} /> Plánujte a publikujte klubové akce mimo soutěžní zápasy. Aktivity se mohou zobrazovat na nástěnce administrace i na veřejném webu. Na začátek Oblečení (Merch) } onClick={() => copyDeepLink('merch')} /> Správa položek klubového merche a jejich zobrazení pro fanoušky. Pro každou položku nastavte název, popis, cenu a obrázek (z Média). Na začátek Zprávy } onClick={() => copyDeepLink('zpravy')} /> Seznam zpráv odeslaných přes kontaktní formulář a systémové notifikace. Odpovídejte uživatelům přímo z vaší schránky, systém ukládá pouze záznamy. Na začátek Reset hesla (admin nástroj) } onClick={() => copyDeepLink('reset-admin')} /> Přejděte na Nástroj pro reset hesla. Zadejte e‑mail uživatele a odešlete ověřovací kód/odkaz pro reset. Uživatel dokončí změnu hesla přes veřejnou stránku pro reset. Na začátek Uživatelé a přístupy } onClick={() => copyDeepLink('uzivatele')} /> Rozlišujeme role admin a user. Admin má přístup do všech sekcí. Hesla mají minimální délku 8 znaků a nesmí obsahovat mezery. Zapomenuté heslo lze obnovit přes stránku „Zapomenuté heslo“ (ověřovací kód e‑mailem). Na začátek SEO a Analytics } onClick={() => copyDeepLink('seo-analytics')} /> U článků vyplňujte SEO titulek a SEO popis. V administraci je k dispozici přehled návštěvnosti a interakcí (sekce Analytics). Na začátek Troubleshooting (řešení problémů) } onClick={() => copyDeepLink('troubleshooting')} /> E‑maily se neodesílají Zkontrolujte SMTP nastavení (host, port, uživatel, heslo, šifrování). Pro port 465 použijte SSL, pro 587 STARTTLS. Využijte tlačítko „Otestovat SMTP“ v průvodci či v newsletteru. Mrkněte do logů serveru na případné chyby SMTP. Obrázky/Logo se nezobrazuje Ověřte, že URL je správná a veřejně dostupná. V případě externích zdrojů lze využít proxy `/api/v1/proxy/image`. Nahrajte logo do sekce Média a použijte relativní cestu (např. /uploads/2025/01/logo.png). FAČR data nejsou aktuální Spusťte Prefetch a porovnejte čas posledního běhu. Zkontrolujte internetové připojení serveru a limity volání. Přihlášení nefunguje Ověřte e‑mail/heslo a zda má účet roli admin. Pokud jste zapomněli heslo, použijte „Zapomenuté heslo“ a kód z e‑mailu. Newsletter padá do spamu Nastavte správně DNS záznamy SPF, DKIM a pokud možno DMARC. Ověřte, že „From“ doména odpovídá doméně vašeho SMTP odesílatele. API základ Veřejná API základna: /api/v1 (Rozšířená dokumentace API bude doplněna v budoucnu.) Na začátek ); }; export default AdminDocsPage;