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:
@@ -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();
|
||||
|
||||
Reference in New Issue
Block a user