doxa-maps/library/stores/dataStore.js
Doxa Maps e19697673d
Some checks are pending
Deploy to GitHub Pages / build (push) Waiting to run
Deploy to GitHub Pages / deploy (push) Blocked by required conditions
Doxa Maps — the map bundler, 7 production plugins and the Experimental shelf
2026-09-25 20:07:59 +00:00

95 lines
2.7 KiB
JavaScript

/**
* dataStore.js — Centralized data cache
*
* All data fetching goes through here — no direct fetch() inside components.
* markRaw() is REQUIRED on all large datasets to prevent Vue proxy wrapping.
*/
import { defineStore, acceptHMRUpdate } from 'pinia'
import { markRaw } from 'vue'
export const useDataStore = defineStore('data', {
state: () => ({
/**
* Cached data per source.
* Key: sourceId (string)
* Value: { features, rawData, timestamp }
*/
sources: {},
/**
* Loading state per source.
* Key: sourceId
* Value: { isLoading, error }
*/
loadingStates: {}
}),
actions: {
/**
* Load data for a sourceId.
* fetchFn: async () => data — caller provides the fetch logic.
* Data is marked raw to avoid Vue proxy overhead on large arrays.
*/
async load(sourceId, fetchFn) {
if (this.sources[sourceId]) return // already cached
this.loadingStates[sourceId] = { isLoading: true, error: null }
try {
const data = await fetchFn()
// markRaw: large datasets (GeoJSON features, CSV rows) must NOT be reactive
this.sources[sourceId] = markRaw({
features: data,
timestamp: Date.now()
})
this.loadingStates[sourceId] = { isLoading: false, error: null }
} catch (err) {
console.error(`[dataStore] Failed to load source "${sourceId}":`, err)
this.loadingStates[sourceId] = { isLoading: false, error: err }
}
},
clearSource(sourceId) {
delete this.sources[sourceId]
delete this.loadingStates[sourceId]
},
/**
* Cache normalized source data — called by useMapData after DataSourceManager loads.
* Stores under sources[sourceId].features so LegendPrayerProgress.localScan() can read it.
*/
cacheSourceData(sourceId, payload) {
this.sources[sourceId] = markRaw({
features: payload.normalizedData || [],
timestamp: payload.timestamp || Date.now()
})
},
/**
* Check if a source is already cached.
*/
hasSourceData(sourceId) {
return !!this.sources[sourceId]
},
/**
* Get cached source data (returns the stored payload object).
*/
getSourceData(sourceId) {
return this.sources[sourceId]
? { normalizedData: this.sources[sourceId].features }
: null
}
},
getters: {
getData: (state) => (sourceId) => state.sources[sourceId]?.features ?? null,
isLoading: (state) => (sourceId) => state.loadingStates[sourceId]?.isLoading ?? false,
getError: (state) => (sourceId) => state.loadingStates[sourceId]?.error ?? null
}
})
if (import.meta.hot) {
import.meta.hot.accept(acceptHMRUpdate(useDataStore, import.meta.hot))
}