// job-cache.js var DB_NAME = "JobInfoCache"; var DB_VERSION = 2; var JOBS_STORE = "jobs"; var META_STORE = "metadata"; var CACHE_TTL = 5 * 60 * 1000; var PAGE_SIZE = 500; class JobCache { db = null; async initialize() { return new Promise((resolve, reject) => { const request = indexedDB.open(DB_NAME, DB_VERSION); request.onerror = () => reject(request.error); request.onsuccess = () => { this.db = request.result; resolve(); }; request.onupgradeneeded = (event) => { const db = event.target.result; if (!db.objectStoreNames.contains(JOBS_STORE)) { db.createObjectStore(JOBS_STORE, { keyPath: "Job_Number" }); } if (!db.objectStoreNames.contains(META_STORE)) { db.createObjectStore(META_STORE); } }; }); } async getCachedJobs() { if (!this.db) throw new Error("Database not initialized"); return new Promise((resolve, reject) => { const transaction = this.db.transaction([JOBS_STORE], "readonly"); const store = transaction.objectStore(JOBS_STORE); const request = store.getAll(); request.onsuccess = () => resolve(request.result); request.onerror = () => reject(request.error); }); } async isCacheValid() { if (!this.db) return false; try { const metadata = await this.getMetadata(); if (!metadata || !metadata.lastUpdated) return false; const age = Date.now() - metadata.lastUpdated; return age < CACHE_TTL; } catch { return false; } } async saveJobs(jobs) { if (!this.db) throw new Error("Database not initialized"); return new Promise((resolve, reject) => { const transaction = this.db.transaction([JOBS_STORE, META_STORE], "readwrite"); const jobsStore = transaction.objectStore(JOBS_STORE); const metaStore = transaction.objectStore(META_STORE); jobsStore.clear(); jobs.forEach((job) => jobsStore.add(job)); const metadata = { lastUpdated: Date.now(), version: DB_VERSION }; metaStore.put(metadata, "main"); transaction.oncomplete = () => resolve(); transaction.onerror = () => reject(transaction.error); }); } async refreshJobs() { try { let page = 1; let all = []; let totalPages = 1; while (page <= totalPages) { const url = `/api/jobs?page=${page}&perPage=${PAGE_SIZE}&sort=-Job_Number`; const response = await fetch(url); if (!response.ok) { throw new Error(`Failed to fetch jobs (status ${response.status})`); } const data = await response.json(); const items = data.items || []; const reportedTotalPages = data.totalPages || 1; all = all.concat(items); totalPages = Math.max(totalPages, reportedTotalPages); page += 1; } await this.saveJobs(all); return all; } catch (err) { console.error("Failed to refresh jobs cache:", err); throw err; } } async getMetadata() { if (!this.db) return null; return new Promise((resolve, reject) => { const transaction = this.db.transaction([META_STORE], "readonly"); const store = transaction.objectStore(META_STORE); const request = store.get("main"); request.onsuccess = () => resolve(request.result || null); request.onerror = () => reject(request.error); }); } async clearCache() { if (!this.db) throw new Error("Database not initialized"); return new Promise((resolve, reject) => { const transaction = this.db.transaction([JOBS_STORE, META_STORE], "readwrite"); transaction.objectStore(JOBS_STORE).clear(); transaction.objectStore(META_STORE).clear(); transaction.oncomplete = () => resolve(); transaction.onerror = () => reject(transaction.error); }); } async getCacheAge() { const metadata = await this.getMetadata(); if (!metadata || !metadata.lastUpdated) return null; return Date.now() - metadata.lastUpdated; } } var jobCache = new JobCache; // home.ts var allJobs = []; var filteredJobs = []; var currentPage = 1; var perPage = 50; var isRefreshing = false; async function checkAuth() { try { const response = await fetch("/api/auth/status"); const data = await response.json(); if (!data.authenticated) { window.location.href = "/signin.html"; return false; } return true; } catch (err) { console.error("Auth check failed:", err); window.location.href = "/signin.html"; return false; } } async function fetchJobs() { try { await jobCache.initialize(); const isCacheValid = await jobCache.isCacheValid(); if (isCacheValid) { const cachedJobs = await jobCache.getCachedJobs(); allJobs = cachedJobs; filteredJobs = [...allJobs]; renderJobs(); const cacheAge = await jobCache.getCacheAge(); console.log(`Loaded ${allJobs.length} jobs from cache (age: ${Math.round((cacheAge || 0) / 1000)}s)`); refreshJobsInBackground(); } else { const jobs = await jobCache.refreshJobs(); allJobs = jobs; filteredJobs = [...allJobs]; renderJobs(); console.log(`Loaded ${allJobs.length} jobs from server (cache updated)`); } } catch (err) { console.error("Failed to fetch jobs:", err); const results = document.getElementById("results"); results.innerHTML = '