chore(insights): retire the InsightAdvisorCard surface

Drop the InsightAdvisorCard component, its four integration tests
under src/components/insights/__tests__, the page-level mount on
/insights, the orphan i18n keys (advisorTitle, aiOverviewTitle), the
e2e advisor-card spec, the dashboard.spec.ts advisor assertion and
every related comment. The InsightsTabStrip regenerate icon stays
untouched as the sole power-user refresh affordance. The iOS-consumed
POST /api/insights/generate endpoint and its request/response shape
stay byte-stable.
This commit is contained in:
Marc-André Bombeck committed 2026-05-16 01:19:14 +02:00
1 parent cad53a68a3
commit 52edf85f02
19 files changed
+32 -2209

No files matched your search

+10 -35
View File
@@ -12,19 +12,12 @@ import { join } from "node:path";
* The underlying `compareBaseline` value is still consumed by
* every dashboard chart; only the on-surface affordance is gone.
* 2. The `/insights` page renders exactly ONE page-level refresh
* affordance — the hero's regenerate button. The advisor card
* no longer carries its own onRegenerate handler that
* duplicated the hero one and again surfaced "Analyse starten"
* in the empty-state CTA. The per-recommendation Regenerate
* stays — that's per-card, not page-level.
* affordance — the regenerate icon on `<InsightsTabStrip>`. The
* hero strip no longer takes an onRegenerate prop. v1.4.28 retired
* the InsightAdvisorCard surface entirely.
* 3. The `/insights` page does NOT render the small BP / Weight /
* Pulse trend tiles — those duplicate the dashboard tile-strip.
* 4. The `/insights` page does NOT pass the `aiOverviewTitle`
* ("Persönlicher Berater") subtitle into `<InsightAdvisorCard>`.
* The CardTitle ("KI-Gesundheitsanalyse") is sufficient framing;
* the second subtitle was an empty-section placeholder the maintainer
* called "Titel da aber NICHTS PASSIERT".
* 5. The `stripChartTokens()` matcher catches lowercase + mixed-
* 4. The `stripChartTokens()` matcher catches lowercase + mixed-
* case AI-emitted tokens (`metric:blood_pressure_sweet_spot`),
* so the literal token text never reaches the DOM. The
* *render-side* parse matcher stays uppercase-only — only the
@@ -100,22 +93,13 @@ describe("v1.4.27 R3d MB4 — the layout mounts the Coach drawer", () => {
});
describe("v1.4.19 A3 — /insights polish", () => {
it("does NOT mount the legacy advisor-card regenerate handler", () => {
it("does NOT mount <InsightAdvisorCard> anywhere (v1.4.28 retire)", () => {
const src = load(INSIGHTS_PATH);
// The advisor card no longer carries its own onRegenerate handler
// that duplicated the hero one. v1.4.20 phase B1 added a second
// wiring (the <DailyBriefing> empty-state CTA), which only renders
// while the briefing payload is null — its purpose is "generate
// today's briefing" rather than "refresh", and it disappears the
// moment a briefing exists. The original v1.4.19 ratchet was the
// advisor-card duplication; that one stays banned.
//
// We extract the InsightAdvisorCard JSX block (everything up to
// the closing `/>`) and assert no `onRegenerate` prop appears
// inside it.
const advisorBlock = src.match(/<InsightAdvisorCard\b[^>]*\/>/);
expect(advisorBlock).not.toBeNull();
expect(advisorBlock?.[0]).not.toContain("onRegenerate");
// v1.4.28 retired the InsightAdvisorCard surface. The component
// file, every test fixture and the page-level mount are gone;
// Coach drawer is the sole conversational entry point on /insights.
expect(src).not.toContain("InsightAdvisorCard");
expect(src).not.toContain("insight-advisor-card");
});
it("tab strip owns the always-visible page-level refresh affordance (v1.4.25 W4)", () => {
@@ -152,15 +136,6 @@ describe("v1.4.19 A3 — /insights polish", () => {
expect(src).not.toMatch(/<TrendCard[\s\n]/);
});
it("does NOT pass the `aiOverviewTitle` placeholder subtitle to <InsightAdvisorCard>", () => {
const src = load(INSIGHTS_PATH);
// The "Persönlicher Berater" / "Personal advisor" string was a
// dead title above an empty-state body when the user had no
// provider configured. Removed; the CardTitle inside the advisor
// card already says "KI-Gesundheitsanalyse".
expect(src).not.toContain('t("insights.aiOverviewTitle")');
});
it("does NOT contain raw `metric:<name>` template strings in static prose", () => {
const src = load(INSIGHTS_PATH);
// The chart-token pattern (`metric:WEIGHT`) is reserved for AI
-9
View File
@@ -9,7 +9,6 @@ import { useAuth } from "@/hooks/use-auth";
import { useTranslations } from "@/lib/i18n/context";
import { Button } from "@/components/ui/button";
import { EmptyState } from "@/components/ui/empty-state";
import { InsightAdvisorCard } from "@/components/insights/insight-advisor-card";
import { HeroStrip } from "@/components/insights/hero-strip";
import { DailyBriefing } from "@/components/insights/daily-briefing";
import { TrendsRow } from "@/components/insights/trends-row";
@@ -208,14 +207,6 @@ export default function InsightsPage() {
)}
<TrendsRow annotations={advisor.payload?.trendAnnotations ?? null} />
<InsightAdvisorCard
insight={advisor.payload?.insights ?? null}
loading={advisor.isLoading}
error={advisor.error?.message ?? null}
cachedAt={advisor.payload?.cachedAt ?? null}
legacyPayload={advisor.payload?.legacyPayload ?? false}
/>
</div>
);
}