TreeTrack / static /js /modules /background-data.js
RoyAalekh's picture
Implement preemptive data loading and remove image loading from tooltips
4c36de1
raw
history blame
5.69 kB
/**
* Background Data Service
* Handles preemptive loading of tree data for better performance
*/
export class BackgroundDataService {
constructor() {
this.treeDataCache = null;
this.isLoading = false;
this.loadPromise = null;
this.authToken = null;
this.batchSize = 1000;
}
setAuthToken(token) {
this.authToken = token;
}
async authenticatedFetch(url, options = {}) {
if (!this.authToken) {
throw new Error('No auth token available');
}
const headers = {
'Content-Type': 'application/json',
'Authorization': `Bearer ${this.authToken}`,
...options.headers
};
const response = await fetch(url, {
...options,
headers
});
if (response.status === 401) {
// Token expired or invalid
localStorage.removeItem('auth_token');
localStorage.removeItem('user_info');
window.location.href = '/login';
return null;
}
return response;
}
/**
* Start preemptive loading of all tree data
*/
async startPreemptiveLoading() {
if (this.isLoading || this.treeDataCache) {
return this.loadPromise;
}
console.log('πŸš€ Starting preemptive tree data loading...');
this.isLoading = true;
this.loadPromise = this.loadAllTreesInBackground();
return this.loadPromise;
}
/**
* Load all trees in background with batching
*/
async loadAllTreesInBackground() {
try {
let allTrees = [];
let offset = 0;
let hasMoreTrees = true;
console.log('πŸ“¦ Loading trees in background batches...');
while (hasMoreTrees && allTrees.length < 3000) { // Safety limit
console.log(`πŸ“₯ Background batch: offset=${offset}, limit=${this.batchSize}`);
const response = await this.authenticatedFetch(`/api/trees?limit=${this.batchSize}&offset=${offset}`);
if (!response) {
console.error('❌ Failed to fetch background batch');
break;
}
const batchTrees = await response.json();
console.log(`βœ… Background batch loaded: ${batchTrees.length} trees`);
if (batchTrees.length === 0) {
hasMoreTrees = false;
break;
}
allTrees = allTrees.concat(batchTrees);
offset += this.batchSize;
// If we got less than the batch size, we've reached the end
if (batchTrees.length < this.batchSize) {
hasMoreTrees = false;
}
// Small delay to prevent overwhelming the server
await this.delay(100);
}
// Filter out problematic trees
const filteredTrees = allTrees.filter(tree => {
// Exclude tree ID 18
if (tree.id === 18) {
console.log('πŸ”„ Background: Excluding tree ID 18 from cache');
return false;
}
return true;
});
this.treeDataCache = filteredTrees;
this.isLoading = false;
console.log(`πŸŽ‰ Background loading complete: ${filteredTrees.length} trees cached`);
// Dispatch custom event to notify that data is ready
window.dispatchEvent(new CustomEvent('treeDataReady', {
detail: { count: filteredTrees.length }
}));
return filteredTrees;
} catch (error) {
console.error('❌ Background tree loading failed:', error);
this.isLoading = false;
throw error;
}
}
/**
* Get cached tree data (returns immediately if available)
*/
getCachedTreeData() {
return this.treeDataCache;
}
/**
* Check if data is ready
*/
isDataReady() {
return this.treeDataCache !== null;
}
/**
* Get tree data - uses cache if available, otherwise loads
*/
async getTreeData() {
if (this.treeDataCache) {
console.log('⚑ Using cached tree data');
return this.treeDataCache;
}
if (this.isLoading) {
console.log('⏳ Waiting for background loading to complete...');
return await this.loadPromise;
}
console.log('πŸ”„ Cache miss, loading trees now...');
return await this.startPreemptiveLoading();
}
/**
* Clear cached data (useful for refresh scenarios)
*/
clearCache() {
this.treeDataCache = null;
this.isLoading = false;
this.loadPromise = null;
console.log('πŸ—‘οΈ Tree data cache cleared');
}
/**
* Simple delay utility
*/
delay(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
/**
* Get loading status for UI feedback
*/
getLoadingStatus() {
return {
isLoading: this.isLoading,
isReady: this.isDataReady(),
cacheSize: this.treeDataCache ? this.treeDataCache.length : 0
};
}
}
// Export singleton instance
export const backgroundDataService = new BackgroundDataService();