This commit is contained in:
Tomáš Dvořák
2025-10-16 13:32:05 +02:00
commit 12cba639b9
663 changed files with 168914 additions and 0 deletions
+126
View File
@@ -0,0 +1,126 @@
import React, { useEffect, useState } from 'react';
import { Image, ImageProps, Skeleton } from '@chakra-ui/react';
import { getTeamLogo } from '../../utils/sportLogosAPI';
import { getLogoStyle, getLogoClassName } from '../../utils/logoUtils';
import '../../styles/logos.css';
interface TeamLogoProps extends Omit<ImageProps, 'src'> {
teamId?: string;
teamName?: string;
facrLogo?: string;
size?: 'small' | 'medium' | 'large' | 'custom';
fallbackIcon?: React.ReactElement;
}
/**
* TeamLogo component with automatic logoapi.sportcreative.eu integration
* Features:
* - Fetches from logoapi first (with local caching)
* - Falls back to FACR logo if logoapi doesn't have it
* - Properly centers and formats logos
* - Handles SVG optimization
*/
export const TeamLogo: React.FC<TeamLogoProps> = ({
teamId,
teamName,
facrLogo,
size = 'medium',
fallbackIcon,
alt,
...imageProps
}) => {
const [logoUrl, setLogoUrl] = useState<string | null>(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(false);
useEffect(() => {
let mounted = true;
const fetchLogo = async () => {
try {
setLoading(true);
setError(false);
const url = await getTeamLogo(teamId, teamName, facrLogo);
if (mounted) {
setLogoUrl(url);
}
} catch (e) {
console.error('Failed to fetch logo:', e);
if (mounted) {
setError(true);
// Fallback to FACR or placeholder
setLogoUrl(facrLogo || '/logo192.png');
}
} finally {
if (mounted) {
setLoading(false);
}
}
};
fetchLogo();
return () => {
mounted = false;
};
}, [teamId, teamName, facrLogo]);
// Size mapping
const sizeMap = {
small: { boxSize: '24px' },
medium: { boxSize: '32px' },
large: { boxSize: '48px' },
custom: {},
};
const sizeProps = size !== 'custom' ? sizeMap[size] : {};
// Class name based on size
const className = `match-logo-${size} ${imageProps.className || ''}`.trim();
if (loading) {
return (
<Skeleton
{...sizeProps}
borderRadius="4px"
className="logo-loading"
/>
);
}
// Check if this is a circular container
const isCircular = imageProps.borderRadius === 'full' || imageProps.style?.borderRadius === '50%';
// Get appropriate styling and className using utility functions
// Only pass size to utils if it's not 'custom' (utils only accept standard sizes)
const utilSize = size !== 'custom' ? size : 'medium';
const logoStyle = getLogoStyle(logoUrl, isCircular, utilSize);
const logoClassName = getLogoClassName(logoUrl, isCircular, utilSize);
return (
<Image
src={logoUrl || '/logo192.png'}
alt={alt || teamName || 'Team logo'}
{...sizeProps}
{...imageProps}
className={`${className} ${logoClassName}`}
objectFit="contain"
loading="lazy"
fallback={fallbackIcon}
style={{
...imageProps.style,
...logoStyle
}}
onError={() => {
if (!error) {
setError(true);
setLogoUrl(facrLogo || '/logo192.png');
}
}}
/>
);
};
export default TeamLogo;