feat: improve ventilation selection logic in GrowTentKonfigurator

- Added functionality to reset ventilation selection when the tent shape changes and the current selection is not deliverable.
- Updated product filtering to include all size-matching products while marking their availability status.
- Enhanced UI to visually indicate non-deliverable ventilation options, improving user experience and clarity in selection.
- Adjusted price calculations to consider only deliverable ventilation products.
This commit is contained in:
sebseb7
2025-09-04 07:07:21 +02:00
parent 8862f0c6b8
commit 3660f80277

View File

@@ -116,6 +116,15 @@ class GrowTentKonfigurator extends Component {
if (prevState.selectedTentShape !== this.state.selectedTentShape && this.state.selectedTentShape !== prevState.selectedTentShape) { if (prevState.selectedTentShape !== this.state.selectedTentShape && this.state.selectedTentShape !== prevState.selectedTentShape) {
this.setState({ selectedTentSize: '' }); this.setState({ selectedTentSize: '' });
} }
// Reset ventilation selection if current selection is not deliverable for new tent shape
if (prevState.selectedTentShape !== this.state.selectedTentShape && this.state.selectedVentilationType) {
const availableVentilation = this.getVentilationForTentShape(this.state.selectedTentShape);
const currentVentilation = availableVentilation.find(v => v.id === this.state.selectedVentilationType);
if (!currentVentilation || !currentVentilation.isDeliverable) {
this.setState({ selectedVentilationType: '' });
}
}
// Recalculate total price when selections change // Recalculate total price when selections change
if ( if (
@@ -341,6 +350,7 @@ class GrowTentKonfigurator extends Component {
}); });
// Filter products by matching tent size in "passend für Zelt" attribute // Filter products by matching tent size in "passend für Zelt" attribute
// Include all size-matching products, but mark availability status
const matchingProducts = products.filter(product => { const matchingProducts = products.filter(product => {
const attrs = attributesByProduct[product.id]; const attrs = attributesByProduct[product.id];
if (!attrs) return false; if (!attrs) return false;
@@ -349,18 +359,22 @@ class GrowTentKonfigurator extends Component {
const tentSizeAttr = attrs['passend für Zelt']; const tentSizeAttr = attrs['passend für Zelt'];
if (!tentSizeAttr) return false; if (!tentSizeAttr) return false;
// Check if tent size matches // Only filter by tent size match, not by availability
const sizeMatch = tentSizeAttr === tentShape; const sizeMatch = tentSizeAttr === tentShape;
// Check availability - only show products that are available for delivery console.log(`Ventilation Product ${product.id}: tentSize=${tentSizeAttr}, match=${sizeMatch}`);
return sizeMatch;
}).map(product => {
// Add availability flag to each product for UI rendering
const isAvailable = (product.available > 0) || (product.availableSupplier === 1); const isAvailable = (product.available > 0) || (product.availableSupplier === 1);
return {
console.log(`Ventilation Product ${product.id}: tentSize=${tentSizeAttr}, match=${sizeMatch}, available=${isAvailable}`); ...product,
isDeliverable: isAvailable
return sizeMatch && isAvailable; };
}); });
console.log('Filtered ventilation:', matchingProducts.length); console.log('Filtered ventilation (including non-deliverable):', matchingProducts.length);
return matchingProducts; return matchingProducts;
} }
@@ -477,7 +491,7 @@ class GrowTentKonfigurator extends Component {
if (selectedVentilationType) { if (selectedVentilationType) {
const availableVentilation = this.getVentilationForTentShape(this.state.selectedTentShape); const availableVentilation = this.getVentilationForTentShape(this.state.selectedTentShape);
const ventilation = availableVentilation.find(v => v.id === selectedVentilationType); const ventilation = availableVentilation.find(v => v.id === selectedVentilationType);
if (ventilation && ventilation.price) { if (ventilation && ventilation.price && ventilation.isDeliverable) {
total += ventilation.price; total += ventilation.price;
itemCount++; itemCount++;
} }
@@ -550,7 +564,7 @@ class GrowTentKonfigurator extends Component {
if (selectedVentilationType) { if (selectedVentilationType) {
const availableVentilation = this.getVentilationForTentShape(this.state.selectedTentShape); const availableVentilation = this.getVentilationForTentShape(this.state.selectedTentShape);
const ventilation = availableVentilation.find(v => v.id === selectedVentilationType); const ventilation = availableVentilation.find(v => v.id === selectedVentilationType);
if (ventilation && ventilation.price) { if (ventilation && ventilation.price && ventilation.isDeliverable) {
originalTotal += ventilation.price; originalTotal += ventilation.price;
itemCount++; itemCount++;
} }
@@ -915,18 +929,53 @@ class GrowTentKonfigurator extends Component {
flexDirection: 'column', flexDirection: 'column',
borderRadius: '8px', borderRadius: '8px',
overflow: 'hidden', overflow: 'hidden',
cursor: 'pointer', cursor: ventilation.isDeliverable ? 'pointer' : 'not-allowed',
border: '2px solid', border: '2px solid',
borderColor: selectedVentilationType === ventilation.id ? '#2e7d32' : '#e0e0e0', borderColor: selectedVentilationType === ventilation.id ? '#2e7d32' : '#e0e0e0',
backgroundColor: selectedVentilationType === ventilation.id ? '#f1f8e9' : '#ffffff', backgroundColor: selectedVentilationType === ventilation.id ? '#f1f8e9' : '#ffffff',
'&:hover': { opacity: ventilation.isDeliverable ? 1 : 0.5,
filter: ventilation.isDeliverable ? 'none' : 'grayscale(50%)',
'&:hover': ventilation.isDeliverable ? {
boxShadow: 6, boxShadow: 6,
borderColor: '#2e7d32' borderColor: '#2e7d32'
}, } : {},
transition: 'all 0.3s ease' transition: 'all 0.3s ease',
position: 'relative'
}}
onClick={() => {
if (ventilation.isDeliverable) {
this.handleVentilationSelect(ventilation.id);
}
}} }}
onClick={() => this.handleVentilationSelect(ventilation.id)}
> >
{/* Non-deliverable overlay */}
{!ventilation.isDeliverable && (
<Box sx={{
position: 'absolute',
top: 0,
left: 0,
right: 0,
bottom: 0,
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
backgroundColor: 'rgba(255, 255, 255, 0.8)',
zIndex: 1,
flexDirection: 'column'
}}>
<Typography variant="h6" sx={{
color: '#d32f2f',
fontWeight: 'bold',
textAlign: 'center',
backgroundColor: 'rgba(255, 255, 255, 0.9)',
p: 1,
borderRadius: 1
}}>
Nicht lieferbar
</Typography>
</Box>
)}
{/* Image */} {/* Image */}
<Box sx={{ height: 200, display: 'flex', alignItems: 'center', justifyContent: 'center', overflow: 'hidden' }}> <Box sx={{ height: 200, display: 'flex', alignItems: 'center', justifyContent: 'center', overflow: 'hidden' }}>
{this.renderTentImage(ventilation)} {this.renderTentImage(ventilation)}
@@ -935,13 +984,16 @@ class GrowTentKonfigurator extends Component {
{/* Content */} {/* Content */}
<Box sx={{ p: 2, flexGrow: 1, display: 'flex', flexDirection: 'column' }}> <Box sx={{ p: 2, flexGrow: 1, display: 'flex', flexDirection: 'column' }}>
{/* Name */} {/* Name */}
<Typography variant="h6" gutterBottom sx={{ fontWeight: 'bold' }}> <Typography variant="h6" gutterBottom sx={{
fontWeight: 'bold',
color: ventilation.isDeliverable ? 'inherit' : '#999'
}}>
{ventilation.name} {ventilation.name}
</Typography> </Typography>
{/* Price with VAT */} {/* Price with VAT */}
<Typography variant="h6" sx={{ <Typography variant="h6" sx={{
color: '#2e7d32', color: ventilation.isDeliverable ? '#2e7d32' : '#999',
fontWeight: 'bold', fontWeight: 'bold',
mt: 2, mt: 2,
display: 'flex', display: 'flex',
@@ -954,14 +1006,14 @@ class GrowTentKonfigurator extends Component {
currency: 'EUR' currency: 'EUR'
}).format(ventilation.price) : 'Kein Preis'}</span> }).format(ventilation.price) : 'Kein Preis'}</span>
{ventilation.vat && ( {ventilation.vat && (
<small style={{ color: '#77aa77', fontSize: '0.6em' }}> <small style={{ color: ventilation.isDeliverable ? '#77aa77' : '#999', fontSize: '0.6em' }}>
(incl. {ventilation.vat}% MwSt.,*) (incl. {ventilation.vat}% MwSt.,*)
</small> </small>
)} )}
</Typography> </Typography>
{/* Selection Indicator */} {/* Selection Indicator */}
{selectedVentilationType === ventilation.id && ( {selectedVentilationType === ventilation.id && ventilation.isDeliverable && (
<Typography variant="body2" sx={{ <Typography variant="body2" sx={{
color: '#2e7d32', color: '#2e7d32',
fontWeight: 'bold', fontWeight: 'bold',
@@ -1009,7 +1061,7 @@ class GrowTentKonfigurator extends Component {
const availableLamps = this.state.selectedTentShape ? this.getLampsForTentShape(this.state.selectedTentShape) : []; const availableLamps = this.state.selectedTentShape ? this.getLampsForTentShape(this.state.selectedTentShape) : [];
const selectedLight = availableLamps.find(l => l.id === selectedLightType); const selectedLight = availableLamps.find(l => l.id === selectedLightType);
const availableVentilation = this.state.selectedTentShape ? this.getVentilationForTentShape(this.state.selectedTentShape) : []; const availableVentilation = this.state.selectedTentShape ? this.getVentilationForTentShape(this.state.selectedTentShape) : [];
const selectedVentilation = availableVentilation.find(v => v.id === selectedVentilationType); const selectedVentilation = availableVentilation.find(v => v.id === selectedVentilationType && v.isDeliverable);
const selectedExtrasItems = extras.filter(e => selectedExtras.includes(e.id)); const selectedExtrasItems = extras.filter(e => selectedExtras.includes(e.id));
const savingsInfo = this.calculateSavings(); const savingsInfo = this.calculateSavings();