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'] },
});