All checks were successful
Deploy baustelle-pwa / deploy (push) Successful in 1s
Bericht-Detail-Ansicht: - Tap auf Seiten-Thumb → openPageActionsModal mit: - Vorschaubild - Textarea für Seiten-Notiz (wird im PDF unter der Seite gedruckt) - '💾 Notiz speichern' → api.updatePageNote - 🗑️ im Header → api.deletePage mit Confirm - Seiten-Thumbs haben Nummer-Badge oben links (1, 2, 3…) - Neuer '👁 PDF-Vorschau'-Button öffnet openPdfModal (iframe mit Blob-URL) für Final-PDF oder on-the-fly Preview - Neuer '✍️ Kunden-Unterschrift hinzufügen'-Button öffnet openSignatureModal: Touch-Canvas 2:1, Clear, Save → PNG wird als neue Bericht-Seite mit note='Unterschrift Kunde' angelegt Web Share Target API: - manifest.webmanifest: share_target mit photos array - share.html: empfängt geteilte Fotos aus IDB (vom SW befüllt), zeigt Auftragsliste, Tap → Upload aller Fotos - Service Worker v5: fängt POST /share.html ab, schreibt Files in IDB Key 'shared_files', redirected 303 Cache-Version bumpt damit neue Files geladen werden. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> [deploy]
82 lines
3.1 KiB
HTML
82 lines
3.1 KiB
HTML
<!doctype html>
|
|
<html lang="de">
|
|
<head>
|
|
<meta charset="utf-8">
|
|
<meta name="viewport" content="width=device-width,initial-scale=1">
|
|
<title>Foto teilen — Baustelle</title>
|
|
<link rel="stylesheet" href="app.css">
|
|
</head>
|
|
<body>
|
|
<div id="app">
|
|
<header id="topbar">
|
|
<button id="back-btn" class="icon-btn" onclick="location.href='./'">←</button>
|
|
<h1 id="page-title">📤 Foto teilen</h1>
|
|
<span></span>
|
|
</header>
|
|
<main id="main">
|
|
<div id="share-content">
|
|
<div class="loader">Foto wird empfangen…</div>
|
|
</div>
|
|
</main>
|
|
</div>
|
|
|
|
<script src="lib/idb.js"></script>
|
|
<script src="lib/api.js"></script>
|
|
<script>
|
|
/* Web Share Target Handler.
|
|
* Browser POST'et das geteilte Foto an diese URL.
|
|
* Wir zeigen eine Auftragsliste, User wählt einen Auftrag → Upload.
|
|
*/
|
|
(async function () {
|
|
const ct = document.getElementById('share-content');
|
|
const t = await api.getToken();
|
|
if (!t) {
|
|
ct.innerHTML = '<div class="empty-state"><div class="icon">🔐</div>Bitte zuerst anmelden<br><button class="btn" onclick="location.href=\'./\'">Zur App</button></div>';
|
|
return;
|
|
}
|
|
|
|
// Service Worker hat die geteilten Files unter 'shared_files' in IDB abgelegt
|
|
const sharedFiles = await idb.get('shared_files');
|
|
if (!sharedFiles || !sharedFiles.length) {
|
|
ct.innerHTML = '<div class="empty-state"><div class="icon">📭</div>Keine geteilten Fotos gefunden<br><button class="btn" onclick="location.href=\'./\'">Zur App</button></div>';
|
|
return;
|
|
}
|
|
|
|
try {
|
|
const data = await api.listOrders({ open: 1 });
|
|
const orders = data.orders || [];
|
|
ct.innerHTML = `
|
|
<p class="label" style="padding:0 16px;">${sharedFiles.length} Foto(s) geteilt. Wähle den Auftrag für den Upload:</p>
|
|
${orders.map(o => `
|
|
<div class="order-card" data-id="${o.id}">
|
|
<div class="ref">${escapeHtml(o.ref)}</div>
|
|
<div class="name">${escapeHtml(o.customer.name || '')}</div>
|
|
<div class="meta"><span>${escapeHtml((o.customer.zip || '') + ' ' + (o.customer.town || ''))}</span></div>
|
|
</div>
|
|
`).join('')}
|
|
`;
|
|
document.querySelectorAll('.order-card').forEach(c => {
|
|
c.addEventListener('click', async () => {
|
|
const orderId = c.dataset.id;
|
|
ct.innerHTML = '<div class="loader">Lade hoch…</div>';
|
|
for (const f of sharedFiles) {
|
|
try {
|
|
// f.data ist ein File/Blob
|
|
await api.uploadOrderPhoto(orderId, f.data, f.name);
|
|
} catch (err) { console.warn('Upload failed', err); }
|
|
}
|
|
await idb.del('shared_files');
|
|
location.href = './#/orders/' + orderId;
|
|
});
|
|
});
|
|
} catch (e) {
|
|
ct.innerHTML = '<div class="empty-state"><div class="icon">⚠</div>' + e.message + '</div>';
|
|
}
|
|
})();
|
|
|
|
function escapeHtml(s) {
|
|
return String(s ?? '').replace(/[&<>"']/g, c => ({'&':'&','<':'<','>':'>','"':'"',"'":'''}[c]));
|
|
}
|
|
</script>
|
|
</body>
|
|
</html>
|