feat: enhance GrowTentKonfigurator with lamp filtering and improved UI

- Implemented filtering logic for lamps based on selected tent shape and availability.
- Updated rendering of lamp selection to dynamically display available options based on user input.
- Enhanced user interface with improved styling and selection indicators for better user experience.
- Added console logging for debugging purposes to track filtering and selection processes.
This commit is contained in:
sebseb7
2025-09-03 11:57:06 +02:00
parent ead44afb69
commit 21ae00b3f7

View File

@@ -16,7 +16,7 @@ import {
} from '@mui/material';
import ShoppingCartIcon from '@mui/icons-material/ShoppingCart';
import { TentShapeSelector, ProductSelector, ExtrasSelector } from '../components/configurator/index.js';
import { tentShapes, lightTypes, ventilationTypes, extras } from '../data/configuratorData.js';
import { tentShapes, ventilationTypes, extras } from '../data/configuratorData.js';
function setCachedCategoryData(categoryId, data) {
if (!window.productCache) {
@@ -244,7 +244,13 @@ class GrowTentKonfigurator extends Component {
const productDepth = parseInt(depthMatch[1]);
// Check if dimensions match
return productWidth === targetWidth && productDepth === targetDepth;
const sizeMatch = productWidth === targetWidth && productDepth === targetDepth;
// Check availability - only show products that are available for delivery
// Following same logic as Content.js: available > 0 OR availableSupplier == 1
const isAvailable = (product.available > 0) || (product.availableSupplier === 1);
return sizeMatch && isAvailable;
});
return matchingProducts.map(product => {
@@ -254,6 +260,58 @@ class GrowTentKonfigurator extends Component {
}); // No sorting needed
}
// Filter lamps by tent size using "passend für Zelt" attribute
filterLampsByTentSize(tentShape, products, attributes) {
if (!products || !attributes || !tentShape) return [];
console.log('Filtering lamps for tent shape:', tentShape);
console.log('Available lamp products:', products.length);
console.log('Available lamp attributes:', attributes.length);
// Group attributes by product ID and attribute name
const attributesByProduct = {};
attributes.forEach(attr => {
if (!attributesByProduct[attr.kArtikel]) {
attributesByProduct[attr.kArtikel] = {};
}
attributesByProduct[attr.kArtikel][attr.cName] = attr.cWert;
});
// Filter products by matching tent size in "passend für Zelt" attribute
const matchingProducts = products.filter(product => {
const attrs = attributesByProduct[product.id];
if (!attrs) return false;
// Check "passend für Zelt" attribute
const tentSizeAttr = attrs['passend für Zelt'];
if (!tentSizeAttr) return false;
// Check if tent size matches
const sizeMatch = tentSizeAttr === tentShape;
// Check availability - only show products that are available for delivery
const isAvailable = (product.available > 0) || (product.availableSupplier === 1);
console.log(`Product ${product.id}: tentSize=${tentSizeAttr}, match=${sizeMatch}, available=${isAvailable}`);
return sizeMatch && isAvailable;
});
console.log('Filtered lamps:', matchingProducts.length);
return matchingProducts;
}
// Get lamps for selected tent shape
getLampsForTentShape(shapeId) {
const cachedData = getCachedCategoryData('Lampen');
if (!cachedData || !cachedData.products || !cachedData.attributes) {
console.log('No cached lamp data available');
return [];
}
return this.filterLampsByTentSize(shapeId, cachedData.products, cachedData.attributes);
}
// Helper function to generate coverage descriptions
getCoverageDescription(width, depth) {
const area = width * depth;
@@ -355,8 +413,9 @@ class GrowTentKonfigurator extends Component {
// Add light price
if (selectedLightType) {
const light = lightTypes.find(l => l.id === selectedLightType);
if (light) {
const availableLamps = this.getLampsForTentShape(this.state.selectedTentShape);
const light = availableLamps.find(l => l.id === selectedLightType);
if (light && light.price) {
total += light.price;
itemCount++;
}
@@ -427,8 +486,9 @@ class GrowTentKonfigurator extends Component {
}
if (selectedLightType) {
const light = lightTypes.find(l => l.id === selectedLightType);
if (light) {
const availableLamps = this.getLampsForTentShape(this.state.selectedTentShape);
const light = availableLamps.find(l => l.id === selectedLightType);
if (light && light.price) {
originalTotal += light.price;
itemCount++;
}
@@ -543,15 +603,16 @@ class GrowTentKonfigurator extends Component {
display: 'flex',
flexDirection: 'column',
borderRadius: '8px',
boxShadow: '0px 2px 8px rgba(0,0,0,0.1)',
overflow: 'hidden',
backgroundColor: '#ffffff',
cursor: 'pointer',
border: '2px solid',
borderColor: this.state.selectedTentSize === product.id ? '#2e7d32' : '#e0e0e0',
backgroundColor: this.state.selectedTentSize === product.id ? '#f1f8e9' : '#ffffff',
'&:hover': {
borderColor: '#90caf9'
}
boxShadow: 6,
borderColor: this.state.selectedTentSize === product.id ? '#2e7d32' : '#90caf9'
},
transition: 'all 0.3s ease'
}}
onClick={() => this.handleTentSizeSelect(product.id)}>
{/* Image */}
@@ -568,48 +629,41 @@ class GrowTentKonfigurator extends Component {
{/* Content */}
<Box sx={{ p: 2, flexGrow: 1, display: 'flex', flexDirection: 'column' }}>
{/* Name */}
<Typography
variant="h6"
sx={{
fontWeight: 600,
mb: 1,
display: '-webkit-box',
WebkitLineClamp: 2,
WebkitBoxOrient: 'vertical',
overflow: 'hidden',
textOverflow: 'ellipsis'
}}
>
<Typography variant="h6" gutterBottom sx={{ fontWeight: 'bold' }}>
{product.name}
</Typography>
{/* Price */}
<Typography
variant="h6"
sx={{
color: '#2e7d32',
fontWeight: 'bold',
mt: 'auto'
}}
>
{product.price ? new Intl.NumberFormat('de-DE', {
{/* Price with VAT - Same as Product.js */}
<Typography variant="h6" sx={{
color: '#2e7d32',
fontWeight: 'bold',
mt: 2,
display: 'flex',
alignItems: 'center',
gap: 1,
flexWrap: 'wrap'
}}>
<span>{product.price ? new Intl.NumberFormat('de-DE', {
style: 'currency',
currency: 'EUR'
}).format(product.price) : 'Kein Preis'}
}).format(product.price) : 'Kein Preis'}</span>
{product.vat && (
<small style={{ color: '#77aa77', fontSize: '0.6em' }}>
(incl. {product.vat}% MwSt.,*)
</small>
)}
</Typography>
{/* VAT */}
<Typography variant="body2" sx={{ color: '#77aa77', fontSize: '0.75em' }}>
(incl. 19% MwSt.,*)
</Typography>
{/* Selection Indicator */}
{/* Selection Indicator - Separate line */}
{this.state.selectedTentSize === product.id && (
<Box sx={{ mt: 1, textAlign: 'center' }}>
<Typography variant="body2" sx={{ color: '#2e7d32', fontWeight: 'bold' }}>
Ausgewählt
</Typography>
</Box>
<Typography variant="body2" sx={{
color: '#2e7d32',
fontWeight: 'bold',
mt: 1,
textAlign: 'center'
}}>
Ausgewählt
</Typography>
)}
</Box>
</Box>
@@ -621,17 +675,128 @@ class GrowTentKonfigurator extends Component {
}
renderLightSection() {
const { selectedLightType } = this.state;
const { selectedLightType, selectedTentShape } = this.state;
if (!selectedTentShape) {
return (
<Box sx={{ mt: 4 }}>
<Typography variant="h2" component="h2" gutterBottom sx={{ color: '#2e7d32', fontWeight: 'bold' }}>
3. Beleuchtung wählen
</Typography>
<Typography variant="body2" color="text.secondary">
Bitte wählen Sie zuerst eine Zeltgröße aus.
</Typography>
</Box>
);
}
// Get real lamps for selected tent shape
const availableLamps = this.getLampsForTentShape(selectedTentShape);
const cachedData = getCachedCategoryData('Lampen');
if (!cachedData) {
return (
<Box sx={{ mt: 4 }}>
<Typography variant="h2" component="h2" gutterBottom sx={{ color: '#2e7d32', fontWeight: 'bold' }}>
3. Beleuchtung wählen - {selectedTentShape}
</Typography>
<Typography variant="body2" color="text.secondary">
Lade Beleuchtungs-Produkte...
</Typography>
</Box>
);
}
if (availableLamps.length === 0) {
return (
<Box sx={{ mt: 4 }}>
<Typography variant="h2" component="h2" gutterBottom sx={{ color: '#2e7d32', fontWeight: 'bold' }}>
3. Beleuchtung wählen - {selectedTentShape}
</Typography>
<Typography variant="body2" color="text.secondary">
Keine passenden Lampen für Zeltgröße {selectedTentShape} verfügbar.
</Typography>
</Box>
);
}
return (
<ProductSelector
products={lightTypes}
selectedValue={selectedLightType}
onSelect={this.handleLightTypeSelect}
productType="light"
title="3. Beleuchtung wählen"
gridSize={{ xs: 12, sm: 6 }}
/>
<Box sx={{ mt: 4 }}>
<Typography variant="h2" component="h2" gutterBottom sx={{ color: '#2e7d32', fontWeight: 'bold' }}>
3. Beleuchtung wählen - {selectedTentShape}
</Typography>
<Grid container spacing={2}>
{availableLamps.map((lamp) => (
<Grid item xs={12} sm={6} md={4} key={lamp.id}>
<Box sx={{
width: { xs: '100%', sm: '250px' },
height: '100%',
display: 'flex',
flexDirection: 'column',
borderRadius: '8px',
overflow: 'hidden',
cursor: 'pointer',
border: '2px solid',
borderColor: selectedLightType === lamp.id ? '#2e7d32' : '#e0e0e0',
backgroundColor: selectedLightType === lamp.id ? '#f1f8e9' : '#ffffff',
'&:hover': {
boxShadow: 6,
borderColor: '#2e7d32'
},
transition: 'all 0.3s ease'
}}
onClick={() => this.handleLightTypeSelect(lamp.id)}
>
{/* Image */}
<Box sx={{ height: 200, display: 'flex', alignItems: 'center', justifyContent: 'center', overflow: 'hidden' }}>
{this.renderTentImage(lamp)}
</Box>
{/* Content */}
<Box sx={{ p: 2, flexGrow: 1, display: 'flex', flexDirection: 'column' }}>
{/* Name */}
<Typography variant="h6" gutterBottom sx={{ fontWeight: 'bold' }}>
{lamp.name}
</Typography>
{/* Price with VAT */}
<Typography variant="h6" sx={{
color: '#2e7d32',
fontWeight: 'bold',
mt: 2,
display: 'flex',
alignItems: 'center',
gap: 1,
flexWrap: 'wrap'
}}>
<span>{lamp.price ? new Intl.NumberFormat('de-DE', {
style: 'currency',
currency: 'EUR'
}).format(lamp.price) : 'Kein Preis'}</span>
{lamp.vat && (
<small style={{ color: '#77aa77', fontSize: '0.6em' }}>
(incl. {lamp.vat}% MwSt.,*)
</small>
)}
</Typography>
{/* Selection Indicator */}
{selectedLightType === lamp.id && (
<Typography variant="body2" sx={{
color: '#2e7d32',
fontWeight: 'bold',
mt: 1,
textAlign: 'center'
}}>
Ausgewählt
</Typography>
)}
</Box>
</Box>
</Grid>
))}
</Grid>
</Box>
);
}
@@ -676,7 +841,8 @@ class GrowTentKonfigurator extends Component {
selectedTent = tents.find(t => t.id === selectedTentSize);
if (selectedTent) break;
}
const selectedLight = lightTypes.find(l => l.id === selectedLightType);
const availableLamps = this.state.selectedTentShape ? this.getLampsForTentShape(this.state.selectedTentShape) : [];
const selectedLight = availableLamps.find(l => l.id === selectedLightType);
const selectedVentilation = ventilationTypes.find(v => v.id === selectedVentilationType);
const selectedExtrasItems = extras.filter(e => selectedExtras.includes(e.id));
const savingsInfo = this.calculateSavings();