@burdenoff/microfe-mybodyshield 2026.821.2 → 2026.830.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (90) hide show
  1. package/dist/mybodyshield/MyBodyShieldRoot.d.ts.map +1 -1
  2. package/dist/mybodyshield/MyBodyShieldRoot.js +54 -56
  3. package/dist/mybodyshield/MyBodyShieldRoot.js.map +1 -1
  4. package/dist/mybodyshield/MyBodyShieldRoutes.d.ts.map +1 -1
  5. package/dist/mybodyshield/MyBodyShieldRoutes.js +121 -62
  6. package/dist/mybodyshield/MyBodyShieldRoutes.js.map +1 -1
  7. package/dist/mybodyshield/components/EvidenceUpload.d.ts.map +1 -1
  8. package/dist/mybodyshield/components/EvidenceUpload.js +46 -45
  9. package/dist/mybodyshield/components/EvidenceUpload.js.map +1 -1
  10. package/dist/mybodyshield/components/FileLink.d.ts.map +1 -1
  11. package/dist/mybodyshield/components/FileLink.js +27 -18
  12. package/dist/mybodyshield/components/FileLink.js.map +1 -1
  13. package/dist/mybodyshield/components/MybDiscussion.d.ts +1 -1
  14. package/dist/mybodyshield/components/MybDiscussion.d.ts.map +1 -1
  15. package/dist/mybodyshield/components/MybDiscussion.js +59 -58
  16. package/dist/mybodyshield/components/MybDiscussion.js.map +1 -1
  17. package/dist/mybodyshield/components/MybTags.d.ts +1 -1
  18. package/dist/mybodyshield/components/MybTags.d.ts.map +1 -1
  19. package/dist/mybodyshield/components/MybTags.js +83 -74
  20. package/dist/mybodyshield/components/MybTags.js.map +1 -1
  21. package/dist/mybodyshield/components/PageDisabled.d.ts.map +1 -1
  22. package/dist/mybodyshield/components/PageDisabled.js +16 -11
  23. package/dist/mybodyshield/components/PageDisabled.js.map +1 -1
  24. package/dist/mybodyshield/components/Pagination.d.ts.map +1 -1
  25. package/dist/mybodyshield/components/Pagination.js +36 -27
  26. package/dist/mybodyshield/components/Pagination.js.map +1 -1
  27. package/dist/mybodyshield/components/StateViews.d.ts.map +1 -1
  28. package/dist/mybodyshield/components/StateViews.js +42 -34
  29. package/dist/mybodyshield/components/StateViews.js.map +1 -1
  30. package/dist/mybodyshield/components/UserSearchSelect.d.ts.map +1 -1
  31. package/dist/mybodyshield/components/UserSearchSelect.js +66 -68
  32. package/dist/mybodyshield/components/UserSearchSelect.js.map +1 -1
  33. package/dist/mybodyshield/hooks/index.d.ts +1 -0
  34. package/dist/mybodyshield/hooks/index.d.ts.map +1 -1
  35. package/dist/mybodyshield/hooks/index.js +1 -0
  36. package/dist/mybodyshield/hooks/useTr.d.ts +5 -0
  37. package/dist/mybodyshield/hooks/useTr.d.ts.map +1 -0
  38. package/dist/mybodyshield/hooks/useTr.js +12 -0
  39. package/dist/mybodyshield/hooks/useTr.js.map +1 -0
  40. package/dist/mybodyshield/pages/DashboardPage.d.ts.map +1 -1
  41. package/dist/mybodyshield/pages/DashboardPage.js +157 -136
  42. package/dist/mybodyshield/pages/DashboardPage.js.map +1 -1
  43. package/dist/mybodyshield/pages/SettingsPage.d.ts.map +1 -1
  44. package/dist/mybodyshield/pages/SettingsPage.js +50 -59
  45. package/dist/mybodyshield/pages/SettingsPage.js.map +1 -1
  46. package/dist/mybodyshield/pages/_shared/visuals.d.ts +2 -1
  47. package/dist/mybodyshield/pages/_shared/visuals.d.ts.map +1 -1
  48. package/dist/mybodyshield/pages/_shared/visuals.js +91 -81
  49. package/dist/mybodyshield/pages/_shared/visuals.js.map +1 -1
  50. package/dist/mybodyshield/pages/ai/AiControlsPage.d.ts.map +1 -1
  51. package/dist/mybodyshield/pages/ai/AiControlsPage.js +279 -231
  52. package/dist/mybodyshield/pages/ai/AiControlsPage.js.map +1 -1
  53. package/dist/mybodyshield/pages/coaching/CoachingPage.d.ts.map +1 -1
  54. package/dist/mybodyshield/pages/coaching/CoachingPage.js +349 -258
  55. package/dist/mybodyshield/pages/coaching/CoachingPage.js.map +1 -1
  56. package/dist/mybodyshield/pages/goals/GoalsPage.d.ts.map +1 -1
  57. package/dist/mybodyshield/pages/goals/GoalsPage.js +247 -251
  58. package/dist/mybodyshield/pages/goals/GoalsPage.js.map +1 -1
  59. package/dist/mybodyshield/pages/insights/InsightsCharts.d.ts.map +1 -1
  60. package/dist/mybodyshield/pages/insights/InsightsCharts.js +216 -213
  61. package/dist/mybodyshield/pages/insights/InsightsCharts.js.map +1 -1
  62. package/dist/mybodyshield/pages/insights/InsightsPage.d.ts.map +1 -1
  63. package/dist/mybodyshield/pages/insights/InsightsPage.js +327 -220
  64. package/dist/mybodyshield/pages/insights/InsightsPage.js.map +1 -1
  65. package/dist/mybodyshield/pages/nutrition/NutritionPage.d.ts.map +1 -1
  66. package/dist/mybodyshield/pages/nutrition/NutritionPage.js +575 -529
  67. package/dist/mybodyshield/pages/nutrition/NutritionPage.js.map +1 -1
  68. package/dist/mybodyshield/pages/programs/ProgramDetailPage.d.ts.map +1 -1
  69. package/dist/mybodyshield/pages/programs/ProgramDetailPage.js +333 -275
  70. package/dist/mybodyshield/pages/programs/ProgramDetailPage.js.map +1 -1
  71. package/dist/mybodyshield/pages/programs/ProgramsPage.d.ts.map +1 -1
  72. package/dist/mybodyshield/pages/programs/ProgramsPage.js +258 -253
  73. package/dist/mybodyshield/pages/programs/ProgramsPage.js.map +1 -1
  74. package/dist/mybodyshield/pages/progress/ProgressPage.d.ts.map +1 -1
  75. package/dist/mybodyshield/pages/progress/ProgressPage.js +271 -254
  76. package/dist/mybodyshield/pages/progress/ProgressPage.js.map +1 -1
  77. package/dist/mybodyshield/pages/recovery/RecoveryPage.d.ts.map +1 -1
  78. package/dist/mybodyshield/pages/recovery/RecoveryPage.js +206 -200
  79. package/dist/mybodyshield/pages/recovery/RecoveryPage.js.map +1 -1
  80. package/dist/mybodyshield/pages/train/SessionDetailPage.d.ts.map +1 -1
  81. package/dist/mybodyshield/pages/train/SessionDetailPage.js +327 -294
  82. package/dist/mybodyshield/pages/train/SessionDetailPage.js.map +1 -1
  83. package/dist/mybodyshield/pages/train/SessionsPage.d.ts.map +1 -1
  84. package/dist/mybodyshield/pages/train/SessionsPage.js +180 -163
  85. package/dist/mybodyshield/pages/train/SessionsPage.js.map +1 -1
  86. package/dist/mybodyshield/utils/i18n.d.ts +1 -2
  87. package/dist/mybodyshield/utils/i18n.d.ts.map +1 -1
  88. package/dist/mybodyshield/utils/i18n.js +15 -0
  89. package/dist/mybodyshield/utils/i18n.js.map +1 -0
  90. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"ProgressPage.js","names":[],"sources":["../../../../src/mybodyshield/pages/progress/ProgressPage.tsx"],"sourcesContent":["/**\n * Progress — body metrics over time.\n * @module mybodyshield/pages/progress\n *\n * A single-metric time-series view over the real `mybListBodyMetrics`\n * endpoint: pick a body-metric type (weight, body-fat, measurements…), see the\n * latest value + trend vs the previous reading, a token-styled line chart of the\n * history window, aggregate stats, and an offset-paginated log table. New\n * readings are recorded through `mybRecordBodyMetric`. No mock data — everything\n * derives from the hooks.\n */\n\nimport { useEffect, useMemo, useState } from 'react';\nimport {\n AreaChart,\n Area,\n XAxis,\n YAxis,\n CartesianGrid,\n Tooltip,\n ReferenceDot,\n ResponsiveContainer,\n} from 'recharts';\nimport { motion, useReducedMotion, type MotionProps } from 'framer-motion';\nimport { Plus, Activity, Sigma, ArrowDownUp } from 'lucide-react';\nimport {\n Button,\n Input,\n Label,\n Textarea,\n GlassCard,\n Select,\n SelectTrigger,\n SelectContent,\n SelectItem,\n SelectValue,\n ResponsiveDialog,\n ResponsiveDialogContent,\n ResponsiveDialogHeader,\n ResponsiveDialogTitle,\n ResponsiveDialogDescription,\n ResponsiveDialogFooter,\n} from '@burdenoff/fe-libs/ui';\nimport {\n PageLayout,\n MetricsCard,\n FilterTabs,\n DataTable,\n Pagination,\n LoadingView,\n ErrorView,\n Section,\n EmptyState,\n EvidenceUpload,\n FileLink,\n type Column,\n type FilterOption,\n} from '../../components';\nimport { IconChip, TrendPill, METRIC_META } from '../_shared/visuals';\nimport {\n useMybBodyMetrics,\n useMybRecordBodyMetric,\n useOffsetPager,\n type UploadedMybFile,\n} from '../../hooks';\nimport type { MybBodyMetric, MybBodyMetricType, MybRecordMetricInput } from '../../types';\nimport {\n formatNumber,\n formatDate,\n formatDateTime,\n formatRelativeTime,\n formatEnumLabel,\n} from '../../utils/formatters';\n\n// Ordered enum surface for the metric-type selector (METRIC_META is a Record).\nconst METRIC_TYPES: MybBodyMetricType[] = [\n 'WEIGHT',\n 'BODY_FAT',\n 'RESTING_HEART_RATE',\n 'WAIST',\n 'CHEST',\n 'HIPS',\n 'ARM',\n 'THIGH',\n];\n\n// Which direction of change is \"good\" per metric (drives TrendPill colouring).\nconst GOOD_DIRECTION: Record<MybBodyMetricType, 'up' | 'down'> = {\n WEIGHT: 'down',\n BODY_FAT: 'down',\n RESTING_HEART_RATE: 'down',\n WAIST: 'down',\n HIPS: 'down',\n CHEST: 'up',\n ARM: 'up',\n THIGH: 'up',\n};\n\n// Window used for the chart / KPIs / aggregates (the log table paginates on top).\nconst CHART_WINDOW = 100;\nconst PAGE_SIZE = 25;\n\n// Brand emerald accent — the dominant color for the area chart, line & endpoint.\nconst CHART_ACCENT = 'var(--color-action-primary-bg)';\n\ninterface RecordForm {\n type: MybBodyMetricType;\n value: string;\n unit: string;\n measuredAt: string;\n notes: string;\n photo: UploadedMybFile | null;\n}\n\n/** A `Date` → `<input type=\"datetime-local\">` value (local wall-clock time). */\nconst toLocalInput = (d: Date): string => {\n const pad = (n: number) => String(n).padStart(2, '0');\n return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())}T${pad(d.getHours())}:${pad(d.getMinutes())}`;\n};\n\nconst makeForm = (type: MybBodyMetricType): RecordForm => ({\n type,\n value: '',\n unit: METRIC_META[type].unit,\n measuredAt: toLocalInput(new Date()),\n notes: '',\n photo: null,\n});\n\nexport function ProgressPage() {\n const [selectedType, setSelectedType] = useState<MybBodyMetricType>('WEIGHT');\n const [open, setOpen] = useState(false);\n const [form, setForm] = useState<RecordForm>(() => makeForm('WEIGHT'));\n const [formError, setFormError] = useState<string | null>(null);\n\n const pager = useOffsetPager(PAGE_SIZE);\n\n // Reset the log table to page 1 whenever the metric type changes.\n // Depend on the stable `pager.reset` (NOT the whole pager, whose identity\n // changes with `page`) so advancing pages doesn't snap back to page 1.\n const resetPager = pager.reset;\n useEffect(() => {\n resetPager();\n }, [selectedType, resetPager]);\n\n // Wide window drives the chart, latest/trend KPIs and aggregate stats.\n const history = useMybBodyMetrics({\n type: selectedType,\n pagination: { limit: CHART_WINDOW },\n });\n // Independent offset-paginated slice powers the log table.\n const table = useMybBodyMetrics({\n type: selectedType,\n pagination: { limit: PAGE_SIZE, offset: pager.offset },\n });\n const record = useMybRecordBodyMetric();\n\n const reduced = useReducedMotion();\n const rise = (delay: number, hover = true): MotionProps =>\n reduced\n ? { initial: false }\n : {\n initial: { opacity: 0, y: 14 },\n animate: { opacity: 1, y: 0 },\n transition: { duration: 0.45, delay, ease: 'easeOut' },\n ...(hover\n ? {\n whileHover: {\n y: -3,\n transition: { type: 'spring', stiffness: 300, damping: 22 },\n },\n }\n : {}),\n };\n\n const meta = METRIC_META[selectedType];\n const MetricIcon = meta.icon;\n const goodDir = GOOD_DIRECTION[selectedType];\n\n const historyRows = useMemo<MybBodyMetric[]>(() => history.data?.items ?? [], [history.data]);\n\n // Ascending by measuredAt → chart series + robust latest/prior derivation.\n const ascending = useMemo(\n () =>\n [...historyRows].sort(\n (a, b) => new Date(a.measuredAt).getTime() - new Date(b.measuredAt).getTime()\n ),\n [historyRows]\n );\n\n const latest = ascending[ascending.length - 1];\n const prior = ascending[ascending.length - 2];\n const delta = latest && prior ? latest.value - prior.value : undefined;\n\n const chartData = useMemo(\n () => ascending.map((m) => ({ label: formatDate(m.measuredAt), value: m.value })),\n [ascending]\n );\n const lastPoint = chartData.length > 0 ? chartData[chartData.length - 1] : undefined;\n\n const stats = useMemo(() => {\n if (ascending.length === 0) return null;\n const values = ascending.map((m) => m.value);\n return {\n count: values.length,\n min: Math.min(...values),\n max: Math.max(...values),\n avg: values.reduce((a, b) => a + b, 0) / values.length,\n };\n }, [ascending]);\n\n const metricOptions: FilterOption<MybBodyMetricType>[] = METRIC_TYPES.map((t) => ({\n value: t,\n label: formatEnumLabel(t),\n }));\n\n const openRecord = () => {\n setForm(makeForm(selectedType));\n setFormError(null);\n setOpen(true);\n };\n\n const submit = async () => {\n const numValue = Number(form.value);\n if (form.value.trim() === '' || !Number.isFinite(numValue)) {\n setFormError('Enter a valid measurement value.');\n return;\n }\n setFormError(null);\n const input: MybRecordMetricInput = {\n type: form.type,\n value: numValue,\n unit: form.unit.trim() || METRIC_META[form.type].unit,\n measuredAt: form.measuredAt\n ? new Date(form.measuredAt).toISOString()\n : new Date().toISOString(),\n notes: form.notes.trim() ? form.notes.trim() : null,\n photoFileId: form.photo?.fileId ?? null,\n };\n try {\n await record.mutateAsync(input);\n setOpen(false);\n // Surface the just-recorded type so the new reading is visible immediately.\n setSelectedType(form.type);\n pager.reset();\n } catch (e) {\n setFormError(e instanceof Error ? e.message : 'Failed to record measurement.');\n }\n };\n\n const tableRows = table.data?.items ?? [];\n const tableColumns: Column<MybBodyMetric>[] = [\n {\n key: 'value',\n header: 'Value',\n align: 'right',\n sortValue: (row) => row.value,\n render: (row) => (\n <span className=\"font-medium tabular-nums text-text-primary\">\n {formatNumber(row.value)}\n <span className=\"ml-1 text-xs font-normal text-text-tertiary\">{row.unit}</span>\n </span>\n ),\n },\n {\n key: 'measuredAt',\n header: 'Measured',\n sortValue: (row) => new Date(row.measuredAt).getTime(),\n render: (row) => (\n <span className=\"whitespace-nowrap text-text-secondary\">\n {formatDateTime(row.measuredAt)}\n </span>\n ),\n },\n {\n key: 'notes',\n header: 'Notes',\n hideOnMobile: true,\n render: (row) =>\n row.notes ? (\n <span className=\"text-text-secondary\">{row.notes}</span>\n ) : (\n <span className=\"text-text-tertiary\">—</span>\n ),\n },\n {\n key: 'photo',\n header: 'Photo',\n render: (row) =>\n row.photo?.id ? (\n <FileLink fileId={row.photo.id} />\n ) : (\n <span className=\"text-text-tertiary\">—</span>\n ),\n },\n ];\n\n const recordButton = (\n <Button onClick={openRecord}>\n <Plus className=\"mr-1.5 h-4 w-4\" /> Record measurement\n </Button>\n );\n\n return (\n <PageLayout\n title=\"Progress\"\n description=\"Body metrics over time — weight, composition & measurements.\"\n actions={recordButton}\n >\n {/* Metric-type selector */}\n <div className=\"mb-6 overflow-x-auto\">\n <FilterTabs options={metricOptions} value={selectedType} onChange={setSelectedType} />\n </div>\n\n {history.isLoading && historyRows.length === 0 ? (\n <LoadingView label={`Loading ${formatEnumLabel(selectedType).toLowerCase()} history…`} />\n ) : history.isError ? (\n <ErrorView\n message=\"We couldn't load your body-metric history.\"\n onRetry={() => history.refetch()}\n />\n ) : historyRows.length === 0 ? (\n <EmptyState\n illustration=\"empty-data\"\n icon={<MetricIcon className=\"h-10 w-10\" />}\n title={`No ${formatEnumLabel(selectedType).toLowerCase()} readings yet`}\n description=\"Record a measurement to start tracking this metric over time.\"\n action={\n <Button onClick={openRecord}>\n <Plus className=\"mr-1.5 h-4 w-4\" /> Record measurement\n </Button>\n }\n />\n ) : (\n <div className=\"space-y-6\">\n {/* Latest + trend + chart */}\n <motion.div {...rise(0)}>\n <GlassCard\n treatment=\"glass\"\n className=\"rounded-2xl p-6 transition-shadow duration-300 hover:shadow-2xl\"\n >\n <div className=\"flex flex-wrap items-start justify-between gap-4\">\n <div className=\"flex items-center gap-3\">\n <IconChip icon={<MetricIcon className=\"h-5 w-5\" />} tint={meta.tint} />\n <div>\n <h2 className=\"text-base font-semibold text-text-primary\">\n {formatEnumLabel(selectedType)}\n </h2>\n <p className=\"text-sm text-text-secondary\">\n {latest\n ? `Last measured ${formatRelativeTime(latest.measuredAt)}`\n : 'No measurements yet'}\n </p>\n </div>\n </div>\n <div className=\"text-right\">\n <p className=\"text-3xl font-bold leading-none tracking-tight tabular-nums text-text-primary sm:text-4xl\">\n {latest ? formatNumber(latest.value) : '—'}\n {latest && (\n <span className=\"ml-1 text-base font-medium text-text-tertiary\">\n {meta.unit}\n </span>\n )}\n </p>\n {delta != null && (\n <div className=\"mt-2 flex justify-end\">\n <span className=\"inline-flex items-center rounded-full bg-bg-sunken px-2.5 py-1 ring-1 ring-border-seam\">\n <TrendPill delta={delta} unit={` ${meta.unit}`} goodDirection={goodDir} />\n </span>\n </div>\n )}\n </div>\n </div>\n\n <div className=\"mt-6 h-64 w-full\">\n <ResponsiveContainer width=\"100%\" height=\"100%\">\n <AreaChart data={chartData} margin={{ top: 8, right: 14, bottom: 4, left: -8 }}>\n <defs>\n <linearGradient id=\"myb-progress-fill\" x1=\"0\" y1=\"0\" x2=\"0\" y2=\"1\">\n <stop offset=\"0%\" stopColor={CHART_ACCENT} stopOpacity={0.38} />\n <stop offset=\"55%\" stopColor={CHART_ACCENT} stopOpacity={0.12} />\n <stop offset=\"100%\" stopColor={CHART_ACCENT} stopOpacity={0} />\n </linearGradient>\n </defs>\n <CartesianGrid\n stroke=\"var(--color-border-seam)\"\n strokeDasharray=\"4 4\"\n vertical={false}\n />\n <XAxis\n dataKey=\"label\"\n stroke=\"var(--color-border-seam)\"\n tickLine={false}\n axisLine={false}\n tick={{ fill: 'var(--color-text-tertiary)', fontSize: 12 }}\n tickMargin={8}\n minTickGap={24}\n />\n <YAxis\n stroke=\"var(--color-border-seam)\"\n tickLine={false}\n axisLine={false}\n tick={{ fill: 'var(--color-text-tertiary)', fontSize: 12 }}\n width={44}\n domain={['auto', 'auto']}\n />\n <Tooltip\n cursor={{ stroke: 'var(--color-border-seam)', strokeDasharray: '4 4' }}\n contentStyle={{\n background: 'var(--color-bg-surface)',\n border: '1px solid var(--color-border-seam)',\n borderRadius: 12,\n color: 'var(--color-text-primary)',\n }}\n labelStyle={{ color: 'var(--color-text-tertiary)' }}\n itemStyle={{ color: 'var(--color-text-primary)' }}\n formatter={(value) => [\n `${formatNumber(Number(value))} ${meta.unit}`,\n formatEnumLabel(selectedType),\n ]}\n />\n <Area\n type=\"monotone\"\n dataKey=\"value\"\n name={formatEnumLabel(selectedType)}\n stroke={CHART_ACCENT}\n strokeWidth={2.5}\n fill=\"url(#myb-progress-fill)\"\n fillOpacity={1}\n dot={false}\n activeDot={{\n r: 5,\n strokeWidth: 2,\n stroke: 'var(--color-bg-surface)',\n fill: CHART_ACCENT,\n }}\n isAnimationActive={!reduced}\n animationDuration={900}\n />\n {lastPoint && (\n <ReferenceDot\n x={lastPoint.label}\n y={lastPoint.value}\n r={12}\n isFront\n ifOverflow=\"visible\"\n fill={CHART_ACCENT}\n fillOpacity={0.16}\n stroke=\"none\"\n />\n )}\n {lastPoint && (\n <ReferenceDot\n x={lastPoint.label}\n y={lastPoint.value}\n r={5}\n isFront\n ifOverflow=\"visible\"\n fill={CHART_ACCENT}\n stroke=\"var(--color-bg-surface)\"\n strokeWidth={2}\n />\n )}\n </AreaChart>\n </ResponsiveContainer>\n </div>\n </GlassCard>\n </motion.div>\n\n {/* Aggregate stats over the loaded window (not full history) */}\n {stats && (\n <div>\n <div className=\"grid grid-cols-1 gap-4 sm:grid-cols-3\">\n <motion.div {...rise(0.08)}>\n <MetricsCard\n className=\"h-full rounded-2xl transition-shadow duration-300 hover:shadow-xl\"\n icon={<IconChip icon={<Activity className=\"h-5 w-5\" />} tint={CHART_ACCENT} />}\n value={formatNumber(stats.count)}\n label=\"Recent readings\"\n />\n </motion.div>\n <motion.div {...rise(0.14)}>\n <MetricsCard\n className=\"h-full rounded-2xl transition-shadow duration-300 hover:shadow-xl\"\n icon={<IconChip icon={<Sigma className=\"h-5 w-5\" />} tint={CHART_ACCENT} />}\n value={`${formatNumber(stats.avg, { maximumFractionDigits: 1 })} ${meta.unit}`}\n label={`Window average ${formatEnumLabel(selectedType).toLowerCase()}`}\n />\n </motion.div>\n <motion.div {...rise(0.2)}>\n <MetricsCard\n className=\"h-full rounded-2xl transition-shadow duration-300 hover:shadow-xl\"\n icon={\n <IconChip icon={<ArrowDownUp className=\"h-5 w-5\" />} tint={CHART_ACCENT} />\n }\n value={`${formatNumber(stats.min)}–${formatNumber(stats.max)}`}\n label={`Window range (${meta.unit})`}\n />\n </motion.div>\n </div>\n <p className=\"mt-2 text-xs text-text-tertiary\">\n Based on your most recent {formatNumber(stats.count)}{' '}\n {formatEnumLabel(selectedType).toLowerCase()} reading\n {stats.count === 1 ? '' : 's'} (up to {formatNumber(CHART_WINDOW)}) — not a\n full-history total.\n </p>\n </div>\n )}\n\n {/* Full measurement log */}\n <motion.div {...rise(0.26, false)}>\n <Section title=\"Measurement log\" description=\"Every recorded reading for this metric.\">\n {table.isError ? (\n <ErrorView\n message=\"We couldn't load this page of measurements.\"\n onRetry={() => table.refetch()}\n />\n ) : table.isLoading && tableRows.length === 0 ? (\n <div className=\"py-8 text-center text-sm text-text-secondary\">\n Loading measurements…\n </div>\n ) : tableRows.length === 0 ? (\n <EmptyState\n illustration=\"empty-data\"\n icon={<MetricIcon className=\"h-10 w-10\" />}\n title=\"No measurements on this page\"\n description=\"Go back a page or record a new measurement.\"\n />\n ) : (\n <>\n <DataTable\n columns={tableColumns}\n rows={tableRows}\n rowKey={(row) => row.id}\n defaultSort={{ key: 'measuredAt', dir: 'desc' }}\n />\n <Pagination\n page={pager.page}\n pageSize={PAGE_SIZE}\n itemCount={tableRows.length}\n hasMore={table.data?.pageInfo?.hasMore ?? false}\n onPageChange={(t) => pager.onPageChange(t)}\n />\n </>\n )}\n </Section>\n </motion.div>\n </div>\n )}\n\n {/* Record-measurement dialog */}\n <ResponsiveDialog open={open} onOpenChange={setOpen}>\n <ResponsiveDialogContent>\n <ResponsiveDialogHeader>\n <ResponsiveDialogTitle>Record measurement</ResponsiveDialogTitle>\n <ResponsiveDialogDescription>\n Log a new body-metric reading to track your progress over time.\n </ResponsiveDialogDescription>\n </ResponsiveDialogHeader>\n\n <div className=\"space-y-4 py-2\">\n <div className=\"space-y-1.5\">\n <Label htmlFor=\"myb-metric-type\">Metric</Label>\n <Select\n value={form.type}\n onValueChange={(v) => {\n // `v` is constrained to METRIC_TYPES by the SelectItems below.\n const nextType = v as MybBodyMetricType;\n setForm((prev) => ({\n ...prev,\n type: nextType,\n unit: METRIC_META[nextType].unit,\n }));\n }}\n >\n <SelectTrigger id=\"myb-metric-type\">\n <SelectValue placeholder=\"Select a metric\" />\n </SelectTrigger>\n <SelectContent>\n {METRIC_TYPES.map((t) => (\n <SelectItem key={t} value={t}>\n {formatEnumLabel(t)}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n\n <div className=\"grid grid-cols-2 gap-3\">\n <div className=\"space-y-1.5\">\n <Label htmlFor=\"myb-metric-value\">Value</Label>\n <Input\n id=\"myb-metric-value\"\n type=\"number\"\n inputMode=\"decimal\"\n step=\"any\"\n value={form.value}\n onChange={(e) => setForm((prev) => ({ ...prev, value: e.target.value }))}\n placeholder=\"0\"\n />\n </div>\n <div className=\"space-y-1.5\">\n <Label htmlFor=\"myb-metric-unit\">Unit</Label>\n <Input\n id=\"myb-metric-unit\"\n value={form.unit}\n onChange={(e) => setForm((prev) => ({ ...prev, unit: e.target.value }))}\n placeholder={METRIC_META[form.type].unit}\n />\n </div>\n </div>\n\n <div className=\"space-y-1.5\">\n <Label htmlFor=\"myb-metric-measured\">Measured at</Label>\n <Input\n id=\"myb-metric-measured\"\n type=\"datetime-local\"\n value={form.measuredAt}\n onChange={(e) => setForm((prev) => ({ ...prev, measuredAt: e.target.value }))}\n />\n </div>\n\n <div className=\"space-y-1.5\">\n <Label htmlFor=\"myb-metric-notes\">Notes</Label>\n <Textarea\n id=\"myb-metric-notes\"\n value={form.notes}\n onChange={(e) => setForm((prev) => ({ ...prev, notes: e.target.value }))}\n placeholder=\"Optional context (fasted, post-workout, morning…)\"\n rows={3}\n />\n </div>\n\n {/* Optional progress photo — uploads via useMybFileUpload (byte-progress\n + inline error handled inside EvidenceUpload) and sets photoFileId. */}\n <EvidenceUpload\n id=\"myb-metric-photo\"\n label=\"Progress photo (optional)\"\n value={form.photo}\n onChange={(photo) => setForm((prev) => ({ ...prev, photo }))}\n accept=\"image/*\"\n disabled={record.isPending}\n hint=\"Attach a progress photo for this reading.\"\n />\n\n {formError && <p className=\"text-sm text-status-error-text\">{formError}</p>}\n </div>\n\n <ResponsiveDialogFooter>\n <Button variant=\"outline\" onClick={() => setOpen(false)} disabled={record.isPending}>\n Cancel\n </Button>\n <Button onClick={submit} disabled={record.isPending}>\n {record.isPending ? 'Recording…' : 'Record'}\n </Button>\n </ResponsiveDialogFooter>\n </ResponsiveDialogContent>\n </ResponsiveDialog>\n </PageLayout>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"ProgressPage.js","names":[],"sources":["../../../../src/mybodyshield/pages/progress/ProgressPage.tsx"],"sourcesContent":["/**\n * Progress — body metrics over time.\n * @module mybodyshield/pages/progress\n *\n * A single-metric time-series view over the real `mybListBodyMetrics`\n * endpoint: pick a body-metric type (weight, body-fat, measurements…), see the\n * latest value + trend vs the previous reading, a token-styled line chart of the\n * history window, aggregate stats, and an offset-paginated log table. New\n * readings are recorded through `mybRecordBodyMetric`. No mock data — everything\n * derives from the hooks.\n */\n\nimport { useEffect, useMemo, useState } from 'react';\nimport {\n AreaChart,\n Area,\n XAxis,\n YAxis,\n CartesianGrid,\n Tooltip,\n ReferenceDot,\n ResponsiveContainer,\n} from 'recharts';\nimport { motion, useReducedMotion, type MotionProps } from 'framer-motion';\nimport { Plus, Activity, Sigma, ArrowDownUp } from 'lucide-react';\nimport {\n Button,\n Input,\n Label,\n Textarea,\n GlassCard,\n Select,\n SelectTrigger,\n SelectContent,\n SelectItem,\n SelectValue,\n ResponsiveDialog,\n ResponsiveDialogContent,\n ResponsiveDialogHeader,\n ResponsiveDialogTitle,\n ResponsiveDialogDescription,\n ResponsiveDialogFooter,\n} from '@burdenoff/fe-libs/ui';\nimport {\n PageLayout,\n MetricsCard,\n FilterTabs,\n DataTable,\n Pagination,\n LoadingView,\n ErrorView,\n Section,\n EmptyState,\n EvidenceUpload,\n FileLink,\n type Column,\n type FilterOption,\n} from '../../components';\nimport { IconChip, TrendPill, METRIC_META } from '../_shared/visuals';\nimport {\n useMybBodyMetrics,\n useMybRecordBodyMetric,\n useOffsetPager,\n useTr,\n type UploadedMybFile,\n} from '../../hooks';\nimport type { MybBodyMetric, MybBodyMetricType, MybRecordMetricInput } from '../../types';\nimport {\n formatNumber,\n formatDate,\n formatDateTime,\n formatRelativeTime,\n} from '../../utils/formatters';\n\n// Ordered enum surface for the metric-type selector (METRIC_META is a Record).\nconst METRIC_TYPES: MybBodyMetricType[] = [\n 'WEIGHT',\n 'BODY_FAT',\n 'RESTING_HEART_RATE',\n 'WAIST',\n 'CHEST',\n 'HIPS',\n 'ARM',\n 'THIGH',\n];\n\n// Which direction of change is \"good\" per metric (drives TrendPill colouring).\nconst GOOD_DIRECTION: Record<MybBodyMetricType, 'up' | 'down'> = {\n WEIGHT: 'down',\n BODY_FAT: 'down',\n RESTING_HEART_RATE: 'down',\n WAIST: 'down',\n HIPS: 'down',\n CHEST: 'up',\n ARM: 'up',\n THIGH: 'up',\n};\n\n// Window used for the chart / KPIs / aggregates (the log table paginates on top).\nconst CHART_WINDOW = 100;\nconst PAGE_SIZE = 25;\n\n// Brand emerald accent — the dominant color for the area chart, line & endpoint.\nconst CHART_ACCENT = 'var(--color-action-primary-bg)';\n\ninterface RecordForm {\n type: MybBodyMetricType;\n value: string;\n unit: string;\n measuredAt: string;\n notes: string;\n photo: UploadedMybFile | null;\n}\n\n/** A `Date` → `<input type=\"datetime-local\">` value (local wall-clock time). */\nconst toLocalInput = (d: Date): string => {\n const pad = (n: number) => String(n).padStart(2, '0');\n return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())}T${pad(d.getHours())}:${pad(d.getMinutes())}`;\n};\n\nconst makeForm = (type: MybBodyMetricType): RecordForm => ({\n type,\n value: '',\n unit: METRIC_META[type].unit,\n measuredAt: toLocalInput(new Date()),\n notes: '',\n photo: null,\n});\n\n/** Localised label for a body-metric enum value. */\nfunction metricLabel(t: ReturnType<typeof useTr>, type: MybBodyMetricType): string {\n const keyRoot = 'mybodyshield.pages.progress.metricNames';\n switch (type) {\n case 'WEIGHT':\n return t(`${keyRoot}.weight`, 'Weight');\n case 'BODY_FAT':\n return t(`${keyRoot}.bodyFat`, 'Body fat');\n case 'RESTING_HEART_RATE':\n return t(`${keyRoot}.restingHeartRate`, 'Resting heart rate');\n case 'WAIST':\n return t(`${keyRoot}.waist`, 'Waist');\n case 'CHEST':\n return t(`${keyRoot}.chest`, 'Chest');\n case 'HIPS':\n return t(`${keyRoot}.hips`, 'Hips');\n case 'ARM':\n return t(`${keyRoot}.arm`, 'Arm');\n case 'THIGH':\n return t(`${keyRoot}.thigh`, 'Thigh');\n }\n}\n\nexport function ProgressPage() {\n const t = useTr();\n const [selectedType, setSelectedType] = useState<MybBodyMetricType>('WEIGHT');\n const [open, setOpen] = useState(false);\n const [form, setForm] = useState<RecordForm>(() => makeForm('WEIGHT'));\n const [formError, setFormError] = useState<string | null>(null);\n\n const pager = useOffsetPager(PAGE_SIZE);\n\n // Reset the log table to page 1 whenever the metric type changes.\n // Depend on the stable `pager.reset` (NOT the whole pager, whose identity\n // changes with `page`) so advancing pages doesn't snap back to page 1.\n const resetPager = pager.reset;\n useEffect(() => {\n resetPager();\n }, [selectedType, resetPager]);\n\n // Wide window drives the chart, latest/trend KPIs and aggregate stats.\n const history = useMybBodyMetrics({\n type: selectedType,\n pagination: { limit: CHART_WINDOW },\n });\n // Independent offset-paginated slice powers the log table.\n const table = useMybBodyMetrics({\n type: selectedType,\n pagination: { limit: PAGE_SIZE, offset: pager.offset },\n });\n const record = useMybRecordBodyMetric();\n\n const reduced = useReducedMotion();\n const rise = (delay: number, hover = true): MotionProps =>\n reduced\n ? { initial: false }\n : {\n initial: { opacity: 0, y: 14 },\n animate: { opacity: 1, y: 0 },\n transition: { duration: 0.45, delay, ease: 'easeOut' },\n ...(hover\n ? {\n whileHover: {\n y: -3,\n transition: { type: 'spring', stiffness: 300, damping: 22 },\n },\n }\n : {}),\n };\n\n const meta = METRIC_META[selectedType];\n const MetricIcon = meta.icon;\n const goodDir = GOOD_DIRECTION[selectedType];\n const selectedMetricLabel = metricLabel(t, selectedType);\n\n const historyRows = useMemo<MybBodyMetric[]>(() => history.data?.items ?? [], [history.data]);\n\n // Ascending by measuredAt → chart series + robust latest/prior derivation.\n const ascending = useMemo(\n () =>\n [...historyRows].sort(\n (a, b) => new Date(a.measuredAt).getTime() - new Date(b.measuredAt).getTime()\n ),\n [historyRows]\n );\n\n const latest = ascending[ascending.length - 1];\n const prior = ascending[ascending.length - 2];\n const delta = latest && prior ? latest.value - prior.value : undefined;\n\n const chartData = useMemo(\n () => ascending.map((m) => ({ label: formatDate(m.measuredAt), value: m.value })),\n [ascending]\n );\n const lastPoint = chartData.length > 0 ? chartData[chartData.length - 1] : undefined;\n\n const stats = useMemo(() => {\n if (ascending.length === 0) return null;\n const values = ascending.map((m) => m.value);\n return {\n count: values.length,\n min: Math.min(...values),\n max: Math.max(...values),\n avg: values.reduce((a, b) => a + b, 0) / values.length,\n };\n }, [ascending]);\n\n const metricOptions: FilterOption<MybBodyMetricType>[] = METRIC_TYPES.map((type) => ({\n value: type,\n label: metricLabel(t, type),\n }));\n\n const openRecord = () => {\n setForm(makeForm(selectedType));\n setFormError(null);\n setOpen(true);\n };\n\n const submit = async () => {\n const numValue = Number(form.value);\n if (form.value.trim() === '' || !Number.isFinite(numValue)) {\n setFormError(\n t('mybodyshield.pages.progress.invalidValue', 'Enter a valid measurement value.')\n );\n return;\n }\n setFormError(null);\n const input: MybRecordMetricInput = {\n type: form.type,\n value: numValue,\n unit: form.unit.trim() || METRIC_META[form.type].unit,\n measuredAt: form.measuredAt\n ? new Date(form.measuredAt).toISOString()\n : new Date().toISOString(),\n notes: form.notes.trim() ? form.notes.trim() : null,\n photoFileId: form.photo?.fileId ?? null,\n };\n try {\n await record.mutateAsync(input);\n setOpen(false);\n // Surface the just-recorded type so the new reading is visible immediately.\n setSelectedType(form.type);\n pager.reset();\n } catch (e) {\n setFormError(\n e instanceof Error\n ? e.message\n : t('mybodyshield.pages.progress.failedToRecord', 'Failed to record measurement.')\n );\n }\n };\n\n const tableRows = table.data?.items ?? [];\n const tableColumns: Column<MybBodyMetric>[] = [\n {\n key: 'value',\n header: t('mybodyshield.pages.progress.valueColumn', 'Value'),\n align: 'right',\n sortValue: (row) => row.value,\n render: (row) => (\n <span className=\"font-medium tabular-nums text-text-primary\">\n {formatNumber(row.value)}\n <span className=\"ml-1 text-xs font-normal text-text-tertiary\">{row.unit}</span>\n </span>\n ),\n },\n {\n key: 'measuredAt',\n header: t('mybodyshield.pages.progress.measuredColumn', 'Measured'),\n sortValue: (row) => new Date(row.measuredAt).getTime(),\n render: (row) => (\n <span className=\"whitespace-nowrap text-text-secondary\">\n {formatDateTime(row.measuredAt)}\n </span>\n ),\n },\n {\n key: 'notes',\n header: t('mybodyshield.pages.progress.notesColumn', 'Notes'),\n hideOnMobile: true,\n render: (row) =>\n row.notes ? (\n <span className=\"text-text-secondary\">{row.notes}</span>\n ) : (\n <span className=\"text-text-tertiary\">—</span>\n ),\n },\n {\n key: 'photo',\n header: t('mybodyshield.pages.progress.photoColumn', 'Photo'),\n render: (row) =>\n row.photo?.id ? (\n <FileLink fileId={row.photo.id} />\n ) : (\n <span className=\"text-text-tertiary\">—</span>\n ),\n },\n ];\n\n const recordButton = (\n <Button onClick={openRecord}>\n <Plus className=\"mr-1.5 h-4 w-4\" />{' '}\n {t('mybodyshield.pages.progress.recordMeasurement', 'Record measurement')}\n </Button>\n );\n\n return (\n <PageLayout\n title={t('mybodyshield.pages.progress.title', 'Progress')}\n description={t(\n 'mybodyshield.pages.progress.description',\n 'Body metrics over time — weight, composition & measurements.'\n )}\n actions={recordButton}\n >\n {/* Metric-type selector */}\n <div className=\"mb-6 overflow-x-auto\">\n <FilterTabs options={metricOptions} value={selectedType} onChange={setSelectedType} />\n </div>\n\n {history.isLoading && historyRows.length === 0 ? (\n <LoadingView\n label={t('mybodyshield.pages.progress.loading', 'Loading {{metric}} history…', {\n metric: selectedMetricLabel.toLowerCase(),\n })}\n />\n ) : history.isError ? (\n <ErrorView\n message={t(\n 'mybodyshield.pages.progress.error',\n \"We couldn't load your body-metric history.\"\n )}\n onRetry={() => history.refetch()}\n />\n ) : historyRows.length === 0 ? (\n <EmptyState\n illustration=\"empty-data\"\n icon={<MetricIcon className=\"h-10 w-10\" />}\n title={t('mybodyshield.pages.progress.emptyTitle', 'No {{metric}} readings yet', {\n metric: selectedMetricLabel.toLowerCase(),\n })}\n description={t(\n 'mybodyshield.pages.progress.emptyDescription',\n 'Record a measurement to start tracking this metric over time.'\n )}\n action={\n <Button onClick={openRecord}>\n <Plus className=\"mr-1.5 h-4 w-4\" />{' '}\n {t('mybodyshield.pages.progress.recordMeasurement', 'Record measurement')}\n </Button>\n }\n />\n ) : (\n <div className=\"space-y-6\">\n {/* Latest + trend + chart */}\n <motion.div {...rise(0)}>\n <GlassCard\n treatment=\"glass\"\n className=\"rounded-2xl p-6 transition-shadow duration-300 hover:shadow-2xl\"\n >\n <div className=\"flex flex-wrap items-start justify-between gap-4\">\n <div className=\"flex items-center gap-3\">\n <IconChip icon={<MetricIcon className=\"h-5 w-5\" />} tint={meta.tint} />\n <div>\n <h2 className=\"text-base font-semibold text-text-primary\">\n {selectedMetricLabel}\n </h2>\n <p className=\"text-sm text-text-secondary\">\n {latest\n ? t('mybodyshield.pages.progress.lastMeasured', 'Last measured {{time}}', {\n time: formatRelativeTime(latest.measuredAt),\n })\n : t('mybodyshield.pages.progress.noMeasurements', 'No measurements yet')}\n </p>\n </div>\n </div>\n <div className=\"text-right\">\n <p className=\"text-3xl font-bold leading-none tracking-tight tabular-nums text-text-primary sm:text-4xl\">\n {latest ? formatNumber(latest.value) : '—'}\n {latest && (\n <span className=\"ml-1 text-base font-medium text-text-tertiary\">\n {meta.unit}\n </span>\n )}\n </p>\n {delta != null && (\n <div className=\"mt-2 flex justify-end\">\n <span className=\"inline-flex items-center rounded-full bg-bg-sunken px-2.5 py-1 ring-1 ring-border-seam\">\n <TrendPill delta={delta} unit={` ${meta.unit}`} goodDirection={goodDir} />\n </span>\n </div>\n )}\n </div>\n </div>\n\n <div className=\"mt-6 h-64 w-full\">\n <ResponsiveContainer width=\"100%\" height=\"100%\">\n <AreaChart data={chartData} margin={{ top: 8, right: 14, bottom: 4, left: -8 }}>\n <defs>\n <linearGradient id=\"myb-progress-fill\" x1=\"0\" y1=\"0\" x2=\"0\" y2=\"1\">\n <stop offset=\"0%\" stopColor={CHART_ACCENT} stopOpacity={0.38} />\n <stop offset=\"55%\" stopColor={CHART_ACCENT} stopOpacity={0.12} />\n <stop offset=\"100%\" stopColor={CHART_ACCENT} stopOpacity={0} />\n </linearGradient>\n </defs>\n <CartesianGrid\n stroke=\"var(--color-border-seam)\"\n strokeDasharray=\"4 4\"\n vertical={false}\n />\n <XAxis\n dataKey=\"label\"\n stroke=\"var(--color-border-seam)\"\n tickLine={false}\n axisLine={false}\n tick={{ fill: 'var(--color-text-tertiary)', fontSize: 12 }}\n tickMargin={8}\n minTickGap={24}\n />\n <YAxis\n stroke=\"var(--color-border-seam)\"\n tickLine={false}\n axisLine={false}\n tick={{ fill: 'var(--color-text-tertiary)', fontSize: 12 }}\n width={44}\n domain={['auto', 'auto']}\n />\n <Tooltip\n cursor={{ stroke: 'var(--color-border-seam)', strokeDasharray: '4 4' }}\n contentStyle={{\n background: 'var(--color-bg-surface)',\n border: '1px solid var(--color-border-seam)',\n borderRadius: 12,\n color: 'var(--color-text-primary)',\n }}\n labelStyle={{ color: 'var(--color-text-tertiary)' }}\n itemStyle={{ color: 'var(--color-text-primary)' }}\n formatter={(value) => [\n `${formatNumber(Number(value))} ${meta.unit}`,\n selectedMetricLabel,\n ]}\n />\n <Area\n type=\"monotone\"\n dataKey=\"value\"\n name={selectedMetricLabel}\n stroke={CHART_ACCENT}\n strokeWidth={2.5}\n fill=\"url(#myb-progress-fill)\"\n fillOpacity={1}\n dot={false}\n activeDot={{\n r: 5,\n strokeWidth: 2,\n stroke: 'var(--color-bg-surface)',\n fill: CHART_ACCENT,\n }}\n isAnimationActive={!reduced}\n animationDuration={900}\n />\n {lastPoint && (\n <ReferenceDot\n x={lastPoint.label}\n y={lastPoint.value}\n r={12}\n isFront\n ifOverflow=\"visible\"\n fill={CHART_ACCENT}\n fillOpacity={0.16}\n stroke=\"none\"\n />\n )}\n {lastPoint && (\n <ReferenceDot\n x={lastPoint.label}\n y={lastPoint.value}\n r={5}\n isFront\n ifOverflow=\"visible\"\n fill={CHART_ACCENT}\n stroke=\"var(--color-bg-surface)\"\n strokeWidth={2}\n />\n )}\n </AreaChart>\n </ResponsiveContainer>\n </div>\n </GlassCard>\n </motion.div>\n\n {/* Aggregate stats over the loaded window (not full history) */}\n {stats && (\n <div>\n <div className=\"grid grid-cols-1 gap-4 sm:grid-cols-3\">\n <motion.div {...rise(0.08)}>\n <MetricsCard\n className=\"h-full rounded-2xl transition-shadow duration-300 hover:shadow-xl\"\n icon={<IconChip icon={<Activity className=\"h-5 w-5\" />} tint={CHART_ACCENT} />}\n value={formatNumber(stats.count)}\n label={t('mybodyshield.pages.progress.recentReadings', 'Recent readings')}\n />\n </motion.div>\n <motion.div {...rise(0.14)}>\n <MetricsCard\n className=\"h-full rounded-2xl transition-shadow duration-300 hover:shadow-xl\"\n icon={<IconChip icon={<Sigma className=\"h-5 w-5\" />} tint={CHART_ACCENT} />}\n value={`${formatNumber(stats.avg, { maximumFractionDigits: 1 })} ${meta.unit}`}\n label={t(\n 'mybodyshield.pages.progress.windowAverage',\n 'Window average {{metric}}',\n { metric: selectedMetricLabel.toLowerCase() }\n )}\n />\n </motion.div>\n <motion.div {...rise(0.2)}>\n <MetricsCard\n className=\"h-full rounded-2xl transition-shadow duration-300 hover:shadow-xl\"\n icon={\n <IconChip icon={<ArrowDownUp className=\"h-5 w-5\" />} tint={CHART_ACCENT} />\n }\n value={`${formatNumber(stats.min)}–${formatNumber(stats.max)}`}\n label={t('mybodyshield.pages.progress.windowRange', 'Window range ({{unit}})', {\n unit: meta.unit,\n })}\n />\n </motion.div>\n </div>\n <p className=\"mt-2 text-xs text-text-tertiary\">\n {t(\n 'mybodyshield.pages.progress.basedOnReadings',\n 'Based on your most recent {{count}} {{metric}} reading{{plural}} (up to {{limit}}) — not a full-history total.',\n {\n count: formatNumber(stats.count),\n metric: selectedMetricLabel.toLowerCase(),\n plural: stats.count === 1 ? '' : 's',\n limit: formatNumber(CHART_WINDOW),\n }\n )}\n </p>\n </div>\n )}\n\n {/* Full measurement log */}\n <motion.div {...rise(0.26, false)}>\n <Section\n title={t('mybodyshield.pages.progress.measurementLog', 'Measurement log')}\n description={t(\n 'mybodyshield.pages.progress.measurementLogDescription',\n 'Every recorded reading for this metric.'\n )}\n >\n {table.isError ? (\n <ErrorView\n message={t(\n 'mybodyshield.pages.progress.pageError',\n \"We couldn't load this page of measurements.\"\n )}\n onRetry={() => table.refetch()}\n />\n ) : table.isLoading && tableRows.length === 0 ? (\n <div className=\"py-8 text-center text-sm text-text-secondary\">\n {t('mybodyshield.pages.progress.pageLoading', 'Loading measurements…')}\n </div>\n ) : tableRows.length === 0 ? (\n <EmptyState\n illustration=\"empty-data\"\n icon={<MetricIcon className=\"h-10 w-10\" />}\n title={t(\n 'mybodyshield.pages.progress.pageEmptyTitle',\n 'No measurements on this page'\n )}\n description={t(\n 'mybodyshield.pages.progress.pageEmptyDescription',\n 'Go back a page or record a new measurement.'\n )}\n />\n ) : (\n <>\n <DataTable\n columns={tableColumns}\n rows={tableRows}\n rowKey={(row) => row.id}\n defaultSort={{ key: 'measuredAt', dir: 'desc' }}\n />\n <Pagination\n page={pager.page}\n pageSize={PAGE_SIZE}\n itemCount={tableRows.length}\n hasMore={table.data?.pageInfo?.hasMore ?? false}\n onPageChange={(t) => pager.onPageChange(t)}\n />\n </>\n )}\n </Section>\n </motion.div>\n </div>\n )}\n\n {/* Record-measurement dialog */}\n <ResponsiveDialog open={open} onOpenChange={setOpen}>\n <ResponsiveDialogContent>\n <ResponsiveDialogHeader>\n <ResponsiveDialogTitle>\n {t('mybodyshield.pages.progress.dialogTitle', 'Record measurement')}\n </ResponsiveDialogTitle>\n <ResponsiveDialogDescription>\n {t(\n 'mybodyshield.pages.progress.dialogDescription',\n 'Log a new body-metric reading to track your progress over time.'\n )}\n </ResponsiveDialogDescription>\n </ResponsiveDialogHeader>\n\n <div className=\"space-y-4 py-2\">\n <div className=\"space-y-1.5\">\n <Label htmlFor=\"myb-metric-type\">\n {t('mybodyshield.pages.progress.metric', 'Metric')}\n </Label>\n <Select\n value={form.type}\n onValueChange={(v) => {\n // `v` is constrained to METRIC_TYPES by the SelectItems below.\n const nextType = v as MybBodyMetricType;\n setForm((prev) => ({\n ...prev,\n type: nextType,\n unit: METRIC_META[nextType].unit,\n }));\n }}\n >\n <SelectTrigger id=\"myb-metric-type\">\n <SelectValue\n placeholder={t(\n 'mybodyshield.pages.progress.selectMetricPlaceholder',\n 'Select a metric'\n )}\n />\n </SelectTrigger>\n <SelectContent>\n {METRIC_TYPES.map((type) => (\n <SelectItem key={type} value={type}>\n {metricLabel(t, type)}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n\n <div className=\"grid grid-cols-2 gap-3\">\n <div className=\"space-y-1.5\">\n <Label htmlFor=\"myb-metric-value\">\n {t('mybodyshield.pages.progress.value', 'Value')}\n </Label>\n <Input\n id=\"myb-metric-value\"\n type=\"number\"\n inputMode=\"decimal\"\n step=\"any\"\n value={form.value}\n onChange={(e) => setForm((prev) => ({ ...prev, value: e.target.value }))}\n placeholder=\"0\"\n />\n </div>\n <div className=\"space-y-1.5\">\n <Label htmlFor=\"myb-metric-unit\">{t('mybodyshield.common.unit', 'Unit')}</Label>\n <Input\n id=\"myb-metric-unit\"\n value={form.unit}\n onChange={(e) => setForm((prev) => ({ ...prev, unit: e.target.value }))}\n placeholder={METRIC_META[form.type].unit}\n />\n </div>\n </div>\n\n <div className=\"space-y-1.5\">\n <Label htmlFor=\"myb-metric-measured\">\n {t('mybodyshield.pages.progress.measuredAt', 'Measured at')}\n </Label>\n <Input\n id=\"myb-metric-measured\"\n type=\"datetime-local\"\n value={form.measuredAt}\n onChange={(e) => setForm((prev) => ({ ...prev, measuredAt: e.target.value }))}\n />\n </div>\n\n <div className=\"space-y-1.5\">\n <Label htmlFor=\"myb-metric-notes\">{t('mybodyshield.common.notes', 'Notes')}</Label>\n <Textarea\n id=\"myb-metric-notes\"\n value={form.notes}\n onChange={(e) => setForm((prev) => ({ ...prev, notes: e.target.value }))}\n placeholder={t(\n 'mybodyshield.pages.progress.notesPlaceholder',\n 'Optional context (fasted, post-workout, morning…)'\n )}\n rows={3}\n />\n </div>\n\n {/* Optional progress photo — uploads via useMybFileUpload (byte-progress\n + inline error handled inside EvidenceUpload) and sets photoFileId. */}\n <EvidenceUpload\n id=\"myb-metric-photo\"\n label={t('mybodyshield.pages.progress.progressPhoto', 'Progress photo (optional)')}\n value={form.photo}\n onChange={(photo) => setForm((prev) => ({ ...prev, photo }))}\n accept=\"image/*\"\n disabled={record.isPending}\n hint={t(\n 'mybodyshield.pages.progress.progressPhotoHint',\n 'Attach a progress photo for this reading.'\n )}\n />\n\n {formError && <p className=\"text-sm text-status-error-text\">{formError}</p>}\n </div>\n\n <ResponsiveDialogFooter>\n <Button variant=\"outline\" onClick={() => setOpen(false)} disabled={record.isPending}>\n {t('mybodyshield.common.cancel', 'Cancel')}\n </Button>\n <Button onClick={submit} disabled={record.isPending}>\n {record.isPending\n ? t('mybodyshield.common.recording', 'Recording…')\n : t('mybodyshield.pages.progress.record', 'Record')}\n </Button>\n </ResponsiveDialogFooter>\n </ResponsiveDialogContent>\n </ResponsiveDialog>\n </PageLayout>\n );\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"RecoveryPage.d.ts","sourceRoot":"","sources":["../../../../src/mybodyshield/pages/recovery/RecoveryPage.tsx"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AA+FH,wBAAgB,YAAY,gCA4hB3B"}
1
+ {"version":3,"file":"RecoveryPage.d.ts","sourceRoot":"","sources":["../../../../src/mybodyshield/pages/recovery/RecoveryPage.tsx"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AA2GH,wBAAgB,YAAY,gCA2nB3B"}