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:
@@ -92,8 +92,7 @@ class GrowTentKonfigurator extends Component {
|
|||||||
this.handleExtraToggle = this.handleExtraToggle.bind(this);
|
this.handleExtraToggle = this.handleExtraToggle.bind(this);
|
||||||
this.calculateTotalPrice = this.calculateTotalPrice.bind(this);
|
this.calculateTotalPrice = this.calculateTotalPrice.bind(this);
|
||||||
this.saveStateToWindow = this.saveStateToWindow.bind(this);
|
this.saveStateToWindow = this.saveStateToWindow.bind(this);
|
||||||
|
this.checkCacheValidity = this.checkCacheValidity.bind(this);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
saveStateToWindow() {
|
saveStateToWindow() {
|
||||||
@@ -116,6 +115,7 @@ class GrowTentKonfigurator extends Component {
|
|||||||
this.fetchCategoryData("Lampen");
|
this.fetchCategoryData("Lampen");
|
||||||
this.fetchCategoryData("Abluft-sets");
|
this.fetchCategoryData("Abluft-sets");
|
||||||
this.fetchCategoryData("Set-zubehoer");
|
this.fetchCategoryData("Set-zubehoer");
|
||||||
|
this.cacheCheckInterval = setInterval(this.checkCacheValidity, 60000);
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidUpdate(prevProps, prevState) {
|
componentDidUpdate(prevProps, prevState) {
|
||||||
@@ -156,12 +156,25 @@ class GrowTentKonfigurator extends Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
componentWillUnmount() {
|
||||||
|
if (this.cacheCheckInterval) {
|
||||||
|
clearInterval(this.cacheCheckInterval);
|
||||||
|
}
|
||||||
|
}
|
||||||
fetchCategoryData(categoryId) {
|
fetchCategoryData(categoryId) {
|
||||||
const cachedData = getCachedCategoryData(categoryId);
|
const cachedData = getCachedCategoryData(categoryId);
|
||||||
if (cachedData) {
|
if (cachedData) {
|
||||||
|
this.setState(prevState => ({
|
||||||
|
categoryLoadStatus: {
|
||||||
|
...prevState.categoryLoadStatus,
|
||||||
|
[categoryId]: true
|
||||||
|
}
|
||||||
|
}));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
console.log(`Cache miss for category ${categoryId}, fetching...`);
|
||||||
|
|
||||||
window.socketManager.off(`productList:${categoryId}`);
|
window.socketManager.off(`productList:${categoryId}`);
|
||||||
|
|
||||||
window.socketManager.on(`productList:${categoryId}`,(response) => {
|
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) {
|
handleTentShapeSelect(shapeId) {
|
||||||
this.setState({ selectedTentShape: shapeId });
|
this.setState({ selectedTentShape: shapeId });
|
||||||
}
|
}
|
||||||
@@ -600,22 +630,20 @@ class GrowTentKonfigurator extends Component {
|
|||||||
return null; // Don't show tent sizes until shape is selected
|
return null; // Don't show tent sizes until shape is selected
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!this.state.categoryLoadStatus["Zelte"]) {
|
||||||
|
return (
|
||||||
|
<Box sx={{ textAlign: 'center', py: 4 }}>
|
||||||
|
<Typography variant="h6" color="text.secondary">
|
||||||
|
Lade Growbox-Produkte...
|
||||||
|
</Typography>
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
// Get real filtered tent products for the selected shape
|
// Get real filtered tent products for the selected shape
|
||||||
const filteredTents = this.getTentsForShape(selectedTentShape);
|
const filteredTents = this.getTentsForShape(selectedTentShape);
|
||||||
|
|
||||||
// Show loading state if data is not yet available
|
|
||||||
if (filteredTents.length === 0) {
|
if (filteredTents.length === 0) {
|
||||||
const cachedData = getCachedCategoryData('Zelte');
|
|
||||||
if (!cachedData) {
|
|
||||||
return (
|
|
||||||
<Box sx={{ textAlign: 'center', py: 4 }}>
|
|
||||||
<Typography variant="h6" color="text.secondary">
|
|
||||||
Lade Growbox-Produkte...
|
|
||||||
</Typography>
|
|
||||||
</Box>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
// If we have cached data but no filtered tents, show empty state
|
|
||||||
return (
|
return (
|
||||||
<Box sx={{ textAlign: 'center', py: 4 }}>
|
<Box sx={{ textAlign: 'center', py: 4 }}>
|
||||||
<Typography variant="h6" color="text.secondary">
|
<Typography variant="h6" color="text.secondary">
|
||||||
@@ -624,18 +652,6 @@ class GrowTentKonfigurator extends Component {
|
|||||||
</Box>
|
</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 (
|
return (
|
||||||
<Box sx={{ mb: 4 }}>
|
<Box sx={{ mb: 4 }}>
|
||||||
<Typography variant="h2" component="h2" gutterBottom sx={{ color: '#2e7d32', fontWeight: 'bold' }}>
|
<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
|
if (!this.state.categoryLoadStatus["Lampen"]) {
|
||||||
const availableLamps = this.getLampsForTentShape(selectedTentShape);
|
|
||||||
const cachedData = getCachedCategoryData('Lampen');
|
|
||||||
|
|
||||||
if (!cachedData) {
|
|
||||||
return (
|
return (
|
||||||
<Box sx={{ mt: 4 }}>
|
<Box sx={{ mt: 4 }}>
|
||||||
<Typography variant="h2" component="h2" gutterBottom sx={{ color: '#2e7d32', fontWeight: 'bold' }}>
|
<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) {
|
if (availableLamps.length === 0) {
|
||||||
return (
|
return (
|
||||||
<Box sx={{ mt: 4 }}>
|
<Box sx={{ mt: 4 }}>
|
||||||
@@ -772,7 +786,7 @@ class GrowTentKonfigurator extends Component {
|
|||||||
</Box>
|
</Box>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box sx={{ mt: 4 }}>
|
<Box sx={{ mt: 4 }}>
|
||||||
<Typography variant="h2" component="h2" gutterBottom sx={{ color: '#2e7d32', fontWeight: 'bold' }}>
|
<Typography variant="h2" component="h2" gutterBottom sx={{ color: '#2e7d32', fontWeight: 'bold' }}>
|
||||||
@@ -872,11 +886,7 @@ class GrowTentKonfigurator extends Component {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get real ventilation products for selected tent shape
|
if (!this.state.categoryLoadStatus["Abluft-sets"]) {
|
||||||
const availableVentilation = this.getVentilationForTentShape(selectedTentShape);
|
|
||||||
const cachedData = getCachedCategoryData('Abluft-sets');
|
|
||||||
|
|
||||||
if (!cachedData) {
|
|
||||||
return (
|
return (
|
||||||
<Box sx={{ mt: 4 }}>
|
<Box sx={{ mt: 4 }}>
|
||||||
<Typography variant="h2" component="h2" gutterBottom sx={{ color: '#2e7d32', fontWeight: 'bold' }}>
|
<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) {
|
if (availableVentilation.length === 0) {
|
||||||
return (
|
return (
|
||||||
<Box sx={{ mt: 4 }}>
|
<Box sx={{ mt: 4 }}>
|
||||||
@@ -901,7 +913,7 @@ class GrowTentKonfigurator extends Component {
|
|||||||
</Box>
|
</Box>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box sx={{ mt: 4 }}>
|
<Box sx={{ mt: 4 }}>
|
||||||
<Typography variant="h2" component="h2" gutterBottom sx={{ color: '#2e7d32', fontWeight: 'bold' }}>
|
<Typography variant="h2" component="h2" gutterBottom sx={{ color: '#2e7d32', fontWeight: 'bold' }}>
|
||||||
@@ -1025,6 +1037,19 @@ class GrowTentKonfigurator extends Component {
|
|||||||
|
|
||||||
renderExtrasSection() {
|
renderExtrasSection() {
|
||||||
const { selectedExtras } = this.state;
|
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');
|
const extrasData = getCachedCategoryData('Set-zubehoer');
|
||||||
|
|
||||||
if (!extrasData) {
|
if (!extrasData) {
|
||||||
@@ -1034,7 +1059,7 @@ class GrowTentKonfigurator extends Component {
|
|||||||
5. Extras hinzufügen (optional)
|
5. Extras hinzufügen (optional)
|
||||||
</Typography>
|
</Typography>
|
||||||
<Typography variant="body1" color="text.secondary" sx={{ mb: 3 }}>
|
<Typography variant="body1" color="text.secondary" sx={{ mb: 3 }}>
|
||||||
Lade Extras...
|
Keine Extras verfügbar
|
||||||
</Typography>
|
</Typography>
|
||||||
</Box>
|
</Box>
|
||||||
);
|
);
|
||||||
@@ -1225,14 +1250,6 @@ class GrowTentKonfigurator extends Component {
|
|||||||
|
|
||||||
|
|
||||||
render() {
|
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 (
|
return (
|
||||||
<Container maxWidth="lg" sx={{ py: 4 }}>
|
<Container maxWidth="lg" sx={{ py: 4 }}>
|
||||||
<Paper elevation={2} sx={{ p: 4, borderRadius: 2 }}>
|
<Paper elevation={2} sx={{ p: 4, borderRadius: 2 }}>
|
||||||
@@ -1297,27 +1314,19 @@ class GrowTentKonfigurator extends Component {
|
|||||||
|
|
||||||
{this.renderTentShapeSection()}
|
{this.renderTentShapeSection()}
|
||||||
<Divider sx={{ my: 4 }} />
|
<Divider sx={{ my: 4 }} />
|
||||||
|
|
||||||
{allDataLoaded && (
|
|
||||||
<>
|
|
||||||
|
|
||||||
|
|
||||||
{this.renderTentSizeSection()}
|
{this.renderTentSizeSection()}
|
||||||
{this.state.selectedTentShape && <Divider sx={{ my: 4 }} />}
|
{this.state.selectedTentShape && <Divider sx={{ my: 4 }} />}
|
||||||
|
|
||||||
{this.renderLightSection()}
|
{this.renderLightSection()}
|
||||||
<Divider sx={{ my: 4 }} />
|
<Divider sx={{ my: 4 }} />
|
||||||
|
|
||||||
{this.renderVentilationSection()}
|
{this.renderVentilationSection()}
|
||||||
<Divider sx={{ my: 4 }} />
|
<Divider sx={{ my: 4 }} />
|
||||||
|
|
||||||
{this.renderExtrasSection()}
|
{this.renderExtrasSection()}
|
||||||
|
|
||||||
{/* Inline summary section - expands when scrolling to bottom */}
|
{/* Inline summary section - expands when scrolling to bottom */}
|
||||||
{this.renderInlineSummary()}
|
{this.renderInlineSummary()}
|
||||||
</>
|
|
||||||
)}
|
|
||||||
|
|
||||||
</Paper>
|
</Paper>
|
||||||
</Container>
|
</Container>
|
||||||
);
|
);
|
||||||
|
|||||||
Reference in New Issue
Block a user