diff --git a/README.md b/README.md index aa5afef..4db4c17 100644 --- a/README.md +++ b/README.md @@ -71,6 +71,10 @@ Mobile Progressive Web App für die Baustellen-Doku — Foto-Upload, Sprach- und - ✅ **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 +- ✅ **Serie ohne Sucherei**: die Teilen-Seite merkt sich die letzten drei benutzten Aufträge und zeigt + sie unter „Zuletzt benutzt" ganz oben. Wurde einer davon in den letzten 30 Minuten benutzt, ist er + **vorausgewählt** — die zweite und dritte Nachricht der Kundin kosten dann nur noch einen Tipp. + Danach steht er nur noch als Schnellzugriff da, damit nichts versehentlich im Auftrag von vorgestern landet - ✅ 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 a3702f2..25b5ee9 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -150,6 +150,9 @@ Vorher endete jeder Teilen-Vorgang in einer Sackgasse: `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 +- [x] **Mehrere Nachrichten hintereinander**: die letzten drei Aufträge stehen unter „Zuletzt benutzt" + oben; innerhalb von 30 Minuten ist der letzte vorausgewählt (danach nur noch Schnellzugriff — + eine Dauer-Vorauswahl würde irgendwann im falschen Auftrag landen) ## Erledigt diff --git a/share.html b/share.html index d1cdbb0..4663d08 100644 --- a/share.html +++ b/share.html @@ -54,6 +54,11 @@ * anmelden"), sondern über das awl_sso-Cookie, geprüft an api/verify.php. */ const SHARE_KEY = 'shared_payload'; +const RECENT_KEY = 'share_recent_orders'; +/* Wer mehrere Sachen hintereinander teilt, will nicht jedes Mal suchen. Innerhalb dieser + * Spanne ist der zuletzt benutzte Auftrag vorausgewaehlt — danach steht er nur noch oben + * als Schnellzugriff, damit nichts versehentlich im Auftrag von vorgestern landet. */ +const VORWAHL_MS = 30 * 60 * 1000; const main = () => document.getElementById('main'); window.showToast = function (msg, kind) { @@ -74,6 +79,8 @@ document.getElementById('back-btn').addEventListener('click', () => { location.h let payload = null; // { title, text, url, files:[{name,type,blob}] } let orders = []; let selectedId = null; +let selectedRef = ''; +let recent = []; // zuletzt benutzte Auftraege, neuester zuerst let searchTimer = null; function toBlob(f) { @@ -148,7 +155,7 @@ function renderLogin() { try { await api.login(fd.get('login'), fd.get('password')); showToast('Angemeldet'); - renderPicker(); + await renderPicker(); } catch (err) { showToast(err.message || 'Anmeldung fehlgeschlagen', 'error'); } @@ -163,7 +170,7 @@ function renderLogin() { const res = await awlauthWebAuthn.login(); if (res && res.user) await idb.set('user', res.user); showToast('Angemeldet'); - renderPicker(); + await renderPicker(); } catch (err) { pk.disabled = false; showToast((err && err.message) || 'Anmeldung fehlgeschlagen', 'error'); @@ -172,6 +179,60 @@ function renderLogin() { } } +/* ----- Zuletzt benutzte Auftraege ----- */ +async function ladeRecent() { + const liste = await idb.get(RECENT_KEY).catch(() => null); + return Array.isArray(liste) ? liste : []; +} + +async function merkeAuftrag(o) { + const eintrag = { id: String(o.id), ref: o.ref || '', name: o.name || '', ort: o.ort || '', ts: Date.now() }; + const rest = recent.filter(x => String(x.id) !== eintrag.id); + await idb.set(RECENT_KEY, [eintrag].concat(rest).slice(0, 3)).catch(() => {}); +} + +function seitdem(ts) { + const min = Math.round((Date.now() - ts) / 60000); + if (min < 1) return 'gerade eben'; + if (min < 60) return 'vor ' + min + ' Min.'; + const std = Math.round(min / 60); + if (std < 24) return 'vor ' + std + ' Std.'; + const tage = Math.round(std / 24); + return tage === 1 ? 'gestern' : 'vor ' + tage + ' Tagen'; +} + +/** Auswahl setzen — gilt ueber beide Listen hinweg (Schnellzugriff und Suchtreffer). */ +function waehleAuftrag(id, ref, name, ort) { + selectedId = String(id); + selectedRef = ref || ''; + document.querySelectorAll('.order-card').forEach(c => c.classList.toggle('selected', c.dataset.id === selectedId)); + const btn = document.getElementById('btn-store'); + if (!btn) return; + btn.disabled = false; + btn.textContent = 'In ' + (selectedRef || 'Auftrag') + ' ablegen'; + btn.dataset.name = name || ''; + btn.dataset.ort = ort || ''; +} + +function karteHtml(o) { + const kunde = o.name !== undefined ? o.name : ((o.customer && o.customer.name) || ''); + const ort = o.ort !== undefined ? o.ort : (((o.customer && o.customer.zip) || '') + ' ' + ((o.customer && o.customer.town) || '')); + return ` +