import React, { Component } from 'react';
import Box from '@mui/material/Box';
import Card from '@mui/material/Card';
import CardContent from '@mui/material/CardContent';
import CardMedia from '@mui/material/CardMedia';
import Typography from '@mui/material/Typography';
import CircularProgress from '@mui/material/CircularProgress';
import IconButton from '@mui/material/IconButton';
import AddToCartButton from './AddToCartButton.js';
import { Link, useNavigate } from 'react-router-dom';
import { withI18n } from '../i18n/withTranslation.js';
import ZoomInIcon from '@mui/icons-material/ZoomIn';
import { STAR_POLYGON_POINTS } from '../utils/starPolygon.js';
import {
PRODUCT_CARD_MOBILE_MAX_WIDTH_PX,
PRODUCT_CARD_WIDTH_SM_PX,
PRODUCT_CARD_WIDTH_XS_PX,
} from '../utils/productCardLayout.js';
// Helper function to find level 1 category ID from any category ID
const findLevel1CategoryId = (categoryId) => {
try {
const currentLanguage = 'de'; // Default to German
const categoryTreeCache = window.categoryService?.getSync(209, currentLanguage);
if (!categoryTreeCache || !categoryTreeCache.children) {
return null;
}
// Helper function to find category by ID and get its level 1 parent
const findCategoryAndLevel1 = (categories, targetId) => {
for (const category of categories) {
if (category.id === targetId) {
// Found the category, now find its level 1 parent
return findLevel1Parent(categoryTreeCache.children, category);
}
if (category.children && category.children.length > 0) {
const result = findCategoryAndLevel1(category.children, targetId);
if (result) return result;
}
}
return null;
};
// Helper function to find the level 1 parent (direct child of root category 209)
const findLevel1Parent = (level1Categories, category) => {
// If this category's parent is 209, it's already level 1
if (category.parentId === 209) {
return category.id;
}
// Otherwise, find the parent and check if it's level 1
for (const level1Category of level1Categories) {
if (level1Category.id === category.parentId) {
return level1Category.id;
}
// If parent has children, search recursively
if (level1Category.children && level1Category.children.length > 0) {
const result = findLevel1Parent(level1Category.children, category);
if (result) return result;
}
}
return null;
};
return findCategoryAndLevel1(categoryTreeCache.children, parseInt(categoryId));
} catch (error) {
console.error('Error finding level 1 category:', error);
return null;
}
};
class Product extends Component {
constructor(props) {
super(props);
this._isMounted = false;
if (!window.smallPicCache) {
window.smallPicCache = {};
}
const pictureIds = (this.props.pictureList && this.props.pictureList.length > 0)
? this.props.pictureList.split(',').filter(id => id.trim().length > 0)
: [];
if (pictureIds.length > 0) {
const initialImages = pictureIds.map(id => window.smallPicCache[id] || null);
const isFirstCached = !!initialImages[0];
this.state = {
images: initialImages,
currentImageIndex: 0,
loading: !isFirstCached,
error: false,
isHovering: false
};
pictureIds.forEach((id, index) => {
if (!window.smallPicCache[id]) {
this.loadImage(id, index);
}
});
} else {
this.state = { images: [], currentImageIndex: 0, loading: false, error: false, isHovering: false };
}
}
componentDidMount() {
this._isMounted = true;
this.startRandomFading();
}
startRandomFading = () => {
if (this.state.isHovering) return;
const pictureIds = (this.props.pictureList && this.props.pictureList.length > 0)
? this.props.pictureList.split(',').filter(id => id.trim().length > 0)
: [];
if (pictureIds.length > 1) {
const minInterval = 4000;
const maxInterval = 8000;
const randomInterval = Math.floor(Math.random() * (maxInterval - minInterval + 1)) + minInterval;
this.fadeTimeout = setTimeout(() => {
if (this._isMounted) {
this.setState(prevState => {
let nextIndex = (prevState.currentImageIndex + 1) % pictureIds.length;
let attempts = 0;
while (!prevState.images[nextIndex] && attempts < pictureIds.length) {
nextIndex = (nextIndex + 1) % pictureIds.length;
attempts++;
}
if (attempts < pictureIds.length && nextIndex !== prevState.currentImageIndex) {
return { currentImageIndex: nextIndex };
}
return null;
}, () => {
this.startRandomFading();
});
}
}, randomInterval);
}
}
handleMouseMove = (e) => {
const pictureIds = (this.props.pictureList && this.props.pictureList.length > 0)
? this.props.pictureList.split(',').filter(id => id.trim().length > 0)
: [];
if (pictureIds.length > 1) {
if (this.fadeTimeout) {
clearTimeout(this.fadeTimeout);
this.fadeTimeout = null;
}
const { left, width } = e.currentTarget.getBoundingClientRect();
const x = e.clientX - left;
const segmentWidth = width / pictureIds.length;
let targetIndex = Math.floor(x / segmentWidth);
if (targetIndex >= pictureIds.length) targetIndex = pictureIds.length - 1;
if (targetIndex < 0) targetIndex = 0;
if (this.state.currentImageIndex !== targetIndex) {
if (this.state.images[targetIndex]) {
this.setState({ currentImageIndex: targetIndex, isHovering: true });
} else {
this.setState({ isHovering: true });
}
} else if (!this.state.isHovering) {
this.setState({ isHovering: true });
}
}
}
handleMouseLeave = () => {
if (this.state.isHovering) {
this.setState({ isHovering: false }, () => {
this.startRandomFading();
});
}
}
loadImage = (bildId, index) => {
console.log('loadImagevisSocket', bildId);
window.socketManager.emit('getPic', { bildId, size: 'small' }, (res) => {
if (res.success) {
window.smallPicCache[bildId] = URL.createObjectURL(new Blob([res.imageBuffer], { type: 'image/avif' }));
if (this._isMounted) {
this.setState(prevState => {
const newImages = [...prevState.images];
newImages[index] = window.smallPicCache[bildId];
return {
images: newImages,
loading: index === 0 ? false : prevState.loading
};
});
} else {
this.state.images[index] = window.smallPicCache[bildId];
if (index === 0) this.state.loading = false;
}
} else {
console.log('Fehler beim Laden des Bildes:', res);
if (this._isMounted) {
this.setState(prevState => ({
error: index === 0 ? true : prevState.error,
loading: index === 0 ? false : prevState.loading
}));
} else {
if (index === 0) {
this.state.error = true;
this.state.loading = false;
}
}
}
});
}
componentWillUnmount() {
this._isMounted = false;
if (this.fadeTimeout) {
clearTimeout(this.fadeTimeout);
}
}
handleQuantityChange = (quantity) => {
console.log(`Product: ${this.props.name}, Quantity: ${quantity}`);
// In a real app, this would update a cart state in a parent component or Redux store
}
handleProductClick = (e) => {
e.preventDefault();
const { categoryId } = this.props;
// Find the level 1 category for this product
const level1CategoryId = categoryId ? findLevel1CategoryId(categoryId) : null;
// Navigate to the product page WITH the category information in the state
const navigate = this.props.navigate;
if (navigate) {
navigate(`/Artikel/${this.props.seoName}`, {
state: { articleCategoryId: level1CategoryId }
});
}
}
render() {
const {
id, name, price, available, manufacturer, seoName,
currency, vat, cGrundEinheit, fGrundPreis, thc,
floweringWeeks, incoming, neu, weight, versandklasse, availableSupplier, komponenten
} = this.props;
const isNew = neu && (new Date().getTime() - new Date(neu).getTime() < 30 * 24 * 60 * 60 * 1000);
const showThcBadge = thc > 0;
let thcBadgeColor = '#4caf50'; // Green default
if (thc > 30) {
thcBadgeColor = '#f44336'; // Red for > 30
} else if (thc > 25) {
thcBadgeColor = '#ffeb3b'; // Yellow for > 25
}
const showFloweringWeeksBadge = floweringWeeks > 0;
let floweringWeeksBadgeColor = '#4caf50'; // Green default
if (floweringWeeks > 12) {
floweringWeeksBadgeColor = '#f44336'; // Red for > 12
} else if (floweringWeeks > 8) {
floweringWeeksBadgeColor = '#ffeb3b'; // Yellow for > 8
}
return (
{isNew && (
{/* Background star - slightly larger and rotated */}
{/* Middle star - medium size with different rotation */}
{/* Foreground star - main star with text */}
{/* Text as a separate element to position it at the top */}