All checks were successful
Deploy baustelle-pwa / deploy (push) Successful in 1s
Mobile Progressive Web App für Baustellen-Doku, spricht die REST-API des Dolibarr-Bericht-Moduls. MVP-Features: - Vanilla JavaScript, kein Build-Step nötig - Login mit Dolibarr-Credentials → JWT (7 Tage) - Auftragsliste mit Suche und Multi-User-Filter - Auftragsdetail mit Kunde, Adresse, Click-to-Call - Foto-Aufnahme via Kamera oder Galerie (multiple) - Clientseitige Bildverkleinerung (max 2000px, JPEG q=0.85) - Offline-Queue in IndexedDB für Uploads ohne Netz - Auto-Sync bei Online-Event mit Status-Badge - Service Worker für App-Shell-Cache - PWA-installierbar (Manifest, Icons, Theme-Color) Hosting: awl.data-it-solution.de/baustelle/ via Apache-Alias Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
89 lines
2.9 KiB
JavaScript
89 lines
2.9 KiB
JavaScript
/* Mini IndexedDB Wrapper für die PWA.
|
|
* Speichert: Auth-Token, Offline-Queue für Uploads.
|
|
*/
|
|
(function () {
|
|
const DB_NAME = 'baustelle-pwa-v1';
|
|
const DB_VERSION = 1;
|
|
let dbPromise = null;
|
|
|
|
function open() {
|
|
if (dbPromise) return dbPromise;
|
|
dbPromise = new Promise((resolve, reject) => {
|
|
const req = indexedDB.open(DB_NAME, DB_VERSION);
|
|
req.onupgradeneeded = () => {
|
|
const db = req.result;
|
|
if (!db.objectStoreNames.contains('kv')) {
|
|
db.createObjectStore('kv');
|
|
}
|
|
if (!db.objectStoreNames.contains('queue')) {
|
|
db.createObjectStore('queue', { keyPath: 'id', autoIncrement: true });
|
|
}
|
|
};
|
|
req.onsuccess = () => resolve(req.result);
|
|
req.onerror = () => reject(req.error);
|
|
});
|
|
return dbPromise;
|
|
}
|
|
|
|
async function get(key) {
|
|
const db = await open();
|
|
return new Promise((res, rej) => {
|
|
const tx = db.transaction('kv', 'readonly');
|
|
const r = tx.objectStore('kv').get(key);
|
|
r.onsuccess = () => res(r.result);
|
|
r.onerror = () => rej(r.error);
|
|
});
|
|
}
|
|
|
|
async function set(key, val) {
|
|
const db = await open();
|
|
return new Promise((res, rej) => {
|
|
const tx = db.transaction('kv', 'readwrite');
|
|
tx.objectStore('kv').put(val, key);
|
|
tx.oncomplete = () => res();
|
|
tx.onerror = () => rej(tx.error);
|
|
});
|
|
}
|
|
|
|
async function del(key) {
|
|
const db = await open();
|
|
return new Promise((res, rej) => {
|
|
const tx = db.transaction('kv', 'readwrite');
|
|
tx.objectStore('kv').delete(key);
|
|
tx.oncomplete = () => res();
|
|
tx.onerror = () => rej(tx.error);
|
|
});
|
|
}
|
|
|
|
async function queuePush(item) {
|
|
const db = await open();
|
|
return new Promise((res, rej) => {
|
|
const tx = db.transaction('queue', 'readwrite');
|
|
const r = tx.objectStore('queue').add(item);
|
|
r.onsuccess = () => res(r.result);
|
|
r.onerror = () => rej(r.error);
|
|
});
|
|
}
|
|
|
|
async function queueAll() {
|
|
const db = await open();
|
|
return new Promise((res, rej) => {
|
|
const tx = db.transaction('queue', 'readonly');
|
|
const r = tx.objectStore('queue').getAll();
|
|
r.onsuccess = () => res(r.result || []);
|
|
r.onerror = () => rej(r.error);
|
|
});
|
|
}
|
|
|
|
async function queueDelete(id) {
|
|
const db = await open();
|
|
return new Promise((res, rej) => {
|
|
const tx = db.transaction('queue', 'readwrite');
|
|
tx.objectStore('queue').delete(id);
|
|
tx.oncomplete = () => res();
|
|
tx.onerror = () => rej(tx.error);
|
|
});
|
|
}
|
|
|
|
window.idb = { get, set, del, queuePush, queueAll, queueDelete };
|
|
})();
|