fix(measurements): show source badge on mobile card too

The Apple Health pink chip rendered only inside the desktop `<Table>`
cell. iOS users — the audience that actually consumes Apple Health
data — land on the mobile card branch and saw no source indicator at
all, risking duplicate hand-entries on top of synced rows. Add a
compact badge inline with the timestamp on the mobile card so the
distinction lands at every viewport. Component test asserts the
`measurement-source-badge` testid appears twice (desktop + mobile)
so the next layout refactor can't silently drop one branch.

Also extends the `POST /api/devices` unit test mocks for the
NotificationChannel auto-upsert added in the previous commit, plus a
new test that pins the same-user apnsToken collision path returning
201 idempotently (the cross-user path keeps its 409).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Marc-André BombeckandClaude Opus 4.7 committed 2026-05-11 02:16:18 +02:00
1 parent d5202e5dd8
commit a2dfc5e256
3 files changed
+60 -1

No files matched your search

@@ -85,4 +85,18 @@ describe("MeasurementList — APPLE_HEALTH badge", () => {
const html = render("de");
expect(html).toContain("Apple Health");
});
it("paints the source badge in BOTH the desktop table and the mobile card", () => {
// v1.4.23 W6 design review HIGH-1: the badge previously rendered
// only inside the desktop `<Table>` cell. iOS users (the audience
// that actually consumes Apple Health data) land on the mobile
// card branch and saw no source indicator at all, risking
// duplicate hand-entries on top of synced rows. Both branches must
// carry the badge so the surface is honest at every viewport.
const html = render("en");
const matches = html.match(
/data-testid="measurement-source-badge"/g,
);
expect(matches?.length ?? 0).toBe(2);
});
});
@@ -447,6 +447,7 @@ export function MeasurementList({ onEdit, onAddFirst }: MeasurementListProps) {
{m.source !== "MANUAL" && (
<Badge
variant="outline"
data-testid="measurement-source-badge"
className={`text-xs ${sourceBadgeClass(m.source)}`.trim()}
>
{formatMeasurementSource(m.source, t)}
@@ -506,7 +507,16 @@ export function MeasurementList({ onEdit, onAddFirst }: MeasurementListProps) {
{m.value} {m.unit}
</span>
<p className="text-muted-foreground truncate text-xs">
{formatDateTime(m.measuredAt)}
<span>{formatDateTime(m.measuredAt)}</span>
{m.source !== "MANUAL" && (
<Badge
variant="outline"
data-testid="measurement-source-badge"
className={`ml-1.5 h-4 px-1 text-[10px] ${sourceBadgeClass(m.source)}`.trim()}
>
{formatMeasurementSource(m.source, t)}
</Badge>
)}
</p>
{m.notes && (
<p className="text-muted-foreground truncate text-xs">