mirror of
https://github.com/Dvorinka/MyClubServer.git
synced 2026-06-04 18:52:56 +00:00
dev day #65
This commit is contained in:
@@ -36,6 +36,8 @@ const MatchesPage: React.FC = () => {
|
||||
const [aliases, setAliases] = useState<CompetitionAlias[]>([]);
|
||||
const [aliasMap, setAliasMap] = useState<Record<string, { alias: string; original_name?: string; display_order?: number }>>({});
|
||||
const [sortAscending, setSortAscending] = useState<boolean>(true); // true = oldest first, false = newest first
|
||||
const [displayedMatchesCount, setDisplayedMatchesCount] = useState<Record<number, number>>({}); // Track displayed matches per competition index
|
||||
const MATCHES_PER_PAGE = 12; // Number of matches to load initially and per load more click
|
||||
|
||||
// Dark mode colors
|
||||
const bgColor = useColorModeValue('#f8f9fb', '#0f1115');
|
||||
@@ -78,11 +80,29 @@ const MatchesPage: React.FC = () => {
|
||||
};
|
||||
|
||||
// Sentiment helpers for win/draw/loss detection
|
||||
const normalize = (s: string) => String(s || '')
|
||||
.normalize('NFD')
|
||||
.replace(/[\u0300-\u036f]/g, '')
|
||||
.replace(/\s+/g, ' ')
|
||||
.trim()
|
||||
.toLowerCase();
|
||||
|
||||
const stripPrefixes = (s: string) => {
|
||||
let x = normalize(s);
|
||||
x = x.replace(/\b(mestsky|m\.?f\.?k\.?|mfk|tj|sk|sokol|fotbalovy|fotbalový|fotbalovy\s+klub|fotbalovy\s+klub)\b/g, '');
|
||||
return x.replace(/\s+/g, ' ').trim();
|
||||
};
|
||||
|
||||
const isClubTeam = (team: string) => {
|
||||
const normalize = (s: string) => s.toLowerCase().trim();
|
||||
const a = normalize(team);
|
||||
const b = normalize(clubName || '');
|
||||
return a.includes(b) || b.includes(a);
|
||||
try {
|
||||
const a = stripPrefixes(team);
|
||||
const b = stripPrefixes(clubName || '');
|
||||
if (!a || !b) return false;
|
||||
// Allow equality or suffix match (handles prefixes like TJ, SK, etc.)
|
||||
return a === b || a.endsWith(b) || b.endsWith(a);
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
const parseScore = (score?: string | null): { h: number; a: number } | null => {
|
||||
@@ -143,6 +163,27 @@ const MatchesPage: React.FC = () => {
|
||||
return sorted;
|
||||
}, [facrCompetitions, sortAscending]);
|
||||
|
||||
// Initialize displayed matches count when competitions change
|
||||
useEffect(() => {
|
||||
const initialCounts: Record<number, number> = {};
|
||||
sortedCompetitions.forEach((_, index) => {
|
||||
if (displayedMatchesCount[index] === undefined) {
|
||||
initialCounts[index] = MATCHES_PER_PAGE;
|
||||
}
|
||||
});
|
||||
if (Object.keys(initialCounts).length > 0) {
|
||||
setDisplayedMatchesCount(prev => ({ ...prev, ...initialCounts }));
|
||||
}
|
||||
}, [sortedCompetitions.length]);
|
||||
|
||||
// Handle load more for a specific competition
|
||||
const handleLoadMore = (competitionIndex: number) => {
|
||||
setDisplayedMatchesCount(prev => ({
|
||||
...prev,
|
||||
[competitionIndex]: (prev[competitionIndex] || MATCHES_PER_PAGE) + MATCHES_PER_PAGE
|
||||
}));
|
||||
};
|
||||
|
||||
// Get all upcoming matches for countdown tracking
|
||||
const upcomingMatches = useMemo(() => {
|
||||
if (activeTab >= sortedCompetitions.length) return [];
|
||||
@@ -416,6 +457,7 @@ const MatchesPage: React.FC = () => {
|
||||
Žádné zápasy k zobrazení
|
||||
</div>
|
||||
) : (
|
||||
<>
|
||||
<div
|
||||
style={{
|
||||
display: 'grid',
|
||||
@@ -423,7 +465,7 @@ const MatchesPage: React.FC = () => {
|
||||
gap: 16,
|
||||
}}
|
||||
>
|
||||
{c.matches.map((m: MatchItem, idx: number) => {
|
||||
{c.matches.slice(0, displayedMatchesCount[compIdx] || MATCHES_PER_PAGE).map((m: MatchItem, idx: number) => {
|
||||
const matchTime = new Date(`${m.date}T${(m.time || '00:00')}:00`).getTime();
|
||||
const currentTime = Date.now();
|
||||
const isFuture = matchTime > currentTime;
|
||||
@@ -607,6 +649,45 @@ const MatchesPage: React.FC = () => {
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
{c.matches.length > (displayedMatchesCount[compIdx] || MATCHES_PER_PAGE) && (
|
||||
<div style={{ textAlign: 'center', marginTop: 32 }}>
|
||||
<button
|
||||
onClick={() => handleLoadMore(compIdx)}
|
||||
style={{
|
||||
padding: '14px 32px',
|
||||
background: 'var(--primary-color, #3b82f6)',
|
||||
color: 'white',
|
||||
border: 'none',
|
||||
borderRadius: 12,
|
||||
fontWeight: 700,
|
||||
fontSize: '1rem',
|
||||
cursor: 'pointer',
|
||||
transition: 'all 0.3s cubic-bezier(0.4, 0, 0.2, 1)',
|
||||
boxShadow: '0 4px 12px rgba(59, 130, 246, 0.3)',
|
||||
display: 'inline-flex',
|
||||
alignItems: 'center',
|
||||
gap: 10
|
||||
}}
|
||||
onMouseEnter={(e) => {
|
||||
e.currentTarget.style.transform = 'translateY(-2px)';
|
||||
e.currentTarget.style.boxShadow = '0 8px 20px rgba(59, 130, 246, 0.4)';
|
||||
}}
|
||||
onMouseLeave={(e) => {
|
||||
e.currentTarget.style.transform = 'translateY(0)';
|
||||
e.currentTarget.style.boxShadow = '0 4px 12px rgba(59, 130, 246, 0.3)';
|
||||
}}
|
||||
>
|
||||
<span>Načíst další zápasy</span>
|
||||
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
|
||||
<polyline points="6 9 12 15 18 9"></polyline>
|
||||
</svg>
|
||||
</button>
|
||||
<div style={{ marginTop: 12, fontSize: '0.875rem', color: textSecondary, fontWeight: 600 }}>
|
||||
Zobrazeno {Math.min(displayedMatchesCount[compIdx] || MATCHES_PER_PAGE, c.matches.length)} z {c.matches.length} zápasů
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</TabPanel>
|
||||
))}
|
||||
|
||||
Reference in New Issue
Block a user