Files
HealthLog/src/components/insights/correlation-row.tsx
T
Marc-André BombeckandClaude Opus 4.7 1631d8042c refactor: simplify-pass apply-yes cleanup
Five independent atomic edits from the W5 simplify review, grouped
in a single commit since none pull weight as a compound theme:

- coach-input: collapse `!disabled && value.trim().length > 0`
  triplication onto a single `canSubmit` (S-01).
- hero-strip: extract the duplicate weekly-report Button shell into
  a shared label fragment with the Link wrapping conditionally
  (S-02).
- api-token-overview-section: extract `<TokenStatusBadge size>` so
  the desktop table and mobile card list stay in lock-step on the
  revoked / expired / active 3-way ternary (S-03).
- trends-row: hoist the dynamic-load chart skeleton to a shared
  `ChartSkeleton` component (S-04). No chart-visual change —
  placeholder only.
- correlation-row: collapse the grid className ternary onto `cn()`
  with a conditional `md:grid-cols-2` (S-05).

Test count unchanged (2105).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-10 22:17:29 +02:00

79 lines
2.4 KiB
TypeScript

"use client";
import { cn } from "@/lib/utils";
import { useTranslations } from "@/lib/i18n/context";
import type { CorrelationResult } from "@/lib/insights/correlations";
import { CorrelationCard } from "./correlation-card";
/**
* v1.4.20 phase B3 — Correlation row.
*
* Renders the pre-defined hypothesis cards in a 2-up grid on `>=md` and
* a single column on `<md`. A single correlation-disclaimer footer sits
* below the row — the disclaimer applies to every card so we don't
* repeat it per-card.
*
* v1.4.22 A4 — empty-state cards are dropped instead of rendered. Any
* hypothesis whose `status !== "ok"` is filtered out so the layout
* collapses cleanly: 2 ok cards → 50/50, 1 ok card → 100 %, 0 ok cards
* → the row hides itself entirely (no header, no disclaimer). Up to
* v1.4.21 the `<CorrelationCard>` painted an EmptyState for below-
* threshold results, which left half-rows of greyed-out placeholders
* on a sparse account.
*/
interface CorrelationRowProps {
results: {
bpCompliance: CorrelationResult;
moodPulse: CorrelationResult;
weightWeekday: CorrelationResult;
};
}
export function CorrelationRow({ results }: CorrelationRowProps) {
const { t } = useTranslations();
// Drop insufficient-data tiles up-front. The grid below picks 1-col vs
// 2-col automatically so 1 ok card spans 100 % width on its own row.
const okResults = [
results.bpCompliance,
results.moodPulse,
results.weightWeekday,
].filter((r) => r.status === "ok");
if (okResults.length === 0) return null;
return (
<section
data-slot="correlation-row"
aria-label={t("insights.correlationRow.title")}
className="space-y-3"
>
<div className="flex items-baseline justify-between">
<h2 className="text-lg font-semibold">
{t("insights.correlationRow.title")}
</h2>
<p className="text-muted-foreground text-xs">
{t("insights.correlationRow.subtitle")}
</p>
</div>
<div
className={cn(
"grid grid-cols-1 gap-4",
okResults.length > 1 && "md:grid-cols-2",
)}
>
{okResults.map((result) => (
<CorrelationCard key={result.kind} result={result} />
))}
</div>
<p
data-slot="correlation-row-disclaimer"
className="text-muted-foreground text-xs italic"
>
{t("insights.correlationRow.disclaimer")}
</p>
</section>
);
}