@burdenoff/microfe-mybodyshield 2026.706.2 → 2026.713.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 (152) hide show
  1. package/dist/dev/main.d.ts +2 -0
  2. package/dist/dev/main.d.ts.map +1 -0
  3. package/dist/generated/global-operations.d.ts +2 -0
  4. package/dist/generated/global-operations.d.ts.map +1 -0
  5. package/dist/generated/global-types.d.ts +18199 -0
  6. package/dist/generated/global-types.d.ts.map +1 -0
  7. package/dist/generated/wspace-operations.d.ts +2 -0
  8. package/dist/generated/wspace-operations.d.ts.map +1 -0
  9. package/dist/generated/wspace-types.d.ts +43046 -0
  10. package/dist/generated/wspace-types.d.ts.map +1 -0
  11. package/dist/index.d.ts +3 -0
  12. package/dist/index.d.ts.map +1 -0
  13. package/dist/index.js +2 -1
  14. package/dist/mybodyshield/MyBodyShieldRoot.d.ts +5 -0
  15. package/dist/mybodyshield/MyBodyShieldRoot.d.ts.map +1 -0
  16. package/dist/mybodyshield/MyBodyShieldRoutes.d.ts +4 -0
  17. package/dist/mybodyshield/MyBodyShieldRoutes.d.ts.map +1 -0
  18. package/dist/mybodyshield/MyBodyShieldRoutes.js +77 -36
  19. package/dist/mybodyshield/MyBodyShieldRoutes.js.map +1 -1
  20. package/dist/mybodyshield/components/DataTable.d.ts +28 -0
  21. package/dist/mybodyshield/components/DataTable.d.ts.map +1 -0
  22. package/dist/mybodyshield/components/EmptyState.d.ts +18 -0
  23. package/dist/mybodyshield/components/EmptyState.d.ts.map +1 -0
  24. package/dist/mybodyshield/components/EvidenceUpload.d.ts +14 -0
  25. package/dist/mybodyshield/components/EvidenceUpload.d.ts.map +1 -0
  26. package/dist/mybodyshield/components/FeatureFlagGuard.d.ts +11 -0
  27. package/dist/mybodyshield/components/FeatureFlagGuard.d.ts.map +1 -0
  28. package/dist/mybodyshield/components/FeatureFlagGuard.js +27 -0
  29. package/dist/mybodyshield/components/FeatureFlagGuard.js.map +1 -0
  30. package/dist/mybodyshield/components/FileLink.d.ts +15 -0
  31. package/dist/mybodyshield/components/FileLink.d.ts.map +1 -0
  32. package/dist/mybodyshield/components/FilterTabs.d.ts +18 -0
  33. package/dist/mybodyshield/components/FilterTabs.d.ts.map +1 -0
  34. package/dist/mybodyshield/components/MetricsCard.d.ts +23 -0
  35. package/dist/mybodyshield/components/MetricsCard.d.ts.map +1 -0
  36. package/dist/mybodyshield/components/MiniBar.d.ts +16 -0
  37. package/dist/mybodyshield/components/MiniBar.d.ts.map +1 -0
  38. package/dist/mybodyshield/components/MybDiscussion.d.ts +18 -0
  39. package/dist/mybodyshield/components/MybDiscussion.d.ts.map +1 -0
  40. package/dist/mybodyshield/components/MybDiscussion.js +5 -5
  41. package/dist/mybodyshield/components/MybTags.d.ts +17 -0
  42. package/dist/mybodyshield/components/MybTags.d.ts.map +1 -0
  43. package/dist/mybodyshield/components/PageDisabled.d.ts +9 -0
  44. package/dist/mybodyshield/components/PageDisabled.d.ts.map +1 -0
  45. package/dist/mybodyshield/components/PageDisabled.js +17 -0
  46. package/dist/mybodyshield/components/PageDisabled.js.map +1 -0
  47. package/dist/mybodyshield/components/PageLayout.d.ts +16 -0
  48. package/dist/mybodyshield/components/PageLayout.d.ts.map +1 -0
  49. package/dist/mybodyshield/components/Pagination.d.ts +22 -0
  50. package/dist/mybodyshield/components/Pagination.d.ts.map +1 -0
  51. package/dist/mybodyshield/components/StateViews.d.ts +25 -0
  52. package/dist/mybodyshield/components/StateViews.d.ts.map +1 -0
  53. package/dist/mybodyshield/components/StateViews.js +2 -1
  54. package/dist/mybodyshield/components/StateViews.js.map +1 -1
  55. package/dist/mybodyshield/components/StatusBadge.d.ts +9 -0
  56. package/dist/mybodyshield/components/StatusBadge.d.ts.map +1 -0
  57. package/dist/mybodyshield/components/Tabs.d.ts +17 -0
  58. package/dist/mybodyshield/components/Tabs.d.ts.map +1 -0
  59. package/dist/mybodyshield/components/UserSearchSelect.d.ts +28 -0
  60. package/dist/mybodyshield/components/UserSearchSelect.d.ts.map +1 -0
  61. package/dist/mybodyshield/components/index.d.ts +22 -0
  62. package/dist/mybodyshield/components/index.d.ts.map +1 -0
  63. package/dist/mybodyshield/components/index.js +4 -2
  64. package/dist/mybodyshield/context/MyBodyShieldContext.d.ts +16 -0
  65. package/dist/mybodyshield/context/MyBodyShieldContext.d.ts.map +1 -0
  66. package/dist/mybodyshield/context/index.d.ts +6 -0
  67. package/dist/mybodyshield/context/index.d.ts.map +1 -0
  68. package/dist/mybodyshield/hooks/index.d.ts +12 -0
  69. package/dist/mybodyshield/hooks/index.d.ts.map +1 -0
  70. package/dist/mybodyshield/hooks/index.js +1 -0
  71. package/dist/mybodyshield/hooks/useMyBodyShieldAnalytics.d.ts +21 -0
  72. package/dist/mybodyshield/hooks/useMyBodyShieldAnalytics.d.ts.map +1 -0
  73. package/dist/mybodyshield/hooks/useMyBodyShieldAnalytics.js +35 -0
  74. package/dist/mybodyshield/hooks/useMyBodyShieldAnalytics.js.map +1 -0
  75. package/dist/mybodyshield/hooks/useMyBodyShieldApi.d.ts +83 -0
  76. package/dist/mybodyshield/hooks/useMyBodyShieldApi.d.ts.map +1 -0
  77. package/dist/mybodyshield/hooks/useMybComments.d.ts +36 -0
  78. package/dist/mybodyshield/hooks/useMybComments.d.ts.map +1 -0
  79. package/dist/mybodyshield/hooks/useMybFiles.d.ts +47 -0
  80. package/dist/mybodyshield/hooks/useMybFiles.d.ts.map +1 -0
  81. package/dist/mybodyshield/hooks/useMybTags.d.ts +44 -0
  82. package/dist/mybodyshield/hooks/useMybTags.d.ts.map +1 -0
  83. package/dist/mybodyshield/hooks/useMybUsers.d.ts +27 -0
  84. package/dist/mybodyshield/hooks/useMybUsers.d.ts.map +1 -0
  85. package/dist/mybodyshield/hooks/usePager.d.ts +29 -0
  86. package/dist/mybodyshield/hooks/usePager.d.ts.map +1 -0
  87. package/dist/mybodyshield/index.d.ts +9 -0
  88. package/dist/mybodyshield/index.d.ts.map +1 -0
  89. package/dist/mybodyshield/pages/DashboardPage.d.ts +10 -0
  90. package/dist/mybodyshield/pages/DashboardPage.d.ts.map +1 -0
  91. package/dist/mybodyshield/pages/DashboardPage.js +91 -86
  92. package/dist/mybodyshield/pages/DashboardPage.js.map +1 -1
  93. package/dist/mybodyshield/pages/_shared/visuals.d.ts +77 -0
  94. package/dist/mybodyshield/pages/_shared/visuals.d.ts.map +1 -0
  95. package/dist/mybodyshield/pages/coaching/CoachingPage.d.ts +11 -0
  96. package/dist/mybodyshield/pages/coaching/CoachingPage.d.ts.map +1 -0
  97. package/dist/mybodyshield/pages/coaching/CoachingPage.js +60 -60
  98. package/dist/mybodyshield/pages/goals/GoalsPage.d.ts +11 -0
  99. package/dist/mybodyshield/pages/goals/GoalsPage.d.ts.map +1 -0
  100. package/dist/mybodyshield/pages/goals/GoalsPage.js +125 -125
  101. package/dist/mybodyshield/pages/goals/GoalsPage.js.map +1 -1
  102. package/dist/mybodyshield/pages/nutrition/NutritionPage.d.ts +13 -0
  103. package/dist/mybodyshield/pages/nutrition/NutritionPage.d.ts.map +1 -0
  104. package/dist/mybodyshield/pages/nutrition/NutritionPage.js +129 -129
  105. package/dist/mybodyshield/pages/nutrition/NutritionPage.js.map +1 -1
  106. package/dist/mybodyshield/pages/programs/ProgramDetailPage.d.ts +10 -0
  107. package/dist/mybodyshield/pages/programs/ProgramDetailPage.d.ts.map +1 -0
  108. package/dist/mybodyshield/pages/programs/ProgramDetailPage.js +218 -191
  109. package/dist/mybodyshield/pages/programs/ProgramDetailPage.js.map +1 -1
  110. package/dist/mybodyshield/pages/programs/ProgramsPage.d.ts +11 -0
  111. package/dist/mybodyshield/pages/programs/ProgramsPage.d.ts.map +1 -0
  112. package/dist/mybodyshield/pages/programs/ProgramsPage.js +197 -193
  113. package/dist/mybodyshield/pages/programs/ProgramsPage.js.map +1 -1
  114. package/dist/mybodyshield/pages/progress/ProgressPage.d.ts +13 -0
  115. package/dist/mybodyshield/pages/progress/ProgressPage.d.ts.map +1 -0
  116. package/dist/mybodyshield/pages/progress/ProgressPage.js +143 -143
  117. package/dist/mybodyshield/pages/progress/ProgressPage.js.map +1 -1
  118. package/dist/mybodyshield/pages/recovery/RecoveryPage.d.ts +11 -0
  119. package/dist/mybodyshield/pages/recovery/RecoveryPage.d.ts.map +1 -0
  120. package/dist/mybodyshield/pages/recovery/RecoveryPage.js +60 -60
  121. package/dist/mybodyshield/pages/recovery/RecoveryPage.js.map +1 -1
  122. package/dist/mybodyshield/pages/train/SessionDetailPage.d.ts +11 -0
  123. package/dist/mybodyshield/pages/train/SessionDetailPage.d.ts.map +1 -0
  124. package/dist/mybodyshield/pages/train/SessionDetailPage.js +184 -181
  125. package/dist/mybodyshield/pages/train/SessionDetailPage.js.map +1 -1
  126. package/dist/mybodyshield/pages/train/SessionsPage.d.ts +11 -0
  127. package/dist/mybodyshield/pages/train/SessionsPage.d.ts.map +1 -0
  128. package/dist/mybodyshield/pages/train/SessionsPage.js +119 -115
  129. package/dist/mybodyshield/pages/train/SessionsPage.js.map +1 -1
  130. package/dist/mybodyshield/services/createSandboxAssistantTransport.d.ts +24 -0
  131. package/dist/mybodyshield/services/createSandboxAssistantTransport.d.ts.map +1 -0
  132. package/dist/mybodyshield/services/createSandboxAssistantTransport.js +14 -0
  133. package/dist/mybodyshield/services/createSandboxAssistantTransport.js.map +1 -0
  134. package/dist/mybodyshield/types/assistant.d.ts +55 -0
  135. package/dist/mybodyshield/types/assistant.d.ts.map +1 -0
  136. package/dist/mybodyshield/types/index.d.ts +419 -0
  137. package/dist/mybodyshield/types/index.d.ts.map +1 -0
  138. package/dist/mybodyshield/utils/cn.d.ts +4 -0
  139. package/dist/mybodyshield/utils/cn.d.ts.map +1 -0
  140. package/dist/mybodyshield/utils/formatters.d.ts +32 -0
  141. package/dist/mybodyshield/utils/formatters.d.ts.map +1 -0
  142. package/dist/mybodyshield/utils/i18n.d.ts +6 -0
  143. package/dist/mybodyshield/utils/i18n.d.ts.map +1 -0
  144. package/dist/mybodyshield/utils/index.d.ts +9 -0
  145. package/dist/mybodyshield/utils/index.d.ts.map +1 -0
  146. package/dist/mybodyshield/utils/navigation.d.ts +14 -0
  147. package/dist/mybodyshield/utils/navigation.d.ts.map +1 -0
  148. package/dist/mybodyshield/utils/pageContext.d.ts +28 -0
  149. package/dist/mybodyshield/utils/pageContext.d.ts.map +1 -0
  150. package/dist/mybodyshield/utils/pageContext.js +62 -0
  151. package/dist/mybodyshield/utils/pageContext.js.map +1 -0
  152. package/package.json +8 -2
@@ -1 +1 @@
1
- {"version":3,"file":"DashboardPage.js","names":[],"sources":["../../../src/mybodyshield/pages/DashboardPage.tsx"],"sourcesContent":["/**\n * Dashboard — MyBodyShield health & fitness overview.\n * @module mybodyshield/pages\n *\n * KPIs are aggregated client-side from the real `myb*` list endpoints:\n * active programs, this-week's sessions, goal progress, today's macros vs\n * target, latest body weight and recovery readiness. No mock data.\n */\n\nimport { useMemo } from 'react';\nimport type { ReactNode } from 'react';\nimport { motion, useReducedMotion } from 'framer-motion';\nimport {\n Dumbbell,\n Flame,\n Target,\n Salad,\n Moon,\n ArrowRight,\n CheckCircle2,\n Weight,\n CalendarCheck,\n} from 'lucide-react';\nimport { GlassCard } from '@burdenoff/fe-libs/ui';\nimport { PageLayout } from '../components/PageLayout';\nimport { MetricsCard } from '../components/MetricsCard';\nimport { StatusBadge } from '../components/StatusBadge';\nimport { MiniBar } from '../components/MiniBar';\nimport { LoadingView, Section } from '../components/StateViews';\nimport { EmptyState } from '../components/EmptyState';\nimport {\n Meter,\n ProgressRing,\n MacroBar,\n MacroLegend,\n IconChip,\n GOAL_TYPE_META,\n RECOVERY_META,\n WORKOUT_TYPE_META,\n computeGoalProgress,\n} from './_shared/visuals';\nimport { useMyBodyShield } from '../context';\nimport {\n useMybPrograms,\n useMybSessions,\n useMybGoals,\n useMybDailyMacros,\n useMybBodyMetrics,\n useMybRecoveryLogs,\n} from '../hooks';\nimport {\n formatNumber,\n formatRelativeTime,\n formatKcal,\n formatWeight,\n formatPercent,\n formatEnumLabel,\n} from '../utils/formatters';\n\n/** Shared easing for entrance / hover motion (smooth ease-out). */\nconst EASE_OUT: [number, number, number, number] = [0.16, 1, 0.3, 1];\n\nexport function DashboardPage() {\n const { navigateTo, currentUser } = useMyBodyShield();\n const reduceMotion = useReducedMotion();\n\n /** Staggered fade/rise entrance — one-shot, skipped under reduced motion. */\n const rise = (i: number) =>\n reduceMotion\n ? {}\n : {\n initial: { opacity: 0, y: 14 },\n whileInView: { opacity: 1, y: 0 },\n viewport: { once: true, amount: 0.15 },\n transition: { duration: 0.45, delay: Math.min(i, 8) * 0.05, ease: EASE_OUT },\n };\n\n /** Gentle hover lift for cards. */\n const lift = reduceMotion\n ? {}\n : { whileHover: { y: -3, transition: { duration: 0.2, ease: EASE_OUT } } };\n\n /** Hover lift + tap feedback for interactive cards. */\n const liftTap = reduceMotion\n ? {}\n : {\n whileHover: { y: -3, transition: { duration: 0.2, ease: EASE_OUT } },\n whileTap: { scale: 0.985 },\n };\n\n const programs = useMybPrograms({ status: 'ACTIVE', pagination: { limit: 50 } });\n const sessions = useMybSessions({ pagination: { limit: 20 } });\n const goals = useMybGoals({ status: 'ACTIVE', pagination: { limit: 50 } });\n const macros = useMybDailyMacros();\n const weightMetrics = useMybBodyMetrics({ type: 'WEIGHT', pagination: { limit: 30 } });\n const readiness = useMybRecoveryLogs('READINESS');\n\n const programRows = programs.data?.items ?? [];\n const sessionRows = sessions.data?.items ?? [];\n const goalRows = goals.data?.items ?? [];\n const weightRows = weightMetrics.data?.items ?? [];\n const readinessRows = readiness.data ?? [];\n\n const now = new Date();\n const weekAgo = now.getTime() - 7 * 24 * 60 * 60 * 1000;\n const sessionsThisWeek = sessionRows.filter((s) => {\n const ref = s.completedAt ?? s.startedAt ?? s.scheduledFor ?? s.createdAt;\n return ref ? new Date(ref).getTime() >= weekAgo : false;\n });\n const completedThisWeek = sessionsThisWeek.filter((s) => s.status === 'COMPLETED').length;\n const activeSession = sessionRows.find((s) => s.status === 'IN_PROGRESS');\n const upcomingSession = sessionRows\n .filter((s) => s.status === 'SCHEDULED' && s.scheduledFor)\n .sort((a, b) => new Date(a.scheduledFor!).getTime() - new Date(b.scheduledFor!).getTime())[0];\n\n const latestWeight = weightRows[0];\n const priorWeight = weightRows[1];\n const weightDelta =\n latestWeight && priorWeight ? latestWeight.value - priorWeight.value : undefined;\n\n const latestReadiness = readinessRows\n .slice()\n .sort((a, b) => new Date(b.loggedAt).getTime() - new Date(a.loggedAt).getTime())[0];\n\n const goalProgressAvg = useMemo(() => {\n if (goalRows.length === 0) return 0;\n const sum = goalRows.reduce((acc, g) => acc + computeGoalProgress(g), 0);\n return sum / goalRows.length;\n }, [goalRows]);\n\n const macroData = macros.data;\n const caloriePct = macroData?.calorieTarget\n ? (macroData.calories / macroData.calorieTarget) * 100\n : 0;\n\n const isInitialLoading =\n programs.isLoading && sessions.isLoading && goals.isLoading && macros.isLoading;\n\n if (isInitialLoading) {\n return (\n <PageLayout title=\"MyBodyShield\" titleGradient aurora>\n <LoadingView label=\"Loading your fitness overview…\" />\n </PageLayout>\n );\n }\n\n const greetingName = currentUser?.firstName || currentUser?.name || 'there';\n\n const kpiCards: { id: string; node: ReactNode }[] = [\n {\n id: 'programs',\n node: (\n <MetricsCard\n icon={<Dumbbell className=\"h-5 w-5\" />}\n value={formatNumber(programRows.length)}\n label=\"Active programs\"\n footer={\n <p className=\"text-xs text-text-tertiary\">\n <button\n type=\"button\"\n onClick={() => navigateTo('programs')}\n className=\"font-medium text-accent hover:underline\"\n >\n Manage programs\n </button>\n </p>\n }\n />\n ),\n },\n {\n id: 'sessions',\n node: (\n <MetricsCard\n icon={<Flame className=\"h-5 w-5\" />}\n value={formatNumber(completedThisWeek)}\n label=\"Sessions this week\"\n accent={activeSession ? 'warning' : undefined}\n footer={\n activeSession ? (\n <button\n type=\"button\"\n onClick={() => navigateTo(`train/${activeSession.id}`)}\n className=\"text-xs font-medium text-status-warning-text hover:underline\"\n >\n Resume live session →\n </button>\n ) : (\n <p className=\"text-xs text-text-tertiary\">\n <span className=\"tabular-nums text-text-secondary\">{sessionsThisWeek.length}</span>{' '}\n logged\n </p>\n )\n }\n />\n ),\n },\n {\n id: 'goals',\n node: (\n <MetricsCard\n icon={<Target className=\"h-5 w-5\" />}\n value={formatNumber(goalRows.length)}\n label=\"Active goals\"\n footer={\n <div className=\"space-y-2\">\n <MiniBar value={goalProgressAvg} height={4} barClassName=\"bg-action-primary-bg\" />\n <p className=\"text-xs text-text-tertiary\">\n <span className=\"tabular-nums text-text-secondary\">\n {formatPercent(goalProgressAvg)}\n </span>{' '}\n avg progress\n </p>\n </div>\n }\n />\n ),\n },\n {\n id: 'weight',\n node: (\n <MetricsCard\n icon={<Weight className=\"h-5 w-5\" />}\n value={latestWeight ? formatWeight(latestWeight.value) : '—'}\n label=\"Latest weight\"\n footer={\n weightDelta != null ? (\n <p className=\"text-xs text-text-tertiary\">\n <span\n className={\n weightDelta <= 0\n ? 'font-medium text-status-success-text'\n : 'font-medium text-text-secondary'\n }\n >\n {weightDelta > 0 ? '+' : ''}\n {weightDelta.toFixed(1)} kg\n </span>{' '}\n vs last\n </p>\n ) : (\n <button\n type=\"button\"\n onClick={() => navigateTo('progress')}\n className=\"text-xs font-medium text-accent hover:underline\"\n >\n Log a measurement →\n </button>\n )\n }\n />\n ),\n },\n {\n id: 'recovery',\n node: (\n <MetricsCard\n icon={<Moon className=\"h-5 w-5\" />}\n value={latestReadiness ? `${latestReadiness.score}` : '—'}\n label=\"Recovery readiness\"\n accent={\n latestReadiness\n ? latestReadiness.score >= 70\n ? 'success'\n : latestReadiness.score >= 40\n ? 'warning'\n : 'error'\n : undefined\n }\n footer={\n latestReadiness ? (\n <p className=\"text-xs text-text-tertiary\">\n {formatRelativeTime(latestReadiness.loggedAt)}\n </p>\n ) : (\n <button\n type=\"button\"\n onClick={() => navigateTo('recovery')}\n className=\"text-xs font-medium text-accent hover:underline\"\n >\n Log recovery →\n </button>\n )\n }\n />\n ),\n },\n ];\n\n return (\n <PageLayout\n title=\"MyBodyShield\"\n titleGradient\n aurora\n description={`Welcome back, ${greetingName} — your training, nutrition, progress & recovery control room.`}\n >\n {/* KPI grid */}\n <div className=\"grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-5\">\n {kpiCards.map((card, i) => (\n <motion.div\n key={card.id}\n className=\"group relative rounded-2xl transition-shadow duration-300 hover:shadow-float\"\n {...rise(i)}\n {...lift}\n >\n {/* Emerald top-edge accent — brightens on hover */}\n <span\n aria-hidden\n className=\"pointer-events-none absolute inset-x-6 top-0 z-10 h-px rounded-full bg-gradient-to-r from-transparent via-action-primary-bg to-transparent opacity-40 transition-opacity duration-300 group-hover:opacity-90\"\n />\n {card.node}\n </motion.div>\n ))}\n </div>\n\n <div className=\"mt-6 grid grid-cols-1 gap-6 lg:grid-cols-3\">\n {/* Today's nutrition */}\n <motion.div className=\"lg:col-span-2\" {...rise(0)}>\n <GlassCard treatment=\"glass\" className=\"h-full p-6\">\n <div className=\"mb-4 flex flex-wrap items-start justify-between gap-3\">\n <div>\n <h2 className=\"text-base font-semibold text-text-primary\">\n Today&apos;s nutrition\n </h2>\n <p className=\"mt-0.5 text-sm text-text-secondary\">\n Calories & macros logged against your active plan.\n </p>\n </div>\n <button\n type=\"button\"\n onClick={() => navigateTo('nutrition')}\n className=\"inline-flex items-center gap-1 text-sm font-medium text-accent hover:underline\"\n >\n Nutrition <ArrowRight className=\"h-4 w-4\" />\n </button>\n </div>\n {!macroData || (macroData.calorieTarget === 0 && macroData.calories === 0) ? (\n <EmptyState\n illustration=\"empty-data\"\n icon={<Salad className=\"h-10 w-10\" />}\n title=\"No nutrition data yet\"\n description=\"Activate a nutrition plan and log meals to track your daily macros here.\"\n />\n ) : (\n <div className=\"flex flex-col gap-8 sm:flex-row sm:items-center\">\n {/* Calorie ring — the nutrition hero */}\n <div className=\"relative mx-auto flex shrink-0 items-center justify-center sm:mx-0\">\n <span\n aria-hidden\n className=\"pointer-events-none absolute inset-2 rounded-full opacity-70 blur-2xl\"\n style={{\n background:\n 'radial-gradient(circle, color-mix(in srgb, var(--color-action-primary-bg) 26%, transparent), transparent 70%)',\n }}\n />\n <ProgressRing value={caloriePct} size={188} stroke={16}>\n <span className=\"text-[11px] font-medium uppercase tracking-wide text-text-tertiary\">\n Calories\n </span>\n <span className=\"text-3xl font-bold tabular-nums text-text-primary\">\n {formatNumber(macroData.calories)}\n </span>\n <span className=\"mt-0.5 text-xs text-text-tertiary\">\n / {formatNumber(macroData.calorieTarget)} kcal\n </span>\n </ProgressRing>\n </div>\n <div className=\"flex-1 space-y-4\">\n <div className=\"space-y-2\">\n <MacroBar\n proteinG={macroData.proteinG}\n carbsG={macroData.carbsG}\n fatG={macroData.fatG}\n height={12}\n />\n <MacroLegend />\n </div>\n <div className=\"grid grid-cols-3 gap-3\">\n {(\n [\n ['Protein', macroData.proteinG, macroData.proteinTarget],\n ['Carbs', macroData.carbsG, macroData.carbsTarget],\n ['Fat', macroData.fatG, macroData.fatTarget],\n ] as const\n ).map(([label, val, target]) => {\n const pct = target ? (val / target) * 100 : 0;\n return (\n <div\n key={label}\n className=\"rounded-2xl bg-bg-sunken/60 p-3 ring-1 ring-inset ring-border-seam/40 transition-shadow hover:shadow-float\"\n >\n <div className=\"flex items-center justify-between gap-1\">\n <p className=\"text-xs font-medium text-text-tertiary\">{label}</p>\n <span className=\"text-[11px] tabular-nums text-text-tertiary\">\n {formatPercent(pct)}\n </span>\n </div>\n <p className=\"mt-1 text-sm font-semibold tabular-nums text-text-primary\">\n {formatNumber(val)}\n <span className=\"text-xs font-normal text-text-tertiary\">\n {' '}\n / {formatNumber(target)} g\n </span>\n </p>\n <Meter value={pct} height={5} className=\"mt-2\" />\n </div>\n );\n })}\n </div>\n </div>\n </div>\n )}\n </GlassCard>\n </motion.div>\n\n {/* Next up */}\n <motion.div {...rise(1)}>\n <GlassCard treatment=\"glass\" className=\"h-full p-6\">\n <div className=\"mb-4 flex items-center justify-between gap-3\">\n <h2 className=\"text-base font-semibold text-text-primary\">Next up</h2>\n <button\n type=\"button\"\n onClick={() => navigateTo('train')}\n className=\"inline-flex items-center gap-1 text-sm font-medium text-accent hover:underline\"\n >\n Train <ArrowRight className=\"h-4 w-4\" />\n </button>\n </div>\n {activeSession ? (\n <motion.button\n type=\"button\"\n onClick={() => navigateTo(`train/${activeSession.id}`)}\n className=\"w-full rounded-2xl border border-status-warning-text/40 bg-status-warning-bg-subtle p-4 text-left transition-shadow hover:shadow-float\"\n {...liftTap}\n >\n <div className=\"flex items-center gap-2\">\n <StatusBadge status={activeSession.status} />\n </div>\n <p className=\"mt-2 text-sm font-medium text-text-primary\">\n Live workout in progress\n </p>\n <p className=\"mt-0.5 text-xs text-text-tertiary\">\n Started {formatRelativeTime(activeSession.startedAt)}\n </p>\n </motion.button>\n ) : upcomingSession ? (\n <motion.button\n type=\"button\"\n onClick={() => navigateTo(`train/${upcomingSession.id}`)}\n className=\"w-full rounded-2xl bg-bg-sunken/60 p-4 text-left ring-1 ring-inset ring-border-seam/40 transition-shadow hover:shadow-float\"\n {...liftTap}\n >\n <div className=\"flex items-center gap-2\">\n <IconChip icon={<CalendarCheck className=\"h-4 w-4\" />} />\n <div>\n <p className=\"text-sm font-medium text-text-primary\">Scheduled session</p>\n <p className=\"text-xs text-text-tertiary\">\n {formatRelativeTime(upcomingSession.scheduledFor)}\n </p>\n </div>\n </div>\n </motion.button>\n ) : (\n <div className=\"flex flex-col items-center justify-center rounded-2xl border border-dashed border-border-seam py-8 text-center\">\n <span className=\"flex size-11 items-center justify-center rounded-full bg-[var(--color-accent-soft)]\">\n <Flame className=\"h-5 w-5 text-accent\" />\n </span>\n <p className=\"mt-3 text-sm font-medium text-text-primary\">No session scheduled</p>\n <button\n type=\"button\"\n onClick={() => navigateTo('train')}\n className=\"mt-1 text-xs font-medium text-accent hover:underline\"\n >\n Start a workout\n </button>\n </div>\n )}\n </GlassCard>\n </motion.div>\n </div>\n\n {/* Active goals */}\n <Section\n title=\"Active goals\"\n description=\"Your current targets across training, nutrition and body composition.\"\n action={\n <button\n type=\"button\"\n onClick={() => navigateTo('goals')}\n className=\"inline-flex items-center gap-1 text-sm font-medium text-accent hover:underline\"\n >\n All goals <ArrowRight className=\"h-4 w-4\" />\n </button>\n }\n >\n {goalRows.length === 0 ? (\n <EmptyState\n illustration=\"empty-data\"\n icon={<Target className=\"h-10 w-10\" />}\n title=\"No active goals\"\n description=\"Set a goal to give your training and nutrition a clear target to work toward.\"\n />\n ) : (\n <div className=\"grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3\">\n {goalRows.slice(0, 6).map((g, i) => {\n const pct = computeGoalProgress(g);\n const meta = GOAL_TYPE_META[g.type];\n const Icon = meta.icon;\n return (\n <motion.button\n key={g.id}\n type=\"button\"\n onClick={() => navigateTo('goals')}\n className=\"text-left\"\n {...rise(i)}\n {...liftTap}\n >\n <GlassCard\n treatment=\"plain\"\n className=\"h-full p-4 transition-shadow hover:shadow-float\"\n >\n <div className=\"flex items-start gap-3\">\n <IconChip icon={<Icon className=\"h-4 w-4\" />} tint={meta.tint} />\n <div className=\"min-w-0 flex-1\">\n <p className=\"truncate text-sm font-semibold text-text-primary\">\n {g.title}\n </p>\n <p className=\"text-xs text-text-tertiary\">{formatEnumLabel(g.type)}</p>\n </div>\n </div>\n <div className=\"mt-3 space-y-1.5\">\n <Meter value={pct} />\n <div className=\"flex items-center justify-between text-xs\">\n <span className=\"tabular-nums text-text-secondary\">\n {formatNumber(g.currentValue)}\n {g.unit ? ` ${g.unit}` : ''} / {formatNumber(g.targetValue)}\n {g.unit ? ` ${g.unit}` : ''}\n </span>\n <span className=\"tabular-nums text-text-tertiary\">\n {formatPercent(pct)}\n </span>\n </div>\n </div>\n </GlassCard>\n </motion.button>\n );\n })}\n </div>\n )}\n </Section>\n\n {/* Recent sessions */}\n <Section\n title=\"Recent sessions\"\n description=\"Your latest logged and scheduled workouts.\"\n action={\n <button\n type=\"button\"\n onClick={() => navigateTo('train')}\n className=\"inline-flex items-center gap-1 text-sm font-medium text-accent hover:underline\"\n >\n All sessions <ArrowRight className=\"h-4 w-4\" />\n </button>\n }\n >\n {sessionRows.length === 0 ? (\n <EmptyState\n illustration=\"empty-data\"\n icon={<Flame className=\"h-10 w-10\" />}\n title=\"No sessions yet\"\n description=\"Start a workout session to begin logging sets and tracking your training.\"\n />\n ) : (\n <div className=\"grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3\">\n {sessionRows.slice(0, 6).map((s, i) => {\n const meta = WORKOUT_TYPE_META.STRENGTH;\n const Icon = s.status === 'COMPLETED' ? CheckCircle2 : meta.icon;\n return (\n <motion.button\n key={s.id}\n type=\"button\"\n onClick={() => navigateTo(`train/${s.id}`)}\n className=\"text-left\"\n {...rise(i)}\n {...liftTap}\n >\n <GlassCard treatment=\"plain\" className=\"p-4 transition-shadow hover:shadow-float\">\n <div className=\"flex items-center justify-between gap-2\">\n <IconChip icon={<Icon className=\"h-4 w-4\" />} tint={meta.tint} />\n <StatusBadge status={s.status} />\n </div>\n <p className=\"mt-3 text-sm font-medium text-text-primary\">\n {s.caloriesBurned > 0\n ? `${formatNumber(s.caloriesBurned)} kcal burned`\n : 'Workout session'}\n </p>\n <p className=\"mt-0.5 text-xs text-text-tertiary\">\n {formatRelativeTime(s.completedAt ?? s.startedAt ?? s.createdAt)}\n </p>\n </GlassCard>\n </motion.button>\n );\n })}\n </div>\n )}\n </Section>\n </PageLayout>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"DashboardPage.js","names":[],"sources":["../../../src/mybodyshield/pages/DashboardPage.tsx"],"sourcesContent":["/**\n * Dashboard — MyBodyShield health & fitness overview.\n * @module mybodyshield/pages\n *\n * KPIs are aggregated client-side from the real `myb*` list endpoints:\n * active programs, this-week's sessions, goal progress, today's macros vs\n * target, latest body weight and recovery readiness. No mock data.\n */\n\nimport { useMemo } from 'react';\nimport type { ReactNode } from 'react';\nimport { motion, useReducedMotion } from 'framer-motion';\nimport {\n Dumbbell,\n Flame,\n Target,\n Salad,\n Moon,\n ArrowRight,\n CheckCircle2,\n Weight,\n CalendarCheck,\n} from 'lucide-react';\nimport { GlassCard } from '@burdenoff/fe-libs/ui';\nimport { PageLayout } from '../components/PageLayout';\nimport { MetricsCard } from '../components/MetricsCard';\nimport { StatusBadge } from '../components/StatusBadge';\nimport { MiniBar } from '../components/MiniBar';\nimport { LoadingView, Section } from '../components/StateViews';\nimport { EmptyState } from '../components/EmptyState';\nimport {\n Meter,\n ProgressRing,\n MacroBar,\n MacroLegend,\n IconChip,\n GOAL_TYPE_META,\n RECOVERY_META,\n WORKOUT_TYPE_META,\n computeGoalProgress,\n} from './_shared/visuals';\nimport { useMyBodyShield } from '../context';\nimport {\n useMybPrograms,\n useMybSessions,\n useMybGoals,\n useMybDailyMacros,\n useMybBodyMetrics,\n useMybRecoveryLogs,\n} from '../hooks';\n\nimport {\n formatNumber,\n formatRelativeTime,\n formatKcal,\n formatWeight,\n formatPercent,\n formatEnumLabel,\n} from '../utils/formatters';\n\n/** Shared easing for entrance / hover motion (smooth ease-out). */\nconst EASE_OUT: [number, number, number, number] = [0.16, 1, 0.3, 1];\n\nexport function DashboardPage() {\n const { navigateTo, currentUser } = useMyBodyShield();\n const reduceMotion = useReducedMotion();\n\n /** Staggered fade/rise entrance — one-shot, skipped under reduced motion. */\n const rise = (i: number) =>\n reduceMotion\n ? {}\n : {\n initial: { opacity: 0, y: 14 },\n whileInView: { opacity: 1, y: 0 },\n viewport: { once: true, amount: 0.15 },\n transition: { duration: 0.45, delay: Math.min(i, 8) * 0.05, ease: EASE_OUT },\n };\n\n /** Gentle hover lift for cards. */\n const lift = reduceMotion\n ? {}\n : { whileHover: { y: -3, transition: { duration: 0.2, ease: EASE_OUT } } };\n\n /** Hover lift + tap feedback for interactive cards. */\n const liftTap = reduceMotion\n ? {}\n : {\n whileHover: { y: -3, transition: { duration: 0.2, ease: EASE_OUT } },\n whileTap: { scale: 0.985 },\n };\n\n const programs = useMybPrograms({ status: 'ACTIVE', pagination: { limit: 50 } });\n const sessions = useMybSessions({ pagination: { limit: 20 } });\n const goals = useMybGoals({ status: 'ACTIVE', pagination: { limit: 50 } });\n const macros = useMybDailyMacros();\n const weightMetrics = useMybBodyMetrics({ type: 'WEIGHT', pagination: { limit: 30 } });\n const readiness = useMybRecoveryLogs('READINESS');\n\n const programRows = programs.data?.items ?? [];\n const sessionRows = sessions.data?.items ?? [];\n const goalRows = goals.data?.items ?? [];\n const weightRows = weightMetrics.data?.items ?? [];\n const readinessRows = readiness.data ?? [];\n\n const now = new Date();\n const weekAgo = now.getTime() - 7 * 24 * 60 * 60 * 1000;\n const sessionsThisWeek = sessionRows.filter((s) => {\n const ref = s.completedAt ?? s.startedAt ?? s.scheduledFor ?? s.createdAt;\n return ref ? new Date(ref).getTime() >= weekAgo : false;\n });\n const completedThisWeek = sessionsThisWeek.filter((s) => s.status === 'COMPLETED').length;\n const activeSession = sessionRows.find((s) => s.status === 'IN_PROGRESS');\n const upcomingSession = sessionRows\n .filter((s) => s.status === 'SCHEDULED' && s.scheduledFor)\n .sort((a, b) => new Date(a.scheduledFor!).getTime() - new Date(b.scheduledFor!).getTime())[0];\n\n const latestWeight = weightRows[0];\n const priorWeight = weightRows[1];\n const weightDelta =\n latestWeight && priorWeight ? latestWeight.value - priorWeight.value : undefined;\n\n const latestReadiness = readinessRows\n .slice()\n .sort((a, b) => new Date(b.loggedAt).getTime() - new Date(a.loggedAt).getTime())[0];\n\n const goalProgressAvg = useMemo(() => {\n if (goalRows.length === 0) return 0;\n const sum = goalRows.reduce((acc, g) => acc + computeGoalProgress(g), 0);\n return sum / goalRows.length;\n }, [goalRows]);\n\n const macroData = macros.data;\n const caloriePct = macroData?.calorieTarget\n ? (macroData.calories / macroData.calorieTarget) * 100\n : 0;\n\n const isInitialLoading =\n programs.isLoading && sessions.isLoading && goals.isLoading && macros.isLoading;\n\n if (isInitialLoading) {\n return (\n <PageLayout title=\"MyBodyShield\" titleGradient aurora>\n <LoadingView label=\"Loading your fitness overview…\" />\n </PageLayout>\n );\n }\n\n const greetingName = currentUser?.firstName || currentUser?.name || 'there';\n\n const kpiCards: { id: string; node: ReactNode }[] = [\n {\n id: 'programs',\n node: (\n <MetricsCard\n icon={<Dumbbell className=\"h-5 w-5\" />}\n value={formatNumber(programRows.length)}\n label=\"Active programs\"\n footer={\n <p className=\"text-xs text-text-tertiary\">\n <button\n type=\"button\"\n onClick={() => navigateTo('programs')}\n className=\"font-medium text-accent hover:underline\"\n >\n Manage programs\n </button>\n </p>\n }\n />\n ),\n },\n {\n id: 'sessions',\n node: (\n <MetricsCard\n icon={<Flame className=\"h-5 w-5\" />}\n value={formatNumber(completedThisWeek)}\n label=\"Sessions this week\"\n accent={activeSession ? 'warning' : undefined}\n footer={\n activeSession ? (\n <button\n type=\"button\"\n onClick={() => navigateTo(`train/${activeSession.id}`)}\n className=\"text-xs font-medium text-status-warning-text hover:underline\"\n >\n Resume live session →\n </button>\n ) : (\n <p className=\"text-xs text-text-tertiary\">\n <span className=\"tabular-nums text-text-secondary\">{sessionsThisWeek.length}</span>{' '}\n logged\n </p>\n )\n }\n />\n ),\n },\n {\n id: 'goals',\n node: (\n <MetricsCard\n icon={<Target className=\"h-5 w-5\" />}\n value={formatNumber(goalRows.length)}\n label=\"Active goals\"\n footer={\n <div className=\"space-y-2\">\n <MiniBar value={goalProgressAvg} height={4} barClassName=\"bg-action-primary-bg\" />\n <p className=\"text-xs text-text-tertiary\">\n <span className=\"tabular-nums text-text-secondary\">\n {formatPercent(goalProgressAvg)}\n </span>{' '}\n avg progress\n </p>\n </div>\n }\n />\n ),\n },\n {\n id: 'weight',\n node: (\n <MetricsCard\n icon={<Weight className=\"h-5 w-5\" />}\n value={latestWeight ? formatWeight(latestWeight.value) : '—'}\n label=\"Latest weight\"\n footer={\n weightDelta != null ? (\n <p className=\"text-xs text-text-tertiary\">\n <span\n className={\n weightDelta <= 0\n ? 'font-medium text-status-success-text'\n : 'font-medium text-text-secondary'\n }\n >\n {weightDelta > 0 ? '+' : ''}\n {weightDelta.toFixed(1)} kg\n </span>{' '}\n vs last\n </p>\n ) : (\n <button\n type=\"button\"\n onClick={() => navigateTo('progress')}\n className=\"text-xs font-medium text-accent hover:underline\"\n >\n Log a measurement →\n </button>\n )\n }\n />\n ),\n },\n {\n id: 'recovery',\n node: (\n <MetricsCard\n icon={<Moon className=\"h-5 w-5\" />}\n value={latestReadiness ? `${latestReadiness.score}` : '—'}\n label=\"Recovery readiness\"\n accent={\n latestReadiness\n ? latestReadiness.score >= 70\n ? 'success'\n : latestReadiness.score >= 40\n ? 'warning'\n : 'error'\n : undefined\n }\n footer={\n latestReadiness ? (\n <p className=\"text-xs text-text-tertiary\">\n {formatRelativeTime(latestReadiness.loggedAt)}\n </p>\n ) : (\n <button\n type=\"button\"\n onClick={() => navigateTo('recovery')}\n className=\"text-xs font-medium text-accent hover:underline\"\n >\n Log recovery →\n </button>\n )\n }\n />\n ),\n },\n ];\n\n return (\n <PageLayout\n title=\"MyBodyShield\"\n titleGradient\n aurora\n description={`Welcome back, ${greetingName} — your training, nutrition, progress & recovery control room.`}\n >\n {/* KPI grid */}\n <div\n data-tour=\"mybodyshield-dashboard-kpi-grid\"\n className=\"grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-5\"\n >\n {kpiCards.map((card, i) => (\n <motion.div\n key={card.id}\n className=\"group relative rounded-2xl transition-shadow duration-300 hover:shadow-float\"\n {...rise(i)}\n {...lift}\n >\n {/* Emerald top-edge accent — brightens on hover */}\n <span\n aria-hidden\n className=\"pointer-events-none absolute inset-x-6 top-0 z-10 h-px rounded-full bg-gradient-to-r from-transparent via-action-primary-bg to-transparent opacity-40 transition-opacity duration-300 group-hover:opacity-90\"\n />\n {card.node}\n </motion.div>\n ))}\n </div>\n\n <div className=\"mt-6 grid grid-cols-1 gap-6 lg:grid-cols-3\">\n {/* Today's nutrition */}\n <motion.div\n data-tour=\"mybodyshield-dashboard-nutrition\"\n className=\"lg:col-span-2\"\n {...rise(0)}\n >\n <GlassCard treatment=\"glass\" className=\"h-full p-6\">\n <div className=\"mb-4 flex flex-wrap items-start justify-between gap-3\">\n <div>\n <h2 className=\"text-base font-semibold text-text-primary\">\n Today&apos;s nutrition\n </h2>\n <p className=\"mt-0.5 text-sm text-text-secondary\">\n Calories & macros logged against your active plan.\n </p>\n </div>\n <button\n type=\"button\"\n onClick={() => navigateTo('nutrition')}\n className=\"inline-flex items-center gap-1 text-sm font-medium text-accent hover:underline\"\n >\n Nutrition <ArrowRight className=\"h-4 w-4\" />\n </button>\n </div>\n {!macroData || (macroData.calorieTarget === 0 && macroData.calories === 0) ? (\n <EmptyState\n illustration=\"empty-data\"\n icon={<Salad className=\"h-10 w-10\" />}\n title=\"No nutrition data yet\"\n description=\"Activate a nutrition plan and log meals to track your daily macros here.\"\n />\n ) : (\n <div className=\"flex flex-col gap-8 sm:flex-row sm:items-center\">\n {/* Calorie ring — the nutrition hero */}\n <div className=\"relative mx-auto flex shrink-0 items-center justify-center sm:mx-0\">\n <span\n aria-hidden\n className=\"pointer-events-none absolute inset-2 rounded-full opacity-70 blur-2xl\"\n style={{\n background:\n 'radial-gradient(circle, color-mix(in srgb, var(--color-action-primary-bg) 26%, transparent), transparent 70%)',\n }}\n />\n <ProgressRing value={caloriePct} size={188} stroke={16}>\n <span className=\"text-[11px] font-medium uppercase tracking-wide text-text-tertiary\">\n Calories\n </span>\n <span className=\"text-3xl font-bold tabular-nums text-text-primary\">\n {formatNumber(macroData.calories)}\n </span>\n <span className=\"mt-0.5 text-xs text-text-tertiary\">\n / {formatNumber(macroData.calorieTarget)} kcal\n </span>\n </ProgressRing>\n </div>\n <div className=\"flex-1 space-y-4\">\n <div className=\"space-y-2\">\n <MacroBar\n proteinG={macroData.proteinG}\n carbsG={macroData.carbsG}\n fatG={macroData.fatG}\n height={12}\n />\n <MacroLegend />\n </div>\n <div className=\"grid grid-cols-3 gap-3\">\n {(\n [\n ['Protein', macroData.proteinG, macroData.proteinTarget],\n ['Carbs', macroData.carbsG, macroData.carbsTarget],\n ['Fat', macroData.fatG, macroData.fatTarget],\n ] as const\n ).map(([label, val, target]) => {\n const pct = target ? (val / target) * 100 : 0;\n return (\n <div\n key={label}\n className=\"rounded-2xl bg-bg-sunken/60 p-3 ring-1 ring-inset ring-border-seam/40 transition-shadow hover:shadow-float\"\n >\n <div className=\"flex items-center justify-between gap-1\">\n <p className=\"text-xs font-medium text-text-tertiary\">{label}</p>\n <span className=\"text-[11px] tabular-nums text-text-tertiary\">\n {formatPercent(pct)}\n </span>\n </div>\n <p className=\"mt-1 text-sm font-semibold tabular-nums text-text-primary\">\n {formatNumber(val)}\n <span className=\"text-xs font-normal text-text-tertiary\">\n {' '}\n / {formatNumber(target)} g\n </span>\n </p>\n <Meter value={pct} height={5} className=\"mt-2\" />\n </div>\n );\n })}\n </div>\n </div>\n </div>\n )}\n </GlassCard>\n </motion.div>\n\n {/* Next up */}\n <motion.div data-tour=\"mybodyshield-dashboard-next-up\" {...rise(1)}>\n <GlassCard treatment=\"glass\" className=\"h-full p-6\">\n <div className=\"mb-4 flex items-center justify-between gap-3\">\n <h2 className=\"text-base font-semibold text-text-primary\">Next up</h2>\n <button\n type=\"button\"\n onClick={() => navigateTo('train')}\n className=\"inline-flex items-center gap-1 text-sm font-medium text-accent hover:underline\"\n >\n Train <ArrowRight className=\"h-4 w-4\" />\n </button>\n </div>\n {activeSession ? (\n <motion.button\n type=\"button\"\n onClick={() => navigateTo(`train/${activeSession.id}`)}\n className=\"w-full rounded-2xl border border-status-warning-text/40 bg-status-warning-bg-subtle p-4 text-left transition-shadow hover:shadow-float\"\n {...liftTap}\n >\n <div className=\"flex items-center gap-2\">\n <StatusBadge status={activeSession.status} />\n </div>\n <p className=\"mt-2 text-sm font-medium text-text-primary\">\n Live workout in progress\n </p>\n <p className=\"mt-0.5 text-xs text-text-tertiary\">\n Started {formatRelativeTime(activeSession.startedAt)}\n </p>\n </motion.button>\n ) : upcomingSession ? (\n <motion.button\n type=\"button\"\n onClick={() => navigateTo(`train/${upcomingSession.id}`)}\n className=\"w-full rounded-2xl bg-bg-sunken/60 p-4 text-left ring-1 ring-inset ring-border-seam/40 transition-shadow hover:shadow-float\"\n {...liftTap}\n >\n <div className=\"flex items-center gap-2\">\n <IconChip icon={<CalendarCheck className=\"h-4 w-4\" />} />\n <div>\n <p className=\"text-sm font-medium text-text-primary\">Scheduled session</p>\n <p className=\"text-xs text-text-tertiary\">\n {formatRelativeTime(upcomingSession.scheduledFor)}\n </p>\n </div>\n </div>\n </motion.button>\n ) : (\n <div className=\"flex flex-col items-center justify-center rounded-2xl border border-dashed border-border-seam py-8 text-center\">\n <span className=\"flex size-11 items-center justify-center rounded-full bg-[var(--color-accent-soft)]\">\n <Flame className=\"h-5 w-5 text-accent\" />\n </span>\n <p className=\"mt-3 text-sm font-medium text-text-primary\">No session scheduled</p>\n <button\n type=\"button\"\n onClick={() => navigateTo('train')}\n className=\"mt-1 text-xs font-medium text-accent hover:underline\"\n >\n Start a workout\n </button>\n </div>\n )}\n </GlassCard>\n </motion.div>\n </div>\n\n {/* Active goals */}\n <Section\n data-tour=\"mybodyshield-dashboard-active-goals\"\n title=\"Active goals\"\n description=\"Your current targets across training, nutrition and body composition.\"\n action={\n <button\n type=\"button\"\n onClick={() => navigateTo('goals')}\n className=\"inline-flex items-center gap-1 text-sm font-medium text-accent hover:underline\"\n >\n All goals <ArrowRight className=\"h-4 w-4\" />\n </button>\n }\n >\n {goalRows.length === 0 ? (\n <EmptyState\n illustration=\"empty-data\"\n icon={<Target className=\"h-10 w-10\" />}\n title=\"No active goals\"\n description=\"Set a goal to give your training and nutrition a clear target to work toward.\"\n />\n ) : (\n <div className=\"grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3\">\n {goalRows.slice(0, 6).map((g, i) => {\n const pct = computeGoalProgress(g);\n const meta = GOAL_TYPE_META[g.type];\n const Icon = meta.icon;\n return (\n <motion.button\n key={g.id}\n type=\"button\"\n onClick={() => navigateTo('goals')}\n className=\"text-left\"\n {...rise(i)}\n {...liftTap}\n >\n <GlassCard\n treatment=\"plain\"\n className=\"h-full p-4 transition-shadow hover:shadow-float\"\n >\n <div className=\"flex items-start gap-3\">\n <IconChip icon={<Icon className=\"h-4 w-4\" />} tint={meta.tint} />\n <div className=\"min-w-0 flex-1\">\n <p className=\"truncate text-sm font-semibold text-text-primary\">\n {g.title}\n </p>\n <p className=\"text-xs text-text-tertiary\">{formatEnumLabel(g.type)}</p>\n </div>\n </div>\n <div className=\"mt-3 space-y-1.5\">\n <Meter value={pct} />\n <div className=\"flex items-center justify-between text-xs\">\n <span className=\"tabular-nums text-text-secondary\">\n {formatNumber(g.currentValue)}\n {g.unit ? ` ${g.unit}` : ''} / {formatNumber(g.targetValue)}\n {g.unit ? ` ${g.unit}` : ''}\n </span>\n <span className=\"tabular-nums text-text-tertiary\">\n {formatPercent(pct)}\n </span>\n </div>\n </div>\n </GlassCard>\n </motion.button>\n );\n })}\n </div>\n )}\n </Section>\n\n {/* Recent sessions */}\n <Section\n data-tour=\"mybodyshield-dashboard-recent-sessions\"\n title=\"Recent sessions\"\n description=\"Your latest logged and scheduled workouts.\"\n action={\n <button\n type=\"button\"\n onClick={() => navigateTo('train')}\n className=\"inline-flex items-center gap-1 text-sm font-medium text-accent hover:underline\"\n >\n All sessions <ArrowRight className=\"h-4 w-4\" />\n </button>\n }\n >\n {sessionRows.length === 0 ? (\n <EmptyState\n illustration=\"empty-data\"\n icon={<Flame className=\"h-10 w-10\" />}\n title=\"No sessions yet\"\n description=\"Start a workout session to begin logging sets and tracking your training.\"\n />\n ) : (\n <div className=\"grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3\">\n {sessionRows.slice(0, 6).map((s, i) => {\n const meta = WORKOUT_TYPE_META.STRENGTH;\n const Icon = s.status === 'COMPLETED' ? CheckCircle2 : meta.icon;\n return (\n <motion.button\n key={s.id}\n type=\"button\"\n onClick={() => navigateTo(`train/${s.id}`)}\n className=\"text-left\"\n {...rise(i)}\n {...liftTap}\n >\n <GlassCard treatment=\"plain\" className=\"p-4 transition-shadow hover:shadow-float\">\n <div className=\"flex items-center justify-between gap-2\">\n <IconChip icon={<Icon className=\"h-4 w-4\" />} tint={meta.tint} />\n <StatusBadge status={s.status} />\n </div>\n <p className=\"mt-3 text-sm font-medium text-text-primary\">\n {s.caloriesBurned > 0\n ? `${formatNumber(s.caloriesBurned)} kcal burned`\n : 'Workout session'}\n </p>\n <p className=\"mt-0.5 text-xs text-text-tertiary\">\n {formatRelativeTime(s.completedAt ?? s.startedAt ?? s.createdAt)}\n </p>\n </GlassCard>\n </motion.button>\n );\n })}\n </div>\n )}\n </Section>\n </PageLayout>\n );\n}\n"],"mappings":"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"}
@@ -0,0 +1,77 @@
1
+ import { FC, ReactNode } from 'react';
2
+ import { Dumbbell, Timer, Weight, Target, Gauge } from 'lucide-react';
3
+ import { MybBodyMetricType, MybGoalType, MybMuscleGroup, MybRecoveryMetric, MybWorkoutType } from '../../types';
4
+
5
+ export declare const Meter: FC<{
6
+ /** 0–100 percentage. */
7
+ value: number;
8
+ /** CSS color for the fill (default: brand emerald). */
9
+ color?: string;
10
+ height?: number;
11
+ className?: string;
12
+ }>;
13
+ export declare const ProgressRing: FC<{
14
+ value: number;
15
+ size?: number;
16
+ stroke?: number;
17
+ color?: string;
18
+ trackColor?: string;
19
+ children?: ReactNode;
20
+ className?: string;
21
+ }>;
22
+ export declare const MACRO_HUE: {
23
+ readonly protein: "var(--color-action-primary-bg)";
24
+ readonly carbs: "var(--color-status-warning-text)";
25
+ readonly fat: "var(--color-accent-primary)";
26
+ };
27
+ export declare const MacroBar: FC<{
28
+ proteinG: number;
29
+ carbsG: number;
30
+ fatG: number;
31
+ height?: number;
32
+ className?: string;
33
+ }>;
34
+ export declare const MacroLegend: FC<{
35
+ className?: string;
36
+ }>;
37
+ export declare const WORKOUT_TYPE_META: Record<MybWorkoutType, {
38
+ icon: typeof Dumbbell;
39
+ tint: string;
40
+ }>;
41
+ export declare const MUSCLE_META: Record<MybMuscleGroup, {
42
+ tint: string;
43
+ }>;
44
+ export declare const GOAL_TYPE_META: Record<MybGoalType, {
45
+ icon: typeof Target;
46
+ tint: string;
47
+ }>;
48
+ export declare const METRIC_META: Record<MybBodyMetricType, {
49
+ icon: typeof Weight;
50
+ tint: string;
51
+ unit: string;
52
+ }>;
53
+ export declare const RECOVERY_META: Record<MybRecoveryMetric, {
54
+ icon: typeof Gauge;
55
+ tint: string;
56
+ label: string;
57
+ }>;
58
+ /** Circular icon chip with a soft tinted background. */
59
+ export declare const IconChip: FC<{
60
+ icon: ReactNode;
61
+ tint?: string;
62
+ className?: string;
63
+ }>;
64
+ /** A small trend delta pill (up/down/flat) with semantic color. */
65
+ export declare const TrendPill: FC<{
66
+ delta: number;
67
+ unit?: string;
68
+ goodDirection?: 'up' | 'down';
69
+ }>;
70
+ /** Compute a goal's completion percentage from baseline → target → current. */
71
+ export declare function computeGoalProgress(goal: {
72
+ baselineValue: number;
73
+ targetValue: number;
74
+ currentValue: number;
75
+ }): number;
76
+ export { Timer };
77
+ //# sourceMappingURL=visuals.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"visuals.d.ts","sourceRoot":"","sources":["../../../../src/mybodyshield/pages/_shared/visuals.tsx"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,EAAE,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAC3C,OAAO,EACL,QAAQ,EAER,KAAK,EAKL,MAAM,EAQN,MAAM,EAIN,KAAK,EAEN,MAAM,cAAc,CAAC;AAEtB,OAAO,KAAK,EACV,iBAAiB,EACjB,WAAW,EACX,cAAc,EACd,iBAAiB,EACjB,cAAc,EACf,MAAM,aAAa,CAAC;AAMrB,eAAO,MAAM,KAAK,EAAE,EAAE,CAAC;IACrB,wBAAwB;IACxB,KAAK,EAAE,MAAM,CAAC;IACd,uDAAuD;IACvD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAiBA,CAAC;AAMF,eAAO,MAAM,YAAY,EAAE,EAAE,CAAC;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,SAAS,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CA6CA,CAAC;AAMF,eAAO,MAAM,SAAS;;;;CAIZ,CAAC;AAEX,eAAO,MAAM,QAAQ,EAAE,EAAE,CAAC;IACxB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAaA,CAAC;AAEF,eAAO,MAAM,WAAW,EAAE,EAAE,CAAC;IAAE,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,CASlD,CAAC;AA+BF,eAAO,MAAM,iBAAiB;UARiC,OAAO,QAAQ;UAAQ,MAAM;EAQL,CAAC;AAWxF,eAAO,MAAM,WAAW;UATiC,MAAM;EASa,CAAC;AAU7E,eAAO,MAAM,cAAc;UAR8B,OAAO,MAAM;UAAQ,MAAM;EAQI,CAAC;AAezF,eAAO,MAAM,WAAW;UAXd,OAAO,MAAM;UAAQ,MAAM;UAAQ,MAAM;EAWsB,CAAC;AAY1E,eAAO,MAAM,aAAa;UARhB,OAAO,KAAK;UAAQ,MAAM;WAAS,MAAM;EAQ6B,CAAC;AAMjF,wDAAwD;AACxD,eAAO,MAAM,QAAQ,EAAE,EAAE,CAAC;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,CAW/E,CAAC;AAEF,mEAAmE;AACnE,eAAO,MAAM,SAAS,EAAE,EAAE,CAAC;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,aAAa,CAAC,EAAE,IAAI,GAAG,MAAM,CAAA;CAAE,CAwBzF,CAAC;AAEF,+EAA+E;AAC/E,wBAAgB,mBAAmB,CAAC,IAAI,EAAE;IACxC,aAAa,EAAE,MAAM,CAAC;IACtB,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;CACtB,GAAG,MAAM,CAKT;AAED,OAAO,EAAE,KAAK,EAAE,CAAC"}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Coaching — coach ↔ member relationships and shared data scope.
3
+ * @module mybodyshield/pages/coaching
4
+ *
5
+ * Lists the member's `MybCoachingRelationship`s (a PLAIN ARRAY from
6
+ * `mybListCoaching` — no pagination) with a status filter, per-relationship
7
+ * sharing scope (workouts / nutrition / metrics), lifecycle transition actions
8
+ * (accept / pause / resume / end) and a create flow. No mock data.
9
+ */
10
+ export declare function CoachingPage(): import("react").JSX.Element;
11
+ //# sourceMappingURL=CoachingPage.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CoachingPage.d.ts","sourceRoot":"","sources":["../../../../src/mybodyshield/pages/coaching/CoachingPage.tsx"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AA6fH,wBAAgB,YAAY,gCA0I3B"}
@@ -1,20 +1,20 @@
1
1
  import { useMyBodyShield as e } from "../../context/MyBodyShieldContext.js";
2
- import { AnimatePresence as t } from "../../../node_modules/framer-motion/dist/es/components/AnimatePresence/index.js";
3
- import { motion as n } from "../../../node_modules/framer-motion/dist/es/render/components/motion/proxy.js";
4
- import { useReducedMotion as r } from "../../../node_modules/framer-motion/dist/es/utils/reduced-motion/use-reduced-motion.js";
5
- import { PageLayout as i } from "../../components/PageLayout.js";
6
- import { formatDate as a } from "../../utils/formatters.js";
7
- import { StatusBadge as o } from "../../components/StatusBadge.js";
8
- import { ErrorView as s, LoadingView as c } from "../../components/StateViews.js";
9
- import { EmptyState as l } from "../../components/EmptyState.js";
10
- import { IconChip as u } from "../_shared/visuals.js";
2
+ import { PageLayout as t } from "../../components/PageLayout.js";
3
+ import { formatDate as n } from "../../utils/formatters.js";
4
+ import { StatusBadge as r } from "../../components/StatusBadge.js";
5
+ import { EmptyState as i } from "../../components/EmptyState.js";
6
+ import { ErrorView as a, LoadingView as o } from "../../components/StateViews.js";
7
+ import { FilterTabs as s } from "../../components/FilterTabs.js";
11
8
  import "../../context/index.js";
12
- import { useMybCoaching as d, useMybCreateCoaching as f, useMybTransitionCoaching as p } from "../../hooks/useMyBodyShieldApi.js";
9
+ import { useMybCoaching as c, useMybCreateCoaching as l, useMybTransitionCoaching as u } from "../../hooks/useMyBodyShieldApi.js";
13
10
  import "../../hooks/index.js";
14
- import { FilterTabs as m } from "../../components/FilterTabs.js";
15
- import { MybDiscussion as h } from "../../components/MybDiscussion.js";
16
- import { UserSearchSelect as g } from "../../components/UserSearchSelect.js";
11
+ import { MybDiscussion as d } from "../../components/MybDiscussion.js";
12
+ import { UserSearchSelect as f } from "../../components/UserSearchSelect.js";
17
13
  import "../../components/index.js";
14
+ import { AnimatePresence as p } from "../../../node_modules/framer-motion/dist/es/components/AnimatePresence/index.js";
15
+ import { motion as m } from "../../../node_modules/framer-motion/dist/es/render/components/motion/proxy.js";
16
+ import { useReducedMotion as h } from "../../../node_modules/framer-motion/dist/es/utils/reduced-motion/use-reduced-motion.js";
17
+ import { IconChip as g } from "../_shared/visuals.js";
18
18
  import { useMemo as _, useState as v } from "react";
19
19
  import { CalendarClock as y, CalendarX as b, Check as x, ChevronDown as S, ChevronUp as C, Dumbbell as w, HeartHandshake as T, LineChart as E, MessageSquare as D, Minus as O, Plus as k, Salad as A, User as j } from "lucide-react";
20
20
  import { jsx as M, jsxs as N } from "react/jsx-runtime";
@@ -108,9 +108,9 @@ function Q({ id: e, label: t, description: n, checked: r, onChange: i }) {
108
108
  });
109
109
  }
110
110
  function ee({ open: e, onOpenChange: t, defaultMember: n }) {
111
- let r = f(), [i, a] = v(() => Z(n)), [o, s] = v(null), c = (e) => {
111
+ let r = l(), [i, a] = v(() => Z(n)), [o, s] = v(null), c = (e) => {
112
112
  e || (a(Z(n)), s(null)), t(e);
113
- }, l = async () => {
113
+ }, u = async () => {
114
114
  let e = i.coachId.trim(), o = i.memberId.trim();
115
115
  if (!e) {
116
116
  s("Coach user id is required.");
@@ -141,14 +141,14 @@ function ee({ open: e, onOpenChange: t, defaultMember: n }) {
141
141
  children: /* @__PURE__ */ N(z, { children: [/* @__PURE__ */ N(H, { children: [/* @__PURE__ */ M(U, { children: "New coaching" }), /* @__PURE__ */ M(B, { children: "Link a coach and member, and choose exactly what training, nutrition and progress data is shared." })] }), /* @__PURE__ */ N("form", {
142
142
  className: "space-y-4",
143
143
  onSubmit: (e) => {
144
- e.preventDefault(), l();
144
+ e.preventDefault(), u();
145
145
  },
146
146
  children: [
147
147
  o && /* @__PURE__ */ M("p", {
148
148
  className: "rounded-lg bg-status-error-bg-subtle px-3 py-2 text-sm text-status-error-text",
149
149
  children: o
150
150
  }),
151
- /* @__PURE__ */ M(g, {
151
+ /* @__PURE__ */ M(f, {
152
152
  label: "Coach",
153
153
  required: !0,
154
154
  htmlId: "myb-coaching-coach",
@@ -160,7 +160,7 @@ function ee({ open: e, onOpenChange: t, defaultMember: n }) {
160
160
  coachName: t
161
161
  }))
162
162
  }),
163
- /* @__PURE__ */ M(g, {
163
+ /* @__PURE__ */ M(f, {
164
164
  label: "Member",
165
165
  htmlId: "myb-coaching-member",
166
166
  userId: i.memberId,
@@ -263,8 +263,8 @@ function $({ label: e, icon: t, on: n }) {
263
263
  ]
264
264
  });
265
265
  }
266
- function te({ relationship: e, currentUserId: i, busy: s, onTransition: c }) {
267
- let l = !!i && e.coachId === i, d = !!i && e.memberId === i, f = Y[e.status], p = e.status === "ACTIVE" || e.status === "PAUSED", [m, g] = v(!1), _ = r();
266
+ function te({ relationship: e, currentUserId: t, busy: i, onTransition: a }) {
267
+ let o = !!t && e.coachId === t, s = !!t && e.memberId === t, c = Y[e.status], l = e.status === "ACTIVE" || e.status === "PAUSED", [u, f] = v(!1), _ = h();
268
268
  return /* @__PURE__ */ N(F, {
269
269
  treatment: "glass",
270
270
  glow: e.status === "ACTIVE",
@@ -274,7 +274,7 @@ function te({ relationship: e, currentUserId: i, busy: s, onTransition: c }) {
274
274
  className: "flex items-start justify-between gap-3",
275
275
  children: [/* @__PURE__ */ N("div", {
276
276
  className: "flex min-w-0 items-start gap-3",
277
- children: [/* @__PURE__ */ M(u, { icon: /* @__PURE__ */ M(T, { className: "h-4 w-4" }) }), /* @__PURE__ */ N("div", {
277
+ children: [/* @__PURE__ */ M(g, { icon: /* @__PURE__ */ M(T, { className: "h-4 w-4" }) }), /* @__PURE__ */ N("div", {
278
278
  className: "min-w-0",
279
279
  children: [/* @__PURE__ */ M("p", {
280
280
  className: "truncate text-sm font-semibold text-text-primary",
@@ -284,7 +284,7 @@ function te({ relationship: e, currentUserId: i, busy: s, onTransition: c }) {
284
284
  children: "Coach ↔ member"
285
285
  })]
286
286
  })]
287
- }), /* @__PURE__ */ M(o, { status: e.status })]
287
+ }), /* @__PURE__ */ M(r, { status: e.status })]
288
288
  }),
289
289
  /* @__PURE__ */ N("div", {
290
290
  className: "grid grid-cols-2 gap-3",
@@ -292,7 +292,7 @@ function te({ relationship: e, currentUserId: i, busy: s, onTransition: c }) {
292
292
  className: "flex items-center gap-2.5 rounded-lg bg-bg-sunken/60 p-2.5",
293
293
  children: [/* @__PURE__ */ M("span", {
294
294
  "aria-hidden": "true",
295
- className: `flex size-8 shrink-0 items-center justify-center rounded-full ring-1 ring-inset ${l ? "bg-[color-mix(in_oklab,var(--color-action-primary-bg)_16%,transparent)] text-action-primary-bg ring-[color-mix(in_oklab,var(--color-action-primary-bg)_40%,transparent)]" : "bg-bg-surface text-text-tertiary ring-border-seam"}`,
295
+ className: `flex size-8 shrink-0 items-center justify-center rounded-full ring-1 ring-inset ${o ? "bg-[color-mix(in_oklab,var(--color-action-primary-bg)_16%,transparent)] text-action-primary-bg ring-[color-mix(in_oklab,var(--color-action-primary-bg)_40%,transparent)]" : "bg-bg-surface text-text-tertiary ring-border-seam"}`,
296
296
  children: /* @__PURE__ */ M(j, { className: "h-4 w-4" })
297
297
  }), /* @__PURE__ */ N("div", {
298
298
  className: "min-w-0",
@@ -302,14 +302,14 @@ function te({ relationship: e, currentUserId: i, busy: s, onTransition: c }) {
302
302
  }), /* @__PURE__ */ M("p", {
303
303
  className: "mt-0.5 truncate text-sm font-medium text-text-primary",
304
304
  title: e.coachId,
305
- children: l ? "You" : `#${X(e.coachId)}`
305
+ children: o ? "You" : `#${X(e.coachId)}`
306
306
  })]
307
307
  })]
308
308
  }), /* @__PURE__ */ N("div", {
309
309
  className: "flex items-center gap-2.5 rounded-lg bg-bg-sunken/60 p-2.5",
310
310
  children: [/* @__PURE__ */ M("span", {
311
311
  "aria-hidden": "true",
312
- className: `flex size-8 shrink-0 items-center justify-center rounded-full ring-1 ring-inset ${d ? "bg-[color-mix(in_oklab,var(--color-action-primary-bg)_16%,transparent)] text-action-primary-bg ring-[color-mix(in_oklab,var(--color-action-primary-bg)_40%,transparent)]" : "bg-bg-surface text-text-tertiary ring-border-seam"}`,
312
+ className: `flex size-8 shrink-0 items-center justify-center rounded-full ring-1 ring-inset ${s ? "bg-[color-mix(in_oklab,var(--color-action-primary-bg)_16%,transparent)] text-action-primary-bg ring-[color-mix(in_oklab,var(--color-action-primary-bg)_40%,transparent)]" : "bg-bg-surface text-text-tertiary ring-border-seam"}`,
313
313
  children: /* @__PURE__ */ M(j, { className: "h-4 w-4" })
314
314
  }), /* @__PURE__ */ N("div", {
315
315
  className: "min-w-0",
@@ -319,7 +319,7 @@ function te({ relationship: e, currentUserId: i, busy: s, onTransition: c }) {
319
319
  }), /* @__PURE__ */ M("p", {
320
320
  className: "mt-0.5 truncate text-sm font-medium text-text-primary",
321
321
  title: e.memberId,
322
- children: d ? "You" : `#${X(e.memberId)}`
322
+ children: s ? "You" : `#${X(e.memberId)}`
323
323
  })]
324
324
  })]
325
325
  })]
@@ -351,42 +351,42 @@ function te({ relationship: e, currentUserId: i, busy: s, onTransition: c }) {
351
351
  children: [
352
352
  /* @__PURE__ */ M(y, { className: "h-3.5 w-3.5" }),
353
353
  "Started ",
354
- a(e.startedAt)
354
+ n(e.startedAt)
355
355
  ]
356
356
  }), e.endedAt && /* @__PURE__ */ N("span", {
357
357
  className: "inline-flex items-center gap-1",
358
358
  children: [
359
359
  /* @__PURE__ */ M(b, { className: "h-3.5 w-3.5" }),
360
360
  "Ended ",
361
- a(e.endedAt)
361
+ n(e.endedAt)
362
362
  ]
363
363
  })]
364
364
  }),
365
- f.length > 0 && /* @__PURE__ */ M("div", {
365
+ c.length > 0 && /* @__PURE__ */ M("div", {
366
366
  className: "mt-auto flex flex-wrap gap-2 pt-1",
367
- children: f.map((t) => /* @__PURE__ */ M(P, {
367
+ children: c.map((t) => /* @__PURE__ */ M(P, {
368
368
  size: "sm",
369
369
  variant: t.primary ? void 0 : "outline",
370
- disabled: s,
371
- onClick: () => c(e.id, t.to),
370
+ disabled: i,
371
+ onClick: () => a(e.id, t.to),
372
372
  children: t.label
373
373
  }, t.to))
374
374
  }),
375
- p && /* @__PURE__ */ N("div", {
376
- className: `border-t border-border-seam pt-3 ${f.length === 0 ? "mt-auto" : ""}`,
375
+ l && /* @__PURE__ */ N("div", {
376
+ className: `border-t border-border-seam pt-3 ${c.length === 0 ? "mt-auto" : ""}`,
377
377
  children: [/* @__PURE__ */ N("button", {
378
378
  type: "button",
379
- onClick: () => g((e) => !e),
380
- "aria-expanded": m,
379
+ onClick: () => f((e) => !e),
380
+ "aria-expanded": u,
381
381
  className: "inline-flex items-center gap-1.5 text-sm font-medium text-accent hover:underline",
382
382
  children: [
383
383
  /* @__PURE__ */ M(D, { className: "h-4 w-4" }),
384
- m ? "Hide discussion" : "Discussion",
385
- M(m ? C : S, { className: "h-4 w-4" })
384
+ u ? "Hide discussion" : "Discussion",
385
+ M(u ? C : S, { className: "h-4 w-4" })
386
386
  ]
387
- }), /* @__PURE__ */ M(t, {
387
+ }), /* @__PURE__ */ M(p, {
388
388
  initial: !1,
389
- children: m && /* @__PURE__ */ M(n.div, {
389
+ children: u && /* @__PURE__ */ M(m.div, {
390
390
  initial: _ ? !1 : {
391
391
  opacity: 0,
392
392
  height: 0
@@ -406,7 +406,7 @@ function te({ relationship: e, currentUserId: i, busy: s, onTransition: c }) {
406
406
  className: "overflow-hidden",
407
407
  children: /* @__PURE__ */ M("div", {
408
408
  className: "mt-3",
409
- children: /* @__PURE__ */ M(h, {
409
+ children: /* @__PURE__ */ M(d, {
410
410
  entityType: "mybodyshield-coaching",
411
411
  entityId: e.id,
412
412
  title: "Coaching discussion",
@@ -420,7 +420,7 @@ function te({ relationship: e, currentUserId: i, busy: s, onTransition: c }) {
420
420
  });
421
421
  }
422
422
  function ne() {
423
- let { currentUser: t } = e(), a = r(), [o, u] = v("ALL"), [f, h] = v(!1), [g, y] = v(null), [b, x] = v(null), S = d(), C = p(), w = S.data ?? [], E = _(() => {
423
+ let { currentUser: n } = e(), r = h(), [l, d] = v("ALL"), [f, p] = v(!1), [g, y] = v(null), [b, x] = v(null), S = c(), C = u(), w = S.data ?? [], E = _(() => {
424
424
  let e = {
425
425
  PENDING: 0,
426
426
  ACTIVE: 0,
@@ -437,7 +437,7 @@ function ne() {
437
437
  value: e,
438
438
  label: e.charAt(0) + e.slice(1).toLowerCase(),
439
439
  count: E[e]
440
- }))], [w.length, E]), O = _(() => o === "ALL" ? w : w.filter((e) => e.status === o), [w, o]), A = async (e, t) => {
440
+ }))], [w.length, E]), O = _(() => l === "ALL" ? w : w.filter((e) => e.status === l), [w, l]), A = async (e, t) => {
441
441
  y(e), x(null);
442
442
  try {
443
443
  await C.mutateAsync({
@@ -450,49 +450,49 @@ function ne() {
450
450
  y(null);
451
451
  }
452
452
  }, j = S.isLoading && !S.data;
453
- return /* @__PURE__ */ N(i, {
453
+ return /* @__PURE__ */ N(t, {
454
454
  title: "Coaching",
455
455
  description: "Coach ↔ member relationships and what's shared.",
456
456
  actions: /* @__PURE__ */ N(P, {
457
- onClick: () => h(!0),
457
+ onClick: () => p(!0),
458
458
  children: [/* @__PURE__ */ M(k, { className: "mr-2 h-4 w-4" }), "New coaching"]
459
459
  }),
460
460
  children: [
461
461
  /* @__PURE__ */ M("div", {
462
462
  className: "mb-6",
463
- children: /* @__PURE__ */ M(m, {
463
+ children: /* @__PURE__ */ M(s, {
464
464
  options: D,
465
- value: o,
466
- onChange: u
465
+ value: l,
466
+ onChange: d
467
467
  })
468
468
  }),
469
469
  b && /* @__PURE__ */ M("p", {
470
470
  className: "mb-4 rounded-lg bg-status-error-bg-subtle px-3 py-2 text-sm text-status-error-text",
471
471
  children: b
472
472
  }),
473
- j ? /* @__PURE__ */ M(c, { label: "Loading coaching relationships…" }) : S.isError ? /* @__PURE__ */ M(s, {
473
+ j ? /* @__PURE__ */ M(o, { label: "Loading coaching relationships…" }) : S.isError ? /* @__PURE__ */ M(a, {
474
474
  message: "We couldn't load your coaching relationships.",
475
475
  onRetry: () => void S.refetch()
476
- }) : O.length === 0 ? /* @__PURE__ */ M(l, {
476
+ }) : O.length === 0 ? /* @__PURE__ */ M(i, {
477
477
  illustration: "empty-data",
478
478
  icon: /* @__PURE__ */ M(T, { className: "h-10 w-10" }),
479
479
  title: w.length === 0 ? "No coaching relationships" : "No relationships match this filter",
480
480
  description: w.length === 0 ? "Connect a coach and a member to start sharing training, nutrition and progress data." : "Try a different status filter, or create a new coaching relationship.",
481
481
  action: /* @__PURE__ */ N(P, {
482
- onClick: () => h(!0),
482
+ onClick: () => p(!0),
483
483
  children: [/* @__PURE__ */ M(k, { className: "mr-2 h-4 w-4" }), "New coaching"]
484
484
  })
485
- }) : /* @__PURE__ */ M(n.div, {
485
+ }) : /* @__PURE__ */ M(m.div, {
486
486
  className: "grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3",
487
- variants: a ? void 0 : q,
488
- initial: a ? !1 : "hidden",
487
+ variants: r ? void 0 : q,
488
+ initial: r ? !1 : "hidden",
489
489
  animate: "show",
490
- children: O.map((e) => /* @__PURE__ */ M(n.div, {
490
+ children: O.map((e) => /* @__PURE__ */ M(m.div, {
491
491
  className: "h-full",
492
- variants: a ? void 0 : J,
492
+ variants: r ? void 0 : J,
493
493
  children: /* @__PURE__ */ M(te, {
494
494
  relationship: e,
495
- currentUserId: t?.id,
495
+ currentUserId: n?.id,
496
496
  busy: g === e.id,
497
497
  onTransition: (e, t) => void A(e, t)
498
498
  })
@@ -500,10 +500,10 @@ function ne() {
500
500
  }),
501
501
  /* @__PURE__ */ M(ee, {
502
502
  open: f,
503
- onOpenChange: h,
503
+ onOpenChange: p,
504
504
  defaultMember: {
505
- userId: t?.id ?? "",
506
- displayName: t?.name || t?.email || ""
505
+ userId: n?.id ?? "",
506
+ displayName: n?.name || n?.email || ""
507
507
  }
508
508
  })
509
509
  ]
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Goals — targets across training, nutrition and body composition.
3
+ * @module mybodyshield/pages/goals
4
+ *
5
+ * Lists the member's `MybGoal`s with a status filter, per-goal progress meters
6
+ * and inline "update progress" / "mark achieved" actions, plus a create flow.
7
+ * KPIs (active count, achieved count, average active progress) are aggregated
8
+ * client-side from the real `mybListGoals` endpoint. No mock data.
9
+ */
10
+ export declare function GoalsPage(): import("react").JSX.Element;
11
+ //# sourceMappingURL=GoalsPage.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"GoalsPage.d.ts","sourceRoot":"","sources":["../../../../src/mybodyshield/pages/goals/GoalsPage.tsx"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AA4fH,wBAAgB,SAAS,gCAoKxB"}