Files
reactShop/src/components/CategoryBox.js

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;