diff --git a/README.md b/README.md index 8fb8c67..c42ac06 100644 --- a/README.md +++ b/README.md @@ -66,7 +66,9 @@ Mobile Progressive Web App für die Baustellen-Doku — Foto-Upload, Sprach- und **PWA** - ✅ Service Worker für Offline-Start - ✅ Installierbar als PWA (Home-Screen-Icon) -- ✅ Web Share Target API (Fotos aus anderer App teilen) +- ✅ **Web Share Target** — aus WhatsApp & Co. Bilder **und** Beschreibungstext an „Baustelle" teilen: + anmelden (falls nötig, direkt in der Teilen-Seite), Auftrag suchen und wählen, ablegen. Bilder gehen + über die normale Upload-Queue, der Text wird als Notiz (`notiz_*.txt`) im Auftrag gespeichert - ✅ Nativer Android-Share-Sheet für Fotos, PDFs und Dokumente (`navigator.share`) — direkt an WhatsApp / Signal / Mail - ✅ Mehrfachauswahl in Foto- und Dokument-Liste mit Batch-Teilen - ✅ Android-Hardware-Back-Button schließt Modale/Ansichten sauber (History-Modal-Stack), bricht Mehrfachauswahl ab statt App zu verlassen diff --git a/ROADMAP.md b/ROADMAP.md index e8a4db3..a3702f2 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -129,6 +129,28 @@ Absprachen, Maße. **Nicht** umgesetzt (und bewusst verworfen): eine Zeichenfläche für echte Handschrift. Am Handy ohne Stift ist das unbrauchbar. +## 4. Teilen aus WhatsApp ✅ (2026-08-30) + +Bilder und Beschreibungstexte, die die Kundin per WhatsApp schickt, landen direkt im Auftrag. +Vorher endete jeder Teilen-Vorgang in einer Sackgasse: + +- `share.html` fragte `api.getToken()` — ein JWT in IndexedDB, das es **seit der SSO-Umstellung + gar nicht mehr gibt** (`api.login()` legt nur noch `user` ab, die Sitzung steckt im + HttpOnly-Cookie `awl_sso`). Ergebnis: immer „Bitte zuerst anmelden", und der Weg „Zur App" + verwarf das Geteilte. +- Der Service Worker sicherte **nur Dateien**. Ein Text-Share (oder Bild + Bildunterschrift) + schrieb nichts in IndexedDB → „Keine geteilten Fotos gefunden". + +- [x] Anmeldung über `api/verify.php` (Cookie) statt über das nicht mehr existierende Token +- [x] Anmelden **in** der Teilen-Seite (Passwort + Passkey) — das Geteilte bleibt dabei gesichert +- [x] Service Worker sichert `title`, `text` und `url` mit; Weiterleitung auch ohne Datei +- [x] Auswahl-Seite: Bildvorschau, Betreff + Text zum Nachbessern, Auftragssuche + (ohne Suchbegriff die offenen Aufträge, mit Suchbegriff alle) +- [x] Ablegen: Bilder über die normale Upload-Queue (Persist-First), Text als Notiz über + `api/note.php`. Schlägt die Notiz fehl (kein Netz), bleibt der Text gesichert und der + Vorgang ist wiederholbar +- [x] Banner in der App, wenn noch etwas Geteiltes unabgelegt bereitliegt + ## Erledigt ### 2026-08-22 diff --git a/app.css b/app.css index 952a458..4b133a3 100644 --- a/app.css +++ b/app.css @@ -1468,3 +1468,22 @@ body { opacity: 0.5; text-align: right; } + +/* Hinweis auf noch nicht abgelegte, geteilte Inhalte (Web Share Target) */ +.shared-banner { + position: fixed; + left: 16px; + right: 16px; + bottom: calc(68px + env(safe-area-inset-bottom, 0px)); + z-index: 60; + padding: 14px 16px; + border: none; + border-radius: 10px; + background: #7aa2f7; + color: #10101a; + font-size: 15px; + font-weight: 600; + box-shadow: 0 6px 20px rgba(0,0,0,0.45); + cursor: pointer; +} +.shared-banner:active { transform: scale(0.98); } diff --git a/app.js b/app.js index 45fc003..556e3c9 100644 --- a/app.js +++ b/app.js @@ -1488,6 +1488,30 @@ router.on('/settings', async () => { }; }); +/* Aus einem abgebrochenen Teilen-Vorgang koennen noch Inhalte bereitliegen — etwa + * weil beim Teilen aus WhatsApp die Anmeldung fehlte oder das Netz weg war. Sie + * bleiben in IndexedDB liegen; ohne diesen Hinweis wuerde sie niemand je wiederfinden. */ +async function checkPendingShare() { + if (document.getElementById('shared-banner')) return; + let n = 0, vorhanden = false; + try { + const p = await idb.get('shared_payload'); + if (p) { vorhanden = true; n = (p.files || []).length; } + else { + const alt = await idb.get('shared_files'); // altes Format + if (alt && alt.length) { vorhanden = true; n = alt.length; } + } + } catch (_) { return; } + if (!vorhanden) return; + + const b = document.createElement('button'); + b.id = 'shared-banner'; + b.className = 'shared-banner'; + b.textContent = '📤 Geteiltes ablegen' + (n ? ' (' + n + ' Bild' + (n > 1 ? 'er' : '') + ')' : ''); + b.addEventListener('click', () => { location.href = 'share.html'; }); + document.body.appendChild(b); +} + /* Bottom nav + Hilfe-Button */ document.addEventListener('DOMContentLoaded', () => { document.querySelectorAll('#bottom-nav button').forEach(b => { @@ -1496,6 +1520,7 @@ document.addEventListener('DOMContentLoaded', () => { const helpBtn = document.getElementById('help-btn'); if (helpBtn) helpBtn.addEventListener('click', openHelpModal); refreshPhotoConfig(); // Admin-Vorgabe zur Fotoqualitaet nachziehen + checkPendingShare(); // liegt noch etwas Geteiltes bereit? }); /** diff --git a/share.html b/share.html index eb2c8b7..d1cdbb0 100644 --- a/share.html +++ b/share.html @@ -2,81 +2,346 @@
- -