banyaro/backend/routes/widget.py
rene 55069d246b Feature: Welten-Onboarding, Wetter-Motivation, UX-Fixes (SW by-v715)
Welten (worlds.js):
- Swipe-Hints beim ersten Öffnen (JETZT ← → WELT animiert, einmalig)
- Kein-Hund-Onboarding: Feature-Preview-Grid statt leerer Karte
- Hintergrund-Foto-Hint: Kamera-Karte wenn noch kein Tagebuchfoto
- worlds-back: navigiert zu Welcome wenn kein User eingeloggt
- Nach Logout: worlds-back Button sofort ausgeblendet

Wetter (wetter.js):
- Standort-Fehlerseite zu Motivations-Seite umgebaut
- Feature-Preview: Gassi-Score, 7-Tage, Regenradar, Rekorde
- CTA: Standort freigeben + Registrieren (nur für Gäste)

Settings (settings.js):
- Logo in Auth-Form: display:block + margin:0 auto zentriert
- Header bleibt sichtbar (FAB/Zurück-Navigation funktioniert)

Jobs (jobs.js):
- 2-Spalten-Grid auf Mobile: auto-fit statt festes 1fr 1fr
- Kein doppeltes Padding im Wrapper

Backend:
- weather.py, achievements.py: diary JOIN fix (d.user_id → dogs JOIN)
- Neue Wetter-Badges: wetter_tapfer, jahreszeiten, schnee
- Ernährungs-, Reise-, Ausgaben-Seite: diverse UX-Verbesserungen
- Presse-Seite erweitert
- Ban Yaro Foto-Assets (WebP + HIRES JPG)
2026-05-05 17:32:03 +02:00

77 lines
2.6 KiB
Python

"""BAN YARO — Widget-Snapshot + Tagesspruch Endpoints"""
import json
from datetime import date
from fastapi import APIRouter, Depends, Query
from typing import Optional
from database import db
from auth import get_current_user
router = APIRouter()
@router.get("/quote")
async def daily_quote(kategorie: Optional[str] = Query(None)):
"""Liefert einen deterministischen Tagesspruch (wechselt täglich)."""
day_num = (date.today() - date(2026, 1, 1)).days
with db() as conn:
if kategorie:
rows = conn.execute(
"SELECT id, text, autor, kategorie FROM daily_quotes WHERE kategorie=?",
(kategorie,)
).fetchall()
else:
rows = conn.execute("SELECT id, text, autor, kategorie FROM daily_quotes").fetchall()
if not rows:
return {"quote": None}
q = rows[day_num % len(rows)]
return {"quote": dict(q)}
@router.get("/snapshot")
async def widget_snapshot(user=Depends(get_current_user)):
"""Liefert kompakte Widget-Daten: Hund, nächste Erinnerung, zufälliges Tagebuchbild."""
with db() as conn:
# Aktiver Hund (erster oder letzter genutzter)
dog = conn.execute(
"SELECT id, name, rasse, foto_url FROM dogs WHERE user_id=? ORDER BY id LIMIT 1",
(user["id"],)
).fetchone()
if not dog:
return {"dog": None}
dog_id = dog["id"]
# Nächste fällige Erinnerung
reminder = conn.execute(
"""SELECT bezeichnung, naechstes, typ FROM health
WHERE dog_id=? AND naechstes IS NOT NULL AND naechstes >= date('now')
ORDER BY naechstes ASC LIMIT 1""",
(dog_id,)
).fetchone()
# Zufälliges Tagebuchbild (letzte 50 Einträge mit Bild)
photos = conn.execute(
"""SELECT media_url, titel, datum FROM diary
WHERE dog_id=? AND media_url IS NOT NULL
ORDER BY datum DESC LIMIT 50""",
(dog_id,)
).fetchall()
day_num = (date.today() - date(2024, 1, 1)).days
random_photo = dict(photos[day_num % len(photos)]) if photos else None
# Anzahl überfälliger Erinnerungen
overdue = conn.execute(
"""SELECT COUNT(*) as n FROM health
WHERE dog_id=? AND naechstes IS NOT NULL AND naechstes < date('now')""",
(dog_id,)
).fetchone()["n"]
return {
"dog": dict(dog),
"reminder": dict(reminder) if reminder else None,
"random_photo": random_photo,
"overdue": overdue,
}