Spaces:
Runtime error
Runtime error
| /** | |
| * 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(); |