refactor(insights): single page-level refresh and drop orphan subtitle

The /insights page used to surface the same regenerate handler three
times — the page hero's "Neu generieren" button, the advisor card
header's icon-only refresh button, and the empty-state "Analyse
starten" CTA inside the same card. Marc described the trio as
"gefuehlt drei Buttons, alle machen das gleiche".

Drop `onRegenerate` from the page's `<InsightAdvisorCard>` mount.
The hero remains the single page-level refresh affordance; the
card-level icon button and empty-state CTA disappear because they
short-circuit on `!onRegenerate`. The per-recommendation Regenerate
(inside `<RecommendationCard>`) is unrelated — that's per-card
context, not page-level — and stays as-is per the v1.4.16 spec.

Same patch drops the placeholder "Persoenlicher Berater" subtitle
(`insights.aiOverviewTitle`) the page passed in as the card's
secondary line. With no provider configured, the empty card
rendered just an icon and that subtitle above blank space, which
Marc described as "Titel da aber NICHTS PASSIERT". The CardTitle
("KI-Gesundheitsanalyse") is enough framing on its own; the
subtitle prop on `<InsightAdvisorCard>` becomes optional and
existing callers that still pass one keep their line.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Marc-André BombeckandClaude Opus 4.7 committed 2026-05-10 13:12:24 +02:00
1 parent a7390852f8
commit 98a3d10705
2 files changed
+30 -12

No files matched your search

+16 -7
View File
@@ -923,16 +923,25 @@ export default function InsightsPage() {
medical-citation footnotes) into the live route. Before this
fix the page rendered only the text-only `<InsightStatusCard>`
per section, hiding all of B5c/d/e/B1b's polish from users.
The per-section status cards stay below as supplemental detail. */}
The per-section status cards stay below as supplemental detail.
v1.4.19 A3 — `onRegenerate` is no longer wired here. The page
hero already owns the single page-level refresh affordance;
the card-level icon button + empty-state "Analyse starten"
button were duplicates that surfaced the same handler three
ways (page hero button, card-header icon button,
empty-state CTA). The per-recommendation Regenerate (inside
`<RecommendationCard>`) is unrelated — it stays under the
v1.4.16 spec. The placeholder `aiOverviewTitle`
("Persönlicher Berater") subtitle is also gone — the
CardTitle ("KI-Gesundheitsanalyse") is enough framing on its
own, and the orphan title above an empty body when the user
has no provider configured was the actual confusion source
Marc reported. */}
<InsightAdvisorCard
title={t("insights.aiOverviewTitle")}
insight={advisor.payload?.insights ?? null}
loading={advisor.isLoading}
error={
advisor.regenerateError?.message ?? advisor.error?.message ?? null
}
onRegenerate={advisor.regenerate}
regenerating={advisor.isRegenerating}
error={advisor.error?.message ?? null}
cachedAt={advisor.payload?.cachedAt ?? null}
legacyPayload={advisor.payload?.legacyPayload ?? false}
/>
@@ -32,7 +32,16 @@ import { RecommendationsGrid } from "./recommendations-grid";
// ─── Types ────────────────────────────────────────────────
interface InsightAdvisorCardProps {
title: string;
/**
* v1.4.19 A3 — optional subtitle below the CardTitle. The
* `/insights` page surface no longer passes a subtitle (the
* CardTitle alone is enough framing); the prop stays optional so
* existing test fixtures + the dashboard preview keep their
* supplementary line. When omitted the `<p>` element is dropped
* entirely so the empty card no longer renders an "orphan
* Persönlicher Berater" title above an empty body.
*/
title?: string;
icon?: React.ReactNode;
insight: InsightResult | null;
loading?: boolean;
@@ -332,7 +341,7 @@ export function InsightAdvisorCard({
{t("insights.aiAnalysisTitle")}
</CardTitle>
</div>
<p className="text-muted-foreground text-sm">{title}</p>
{title && <p className="text-muted-foreground text-sm">{title}</p>}
</CardHeader>
<CardContent className="space-y-4">
<div className="bg-muted/60 h-4 w-3/4 animate-pulse rounded-md motion-reduce:animate-none" />
@@ -365,7 +374,7 @@ export function InsightAdvisorCard({
</CardTitle>
</div>
</div>
<p className="text-muted-foreground text-sm">{title}</p>
{title && <p className="text-muted-foreground text-sm">{title}</p>}
</CardHeader>
<CardContent>
{error && (
@@ -473,7 +482,7 @@ export function InsightAdvisorCard({
</Button>
)}
</div>
<p className="text-muted-foreground text-sm">{title}</p>
{title && <p className="text-muted-foreground text-sm">{title}</p>}
</CardHeader>
<CardContent>
<div
@@ -540,7 +549,7 @@ export function InsightAdvisorCard({
)}
</div>
</div>
<p className="text-muted-foreground text-sm">{title}</p>
{title && <p className="text-muted-foreground text-sm">{title}</p>}
</CardHeader>
<CardContent className="space-y-5">