This commit is contained in:
Tomas Dvorak
2025-11-11 10:29:30 +01:00
parent d5b4faea61
commit 8762bde4bf
139 changed files with 7240 additions and 2870 deletions
+14 -15
View File
@@ -20,7 +20,7 @@ const VideosSection = React.lazy(() => import('../components/home/VideosSection'
const MerchSection = React.lazy(() => import('../components/home/MerchSection'));
const PollsWidget = React.lazy(() => import('../components/home/PollsWidget'));
const GallerySection = React.lazy(() => import('../components/home/GallerySection'));
import { getArticles as apiGetArticles, Article as ApiArticle } from '../services/articles';
import { getArticles as apiGetArticles, getFeaturedArticles, Article as ApiArticle } from '../services/articles';
import { getCompetitionAliasesPublic, CompetitionAlias } from '../services/competitionAliases';
import { getUpcomingEvents } from '../services/eventService';
const NewsletterSubscribe = React.lazy(() => import('../components/newsletter/NewsletterSubscribe'));
@@ -104,7 +104,7 @@ const HomePage: React.FC = () => {
// Matches slider auto-centering handled internally by MatchesSlider component
// API-driven players and sponsors
type UiPlayer = { id:number|string; name:string; number?:number; position?:string; image?:string; slug?:string; age?: number; nationality?: string };
type UiPlayer = { id:number|string; name:string; number?:number; position?:string; image?:string; slug?:string; age?: number; nationality?: string; active?: boolean };
type UiSponsor = { id:number|string; name:string; logo:string; url?:string; tier?: string };
type UiBanner = { id:number|string; name:string; image:string; url?:string; placement?:string; width?:number; height?:number };
type UiMerch = { id?: number|string; title?: string; image_url: string; url?: string };
@@ -412,9 +412,9 @@ const HomePage: React.FC = () => {
if (name) setClubName(name);
if (logo) setClubLogo(logo);
// Load players via API
// Load players via API (include inactive to show as non-active instead of hiding)
try {
const apiPlayers: ApiPlayer[] = await apiGetPlayers();
const apiPlayers: ApiPlayer[] = await apiGetPlayers({ active: false });
const mappedPlayers: UiPlayer[] = (apiPlayers || []).map((p: ApiPlayer) => ({
id: p.id,
name: [p.first_name, p.last_name].filter(Boolean).join(' '),
@@ -422,6 +422,7 @@ const HomePage: React.FC = () => {
position: p.position,
image: assetUrl(p.image_url) || undefined,
nationality: (p as any).nationality,
active: Boolean((p as any).is_active),
age: (function(iso?: string){
if (!iso) return undefined;
const d = new Date(iso);
@@ -464,10 +465,10 @@ const HomePage: React.FC = () => {
setBanners(mappedBanners);
} catch {}
// Load featured articles (homepage primary) via API
// Load featured articles (homepage primary) via dedicated endpoint
try {
const resp = await apiGetArticles({ featured: true, page_size: 3 });
const items = (resp?.data || []).map((a: ApiArticle, idx: number) => ({
const resp = await getFeaturedArticles({ page_size: 100 });
const all = (resp?.data || []).map((a: ApiArticle, idx: number) => ({
id: a.id ?? idx + 1,
title: a.title,
excerpt: (a as any).excerpt || (a.content || '').slice(0, 140),
@@ -476,10 +477,11 @@ const HomePage: React.FC = () => {
category: 'Aktuality',
slug: a.slug,
}));
setFeatured(items);
// Ensure non-featured 'news' excludes featured items
// Show only first 3 in hero; exclude only those 3 from the other news list
const top3 = all.slice(0, 3);
setFeatured(top3);
setNews((prev) => {
const featuredKeys = new Set(items.map((f) => (f.slug ? `s:${f.slug}` : `i:${f.id}`)));
const featuredKeys = new Set(top3.map((f) => (f.slug ? `s:${f.slug}` : `i:${f.id}`)));
return (prev || []).filter((n) => !featuredKeys.has(n.slug ? `s:${n.slug}` : `i:${n.id}`));
});
} catch {}
@@ -1064,12 +1066,11 @@ const HomePage: React.FC = () => {
</div>
<div className="track">
{items.map((p)=> (
<div key={p.id} className="card">
<div key={p.id} className="card" style={{ opacity: p.active === false ? 0.6 : 1 }}>
<div className="photo" style={{ backgroundImage: `url(${assetUrl((p as any).image) || '/images/player-placeholder.jpg'})` }} />
<div className="name">{p.name}</div>
<div className="role">{p.position || 'Hráč'}</div>
{typeof p.number !== 'undefined' && <div className="number">#{p.number}</div>}
{typeof p.age === 'number' && <div className="age">{p.age} {czYears(p.age)}</div>}
</div>
))}
</div>
@@ -1678,12 +1679,10 @@ const HomePage: React.FC = () => {
</div>
<div className="scroll-x">
{players.map((p) => (
<a key={p.id} href={p.slug ? `/players/${p.slug}` : `/players/${p.id}`} className="player-card card">
<a key={p.id} href={p.slug ? `/players/${p.slug}` : `/players/${p.id}`} className="player-card card" style={{ opacity: p.active === false ? 0.6 : 1 }}>
<div className="photo" style={{ backgroundImage: `url(${assetUrl(p.image) || p.image})` }} />
<div className="meta">{typeof p.number !== 'undefined' ? (<><span className="nr">#{p.number}</span> {p.name}</>) : p.name}</div>
<div className="pos">{p.position}</div>
{p.nationality ? (<div className="nat"><span className="flag" style={{ marginRight: 6 }}>{getCountryFlag(p.nationality)}</span>{translateNationality(p.nationality)}</div>) : null}
{typeof p.age === 'number' && <div className="age">{p.age} let</div>}
</a>
))}
</div>