mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-14 06:40:50 +00:00
feat(weight): judge the weight trend against the stored target
The weight tile's arrow, 7-day delta and comparison caption were wired as "up is bad", so a person below their own target who was gaining saw every step toward it coloured as a setback. Movement is now judged against the target they entered: below the band a gain is progress, above it a loss is, and inside it holding steady is, with a move either way shown neutral rather than orange. Without a stored target the tile reads exactly as before; the height-derived band is not treated as a target because nobody chose it. The direction is resolved once on the server and published on the dashboard snapshot as tiles.weightTrend, so the web tile and the native client colour the same reading the same way. The personal-record direction reads the same placement helper. The feature payload behind the briefing, the overview analysis and the Coach now carries the target band and which way is progress, so a narrative no longer calls a gain a regression when gaining is the goal. The insights vitals grid drops weight from its fixed "up is bad" set. Refs #1006
This commit is contained in:
1 parent
0c3195fd41
commit
1273a76a63
14 files changed
+577
-24
No files matched your search
+30
-14
@@ -157,6 +157,10 @@ import { mergeSlimAndThickAnalytics } from "@/lib/analytics/merge-slim-thick";
|
||||
import { isWindowSufficient } from "@/lib/analytics/window-confidence";
|
||||
import { buildDashboardBands, viewerBandProfile } from "@/lib/dashboard/bands";
|
||||
import { resolveWeightTargetOverride } from "@/lib/analytics/effective-range";
|
||||
import {
|
||||
resolveWeightTrend,
|
||||
weightTrendReferenceKg,
|
||||
} from "@/lib/targets/weight-trend";
|
||||
import { toProfileSex } from "@/lib/profile/sex";
|
||||
import { apiGet } from "@/lib/api/api-fetch";
|
||||
|
||||
@@ -766,24 +770,36 @@ export default function DashboardPageClient({
|
||||
// client-side band at all and waits for the snapshot's, which resolve
|
||||
// against the record.
|
||||
const inSharedRecord = user?.accountAccess?.active != null;
|
||||
const clientBands = useMemo(
|
||||
const clientBandProfile = useMemo(
|
||||
() =>
|
||||
buildDashboardBands(
|
||||
viewerBandProfile(
|
||||
{
|
||||
dateOfBirth: user?.dateOfBirth ? new Date(user.dateOfBirth) : null,
|
||||
gender: toProfileSex(user?.gender),
|
||||
heightCm: user?.heightCm ?? null,
|
||||
weightTargetOverride: resolveWeightTargetOverride(
|
||||
thresholdsData?.overrides ?? null,
|
||||
),
|
||||
},
|
||||
inSharedRecord,
|
||||
),
|
||||
viewerBandProfile(
|
||||
{
|
||||
dateOfBirth: user?.dateOfBirth ? new Date(user.dateOfBirth) : null,
|
||||
gender: toProfileSex(user?.gender),
|
||||
heightCm: user?.heightCm ?? null,
|
||||
weightTargetOverride: resolveWeightTargetOverride(
|
||||
thresholdsData?.overrides ?? null,
|
||||
),
|
||||
},
|
||||
inSharedRecord,
|
||||
),
|
||||
[user, thresholdsData, inSharedRecord],
|
||||
);
|
||||
const clientBands = useMemo(
|
||||
() => buildDashboardBands(clientBandProfile),
|
||||
[clientBandProfile],
|
||||
);
|
||||
const bands = serverBands ?? clientBands;
|
||||
// v1.39 — which way a weight change counts as progress, judged against the
|
||||
// stored target. The snapshot carries the server's answer; the
|
||||
// snapshot-disabled fallback asks the same resolver from the same profile
|
||||
// the band fallback above reads, so the two paths cannot disagree.
|
||||
const weightTrend =
|
||||
(snapshotEnabled ? snapshotQuery.data?.tiles.weightTrend : undefined) ??
|
||||
resolveWeightTrend(
|
||||
clientBandProfile.weightTargetOverride,
|
||||
weightTrendReferenceKg(w),
|
||||
);
|
||||
const bpTargets = bands.bpTargets;
|
||||
const weightRange = bands.weightRange;
|
||||
// The range hint tooltip prints its band bounds in the display unit, so scale
|
||||
@@ -1028,7 +1044,7 @@ export default function DashboardPageClient({
|
||||
slope30={w?.slope30 ?? null}
|
||||
trend7Delta={tdd("WEIGHT", summaryToTrend7Delta(w))}
|
||||
icon={Activity}
|
||||
directionSentiment="up-bad"
|
||||
directionSentiment={weightTrend.direction}
|
||||
compareBaseline={compareBaseline}
|
||||
compareDelta={tdd("WEIGHT", tileCompareDelta(w))}
|
||||
staleDays={tileStaleDays("WEIGHT")}
|
||||
|
||||
Reference in new issue
Block a user