feat(GrowTentKonfigurator): add periodic cache validity checking

Implement interval-based cache monitoring every 60 seconds to detect
misses or expirations across categories (Zelte, Lampen, Abluft-sets,
Set-zubehoer). Update per-category load status tracking to conditionally
render sections independently, improving UX by avoiding global loading
delays and ensuring timely refetches. Clear interval on unmount to prevent
memory leaks.
This commit is contained in:
sebseb7
2025-09-09 18:10:08 +02:00
parent 77ffe864b1
commit 0dd1e01018

View File

@@ -92,8 +92,7 @@ class GrowTentKonfigurator extends Component {
this.handleExtraToggle = this.handleExtraToggle.bind(this);
this.calculateTotalPrice = this.calculateTotalPrice.bind(this);
this.saveStateToWindow = this.saveStateToWindow.bind(this);
this.checkCacheValidity = this.checkCacheValidity.bind(this);
}
saveStateToWindow() {
@@ -116,6 +115,7 @@ class GrowTentKonfigurator extends Component {
this.fetchCategoryData("Lampen");
this.fetchCategoryData("Abluft-sets");
this.fetchCategoryData("Set-zubehoer");
this.cacheCheckInterval = setInterval(this.checkCacheValidity, 60000);
}
componentDidUpdate(prevProps, prevState) {
@@ -156,12 +156,25 @@ class GrowTentKonfigurator extends Component {
}
}
componentWillUnmount() {
if (this.cacheCheckInterval) {
clearInterval(this.cacheCheckInterval);
}
}
fetchCategoryData(categoryId) {
const cachedData = getCachedCategoryData(categoryId);
if (cachedData) {
this.setState(prevState => ({
categoryLoadStatus: {
...prevState.categoryLoadStatus,
[categoryId]: true
}
}));
return;
}
console.log(`Cache miss for category ${categoryId}, fetching...`);
window.socketManager.off(`productList:${categoryId}`);
window.socketManager.on(`productList:${categoryId}`,(response) => {
@@ -182,6 +195,23 @@ class GrowTentKonfigurator extends Component {
);
}
checkCacheValidity() {
const categories = ["Zelte", "Lampen", "Abluft-sets", "Set-zubehoer"];
let needsUpdate = false;
const newStatus = { ...this.state.categoryLoadStatus };
for (const categoryId of categories) {
if (newStatus[categoryId] && !getCachedCategoryData(categoryId)) {
console.log(`Refetching ${categoryId} due to cache miss/expiry`);
newStatus[categoryId] = false;
needsUpdate = true;
this.fetchCategoryData(categoryId);
}
}
if (needsUpdate) {
this.setState({ categoryLoadStatus: newStatus });
}
}
handleTentShapeSelect(shapeId) {
this.setState({ selectedTentShape: shapeId });
}
@@ -600,13 +630,7 @@ class GrowTentKonfigurator extends Component {
return null; // Don't show tent sizes until shape is selected
}
// Get real filtered tent products for the selected shape
const filteredTents = this.getTentsForShape(selectedTentShape);
// Show loading state if data is not yet available
if (filteredTents.length === 0) {
const cachedData = getCachedCategoryData('Zelte');
if (!cachedData) {
if (!this.state.categoryLoadStatus["Zelte"]) {
return (
<Box sx={{ textAlign: 'center', py: 4 }}>
<Typography variant="h6" color="text.secondary">
@@ -615,7 +639,11 @@ class GrowTentKonfigurator extends Component {
</Box>
);
}
// If we have cached data but no filtered tents, show empty state
// Get real filtered tent products for the selected shape
const filteredTents = this.getTentsForShape(selectedTentShape);
if (filteredTents.length === 0) {
return (
<Box sx={{ textAlign: 'center', py: 4 }}>
<Typography variant="h6" color="text.secondary">
@@ -624,18 +652,6 @@ class GrowTentKonfigurator extends Component {
</Box>
);
}
if (filteredTents.length === 0) {
return (
<Box sx={{ textAlign: 'center', py: 4 }}>
<Typography variant="h6" color="text.secondary">
Keine Produkte verfügbar
</Typography>
</Box>
);
}
return (
<Box sx={{ mb: 4 }}>
<Typography variant="h2" component="h2" gutterBottom sx={{ color: '#2e7d32', fontWeight: 'bold' }}>
@@ -743,11 +759,7 @@ class GrowTentKonfigurator extends Component {
);
}
// Get real lamps for selected tent shape
const availableLamps = this.getLampsForTentShape(selectedTentShape);
const cachedData = getCachedCategoryData('Lampen');
if (!cachedData) {
if (!this.state.categoryLoadStatus["Lampen"]) {
return (
<Box sx={{ mt: 4 }}>
<Typography variant="h2" component="h2" gutterBottom sx={{ color: '#2e7d32', fontWeight: 'bold' }}>
@@ -760,6 +772,8 @@ class GrowTentKonfigurator extends Component {
);
}
const availableLamps = this.getLampsForTentShape(selectedTentShape);
if (availableLamps.length === 0) {
return (
<Box sx={{ mt: 4 }}>
@@ -872,11 +886,7 @@ class GrowTentKonfigurator extends Component {
);
}
// Get real ventilation products for selected tent shape
const availableVentilation = this.getVentilationForTentShape(selectedTentShape);
const cachedData = getCachedCategoryData('Abluft-sets');
if (!cachedData) {
if (!this.state.categoryLoadStatus["Abluft-sets"]) {
return (
<Box sx={{ mt: 4 }}>
<Typography variant="h2" component="h2" gutterBottom sx={{ color: '#2e7d32', fontWeight: 'bold' }}>
@@ -889,6 +899,8 @@ class GrowTentKonfigurator extends Component {
);
}
const availableVentilation = this.getVentilationForTentShape(selectedTentShape);
if (availableVentilation.length === 0) {
return (
<Box sx={{ mt: 4 }}>
@@ -1025,6 +1037,19 @@ class GrowTentKonfigurator extends Component {
renderExtrasSection() {
const { selectedExtras } = this.state;
if (!this.state.categoryLoadStatus["Set-zubehoer"]) {
return (
<Box sx={{ mb: 4 }}>
<Typography variant="h2" component="h2" gutterBottom sx={{ color: '#2e7d32', fontWeight: 'bold' }}>
5. Extras hinzufügen (optional)
</Typography>
<Typography variant="body1" color="text.secondary" sx={{ mb: 3 }}>
Lade Extras...
</Typography>
</Box>
);
}
const extrasData = getCachedCategoryData('Set-zubehoer');
if (!extrasData) {
@@ -1034,7 +1059,7 @@ class GrowTentKonfigurator extends Component {
5. Extras hinzufügen (optional)
</Typography>
<Typography variant="body1" color="text.secondary" sx={{ mb: 3 }}>
Lade Extras...
Keine Extras verfügbar
</Typography>
</Box>
);
@@ -1225,14 +1250,6 @@ class GrowTentKonfigurator extends Component {
render() {
// Check if all 4 category data sections have loaded
const tentsData = getCachedCategoryData('Zelte');
const lampsData = getCachedCategoryData('Lampen');
const ventilationData = getCachedCategoryData('Abluft-sets');
const extrasData = getCachedCategoryData('Set-zubehoer');
const allDataLoaded = tentsData && lampsData && ventilationData && extrasData;
return (
<Container maxWidth="lg" sx={{ py: 4 }}>
<Paper elevation={2} sx={{ p: 4, borderRadius: 2 }}>
@@ -1297,11 +1314,6 @@ class GrowTentKonfigurator extends Component {
{this.renderTentShapeSection()}
<Divider sx={{ my: 4 }} />
{allDataLoaded && (
<>
{this.renderTentSizeSection()}
{this.state.selectedTentShape && <Divider sx={{ my: 4 }} />}
@@ -1315,9 +1327,6 @@ class GrowTentKonfigurator extends Component {
{/* Inline summary section - expands when scrolling to bottom */}
{this.renderInlineSummary()}
</>
)}
</Paper>
</Container>
);