Modernize Destinataer detail page: tabbed UI with integrated timeline
Replaces the old multi-card layout (1368 lines) with a compact, modern tabbed interface (Stammdaten | Nachweise | Zahlungen | Timeline | Dokumente | Notizen). All information is now accessible from one page without excessive clicking. - Add timeline events to destinataer_detail view (merged from timeline view logic) - Compact profile header with avatar initials, status badges, key contact info - Inline editing preserved with table-based layout for cleaner data display - Tab state persisted in URL hash for bookmarkable deep links - Dropdown menu for less-used actions (export, archive, delete) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -316,6 +316,52 @@ def destinataer_detail(request, pk):
|
||||
# Alle verfügbaren StiftungsKonten für das Select-Feld laden
|
||||
stiftungskonten = StiftungsKonto.objects.all().order_by("kontoname")
|
||||
|
||||
# Timeline events (merged from destinataer_timeline view)
|
||||
timeline_events = []
|
||||
for u in destinataer.unterstuetzungen.select_related("konto", "ausgezahlt_von", "freigegeben_von").order_by("-faellig_am"):
|
||||
timeline_events.append({
|
||||
"datum": u.faellig_am,
|
||||
"typ": "zahlung",
|
||||
"icon": "fa-money-bill-wave",
|
||||
"farbe": "success" if u.status == "ausgezahlt" else ("danger" if u.is_overdue() else "primary"),
|
||||
"titel": f"Zahlung \u20ac{u.betrag}",
|
||||
"beschreibung": u.beschreibung or u.get_status_display(),
|
||||
"status": u.get_status_display(),
|
||||
})
|
||||
for n in destinataer.quartalseinreichungen.order_by("-jahr", "-quartal"):
|
||||
datum = n.zahlung_faelligkeitsdatum or n.faelligkeitsdatum
|
||||
if datum:
|
||||
timeline_events.append({
|
||||
"datum": datum,
|
||||
"typ": "nachweis",
|
||||
"icon": "fa-file-alt",
|
||||
"farbe": "success" if n.status in ("geprueft", "auto_geprueft") else ("danger" if n.is_overdue() else "warning"),
|
||||
"titel": f"Nachweis {n.jahr} Q{n.quartal}",
|
||||
"beschreibung": n.get_status_display(),
|
||||
"status": n.get_status_display(),
|
||||
})
|
||||
for e in destinataer.email_eingaenge.order_by("-eingangsdatum"):
|
||||
timeline_events.append({
|
||||
"datum": e.eingangsdatum.date() if hasattr(e.eingangsdatum, "date") else e.eingangsdatum,
|
||||
"typ": "email",
|
||||
"icon": "fa-envelope",
|
||||
"farbe": "info",
|
||||
"titel": e.betreff or "(kein Betreff)",
|
||||
"beschreibung": e.absender_email,
|
||||
"status": e.get_status_display(),
|
||||
})
|
||||
for n in destinataer.notizen_eintraege.order_by("-erstellt_am"):
|
||||
timeline_events.append({
|
||||
"datum": n.erstellt_am.date() if hasattr(n.erstellt_am, "date") else n.erstellt_am,
|
||||
"typ": "notiz",
|
||||
"icon": "fa-sticky-note",
|
||||
"farbe": "secondary",
|
||||
"titel": n.titel or "Notiz",
|
||||
"beschreibung": (n.text[:100] + "\u2026") if n.text and len(n.text) > 100 else n.text,
|
||||
"status": f"von {n.erstellt_von.get_full_name() or n.erstellt_von.username}" if n.erstellt_von else "",
|
||||
})
|
||||
timeline_events.sort(key=lambda e: e["datum"] if e["datum"] else date.min, reverse=True)
|
||||
|
||||
context = {
|
||||
"destinataer": destinataer,
|
||||
"verknuepfte_dokumente": verknuepfte_dokumente,
|
||||
@@ -326,6 +372,7 @@ def destinataer_detail(request, pk):
|
||||
"quarterly_confirmations": quarterly_confirmations,
|
||||
"available_years": available_years,
|
||||
"current_year": current_year,
|
||||
"timeline_events": timeline_events,
|
||||
}
|
||||
return render(request, "stiftung/destinataer_detail.html", context)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user