200 lines
6.3 KiB
JavaScript
200 lines
6.3 KiB
JavaScript
import React, { useState, useEffect } from 'react';
|
|
import Box from '@mui/material/Box';
|
|
import Paper from '@mui/material/Paper';
|
|
import { Link } from 'react-router-dom';
|
|
|
|
|
|
// @note SwashingtonCP font is now loaded globally via index.css
|
|
|
|
// Initialize cache in window object if it doesn't exist
|
|
if (typeof window !== 'undefined' && !window.categoryImageCache) {
|
|
window.categoryImageCache = new Map();
|
|
}
|
|
|
|
const CategoryBox = ({
|
|
id,
|
|
name,
|
|
seoName,
|
|
bgcolor,
|
|
fontSize = '1.2rem',
|
|
...props
|
|
}) => {
|
|
const [imageUrl, setImageUrl] = useState(null);
|
|
const [imageError, setImageError] = useState(false);
|
|
const [isLoading, setIsLoading] = useState(false);
|
|
|
|
|
|
useEffect(() => {
|
|
let objectUrl = null;
|
|
|
|
// Skip image loading entirely if prerender fallback is active
|
|
// @note Check both browser and SSR environments for prerender flag
|
|
const isPrerenderFallback = (typeof window !== 'undefined' && window.__PRERENDER_FALLBACK__) ||
|
|
(typeof global !== 'undefined' && global.window && global.window.__PRERENDER_FALLBACK__);
|
|
|
|
if (isPrerenderFallback) {
|
|
return;
|
|
}
|
|
|
|
// Check if we have the image data cached first
|
|
if (typeof window !== 'undefined' && window.categoryImageCache.has(id)) {
|
|
const cachedImageData = window.categoryImageCache.get(id);
|
|
if (cachedImageData === null) {
|
|
// @note Cached as null - this category has no image
|
|
setImageUrl(null);
|
|
setImageError(false);
|
|
} else {
|
|
// Create fresh blob URL from cached binary data
|
|
try {
|
|
const uint8Array = new Uint8Array(cachedImageData);
|
|
const blob = new Blob([uint8Array], { type: 'image/jpeg' });
|
|
objectUrl = URL.createObjectURL(blob);
|
|
setImageUrl(objectUrl);
|
|
setImageError(false);
|
|
} catch (error) {
|
|
console.error('Error creating blob URL from cached data:', error);
|
|
setImageError(true);
|
|
setImageUrl(null);
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
|
|
if (id && !isLoading) {
|
|
setIsLoading(true);
|
|
|
|
window.socketManager.emit('getCategoryPic', { categoryId: id }, (response) => {
|
|
setIsLoading(false);
|
|
|
|
if (response.success) {
|
|
const imageData = response.image; // Binary image data or null
|
|
|
|
if (imageData) {
|
|
try {
|
|
// Convert binary data to blob URL
|
|
const uint8Array = new Uint8Array(imageData);
|
|
const blob = new Blob([uint8Array], { type: 'image/jpeg' });
|
|
objectUrl = URL.createObjectURL(blob);
|
|
setImageUrl(objectUrl);
|
|
setImageError(false);
|
|
|
|
// @note Cache the raw binary data in window object (not the blob URL)
|
|
if (typeof window !== 'undefined') {
|
|
window.categoryImageCache.set(id, imageData);
|
|
}
|
|
} catch (error) {
|
|
console.error('Error converting image data to URL:', error);
|
|
setImageError(true);
|
|
setImageUrl(null);
|
|
// Cache as null to avoid repeated requests
|
|
if (typeof window !== 'undefined') {
|
|
window.categoryImageCache.set(id, null);
|
|
}
|
|
}
|
|
} else {
|
|
// @note No image available for this category
|
|
setImageUrl(null);
|
|
setImageError(false);
|
|
// Cache as null so we don't keep requesting
|
|
if (typeof window !== 'undefined') {
|
|
window.categoryImageCache.set(id, null);
|
|
}
|
|
}
|
|
} else {
|
|
console.error('Error fetching category image:', response.error);
|
|
setImageError(true);
|
|
setImageUrl(null);
|
|
// Cache as null to avoid repeated failed requests
|
|
if (typeof window !== 'undefined') {
|
|
window.categoryImageCache.set(id, null);
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
// Clean up the object URL when component unmounts or image changes
|
|
return () => {
|
|
if (objectUrl) {
|
|
URL.revokeObjectURL(objectUrl);
|
|
}
|
|
};
|
|
}, [id, isLoading]);
|
|
|
|
return (
|
|
<Paper
|
|
component={Link}
|
|
to={`/Kategorie/${seoName}`}
|
|
style={{
|
|
textDecoration: 'none',
|
|
color: 'inherit',
|
|
borderRadius: '8px',
|
|
overflow: 'hidden',
|
|
width: '130px',
|
|
height: '130px',
|
|
minHeight: '130px',
|
|
minWidth: '130px',
|
|
maxWidth: '130px',
|
|
maxHeight: '130px',
|
|
display: 'block',
|
|
position: 'relative',
|
|
zIndex: 10,
|
|
backgroundColor: bgcolor || '#f0f0f0',
|
|
boxShadow: '0px 2px 1px -1px rgba(0,0,0,0.2), 0px 1px 1px 0px rgba(0,0,0,0.14), 0px 1px 3px 0px rgba(0,0,0,0.12)'
|
|
}}
|
|
sx={{
|
|
'&:hover': {
|
|
transform: 'translateY(-5px)',
|
|
boxShadow: 8
|
|
},
|
|
...props.sx
|
|
}}
|
|
{...props}
|
|
>
|
|
{/* Main content area - using flex to fill space */}
|
|
<Box sx={{
|
|
width: '130px',
|
|
height: '130px',
|
|
bgcolor: bgcolor || '#e0e0e0',
|
|
position: 'relative',
|
|
backgroundImage: ((typeof window !== 'undefined' && window.__PRERENDER_FALLBACK__) ||
|
|
(typeof global !== 'undefined' && global.window && global.window.__PRERENDER_FALLBACK__))
|
|
? `url("/assets/images/cat${id}.jpg")`
|
|
: (imageUrl && !imageError ? `url("${imageUrl}")` : 'none'),
|
|
backgroundSize: 'cover',
|
|
backgroundPosition: 'center',
|
|
backgroundRepeat: 'no-repeat'
|
|
}}>
|
|
|
|
{/* Category name at bottom */}
|
|
<div style={{
|
|
position: 'absolute',
|
|
bottom: '0px',
|
|
left: '0px',
|
|
width: '130px',
|
|
height: '40px',
|
|
backgroundColor: 'rgba(0,0,0,0.7)',
|
|
display: 'table',
|
|
tableLayout: 'fixed'
|
|
}}>
|
|
<div style={{
|
|
display: 'table-cell',
|
|
textAlign: 'center',
|
|
verticalAlign: 'middle',
|
|
color: 'white',
|
|
fontSize: fontSize,
|
|
fontFamily: 'SwashingtonCP, "Times New Roman", Georgia, serif',
|
|
fontWeight: 'normal',
|
|
lineHeight: '1.2',
|
|
padding: '12px 8px'
|
|
}}>
|
|
{name}
|
|
</div>
|
|
</div>
|
|
|
|
|
|
</Box>
|
|
</Paper>
|
|
);
|
|
};
|
|
|
|
export default CategoryBox; |