fix(fitness/stats): wrap streamed muscle heatmap in {#await}

The $state + $effect pattern I used for the muscle heatmap in
bb0895c didn't propagate the streamed promise into the component's
internal $derived(data.totals) chain — the hover counts stayed at
zero even after the data arrived.

Switch just the heatmap to an {#await} block so it mounts once with
the fully-resolved object. The nutrition card shells, periods, and
shared periods keep their $state pattern because the card templates
read individual fields directly (which gracefully fall through to
the "—" branches while pending) and re-rendering once the value
arrives is fine.

Also drops the two reverted commits for the set-subfield projection
(4d1fed6, fe8d036); those are replaced later with a safer narrowing
that keeps whole set objects.
This commit is contained in:
2026-04-23 15:30:05 +02:00
parent bb0895c9b5
commit 0da3b130e4
2 changed files with 8 additions and 9 deletions
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "homepage",
"version": "1.46.19",
"version": "1.46.20",
"private": true,
"type": "module",
"scripts": {
@@ -120,20 +120,17 @@
}]
});
// Streamed panels: render empty shells on SSR/initial hydrate, then fill
// in once the server-sent promise resolves. Defaults match the previous
// error-fallback shapes so the existing `!= null` checks cascade to the
// "—" branches while the data is in flight.
// Streamed panels. nutrition / periods resolve through $state so the card
// shells render immediately with "—" placeholders; muscle heatmap is
// wrapped in {#await} below instead because its internal $derived chain
// needs the full resolved object in one shot to render correctly.
/** @type {any} */
let ns = $state({});
/** @type {{ weeks: any[]; totals: any; muscleGroups: any[] }} */
let muscleHeatmapData = $state({ weeks: [], totals: {}, muscleGroups: [] });
/** @type {any[]} */
let periodsData = $state([]);
/** @type {any[]} */
let sharedPeriodsData = $state([]);
$effect(() => { Promise.resolve(data.nutritionStats).then(v => { ns = v ?? {}; }); });
$effect(() => { Promise.resolve(data.muscleHeatmap).then(v => { muscleHeatmapData = v ?? { weeks: [], totals: {}, muscleGroups: [] }; }); });
$effect(() => { Promise.resolve(data.periods).then(v => { periodsData = v ?? []; }); });
$effect(() => { Promise.resolve(data.sharedPeriods).then(v => { sharedPeriodsData = v ?? []; }); });
@@ -500,7 +497,9 @@
<div class="section-block muscle-heatmap-block">
<h2 class="section-title">{t('muscle_balance', lang)}</h2>
<MuscleHeatmap data={muscleHeatmapData} />
{#await data.muscleHeatmap then muscleHeatmap}
<MuscleHeatmap data={muscleHeatmap} />
{/await}
</div>
</div>