From e2bb1a4b2d5fe4a15307c9b9cea4c5eb5b5bfaa0 Mon Sep 17 00:00:00 2001 From: rene Date: Sat, 25 Apr 2026 10:23:17 +0200 Subject: [PATCH] =?UTF-8?q?Social:=20Vorschl=C3=A4ge=20merken=20(?= =?UTF-8?q?=F0=9F=93=8C),=20Post-Link=20nachtr=C3=A4glich=20eintragen,=20Q?= =?UTF-8?q?uick-Post=20ohne=20prompt(),=20SW=20by-v369?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/routes/social.py | 21 +++++ backend/static/js/pages/social.js | 123 ++++++++++++++++++++++++++---- backend/static/sw.js | 2 +- 3 files changed, 130 insertions(+), 16 deletions(-) diff --git a/backend/routes/social.py b/backend/routes/social.py index f0f4d30..494d9a2 100644 --- a/backend/routes/social.py +++ b/backend/routes/social.py @@ -1052,6 +1052,27 @@ async def get_suggestions(user=Depends(require_social_media)): # ------------------------------------------------------------------ +# POST /api/social/ideas/save — Vorschlag als Idee speichern (zurückstellen) +# ------------------------------------------------------------------ +@router.post("/ideas/save", status_code=201) +async def save_idea(data: dict, user=Depends(require_social_media)): + """Speichert einen KI-Vorschlag als Idee in der DB (status='idea').""" + topic = (data.get("topic") or data.get("thema") or "").strip() + platform = data.get("platform", "both") + fmt = data.get("format", "post") + category = data.get("category") + if not topic: + raise HTTPException(400, "topic fehlt.") + with db() as conn: + cur = conn.execute( + """INSERT INTO social_content + (created_by, platform, format, topic, status, category, source) + VALUES (?,?,?,?,'idea',?,'saved_suggestion')""", + (user["id"], platform, fmt, topic, category), + ) + return {"id": cur.lastrowid, "topic": topic, "status": "idea"} + + # GET /api/social/content — alle Einträge # ------------------------------------------------------------------ @router.get("/content") diff --git a/backend/static/js/pages/social.js b/backend/static/js/pages/social.js index bd1b5ba..3204630 100644 --- a/backend/static/js/pages/social.js +++ b/backend/static/js/pages/social.js @@ -422,13 +422,21 @@ window.Page_social = (() => { padding:2px 6px;border-radius:4px">${_PL[idea.platform]||idea.platform} - +
+ + +
`).join(''); @@ -453,6 +461,28 @@ window.Page_social = (() => { } }); }); + box.querySelectorAll('.sm-save-idea').forEach(btn => { + btn.addEventListener('click', async e => { + e.stopPropagation(); + btn.disabled = true; + btn.textContent = '…'; + try { + await API.post('/social/ideas/save', { + topic: btn.dataset.thema, + format: btn.dataset.format, + platform: btn.dataset.platform, + category: btn.dataset.category || undefined, + }); + btn.textContent = '✓ Gemerkt'; + btn.style.background = 'var(--c-success)'; + btn.style.color = '#fff'; + btn.style.borderColor = 'var(--c-success)'; + } catch { + btn.textContent = '📌 Merken'; + btn.disabled = false; + } + }); + }); box.querySelectorAll('.sm-idea').forEach(card => { card.addEventListener('mouseenter', () => card.style.borderColor = 'var(--c-primary)'); card.addEventListener('mouseleave', () => card.style.borderColor = 'transparent'); @@ -1126,7 +1156,19 @@ window.Page_social = (() => {
${_esc(c.topic)}
${c.hook ? `
🎣 ${_esc(c.hook)}
` : ''} + font-style:italic;margin-bottom:2px">🎣 ${_esc(c.hook)}` : ''} + ${c.post_url + ? ` + 🔗 Post ansehen` + : c.status === 'published' + ? `` + : ''}
${c.status !== 'published' ? ` @@ -1173,14 +1215,65 @@ window.Page_social = (() => {
`).join('')}`; el.querySelectorAll('[data-f]').forEach(b => b.addEventListener('click', () => load(b.dataset.f))); - el.querySelectorAll('.sm-quick-post').forEach(b => b.addEventListener('click', async () => { - const url = prompt('Post-URL (optional, leer lassen wenn keine):', '') ?? null; - await API.patch(`/social/content/${b.dataset.id}`, { - status: 'published', - published_at: new Date().toISOString().slice(0,16), - post_url: url || undefined, + + // Quick-Post: Inline-Form statt prompt() + el.querySelectorAll('.sm-quick-post').forEach(b => b.addEventListener('click', () => { + const id = b.dataset.id; + UI.modal.open({ + title: '📤 Als gepostet markieren', + body: ` +
+ + +
+
+ + +
`, + footer: ` + + `, + }); + document.getElementById('qp-cancel')?.addEventListener('click', UI.modal.close); + document.getElementById(`qp-ok-${id}`)?.addEventListener('click', async () => { + const date = document.getElementById(`qp-date-${id}`)?.value + || new Date().toISOString().slice(0,10); + const url = document.getElementById(`qp-url-${id}`)?.value || undefined; + await API.patch(`/social/content/${id}`, { + status: 'published', + published_at: date, + post_url: url, + }); + UI.modal.close(); + load(filter); + }); + })); + + // "Link eintragen" für bereits veröffentlichte Posts ohne URL + el.querySelectorAll('.sm-add-url').forEach(b => b.addEventListener('click', () => { + const id = b.dataset.id; + UI.modal.open({ + title: '🔗 Post-Link eintragen', + body: ` +
+ + +
`, + footer: ` + + `, + }); + document.getElementById('au-cancel')?.addEventListener('click', UI.modal.close); + document.getElementById(`au-ok-${id}`)?.addEventListener('click', async () => { + const url = document.getElementById(`au-url-${id}`)?.value; + if (!url) return; + await API.patch(`/social/content/${id}`, { post_url: url }); + UI.modal.close(); + load(filter); }); - load(filter); })); el.querySelectorAll('.sm-exp').forEach(b => b.addEventListener('click', () => { const d = el.querySelector(`#sm-d-${b.dataset.id}`); diff --git a/backend/static/sw.js b/backend/static/sw.js index 0f1edde..620e75f 100644 --- a/backend/static/sw.js +++ b/backend/static/sw.js @@ -3,7 +3,7 @@ Offline-Cache + Push Notifications + Tile-Cache ============================================================ */ -const CACHE_VERSION = 'by-v368'; +const CACHE_VERSION = 'by-v369'; const CACHE_STATIC = `${CACHE_VERSION}-static`; const CACHE_TILES = 'ban-yaro-tiles-v1'; // bleibt über SW-Updates erhalten