Improved initial loading. Uses on device cach first
This commit is contained in:
+37
-12
@@ -1,9 +1,9 @@
|
||||
// ... (imports)
|
||||
import { createStore } from "solid-js/store";
|
||||
import { createSignal } from "solid-js";
|
||||
import { createStore, reconcile } from "solid-js/store";
|
||||
import { createSignal, createEffect, createRoot } from "solid-js";
|
||||
import { pb, TASGRID_COLLECTION } from "@/lib/pocketbase";
|
||||
import { toast } from "solid-sonner";
|
||||
|
||||
const STORAGE_KEY = "tasgrid_data_v1";
|
||||
|
||||
export const [now, setNow] = createSignal(Date.now());
|
||||
export const [activeTaskId, setActiveTaskId] = createSignal<string | null>(null);
|
||||
@@ -30,12 +30,31 @@ interface TaskStore {
|
||||
prefId?: string; // ID of the user_preferences record
|
||||
}
|
||||
|
||||
// Initial state
|
||||
export const [store, setStore] = createStore<TaskStore>({
|
||||
tasks: [],
|
||||
pWeight: 1.0,
|
||||
uWeight: 1.0,
|
||||
matrixScaleDays: 30, // Default requested by user
|
||||
// Synchronous hydration from localStorage for "instant" first paint
|
||||
const getInitialState = (): TaskStore => {
|
||||
const saved = localStorage.getItem(STORAGE_KEY);
|
||||
if (saved) {
|
||||
try {
|
||||
return JSON.parse(saved);
|
||||
} catch (e) {
|
||||
console.error("Failed to parse cached data", e);
|
||||
}
|
||||
}
|
||||
return {
|
||||
tasks: [],
|
||||
pWeight: 1.0,
|
||||
uWeight: 1.0,
|
||||
matrixScaleDays: 30,
|
||||
};
|
||||
};
|
||||
|
||||
export const [store, setStore] = createStore<TaskStore>(getInitialState());
|
||||
|
||||
// Auto-persist changes to localStorage (wrapped in root to avoid console warning)
|
||||
createRoot(() => {
|
||||
createEffect(() => {
|
||||
localStorage.setItem(STORAGE_KEY, JSON.stringify(store));
|
||||
});
|
||||
});
|
||||
|
||||
// -- Calibration --
|
||||
@@ -126,11 +145,17 @@ export const initStore = async () => {
|
||||
deletedAt: r.deletedAt ? new Date(r.deletedAt).getTime() : undefined
|
||||
}));
|
||||
|
||||
setStore("tasks", loadedTasks);
|
||||
// Use reconcile for efficient store update (keeps observers happy)
|
||||
setStore("tasks", reconcile(loadedTasks));
|
||||
|
||||
} catch (err) {
|
||||
console.error("Failed to load data:", err);
|
||||
toast.error("Failed to sync with server.");
|
||||
// If we fail but have cached data, don't toast an error unless it's a hard failure
|
||||
if (store.tasks.length === 0) {
|
||||
console.error("Failed to load data:", err);
|
||||
toast.error("Failed to sync with server.");
|
||||
} else {
|
||||
console.warn("Sync failed, using cached data", err);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
+23
-2
@@ -20,12 +20,33 @@ export default defineConfig({
|
||||
{
|
||||
src: 'pwa-192x192.png',
|
||||
sizes: '192x192',
|
||||
type: 'image/png'
|
||||
type: 'image/png',
|
||||
purpose: 'any maskable'
|
||||
},
|
||||
{
|
||||
src: 'pwa-512x512.png',
|
||||
sizes: '512x512',
|
||||
type: 'image/png'
|
||||
type: 'image/png',
|
||||
purpose: 'any maskable'
|
||||
}
|
||||
]
|
||||
},
|
||||
workbox: {
|
||||
globPatterns: ['**/*.{js,css,html,ico,png,svg,woff2}'],
|
||||
runtimeCaching: [
|
||||
{
|
||||
urlPattern: /^https:\/\/pocketbase\.ccllc\.pro\/api\/.*/i,
|
||||
handler: 'NetworkFirst',
|
||||
options: {
|
||||
cacheName: 'api-cache',
|
||||
expiration: {
|
||||
maxEntries: 100,
|
||||
maxAgeSeconds: 60 * 60 * 24 * 7 // 1 week
|
||||
},
|
||||
cacheableResponse: {
|
||||
statuses: [0, 200]
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user