From 80c5f1474826564aa0c1bc6b92d785ad30f20d2f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Bombeck?= Date: Fri, 5 Jun 2026 13:46:42 +0200 Subject: [PATCH] feat(insights): reorder the mood page to the calendar-first spine MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Lift the Stimmungskalender above the line chart and place the better-days assessment directly under the Ziel card. `MoodInsightsSections` now renders by region (`heatmap` / `assessment` / `rest`); the page threads them so the spine reads heading → summary → calendar → chart → target → assessment → classification + breakdowns. All three regions share the one `moodInsights` query so the fetch is deduped. Every `data-slot` is preserved. Co-Authored-By: Claude Opus 4.8 (1M context) --- src/app/insights/mood/page.tsx | 14 ++- .../insights/mood/mood-insights-sections.tsx | 112 +++++++++++------- 2 files changed, 84 insertions(+), 42 deletions(-) diff --git a/src/app/insights/mood/page.tsx b/src/app/insights/mood/page.tsx index a49461cbd..442bfb78f 100644 --- a/src/app/insights/mood/page.tsx +++ b/src/app/insights/mood/page.tsx @@ -97,6 +97,14 @@ export default function InsightsStimmungPage() { explainerMetric="mood" coachLaunch > + {/* v1.12.7 — operator spine: heading + summary (the shell above), then + the Stimmungskalender, then the line chart, then the Ziel card, then + the better-days Einschätzung, then the classification + breakdowns. + The heatmap and the assessment are lifted out of `MoodInsightsSections` + into their own regions so they land in this exact order; all three + regions share one `moodInsights` query (TanStack dedups the fetch). */} + + {/* No `` here: mood is event-driven, not a MeasurementType series, so the period-over-period range read (`/api/analytics/range`, keyed on a MeasurementType enum) has @@ -109,7 +117,11 @@ export default function InsightsStimmungPage() { - + {/* The better-days Einschätzung sits directly under the Ziel card, + ahead of the classification tiles and breakdowns. */} + + + {/* v1.12.2 — the assessment is the LAST block on every bespoke metric-detail page, matching the canonical spine the generic diff --git a/src/components/insights/mood/mood-insights-sections.tsx b/src/components/insights/mood/mood-insights-sections.tsx index d1f867529..75c6df4ec 100644 --- a/src/components/insights/mood/mood-insights-sections.tsx +++ b/src/components/insights/mood/mood-insights-sections.tsx @@ -167,7 +167,28 @@ function SectionCard({ ); } -export function MoodInsightsSections() { +/** + * v1.12.7 — the mood spine is split into three render regions so the page can + * thread the operator's exact top-to-bottom order without prop-drilling the + * whole aggregate payload: + * + * - "heatmap" — the Stimmungskalender, lifted above the line chart. + * - "assessment" — the better-days Einschätzung, placed right after the + * Ziel card. + * - "rest" — the Einordnung classification tiles, the "what stands + * out" card, and every deep-dive breakdown. + * + * All three regions read the SAME `queryKeys.moodInsights()` query, so + * TanStack Query dedups the fetch (single network read, 60 s staleTime); the + * regions are pure JSX slices of one resolved payload. + */ +export type MoodInsightsRegion = "heatmap" | "assessment" | "rest"; + +export function MoodInsightsSections({ + region = "rest", +}: { + region?: MoodInsightsRegion; +} = {}) { const { isAuthenticated } = useAuth(); const { t } = useTranslations(); @@ -184,7 +205,12 @@ export function MoodInsightsSections() { }); if (isLoading) { - return ; + // Only the "rest" region carries the page-level loading skeleton; the + // heatmap / assessment regions stay invisible while loading so they don't + // stack three skeletons down the page. + return region === "rest" ? ( + + ) : null; } if (!data || data.summary.totalEntries === 0) { @@ -225,13 +251,50 @@ export function MoodInsightsSections() { const crosstabRows = data.tagMetricCrosstab ?? []; const hasCrosstab = crosstabRows.length > 0; + // v1.12.7 — the Stimmungskalender is lifted above the line chart on the page, + // so it renders as its own region here. + if (region === "heatmap") { + return ( + + + + ); + } + + // v1.12.7 — the better-days Einschätzung is placed right after the Ziel card + // on the page, ahead of the classification tiles, so it renders as its own + // region. It carries the same assessment-card weight the per-metric + // `` uses on the other subpages (tighter `gap`/`py`, the + // `insight-in` entry, and the `insight-assessment` hook) so it reads as THE + // mood assessment, consistent across the app. + if (region === "assessment") { + if (!hasBetterDays) return null; + return ( + + + + + + + + + ); + } + return ( - // v1.12.6 — the mood spine is ordered as: Einordnung (the classification - // tiles: in-target share + stability band) FIRST, then the "what goes with - // your better days" assessment read, then the descriptive breakdown - // sections. The classification answers "where do I stand", the better-days - // board answers "what associates with my good days", and the rest is the - // supporting detail. + // v1.12.7 — "rest" region. The Stimmungskalender (now above the chart) and + // the better-days Einschätzung (now right after the Ziel card) render in + // their own regions above; this region carries the Einordnung classification + // tiles (in-target share + stability band) FIRST, then the "what stands + // out" card, then the descriptive breakdown sections. The classification + // answers "where do I stand", and the rest is the supporting detail.
{/* Einordnung — the classification tiles. */} {(hasInTargetTile || hasStabilityTile) && ( @@ -252,45 +315,12 @@ export function MoodInsightsSections() {
)} - {/* "Was zu deinen besseren Tagen passt" — the better-days assessment, - ranked by effect size. The substance of the Einschätzung sits here, - directly under the classification. v1.12.7 — it now carries the same - assessment-card weight the per-metric `` uses on - the other subpages (tighter `gap`/`py`, the `insight-in` entry, and - the `insight-assessment` hook) so it reads as THE mood assessment, - consistent across the app. */} - {hasBetterDays && ( - - - - - - - - - )} - {/* v1.12.7 — the single "What stands out" card folds the narrative one-liners AND the FDR-controlled discovered relations into one tile (was two separate cards). Self-fetches the discovery surface and renders nothing when both halves are empty. */} - - - -