From e172cbe0851b59455a507d320871aa43a13038d6 Mon Sep 17 00:00:00 2001 From: Dicken Date: Sat, 18 Jul 2026 21:14:22 +0200 Subject: [PATCH] feat: KoePi oeffentlicher Link bekommt eigenes PWA-Manifest (Dickens Prospekte, eigener Startpunkt) --- backend/src/tools/koepi/routes.js | 26 ++++++++++++++++++++++++++ frontend/src/App.jsx | 12 ++++++++++++ 2 files changed, 38 insertions(+) diff --git a/backend/src/tools/koepi/routes.js b/backend/src/tools/koepi/routes.js index a71753b..f820561 100644 --- a/backend/src/tools/koepi/routes.js +++ b/backend/src/tools/koepi/routes.js @@ -873,6 +873,32 @@ router.post('/share-link/disable', authenticate, (req, res) => { res.json({ ok: true }); }); +// GET /public/:token/manifest.json – eigenes PWA-Manifest für die öffentliche +// Prospekt-Seite: eigener Name ("Dickens Prospekte") und eigener start_url, +// damit die installierte App direkt wieder auf der öffentlichen Seite landet +// statt auf dem normalen Login der Haupt-App. +router.get('/public/:token/manifest.json', (req, res) => { + const active = getShareToken(); + if (!active || req.params.token !== active) return res.status(404).json({ error: 'Nicht gefunden' }); + res.setHeader('Content-Type', 'application/manifest+json'); + res.json({ + name: 'Dickens Prospekte', + short_name: 'Prospekte', + description: 'Wöchentliche Prospekte', + start_url: `/kp/${req.params.token}`, + scope: `/kp/${req.params.token}`, + display: 'standalone', + orientation: 'portrait', + background_color: '#0f1117', + theme_color: '#0f1117', + icons: [ + { src: '/favicon.svg', type: 'image/svg+xml', sizes: 'any', purpose: 'any maskable' }, + { src: '/icon-192.png', type: 'image/png', sizes: '192x192' }, + { src: '/icon-512.png', type: 'image/png', sizes: '512x512' }, + ], + }); +}); + // GET /public/:token/offers – öffentlich, nur Cache, kein Login router.get('/public/:token/offers', publicRateLimit, async (req, res) => { const active = getShareToken(); diff --git a/frontend/src/App.jsx b/frontend/src/App.jsx index 7d8892d..c064583 100644 --- a/frontend/src/App.jsx +++ b/frontend/src/App.jsx @@ -4093,6 +4093,18 @@ function PublicKoepi({ token }) { const [invalid, setInvalid] = useState(false); const BASE = '/api/tools/koepi/public/' + token; + // Eigenes PWA-Manifest (eigener Name "Dickens Prospekte", eigener + // start_url) statt des normalen App-Manifests — damit eine über diesen + // Link installierte App direkt wieder hier landet, nicht beim Login + useEffect(() => { + document.title = 'Dickens Prospekte'; + let link = document.querySelector('link[rel="manifest"]'); + const original = link?.getAttribute('href'); + if (!link) { link = document.createElement('link'); link.rel = 'manifest'; document.head.appendChild(link); } + link.setAttribute('href', `${BASE}/manifest.json`); + return () => { if (link && original) link.setAttribute('href', original); }; + }, [token]); + useEffect(() => { fetch(BASE + '/prospekte') .then(async r => { if (!r.ok) throw new Error(); return r.json(); })