From 959fff4651084f37475f3a616768f98d7d9f9d9a Mon Sep 17 00:00:00 2001 From: rene Date: Thu, 14 May 2026 16:41:52 +0200 Subject: [PATCH 1/4] =?UTF-8?q?UX:=20K=C3=BCndigung-Toast=20zeigt=20Ablauf?= =?UTF-8?q?datum=20(SW=20by-v949)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/main.py | 2 +- backend/static/js/app.js | 2 +- backend/static/js/pages/settings.js | 12 +++++++++++- backend/static/sw.js | 2 +- 4 files changed, 14 insertions(+), 4 deletions(-) diff --git a/backend/main.py b/backend/main.py index c1aee66..aab3ca0 100644 --- a/backend/main.py +++ b/backend/main.py @@ -406,7 +406,7 @@ async def serve_media(path: str, request: _Request): raise _HE(404, "Nicht gefunden.") return _media_response(filepath) -APP_VER = "948" # muss mit APP_VER in app.js übereinstimmen +APP_VER = "949" # muss mit APP_VER in app.js übereinstimmen @app.get("/.well-known/assetlinks.json") async def assetlinks(): diff --git a/backend/static/js/app.js b/backend/static/js/app.js index a2302f4..d0cdbf1 100644 --- a/backend/static/js/app.js +++ b/backend/static/js/app.js @@ -3,7 +3,7 @@ Router, State-Management, Navigation, Initialisierung. ============================================================ */ -const APP_VER = '948'; // ← bei jedem Deploy mit Frontend-Änderungen erhöhen +const APP_VER = '949'; // ← bei jedem Deploy mit Frontend-Änderungen erhöhen const APP_VERSION = '1.5.1'; // ← semantische Version, wird bei make release gesetzt const IS_STAGING = location.hostname === 'staging.banyaro.app'; // Cache-Bust-Parameter nach Update-Reload sofort entfernen diff --git a/backend/static/js/pages/settings.js b/backend/static/js/pages/settings.js index 89e527b..d5cb453 100644 --- a/backend/static/js/pages/settings.js +++ b/backend/static/js/pages/settings.js @@ -422,7 +422,17 @@ window.Page_settings = (() => { const fresh = await API.auth.me(); Object.assign(_appState.user, fresh); UI.modal.close(); - UI.toast.success('Kündigung bestätigt. Eine Bestätigungsmail wurde gesendet.'); + const tier = fresh.subscription_tier || ''; + const label = { pro: 'Pro', breeder: 'Züchter' }[tier] || tier; + const exp = fresh.subscription_expires_at; + const expFmt = exp + ? new Date(exp).toLocaleDateString('de-DE', {day:'numeric',month:'long',year:'numeric'}) + : null; + UI.toast.success( + expFmt + ? `Kündigung bestätigt — ${label} läuft noch bis ${expFmt}.` + : 'Kündigung bestätigt. Eine Bestätigungsmail wurde gesendet.' + ); _render(); } catch (e) { btn.disabled = false; diff --git a/backend/static/sw.js b/backend/static/sw.js index 0242bac..cbb7241 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-v948'; +const CACHE_VERSION = 'by-v949'; const CACHE_STATIC = `${CACHE_VERSION}-static`; const CACHE_TILES = 'ban-yaro-tiles-v1'; // bleibt über SW-Updates erhalten const CACHE_API = 'ban-yaro-api-v1'; // API-Response-Cache From da4879b4c4dae6596dc7a8495a5f82c7b3977440 Mon Sep 17 00:00:00 2001 From: rene Date: Thu, 14 May 2026 16:45:36 +0200 Subject: [PATCH 2/4] =?UTF-8?q?Fix:=20K=C3=BCndigung-Anzeige=20auch=20ohne?= =?UTF-8?q?=20Ablaufdatum=20(SW=20by-v950)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/main.py | 2 +- backend/static/js/app.js | 2 +- backend/static/js/pages/settings.js | 8 +++++++- backend/static/sw.js | 2 +- 4 files changed, 10 insertions(+), 4 deletions(-) diff --git a/backend/main.py b/backend/main.py index aab3ca0..4d6e1fa 100644 --- a/backend/main.py +++ b/backend/main.py @@ -406,7 +406,7 @@ async def serve_media(path: str, request: _Request): raise _HE(404, "Nicht gefunden.") return _media_response(filepath) -APP_VER = "949" # muss mit APP_VER in app.js übereinstimmen +APP_VER = "950" # muss mit APP_VER in app.js übereinstimmen @app.get("/.well-known/assetlinks.json") async def assetlinks(): diff --git a/backend/static/js/app.js b/backend/static/js/app.js index d0cdbf1..289e1b0 100644 --- a/backend/static/js/app.js +++ b/backend/static/js/app.js @@ -3,7 +3,7 @@ Router, State-Management, Navigation, Initialisierung. ============================================================ */ -const APP_VER = '949'; // ← bei jedem Deploy mit Frontend-Änderungen erhöhen +const APP_VER = '950'; // ← bei jedem Deploy mit Frontend-Änderungen erhöhen const APP_VERSION = '1.5.1'; // ← semantische Version, wird bei make release gesetzt const IS_STAGING = location.hostname === 'staging.banyaro.app'; // Cache-Bust-Parameter nach Update-Reload sofort entfernen diff --git a/backend/static/js/pages/settings.js b/backend/static/js/pages/settings.js index d5cb453..d0c6021 100644 --- a/backend/static/js/pages/settings.js +++ b/backend/static/js/pages/settings.js @@ -110,7 +110,13 @@ window.Page_settings = (() => { const isPaid = (isPro || isBreeder) && !tier.endsWith('_test') && !isAdmin; const _expiryInfo = () => { - if (!isPaid || !expiresDate) return ''; + if (!isPaid) return ''; + if (cancelled && !expiresDate) { + return `
+ Gekündigt — läuft bis Ablauf des bezahlten Zeitraums +
`; + } + if (!expiresDate) return ''; const color = cancelled ? '#e65100' : 'var(--c-text-secondary)'; const text = cancelled ? `Gekündigt — läuft bis ${expiresDate}` diff --git a/backend/static/sw.js b/backend/static/sw.js index cbb7241..fe5a5b9 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-v949'; +const CACHE_VERSION = 'by-v950'; const CACHE_STATIC = `${CACHE_VERSION}-static`; const CACHE_TILES = 'ban-yaro-tiles-v1'; // bleibt über SW-Updates erhalten const CACHE_API = 'ban-yaro-api-v1'; // API-Response-Cache From 0bd4c335572cc98d4db4e35fee04ec9c340b7a10 Mon Sep 17 00:00:00 2001 From: rene Date: Thu, 14 May 2026 16:47:57 +0200 Subject: [PATCH 3/4] =?UTF-8?q?Fix:=20K=C3=BCndigungs-Mail=20+=20Settings?= =?UTF-8?q?=20=E2=80=94=20Ablaufdatum=20korrekt=20formatiert=20(SW=20by-v9?= =?UTF-8?q?50)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/routes/auth.py | 26 +++++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/backend/routes/auth.py b/backend/routes/auth.py index 59ad6e8..895c94c 100644 --- a/backend/routes/auth.py +++ b/backend/routes/auth.py @@ -418,20 +418,36 @@ async def cancel_subscription(user=Depends(get_current_user)): try: from mailer import send_email, email_html import html as _html - tier_label = {"pro": "Ban Yaro Pro", "breeder": "Züchter"}.get(row["subscription_tier"], row["subscription_tier"]) - expires_fmt = expires[:10] if expires else "—" + tier_label = {"pro": "Ban Yaro Pro", "breeder": "Züchter"}.get(row["subscription_tier"], row["subscription_tier"]) + expires_de = None + if expires: + from datetime import date as _date + try: + d = _date.fromisoformat(expires[:10]) + monate = ["Januar","Februar","März","April","Mai","Juni", + "Juli","August","September","Oktober","November","Dezember"] + expires_de = f"{d.day}. {monate[d.month-1]} {d.year}" + except Exception: + expires_de = expires[:10] + + expiry_line = ( + f"

Dein Abo ist weiterhin aktiv bis zum {expires_de}. " + f"Ab diesem Datum wirst du automatisch auf den kostenlosen Tarif gesetzt.

" + if expires_de else + "

Dein Abo bleibt bis zum Ende des bezahlten Zeitraums aktiv.

" + ) body_html = f"""

Hallo {_html.escape(user['name'])},

deine Kündigung für {tier_label} wurde bestätigt.

-

Dein Abo ist weiterhin aktiv bis zum {expires_fmt}. - Ab diesem Datum wirst du automatisch auf den kostenlosen Tarif gesetzt.

+ {expiry_line}

Deine Daten (Tagebuch, Gesundheit, Notizen) bleiben vollständig erhalten. Wenn du mehrere Hunde hast, kannst du vor dem Ablauf einen als Haupthund festlegen.

Wir hoffen, dich bald wieder begrüßen zu dürfen!

Viele Grüße
René & das Ban Yaro Team

""" html = email_html(body_html, cta_url="https://banyaro.app", cta_label="Ban Yaro öffnen") plain = (f"Hallo {user['name']},\n\nKündigung bestätigt für {tier_label}.\n" - f"Aktiv bis: {expires_fmt}\n\nAlle Daten bleiben erhalten.\n\nViele Grüße\nRené") + + (f"Aktiv bis: {expires_de}\n" if expires_de else "") + + "\nAlle Daten bleiben erhalten.\n\nViele Grüße\nRené") await send_email(user["email"], f"Kündigung bestätigt — {tier_label}", html, plain) except Exception: pass From c8f9bd4c0924ea1d06fc8284f81ae38009c5cded Mon Sep 17 00:00:00 2001 From: rene Date: Thu, 14 May 2026 16:51:39 +0200 Subject: [PATCH 4/4] =?UTF-8?q?Fix:=20Konto-L=C3=B6schen-Dialog=20body?= =?UTF-8?q?=E2=86=92message=20(SW=20by-v951)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/main.py | 2 +- backend/static/js/app.js | 2 +- backend/static/js/pages/settings.js | 6 +++--- backend/static/sw.js | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/backend/main.py b/backend/main.py index 4d6e1fa..1f8dd9c 100644 --- a/backend/main.py +++ b/backend/main.py @@ -406,7 +406,7 @@ async def serve_media(path: str, request: _Request): raise _HE(404, "Nicht gefunden.") return _media_response(filepath) -APP_VER = "950" # muss mit APP_VER in app.js übereinstimmen +APP_VER = "951" # muss mit APP_VER in app.js übereinstimmen @app.get("/.well-known/assetlinks.json") async def assetlinks(): diff --git a/backend/static/js/app.js b/backend/static/js/app.js index 289e1b0..2282add 100644 --- a/backend/static/js/app.js +++ b/backend/static/js/app.js @@ -3,7 +3,7 @@ Router, State-Management, Navigation, Initialisierung. ============================================================ */ -const APP_VER = '950'; // ← bei jedem Deploy mit Frontend-Änderungen erhöhen +const APP_VER = '951'; // ← bei jedem Deploy mit Frontend-Änderungen erhöhen const APP_VERSION = '1.5.1'; // ← semantische Version, wird bei make release gesetzt const IS_STAGING = location.hostname === 'staging.banyaro.app'; // Cache-Bust-Parameter nach Update-Reload sofort entfernen diff --git a/backend/static/js/pages/settings.js b/backend/static/js/pages/settings.js index d0c6021..2d23a96 100644 --- a/backend/static/js/pages/settings.js +++ b/backend/static/js/pages/settings.js @@ -1314,10 +1314,10 @@ window.Page_settings = (() => { document.getElementById('settings-delete-account-btn')?.addEventListener('click', async () => { const ok = await UI.modal.confirm({ - title: 'Konto unwiderruflich löschen?', - body: 'Alle deine Daten (Tagebuch, Gesundheit, Training, Fotos) werden dauerhaft gelöscht. Diese Aktion kann nicht rückgängig gemacht werden.', + title: 'Konto unwiderruflich löschen?', + message: 'Alle deine Daten (Tagebuch, Gesundheit, Training, Fotos) werden dauerhaft gelöscht. Diese Aktion kann nicht rückgängig gemacht werden.', confirmText: 'Ja, Konto löschen', - danger: true, + danger: true, }); if (!ok) return; try { diff --git a/backend/static/sw.js b/backend/static/sw.js index fe5a5b9..5be5d42 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-v950'; +const CACHE_VERSION = 'by-v951'; const CACHE_STATIC = `${CACHE_VERSION}-static`; const CACHE_TILES = 'ban-yaro-tiles-v1'; // bleibt über SW-Updates erhalten const CACHE_API = 'ban-yaro-api-v1'; // API-Response-Cache