import React from 'react'; import { StyleSheet, Text, View } from 'react-native'; import { ErrBox, Loading, Panel, Screen, Sec, SrcNote, Tile, TileGrid } from '../components/ui'; import { load } from '../lib/api'; import { fmtD, fmtDY, num } from '../lib/format'; import { C } from '../lib/theme'; import type { DexaIndex, DexaResponse } from '../lib/types'; import { useLoad } from '../lib/use-load'; function delta( curV: number | null | undefined, prevV: number | null | undefined, goodDir: -1 | 0 | 1, unit: string, prevDate: string, dp = 1, ): { text: string; tone: 'good' | 'bad' | 'neutral' } | undefined { if (prevV == null || curV == null) return undefined; const d = curV - prevV; if (Math.abs(d) < 1e-9) return { text: 'unchanged', tone: 'neutral' }; const good = goodDir === 0 ? null : (d > 0) === (goodDir > 0); return { text: `${d > 0 ? '▲' : '▼'} ${Math.abs(d).toFixed(dp)}${unit} vs ${fmtD(prevDate)}`, tone: good == null ? 'neutral' : good ? 'good' : 'bad', }; } function IdxTable({ title, arr }: { title: string; arr?: DexaIndex[] }) { if (!Array.isArray(arr) || !arr.length) return null; return ( <> MEASURE RESULT %ILE (YN) {arr.map((r) => ( {r.measure} {r.result} {r.unit ? ` ${r.unit}` : ''} {r.percentile_yn != null ? `${r.percentile_yn}%` : '—'} ))} ); } export default function Body() { const { data, err, loading, refresh } = useLoad(() => load('dexa')); let body: React.ReactNode = null; if (loading && !data) body = ; else if (err) body = ; else if (data) { const scans = data.scans; const cur = scans[scans.length - 1]; const prev = scans.length > 1 ? scans[scans.length - 2] : null; const sm = cur.summary; const p = prev?.summary; const pd = prev?.scan_date ?? ''; const reg = cur.body_composition_by_region; body = ( <> DXA scan {fmtDY(cur.scan_date)} — {cur.provider}, {cur.model || 'Hologic Horizon'}. {prev ? ` Deltas vs ${fmtDY(prev.scan_date)}.` : ''} {Array.isArray(reg) && reg.length ? ( <> REGION FAT % LEAN KG FAT KG {reg.map((r) => ( {r.region} {r.fat_pct ?? '—'} {r.lean_mass_g ? (r.lean_mass_g / 1000).toFixed(1) : '—'} {r.fat_mass_g ? (r.fat_mass_g / 1000).toFixed(1) : '—'} ))} ) : null} ); } return {body}; } function toDelta(d?: { text: string; tone: 'good' | 'bad' | 'neutral' }) { return d ? { delta: d.text, deltaTone: d.tone } : {}; } const s = StyleSheet.create({ tr: { flexDirection: 'row', gap: 8, paddingVertical: 6, borderBottomWidth: StyleSheet.hairlineWidth, borderBottomColor: '#1e1e23', }, th: { flex: 1, fontSize: 10, letterSpacing: 0.5, color: C.muted, fontWeight: '600' }, td: { flex: 1, fontSize: 12, color: C.text, fontVariant: ['tabular-nums'] }, });