Merge laatste worktree in master

Neemt de laatste PantryHub-implementatie over in de hoofdbranch.\n\nCo-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
2026-08-07 20:46:00 +02:00
21 changed files with 345 additions and 1128 deletions
+9 -46
View File
@@ -1,48 +1,11 @@
// Socket.IO Client
const socket = typeof io === 'function' ? io() : null;
(() => {
const socket = window.io && window.io();
if (!socket) return;
// Join household room if available
const householdId = document.querySelector('[data-household-id]')?.dataset.householdId;
if (socket && householdId) {
socket.emit('join:household', householdId);
}
const listMatch = window.location.pathname.match(/^\/lists\/(\d+)$/);
if (listMatch) socket.emit("list:join", listMatch[1]);
// Real-time list updates
socket?.on('list:updated', (data) => {
console.log('📝 Lijst bijgewerkt:', data);
window.location.reload();
});
socket?.on('item:added', (data) => {
console.log(' Item toegevoegd:', data);
window.location.reload();
});
socket?.on('item:toggled', (data) => {
console.log('✓ Item afgevinkt:', data);
window.location.reload();
});
socket?.on('item:removed', (data) => {
console.log('✕ Item verwijderd:', data);
window.location.reload();
});
// Auto-remove alerts
document.addEventListener("DOMContentLoaded", () => {
setTimeout(() => {
document
.querySelectorAll(".alert")
.forEach(alert => {
alert.remove();
});
}, 4000);
});
console.log('✅ PantryHub app geladen');
socket.on("list:updated", ({ listId }) => {
if (window.location.pathname === `/lists/${listId}`) window.location.reload();
});
})();
+37 -92
View File
@@ -1,98 +1,43 @@
const CACHE_NAME = 'pantryhub-v2';
const urlsToCache = [
'/',
'/css/style.css',
'/js/app.js',
'/manifest.json',
'/icons/icon.svg'
];
const CACHE_NAME = "pantryhub-static-v3";
// Install event
self.addEventListener('install', (event) => {
self.addEventListener("install", () => {
self.skipWaiting();
});
self.addEventListener("activate", (event) => {
event.waitUntil(
caches.open(CACHE_NAME).then((cache) => {
return cache.addAll(urlsToCache).catch(err => {
console.log('Cache addAll error:', err);
caches.keys().then((keys) =>
Promise.all(
keys
.filter((key) => key !== CACHE_NAME)
.map((key) => caches.delete(key))
)
).then(() => self.clients.claim())
);
});
self.addEventListener("fetch", (event) => {
if (event.request.method !== "GET") return;
const url = new URL(event.request.url);
if (url.origin !== self.location.origin) return;
// Authenticated HTML and API responses must never be served from stale cache.
if (event.request.mode === "navigate" || url.pathname.startsWith("/api/")) {
event.respondWith(fetch(event.request));
return;
}
event.respondWith(
caches.match(event.request).then((cached) => {
if (cached) return cached;
return fetch(event.request).then((response) => {
if (response.ok && response.type === "basic") {
const copy = response.clone();
caches.open(CACHE_NAME).then((cache) => cache.put(event.request, copy));
}
return response;
});
})
);
});
// Activate event
self.addEventListener('activate', (event) => {
event.waitUntil(
caches.keys().then((cacheNames) => {
return Promise.all(
cacheNames.map((cacheName) => {
if (cacheName !== CACHE_NAME) {
return caches.delete(cacheName);
}
})
);
})
);
});
// Fetch event
self.addEventListener('fetch', (event) => {
// Skip non-GET requests
if (event.request.method !== 'GET') {
return;
}
// Browser extensions and third-party resources cannot be stored by Cache API.
// Only handle same-origin HTTP(S) requests belonging to PantryHub.
const url = new URL(event.request.url);
if (!['http:', 'https:'].includes(url.protocol) || url.origin !== self.location.origin) {
return;
}
// For API calls, use network-first strategy
if (event.request.url.includes('/api/')) {
event.respondWith(
fetch(event.request)
.then(response => {
const responseClone = response.clone();
caches.open(CACHE_NAME).then(cache => {
cache.put(event.request, responseClone);
});
return response;
})
.catch(() => {
return caches.match(event.request);
})
);
return;
}
// For other requests, use cache-first strategy
event.respondWith(
caches.match(event.request)
.then(response => {
if (response) {
return response;
}
return fetch(event.request).then(response => {
if (!response || response.status !== 200 || response.type !== 'basic') {
return response;
}
const responseClone = response.clone();
caches.open(CACHE_NAME)
.then(cache => {
cache.put(event.request, responseClone);
});
return response;
});
})
.catch(() => {
// Return offline page or empty response
return new Response('Offline - pagina niet beschikbaar', {
status: 503,
statusText: 'Service Unavailable',
headers: new Headers({
'Content-Type': 'text/plain'
})
});
})
);
});