mirror of
https://github.com/Dvorinka/MyClubServer.git
synced 2026-06-04 02:32:57 +00:00
dev day #62
This commit is contained in:
@@ -44,6 +44,11 @@ import { Image } from '@chakra-ui/react';
|
||||
import { getCategories, Category } from '../services/public';
|
||||
import { FaSearch as FaSearchIcon } from 'react-icons/fa';
|
||||
import { getNavigationItems, NavigationItem, seedDefaultNavigation } from '../services/navigation';
|
||||
import { getEvents } from '../services/eventService';
|
||||
import { getPlayers } from '../services/public';
|
||||
import { getArticles } from '../services/articles';
|
||||
import { getCachedYouTube } from '../services/youtube';
|
||||
import { getZoneramaManifestWithFallbacks } from '../services/zonerama';
|
||||
|
||||
type NavLink = { label: string; to?: string; items?: { label: string; to: string }[]; external?: boolean };
|
||||
|
||||
@@ -72,7 +77,7 @@ const normalizeSocialUrl = (network: 'facebook' | 'instagram' | 'youtube', raw?:
|
||||
};
|
||||
|
||||
// Mobile menu component
|
||||
const MobileMenu = ({ isOpen, onClose, isAdmin, menuBg, dividerColor, settings, categories, galleryHref, galleryLabel, hasTables, dynamicNavItems, navLoading }: {
|
||||
const MobileMenu = ({ isOpen, onClose, isAdmin, menuBg, dividerColor, settings, categories, galleryHref, galleryLabel, hasTables, hasActivities, hasPlayers, hasArticles, hasVideos, hasGallery, dynamicNavItems, navLoading }: {
|
||||
isOpen: boolean;
|
||||
onClose: () => void;
|
||||
isAdmin: boolean;
|
||||
@@ -83,6 +88,11 @@ const MobileMenu = ({ isOpen, onClose, isAdmin, menuBg, dividerColor, settings,
|
||||
galleryHref?: string | null;
|
||||
galleryLabel?: string;
|
||||
hasTables?: boolean | null;
|
||||
hasActivities?: boolean | null;
|
||||
hasPlayers?: boolean | null;
|
||||
hasArticles?: boolean | null;
|
||||
hasVideos?: boolean | null;
|
||||
hasGallery?: boolean | null;
|
||||
dynamicNavItems: NavigationItem[];
|
||||
navLoading: boolean;
|
||||
}) => (
|
||||
@@ -150,8 +160,12 @@ const MobileMenu = ({ isOpen, onClose, isAdmin, menuBg, dividerColor, settings,
|
||||
)}
|
||||
<Button as={RouterLink} to="/kalendar" variant="ghost" justifyContent="flex-start">Kalendář</Button>
|
||||
<Button as={RouterLink} to="/zapasy" variant="ghost" justifyContent="flex-start">Zápasy</Button>
|
||||
<Button as={RouterLink} to="/aktivity" variant="ghost" justifyContent="flex-start">Aktivity</Button>
|
||||
<Button as={RouterLink} to="/hraci" variant="ghost" justifyContent="flex-start">Hráči</Button>
|
||||
{hasActivities !== false && (
|
||||
<Button as={RouterLink} to="/aktivity" variant="ghost" justifyContent="flex-start">Aktivity</Button>
|
||||
)}
|
||||
{hasPlayers !== false && (
|
||||
<Button as={RouterLink} to="/hraci" variant="ghost" justifyContent="flex-start">Hráči</Button>
|
||||
)}
|
||||
{hasTables ? (
|
||||
<Button as={RouterLink} to="/tabulky" variant="ghost" justifyContent="flex-start">Tabulky</Button>
|
||||
) : null}
|
||||
@@ -173,24 +187,32 @@ const MobileMenu = ({ isOpen, onClose, isAdmin, menuBg, dividerColor, settings,
|
||||
</Button>
|
||||
);
|
||||
})}
|
||||
<Button as={RouterLink} to="/blog" variant="ghost" justifyContent="flex-start" fontWeight="bold">Články</Button>
|
||||
{Array.isArray(categories) && categories.length > 0 && (
|
||||
<VStack align="stretch" pl={4} spacing={1}>
|
||||
{categories.map((cat: any) => {
|
||||
const catIsExternal = typeof cat.url === 'string' && /^https?:\/\//i.test(cat.url);
|
||||
const catHref = cat.url || (cat.slug ? `/blog?category=${encodeURIComponent(cat.slug)}` : '/blog');
|
||||
const catLinkProps = catIsExternal ? { href: catHref } : { to: catHref };
|
||||
return (
|
||||
<Button key={cat.slug || cat.name} as={catIsExternal ? 'a' : RouterLink} {...(catLinkProps as any)} variant="ghost" justifyContent="flex-start" fontWeight="normal" size="sm">
|
||||
{cat.name}
|
||||
</Button>
|
||||
);
|
||||
})}
|
||||
</VStack>
|
||||
{hasArticles !== false && (
|
||||
<>
|
||||
<Button as={RouterLink} to="/blog" variant="ghost" justifyContent="flex-start" fontWeight="bold">Články</Button>
|
||||
{Array.isArray(categories) && categories.length > 0 && (
|
||||
<VStack align="stretch" pl={4} spacing={1}>
|
||||
{categories.map((cat: any) => {
|
||||
const catIsExternal = typeof cat.url === 'string' && /^https?:\/\//i.test(cat.url);
|
||||
const catHref = cat.url || (cat.slug ? `/blog?category=${encodeURIComponent(cat.slug)}` : '/blog');
|
||||
const catLinkProps = catIsExternal ? { href: catHref } : { to: catHref };
|
||||
return (
|
||||
<Button key={cat.slug || cat.name} as={catIsExternal ? 'a' : RouterLink} {...(catLinkProps as any)} variant="ghost" justifyContent="flex-start" fontWeight="normal" size="sm">
|
||||
{cat.name}
|
||||
</Button>
|
||||
);
|
||||
})}
|
||||
</VStack>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
{hasVideos !== false && (
|
||||
<Button as={RouterLink} to="/videa" variant="ghost" justifyContent="flex-start">Videa</Button>
|
||||
)}
|
||||
<Button as={RouterLink} to="/videa" variant="ghost" justifyContent="flex-start">Videa</Button>
|
||||
<Button as={RouterLink} to="/hledat" variant="ghost" justifyContent="flex-start">Hledat</Button>
|
||||
<Button as={RouterLink} to="/galerie" variant="ghost" justifyContent="flex-start">{galleryLabel || 'Fotogalerie'}</Button>
|
||||
{hasGallery !== false && (
|
||||
<Button as={RouterLink} to="/galerie" variant="ghost" justifyContent="flex-start">{galleryLabel || 'Fotogalerie'}</Button>
|
||||
)}
|
||||
{settings?.shop_url && (
|
||||
<Button as="a" href={settings.shop_url} target="_blank" rel="noreferrer" variant="ghost" justifyContent="flex-start">Fanshop</Button>
|
||||
)}
|
||||
@@ -232,6 +254,11 @@ const Navbar = () => {
|
||||
const navTextColor = useColorModeValue('gray.700', 'gray.200');
|
||||
const [scrolled, setScrolled] = useState(false);
|
||||
const [hasTables, setHasTables] = useState<boolean | null>(null);
|
||||
const [hasActivities, setHasActivities] = useState<boolean | null>(null);
|
||||
const [hasPlayers, setHasPlayers] = useState<boolean | null>(null);
|
||||
const [hasArticles, setHasArticles] = useState<boolean | null>(null);
|
||||
const [hasVideos, setHasVideos] = useState<boolean | null>(null);
|
||||
const [hasGallery, setHasGallery] = useState<boolean | null>(null);
|
||||
const [dynamicNavItems, setDynamicNavItems] = useState<NavigationItem[]>([]);
|
||||
const [navLoading, setNavLoading] = useState(true);
|
||||
|
||||
@@ -381,6 +408,76 @@ const Navbar = () => {
|
||||
return () => { disposed = true; };
|
||||
}, []);
|
||||
|
||||
// Determine if there are any activities/events available
|
||||
useEffect(() => {
|
||||
let disposed = false;
|
||||
(async () => {
|
||||
try {
|
||||
const events = await getEvents();
|
||||
if (!disposed) setHasActivities(Array.isArray(events) && events.length > 0);
|
||||
} catch {
|
||||
if (!disposed) setHasActivities(false);
|
||||
}
|
||||
})();
|
||||
return () => { disposed = true; };
|
||||
}, []);
|
||||
|
||||
// Determine if there are any players available
|
||||
useEffect(() => {
|
||||
let disposed = false;
|
||||
(async () => {
|
||||
try {
|
||||
const players = await getPlayers();
|
||||
if (!disposed) setHasPlayers(Array.isArray(players) && players.length > 0);
|
||||
} catch {
|
||||
if (!disposed) setHasPlayers(false);
|
||||
}
|
||||
})();
|
||||
return () => { disposed = true; };
|
||||
}, []);
|
||||
|
||||
// Determine if there are any articles available
|
||||
useEffect(() => {
|
||||
let disposed = false;
|
||||
(async () => {
|
||||
try {
|
||||
const result = await getArticles({ page: 1, page_size: 1, published: true });
|
||||
if (!disposed) setHasArticles(result.total > 0);
|
||||
} catch {
|
||||
if (!disposed) setHasArticles(false);
|
||||
}
|
||||
})();
|
||||
return () => { disposed = true; };
|
||||
}, []);
|
||||
|
||||
// Determine if there are any videos available
|
||||
useEffect(() => {
|
||||
let disposed = false;
|
||||
(async () => {
|
||||
try {
|
||||
const youtube = await getCachedYouTube();
|
||||
if (!disposed) setHasVideos(youtube && Array.isArray(youtube.videos) && youtube.videos.length > 0);
|
||||
} catch {
|
||||
if (!disposed) setHasVideos(false);
|
||||
}
|
||||
})();
|
||||
return () => { disposed = true; };
|
||||
}, []);
|
||||
|
||||
// Determine if there is any gallery content available
|
||||
useEffect(() => {
|
||||
let disposed = false;
|
||||
(async () => {
|
||||
try {
|
||||
const manifest = await getZoneramaManifestWithFallbacks();
|
||||
if (!disposed) setHasGallery(Array.isArray(manifest) && manifest.length > 0);
|
||||
} catch {
|
||||
if (!disposed) setHasGallery(false);
|
||||
}
|
||||
})();
|
||||
return () => { disposed = true; };
|
||||
}, []);
|
||||
|
||||
const isPathActive = (to?: string) => {
|
||||
if (!to) return false;
|
||||
// Active when current pathname starts with target (handles subroutes)
|
||||
@@ -459,8 +556,33 @@ const Navbar = () => {
|
||||
links = links.filter((n) => n.label !== 'Tabulky');
|
||||
}
|
||||
|
||||
// Hide Aktivity when there are no activities
|
||||
if (hasActivities === false) {
|
||||
links = links.filter((n) => n.label !== 'Aktivity');
|
||||
}
|
||||
|
||||
// Hide Hráči when there are no players
|
||||
if (hasPlayers === false) {
|
||||
links = links.filter((n) => n.label !== 'Hráči');
|
||||
}
|
||||
|
||||
// Hide Články when there are no articles
|
||||
if (hasArticles === false) {
|
||||
links = links.filter((n) => n.label !== 'Články');
|
||||
}
|
||||
|
||||
// Hide Videa when there are no videos
|
||||
if (hasVideos === false) {
|
||||
links = links.filter((n) => n.label !== 'Videa');
|
||||
}
|
||||
|
||||
// Hide Fotogalerie when there is no gallery content
|
||||
if (hasGallery === false) {
|
||||
links = links.filter((n) => n.label === galleryLabel).length === 0 ? links : links.filter((n) => n.label !== galleryLabel);
|
||||
}
|
||||
|
||||
return links;
|
||||
}, [dynamicNavItems, navLoading, settings, categoryItems, hasTables, galleryLabel]);
|
||||
}, [dynamicNavItems, navLoading, settings, categoryItems, hasTables, hasActivities, hasPlayers, hasArticles, hasVideos, hasGallery, galleryLabel]);
|
||||
|
||||
return (
|
||||
<Box position="sticky" top={0} zIndex={1000}>
|
||||
@@ -501,7 +623,7 @@ const Navbar = () => {
|
||||
boxShadow={scrolled ? 'sm' : 'none'}
|
||||
transition="box-shadow 0.2s ease, background-color 0.2s ease, backdrop-filter 0.2s ease"
|
||||
>
|
||||
<MobileMenu isOpen={isOpen} onClose={onClose} isAdmin={isAdmin} menuBg={menuBg} dividerColor={dividerColor} settings={settings} categories={navCategories} galleryHref={galleryHref} galleryLabel={galleryLabel} hasTables={hasTables} dynamicNavItems={dynamicNavItems} navLoading={navLoading} />
|
||||
<MobileMenu isOpen={isOpen} onClose={onClose} isAdmin={isAdmin} menuBg={menuBg} dividerColor={dividerColor} settings={settings} categories={navCategories} galleryHref={galleryHref} galleryLabel={galleryLabel} hasTables={hasTables} hasActivities={hasActivities} hasPlayers={hasPlayers} hasArticles={hasArticles} hasVideos={hasVideos} hasGallery={hasGallery} dynamicNavItems={dynamicNavItems} navLoading={navLoading} />
|
||||
<Container maxW="7xl">
|
||||
<Flex h={16} alignItems="center" justifyContent="space-between">
|
||||
<HStack spacing={4} alignItems="center">
|
||||
|
||||
Reference in New Issue
Block a user