@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.
- package/dist/dev/main.d.ts +2 -0
- package/dist/dev/main.d.ts.map +1 -0
- package/dist/generated/global-operations.d.ts +2 -0
- package/dist/generated/global-operations.d.ts.map +1 -0
- package/dist/generated/global-types.d.ts +18199 -0
- package/dist/generated/global-types.d.ts.map +1 -0
- package/dist/generated/wspace-operations.d.ts +2 -0
- package/dist/generated/wspace-operations.d.ts.map +1 -0
- package/dist/generated/wspace-types.d.ts +43046 -0
- package/dist/generated/wspace-types.d.ts.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +2 -1
- package/dist/mybodyshield/MyBodyShieldRoot.d.ts +5 -0
- package/dist/mybodyshield/MyBodyShieldRoot.d.ts.map +1 -0
- package/dist/mybodyshield/MyBodyShieldRoutes.d.ts +4 -0
- package/dist/mybodyshield/MyBodyShieldRoutes.d.ts.map +1 -0
- package/dist/mybodyshield/MyBodyShieldRoutes.js +77 -36
- package/dist/mybodyshield/MyBodyShieldRoutes.js.map +1 -1
- package/dist/mybodyshield/components/DataTable.d.ts +28 -0
- package/dist/mybodyshield/components/DataTable.d.ts.map +1 -0
- package/dist/mybodyshield/components/EmptyState.d.ts +18 -0
- package/dist/mybodyshield/components/EmptyState.d.ts.map +1 -0
- package/dist/mybodyshield/components/EvidenceUpload.d.ts +14 -0
- package/dist/mybodyshield/components/EvidenceUpload.d.ts.map +1 -0
- package/dist/mybodyshield/components/FeatureFlagGuard.d.ts +11 -0
- package/dist/mybodyshield/components/FeatureFlagGuard.d.ts.map +1 -0
- package/dist/mybodyshield/components/FeatureFlagGuard.js +27 -0
- package/dist/mybodyshield/components/FeatureFlagGuard.js.map +1 -0
- package/dist/mybodyshield/components/FileLink.d.ts +15 -0
- package/dist/mybodyshield/components/FileLink.d.ts.map +1 -0
- package/dist/mybodyshield/components/FilterTabs.d.ts +18 -0
- package/dist/mybodyshield/components/FilterTabs.d.ts.map +1 -0
- package/dist/mybodyshield/components/MetricsCard.d.ts +23 -0
- package/dist/mybodyshield/components/MetricsCard.d.ts.map +1 -0
- package/dist/mybodyshield/components/MiniBar.d.ts +16 -0
- package/dist/mybodyshield/components/MiniBar.d.ts.map +1 -0
- package/dist/mybodyshield/components/MybDiscussion.d.ts +18 -0
- package/dist/mybodyshield/components/MybDiscussion.d.ts.map +1 -0
- package/dist/mybodyshield/components/MybDiscussion.js +5 -5
- package/dist/mybodyshield/components/MybTags.d.ts +17 -0
- package/dist/mybodyshield/components/MybTags.d.ts.map +1 -0
- package/dist/mybodyshield/components/PageDisabled.d.ts +9 -0
- package/dist/mybodyshield/components/PageDisabled.d.ts.map +1 -0
- package/dist/mybodyshield/components/PageDisabled.js +17 -0
- package/dist/mybodyshield/components/PageDisabled.js.map +1 -0
- package/dist/mybodyshield/components/PageLayout.d.ts +16 -0
- package/dist/mybodyshield/components/PageLayout.d.ts.map +1 -0
- package/dist/mybodyshield/components/Pagination.d.ts +22 -0
- package/dist/mybodyshield/components/Pagination.d.ts.map +1 -0
- package/dist/mybodyshield/components/StateViews.d.ts +25 -0
- package/dist/mybodyshield/components/StateViews.d.ts.map +1 -0
- package/dist/mybodyshield/components/StateViews.js +2 -1
- package/dist/mybodyshield/components/StateViews.js.map +1 -1
- package/dist/mybodyshield/components/StatusBadge.d.ts +9 -0
- package/dist/mybodyshield/components/StatusBadge.d.ts.map +1 -0
- package/dist/mybodyshield/components/Tabs.d.ts +17 -0
- package/dist/mybodyshield/components/Tabs.d.ts.map +1 -0
- package/dist/mybodyshield/components/UserSearchSelect.d.ts +28 -0
- package/dist/mybodyshield/components/UserSearchSelect.d.ts.map +1 -0
- package/dist/mybodyshield/components/index.d.ts +22 -0
- package/dist/mybodyshield/components/index.d.ts.map +1 -0
- package/dist/mybodyshield/components/index.js +4 -2
- package/dist/mybodyshield/context/MyBodyShieldContext.d.ts +16 -0
- package/dist/mybodyshield/context/MyBodyShieldContext.d.ts.map +1 -0
- package/dist/mybodyshield/context/index.d.ts +6 -0
- package/dist/mybodyshield/context/index.d.ts.map +1 -0
- package/dist/mybodyshield/hooks/index.d.ts +12 -0
- package/dist/mybodyshield/hooks/index.d.ts.map +1 -0
- package/dist/mybodyshield/hooks/index.js +1 -0
- package/dist/mybodyshield/hooks/useMyBodyShieldAnalytics.d.ts +21 -0
- package/dist/mybodyshield/hooks/useMyBodyShieldAnalytics.d.ts.map +1 -0
- package/dist/mybodyshield/hooks/useMyBodyShieldAnalytics.js +35 -0
- package/dist/mybodyshield/hooks/useMyBodyShieldAnalytics.js.map +1 -0
- package/dist/mybodyshield/hooks/useMyBodyShieldApi.d.ts +83 -0
- package/dist/mybodyshield/hooks/useMyBodyShieldApi.d.ts.map +1 -0
- package/dist/mybodyshield/hooks/useMybComments.d.ts +36 -0
- package/dist/mybodyshield/hooks/useMybComments.d.ts.map +1 -0
- package/dist/mybodyshield/hooks/useMybFiles.d.ts +47 -0
- package/dist/mybodyshield/hooks/useMybFiles.d.ts.map +1 -0
- package/dist/mybodyshield/hooks/useMybTags.d.ts +44 -0
- package/dist/mybodyshield/hooks/useMybTags.d.ts.map +1 -0
- package/dist/mybodyshield/hooks/useMybUsers.d.ts +27 -0
- package/dist/mybodyshield/hooks/useMybUsers.d.ts.map +1 -0
- package/dist/mybodyshield/hooks/usePager.d.ts +29 -0
- package/dist/mybodyshield/hooks/usePager.d.ts.map +1 -0
- package/dist/mybodyshield/index.d.ts +9 -0
- package/dist/mybodyshield/index.d.ts.map +1 -0
- package/dist/mybodyshield/pages/DashboardPage.d.ts +10 -0
- package/dist/mybodyshield/pages/DashboardPage.d.ts.map +1 -0
- package/dist/mybodyshield/pages/DashboardPage.js +91 -86
- package/dist/mybodyshield/pages/DashboardPage.js.map +1 -1
- package/dist/mybodyshield/pages/_shared/visuals.d.ts +77 -0
- package/dist/mybodyshield/pages/_shared/visuals.d.ts.map +1 -0
- package/dist/mybodyshield/pages/coaching/CoachingPage.d.ts +11 -0
- package/dist/mybodyshield/pages/coaching/CoachingPage.d.ts.map +1 -0
- package/dist/mybodyshield/pages/coaching/CoachingPage.js +60 -60
- package/dist/mybodyshield/pages/goals/GoalsPage.d.ts +11 -0
- package/dist/mybodyshield/pages/goals/GoalsPage.d.ts.map +1 -0
- package/dist/mybodyshield/pages/goals/GoalsPage.js +125 -125
- package/dist/mybodyshield/pages/goals/GoalsPage.js.map +1 -1
- package/dist/mybodyshield/pages/nutrition/NutritionPage.d.ts +13 -0
- package/dist/mybodyshield/pages/nutrition/NutritionPage.d.ts.map +1 -0
- package/dist/mybodyshield/pages/nutrition/NutritionPage.js +129 -129
- package/dist/mybodyshield/pages/nutrition/NutritionPage.js.map +1 -1
- package/dist/mybodyshield/pages/programs/ProgramDetailPage.d.ts +10 -0
- package/dist/mybodyshield/pages/programs/ProgramDetailPage.d.ts.map +1 -0
- package/dist/mybodyshield/pages/programs/ProgramDetailPage.js +218 -191
- package/dist/mybodyshield/pages/programs/ProgramDetailPage.js.map +1 -1
- package/dist/mybodyshield/pages/programs/ProgramsPage.d.ts +11 -0
- package/dist/mybodyshield/pages/programs/ProgramsPage.d.ts.map +1 -0
- package/dist/mybodyshield/pages/programs/ProgramsPage.js +197 -193
- package/dist/mybodyshield/pages/programs/ProgramsPage.js.map +1 -1
- package/dist/mybodyshield/pages/progress/ProgressPage.d.ts +13 -0
- package/dist/mybodyshield/pages/progress/ProgressPage.d.ts.map +1 -0
- package/dist/mybodyshield/pages/progress/ProgressPage.js +143 -143
- package/dist/mybodyshield/pages/progress/ProgressPage.js.map +1 -1
- package/dist/mybodyshield/pages/recovery/RecoveryPage.d.ts +11 -0
- package/dist/mybodyshield/pages/recovery/RecoveryPage.d.ts.map +1 -0
- package/dist/mybodyshield/pages/recovery/RecoveryPage.js +60 -60
- package/dist/mybodyshield/pages/recovery/RecoveryPage.js.map +1 -1
- package/dist/mybodyshield/pages/train/SessionDetailPage.d.ts +11 -0
- package/dist/mybodyshield/pages/train/SessionDetailPage.d.ts.map +1 -0
- package/dist/mybodyshield/pages/train/SessionDetailPage.js +184 -181
- package/dist/mybodyshield/pages/train/SessionDetailPage.js.map +1 -1
- package/dist/mybodyshield/pages/train/SessionsPage.d.ts +11 -0
- package/dist/mybodyshield/pages/train/SessionsPage.d.ts.map +1 -0
- package/dist/mybodyshield/pages/train/SessionsPage.js +119 -115
- package/dist/mybodyshield/pages/train/SessionsPage.js.map +1 -1
- package/dist/mybodyshield/services/createSandboxAssistantTransport.d.ts +24 -0
- package/dist/mybodyshield/services/createSandboxAssistantTransport.d.ts.map +1 -0
- package/dist/mybodyshield/services/createSandboxAssistantTransport.js +14 -0
- package/dist/mybodyshield/services/createSandboxAssistantTransport.js.map +1 -0
- package/dist/mybodyshield/types/assistant.d.ts +55 -0
- package/dist/mybodyshield/types/assistant.d.ts.map +1 -0
- package/dist/mybodyshield/types/index.d.ts +419 -0
- package/dist/mybodyshield/types/index.d.ts.map +1 -0
- package/dist/mybodyshield/utils/cn.d.ts +4 -0
- package/dist/mybodyshield/utils/cn.d.ts.map +1 -0
- package/dist/mybodyshield/utils/formatters.d.ts +32 -0
- package/dist/mybodyshield/utils/formatters.d.ts.map +1 -0
- package/dist/mybodyshield/utils/i18n.d.ts +6 -0
- package/dist/mybodyshield/utils/i18n.d.ts.map +1 -0
- package/dist/mybodyshield/utils/index.d.ts +9 -0
- package/dist/mybodyshield/utils/index.d.ts.map +1 -0
- package/dist/mybodyshield/utils/navigation.d.ts +14 -0
- package/dist/mybodyshield/utils/navigation.d.ts.map +1 -0
- package/dist/mybodyshield/utils/pageContext.d.ts +28 -0
- package/dist/mybodyshield/utils/pageContext.d.ts.map +1 -0
- package/dist/mybodyshield/utils/pageContext.js +62 -0
- package/dist/mybodyshield/utils/pageContext.js.map +1 -0
- package/package.json +8 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SessionDetailPage.js","names":[],"sources":["../../../../src/mybodyshield/pages/train/SessionDetailPage.tsx"],"sourcesContent":["/**\n * Train — workout session detail & live logging.\n * @module mybodyshield/pages/train\n *\n * Renders a single workout session (real `mybSession`, including its `sets`).\n * While a session is IN_PROGRESS you can log sets and complete it; completed /\n * scheduled sessions render read-only. Sets are grouped by exercise. No mock\n * data — everything comes from the myb* hooks.\n */\n\nimport { useMemo, useState } from 'react';\nimport { motion, useReducedMotion } from 'framer-motion';\nimport { useParams } from 'react-router-dom';\nimport {\n ArrowLeft,\n Plus,\n CheckCircle2,\n Dumbbell,\n Weight,\n Timer,\n Flame,\n Ruler,\n Gauge,\n AlertTriangle,\n} from 'lucide-react';\nimport {\n Button,\n GlassCard,\n Label,\n Input,\n Textarea,\n Switch,\n ResponsiveDialog,\n ResponsiveDialogContent,\n ResponsiveDialogHeader,\n ResponsiveDialogTitle,\n ResponsiveDialogDescription,\n ResponsiveDialogFooter,\n} from '@burdenoff/fe-libs/ui';\nimport {\n PageLayout,\n MetricsCard,\n StatusBadge,\n EmptyState,\n LoadingView,\n ErrorView,\n MybDiscussion,\n} from '../../components';\nimport { IconChip } from '../_shared/visuals';\nimport { useMyBodyShield } from '../../context';\nimport { useMybSession, useMybLogSet, useMybCompleteSession } from '../../hooks';\nimport {\n formatDateTime,\n formatRelativeTime,\n formatNumber,\n formatWeight,\n formatKcal,\n formatDuration,\n} from '../../utils/formatters';\nimport type { MybSessionSet } from '../../types';\n\n/** Shared entrance easing — a soft, decelerating cubic-bezier. */\nconst MOTION_EASE: [number, number, number, number] = [0.16, 1, 0.3, 1];\n\n/** Stagger container + rise-in child variants for grouped card entrances. */\nconst STAGGER_CONTAINER = {\n hidden: {},\n show: { transition: { staggerChildren: 0.06 } },\n};\nconst RISE_ITEM = {\n hidden: { opacity: 0, y: 12 },\n show: { opacity: 1, y: 0, transition: { duration: 0.35, ease: MOTION_EASE } },\n};\n\n/** Parse an optional numeric string into a number, or undefined when blank. */\nfunction numOrUndef(value: string): number | undefined {\n const trimmed = value.trim();\n if (!trimmed) return undefined;\n const n = Number(trimmed);\n return Number.isFinite(n) ? n : undefined;\n}\n\ninterface LogSetForm {\n exerciseName: string;\n setNumber: string;\n reps: string;\n weight: string;\n distanceM: string;\n durationSec: string;\n isPersonalRecord: boolean;\n}\n\nconst EMPTY_LOG_FORM: LogSetForm = {\n exerciseName: '',\n setNumber: '',\n reps: '',\n weight: '',\n distanceM: '',\n durationSec: '',\n isPersonalRecord: false,\n};\n\ninterface CompleteForm {\n caloriesBurned: string;\n perceivedExertion: string;\n notes: string;\n}\n\nconst EMPTY_COMPLETE_FORM: CompleteForm = { caloriesBurned: '', perceivedExertion: '', notes: '' };\n\nexport function SessionDetailPage() {\n const { navigateTo } = useMyBodyShield();\n const reduce = useReducedMotion();\n const { id } = useParams<{ id: string }>();\n\n const session = useMybSession(id);\n const logSet = useMybLogSet();\n const completeSession = useMybCompleteSession();\n\n const [logOpen, setLogOpen] = useState(false);\n const [logForm, setLogForm] = useState<LogSetForm>(EMPTY_LOG_FORM);\n const [logError, setLogError] = useState<string | null>(null);\n\n const [completeOpen, setCompleteOpen] = useState(false);\n const [completeForm, setCompleteForm] = useState<CompleteForm>(EMPTY_COMPLETE_FORM);\n const [completeError, setCompleteError] = useState<string | null>(null);\n\n const data = session.data;\n const sets = useMemo<MybSessionSet[]>(() => data?.sets ?? [], [data?.sets]);\n\n const groups = useMemo(() => {\n const map = new Map<string, MybSessionSet[]>();\n for (const st of sets) {\n const arr = map.get(st.exerciseName) ?? [];\n arr.push(st);\n map.set(st.exerciseName, arr);\n }\n return Array.from(map.entries()).map(([name, list]) => ({\n name,\n sets: list.slice().sort((a, b) => a.setNumber - b.setNumber),\n }));\n }, [sets]);\n\n const totalVolume = useMemo(() => sets.reduce((acc, st) => acc + st.reps * st.weight, 0), [sets]);\n\n const startedAt = data?.startedAt;\n const completedAt = data?.completedAt;\n const durationSec = useMemo(() => {\n if (!startedAt || !completedAt) return undefined;\n const start = new Date(startedAt).getTime();\n const end = new Date(completedAt).getTime();\n if (!Number.isFinite(start) || !Number.isFinite(end) || end < start) return undefined;\n return (end - start) / 1000;\n }, [startedAt, completedAt]);\n\n if (!id) {\n return (\n <PageLayout title=\"Workout session\">\n <ErrorView message=\"No session was specified.\" onRetry={() => navigateTo('train')} />\n </PageLayout>\n );\n }\n\n if (session.isLoading) {\n return (\n <PageLayout title=\"Workout session\">\n <LoadingView label=\"Loading session…\" />\n </PageLayout>\n );\n }\n\n if (session.isError || !data) {\n return (\n <PageLayout title=\"Workout session\">\n <ErrorView\n title=\"Session not found\"\n message=\"This workout session may have been removed, or you don't have access to it.\"\n onRetry={() => session.refetch()}\n />\n </PageLayout>\n );\n }\n\n const isLive = data.status === 'IN_PROGRESS';\n\n const summary = data.completedAt\n ? `Completed ${formatRelativeTime(data.completedAt)}`\n : data.startedAt\n ? `Started ${formatRelativeTime(data.startedAt)}`\n : data.scheduledFor\n ? `Scheduled ${formatRelativeTime(data.scheduledFor)}`\n : `Created ${formatRelativeTime(data.createdAt)}`;\n\n const openLog = () => {\n setLogForm(EMPTY_LOG_FORM);\n setLogError(null);\n setLogOpen(true);\n };\n\n const submitLog = async () => {\n setLogError(null);\n const exerciseName = logForm.exerciseName.trim();\n if (!exerciseName) {\n setLogError('Exercise name is required.');\n return;\n }\n try {\n const created = await logSet.mutateAsync({\n sessionId: id,\n exerciseName,\n setNumber: numOrUndef(logForm.setNumber),\n reps: numOrUndef(logForm.reps),\n weight: numOrUndef(logForm.weight),\n distanceM: numOrUndef(logForm.distanceM),\n durationSec: numOrUndef(logForm.durationSec),\n isPersonalRecord: logForm.isPersonalRecord,\n });\n // Keep the dialog open for rapid multi-set entry: preserve the exercise and\n // pre-fill the next set number, clearing the per-set measurements.\n setLogForm({\n ...EMPTY_LOG_FORM,\n exerciseName,\n setNumber: String(created.setNumber + 1),\n });\n } catch (e) {\n setLogError(e instanceof Error ? e.message : 'Failed to log the set.');\n }\n };\n\n const openComplete = () => {\n setCompleteForm(EMPTY_COMPLETE_FORM);\n setCompleteError(null);\n setCompleteOpen(true);\n };\n\n const submitComplete = async () => {\n setCompleteError(null);\n try {\n await completeSession.mutateAsync({\n id,\n input: {\n caloriesBurned: numOrUndef(completeForm.caloriesBurned),\n perceivedExertion: numOrUndef(completeForm.perceivedExertion),\n notes: completeForm.notes.trim() ? completeForm.notes.trim() : undefined,\n },\n });\n setCompleteOpen(false);\n } catch (e) {\n setCompleteError(e instanceof Error ? e.message : 'Failed to complete the session.');\n }\n };\n\n const actions = isLive ? (\n <>\n <Button variant=\"outline\" onClick={openLog}>\n <Plus className=\"h-4 w-4\" /> Log set\n </Button>\n <Button onClick={openComplete}>\n <CheckCircle2 className=\"h-4 w-4\" /> Complete\n </Button>\n </>\n ) : undefined;\n\n return (\n <PageLayout title=\"Workout session\" description={summary} actions={actions}>\n <button\n type=\"button\"\n onClick={() => navigateTo('train')}\n className=\"mb-4 inline-flex items-center gap-1.5 text-sm font-medium text-text-secondary hover:text-text-primary\"\n >\n <ArrowLeft className=\"h-4 w-4\" /> Back to sessions\n </button>\n\n {/* Header card */}\n <motion.div\n initial={reduce ? false : { opacity: 0, y: 10 }}\n animate={{ opacity: 1, y: 0 }}\n transition={reduce ? { duration: 0 } : { duration: 0.35, ease: MOTION_EASE }}\n >\n <GlassCard treatment=\"glass\" glow={isLive} className=\"p-6\">\n <div className=\"flex flex-wrap items-start justify-between gap-3\">\n <div className=\"flex items-center gap-3\">\n <IconChip\n icon={isLive ? <Flame className=\"h-5 w-5\" /> : <Dumbbell className=\"h-5 w-5\" />}\n tint={isLive ? 'var(--color-accent-teal)' : 'var(--color-accent-primary)'}\n />\n <div>\n <div className=\"flex items-center gap-2\">\n <StatusBadge status={data.status} />\n </div>\n <p className=\"mt-1 text-sm text-text-secondary\">{summary}</p>\n </div>\n </div>\n </div>\n\n <div className=\"mt-5 grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3\">\n {data.scheduledFor && (\n <div>\n <p className=\"text-xs text-text-tertiary\">Scheduled for</p>\n <p className=\"mt-0.5 text-sm font-medium text-text-primary\">\n {formatDateTime(data.scheduledFor)}\n </p>\n </div>\n )}\n {data.startedAt && (\n <div>\n <p className=\"text-xs text-text-tertiary\">Started</p>\n <p className=\"mt-0.5 text-sm font-medium text-text-primary\">\n {formatDateTime(data.startedAt)}\n </p>\n </div>\n )}\n {data.completedAt && (\n <div>\n <p className=\"text-xs text-text-tertiary\">Completed</p>\n <p className=\"mt-0.5 text-sm font-medium text-text-primary\">\n {formatDateTime(data.completedAt)}\n </p>\n </div>\n )}\n {data.perceivedExertion != null && (\n <div>\n <p className=\"text-xs text-text-tertiary\">Perceived exertion</p>\n <p className=\"mt-0.5 text-sm font-medium tabular-nums text-text-primary\">\n {data.perceivedExertion}/10 RPE\n </p>\n </div>\n )}\n {data.caloriesBurned > 0 && (\n <div>\n <p className=\"text-xs text-text-tertiary\">Calories burned</p>\n <p className=\"mt-0.5 text-sm font-medium tabular-nums text-text-primary\">\n {formatKcal(data.caloriesBurned)}\n </p>\n </div>\n )}\n </div>\n\n {data.notes && (\n <div className=\"mt-5 rounded-xl bg-bg-sunken/60 p-4\">\n <p className=\"text-xs text-text-tertiary\">Notes</p>\n <p className=\"mt-1 whitespace-pre-wrap text-sm text-text-secondary\">{data.notes}</p>\n </div>\n )}\n </GlassCard>\n </motion.div>\n\n {/* Stat cards */}\n <motion.div\n className=\"mt-6 grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-4\"\n variants={reduce ? undefined : STAGGER_CONTAINER}\n initial={reduce ? false : 'hidden'}\n animate=\"show\"\n >\n <motion.div variants={reduce ? undefined : RISE_ITEM}>\n <MetricsCard\n icon={\n <span className=\"text-action-primary-bg\">\n <Dumbbell className=\"h-5 w-5\" />\n </span>\n }\n value={formatNumber(sets.length)}\n label=\"Total sets\"\n />\n </motion.div>\n <motion.div variants={reduce ? undefined : RISE_ITEM}>\n <MetricsCard\n icon={\n <span className=\"text-action-primary-bg\">\n <Weight className=\"h-5 w-5\" />\n </span>\n }\n value={`${formatNumber(totalVolume)} kg`}\n label=\"Total volume\"\n />\n </motion.div>\n <motion.div variants={reduce ? undefined : RISE_ITEM}>\n <MetricsCard\n icon={\n <span className=\"text-action-primary-bg\">\n <Timer className=\"h-5 w-5\" />\n </span>\n }\n value={durationSec != null ? formatDuration(durationSec) : '—'}\n label=\"Duration\"\n />\n </motion.div>\n <motion.div variants={reduce ? undefined : RISE_ITEM}>\n <MetricsCard\n icon={\n <span className=\"text-action-primary-bg\">\n <Flame className=\"h-5 w-5\" />\n </span>\n }\n value={data.caloriesBurned > 0 ? formatKcal(data.caloriesBurned) : '—'}\n label=\"Calories burned\"\n />\n </motion.div>\n </motion.div>\n\n {/* Logged sets */}\n <div className=\"mt-8\">\n <div className=\"mb-3 flex items-end justify-between gap-3\">\n <div>\n <h2 className=\"text-base font-semibold text-text-primary\">Logged sets</h2>\n <p className=\"mt-0.5 text-sm text-text-secondary\">\n Every set recorded during this session, grouped by exercise.\n </p>\n </div>\n {isLive && (\n <Button variant=\"outline\" size=\"sm\" onClick={openLog} className=\"shrink-0\">\n <Plus className=\"h-4 w-4\" /> Log set\n </Button>\n )}\n </div>\n\n {groups.length === 0 ? (\n <EmptyState\n illustration=\"empty-data\"\n icon={<Dumbbell className=\"h-10 w-10\" />}\n title=\"No sets logged yet\"\n description={\n isLive\n ? 'Log your first set to start tracking this workout.'\n : 'No sets were recorded for this session.'\n }\n action={\n isLive ? (\n <Button onClick={openLog}>\n <Plus className=\"h-4 w-4\" /> Log set\n </Button>\n ) : undefined\n }\n />\n ) : (\n <motion.div\n className=\"space-y-4\"\n variants={reduce ? undefined : STAGGER_CONTAINER}\n initial={reduce ? false : 'hidden'}\n animate=\"show\"\n >\n {groups.map((group) => {\n const prCount = group.sets.filter((st) => st.isPersonalRecord).length;\n return (\n <motion.div key={group.name} variants={reduce ? undefined : RISE_ITEM}>\n <GlassCard treatment=\"plain\" className=\"p-4 transition-shadow hover:shadow-float\">\n <div className=\"mb-3 flex items-center justify-between gap-2\">\n <div className=\"flex min-w-0 items-center gap-2.5\">\n <IconChip icon={<Dumbbell className=\"h-4 w-4\" />} />\n <h3 className=\"truncate text-sm font-semibold text-text-primary\">\n {group.name}\n </h3>\n {prCount > 0 && (\n <span className=\"inline-flex items-center rounded-full bg-status-success-bg-subtle px-2 py-0.5 text-[11px] font-semibold text-status-success-text shadow-[0_0_0_3px_color-mix(in_oklab,var(--color-status-success-text)_14%,transparent)]\">\n {prCount} PR{prCount === 1 ? '' : 's'}\n </span>\n )}\n </div>\n <span className=\"shrink-0 text-xs tabular-nums text-text-tertiary\">\n {formatNumber(group.sets.length)} {group.sets.length === 1 ? 'set' : 'sets'}\n </span>\n </div>\n <ul className=\"divide-y divide-border-seam\">\n {group.sets.map((st) => {\n const isCardio = st.durationSec > 0 || st.distanceM > 0;\n return (\n <li\n key={st.id}\n className={\n 'flex flex-wrap items-center justify-between gap-2 rounded-lg px-2 py-2 transition-colors' +\n (st.isPersonalRecord\n ? ' bg-[color-mix(in_oklab,var(--color-status-success-text)_9%,transparent)]'\n : ' hover:bg-bg-sunken/40')\n }\n >\n <div className=\"flex items-center gap-2\">\n <span className=\"text-sm font-medium text-text-primary tabular-nums\">\n Set {st.setNumber}: {formatNumber(st.reps)} ×{' '}\n {formatWeight(st.weight)}\n </span>\n {st.isPersonalRecord && (\n <span className=\"inline-flex rounded-full shadow-[0_0_0_3px_color-mix(in_oklab,var(--color-status-success-text)_16%,transparent)]\">\n <StatusBadge status=\"PR\" />\n </span>\n )}\n </div>\n <div className=\"flex flex-wrap items-center gap-x-3 gap-y-1 text-xs text-text-secondary\">\n {isCardio && st.durationSec > 0 && (\n <span className=\"inline-flex items-center gap-1 tabular-nums\">\n <Timer className=\"h-3.5 w-3.5 text-accent\" />\n {formatDuration(st.durationSec)}\n </span>\n )}\n {isCardio && st.distanceM > 0 && (\n <span className=\"inline-flex items-center gap-1 tabular-nums\">\n <Ruler className=\"h-3.5 w-3.5 text-accent\" />\n {formatNumber(st.distanceM)} m\n </span>\n )}\n </div>\n </li>\n );\n })}\n </ul>\n </GlassCard>\n </motion.div>\n );\n })}\n </motion.div>\n )}\n </div>\n\n {/* Coach feedback / discussion — available for any session */}\n <div className=\"mt-8\">\n <MybDiscussion\n entityType=\"mybodyshield-session\"\n entityId={data.id}\n title=\"Coach feedback\"\n description=\"Discuss form, cues and this session's results with your coach and team.\"\n />\n </div>\n\n {/* Log set dialog */}\n <ResponsiveDialog open={logOpen} onOpenChange={setLogOpen}>\n <ResponsiveDialogContent>\n <ResponsiveDialogHeader>\n <ResponsiveDialogTitle>Log a set</ResponsiveDialogTitle>\n <ResponsiveDialogDescription>\n Record reps and load for strength work, or duration and distance for cardio. The\n dialog stays open so you can log sets back-to-back.\n </ResponsiveDialogDescription>\n </ResponsiveDialogHeader>\n\n <div className=\"space-y-4 px-1\">\n <div className=\"space-y-1.5\">\n <Label htmlFor=\"myb-set-exercise\">Exercise</Label>\n <Input\n id=\"myb-set-exercise\"\n value={logForm.exerciseName}\n onChange={(e) => setLogForm((f) => ({ ...f, exerciseName: e.target.value }))}\n placeholder=\"e.g. Back Squat\"\n />\n </div>\n\n <div className=\"grid grid-cols-2 gap-3\">\n <div className=\"space-y-1.5\">\n <Label htmlFor=\"myb-set-number\">Set number</Label>\n <Input\n id=\"myb-set-number\"\n type=\"number\"\n inputMode=\"numeric\"\n min={1}\n value={logForm.setNumber}\n onChange={(e) => setLogForm((f) => ({ ...f, setNumber: e.target.value }))}\n placeholder=\"1\"\n />\n </div>\n <div className=\"space-y-1.5\">\n <Label htmlFor=\"myb-set-reps\">Reps</Label>\n <Input\n id=\"myb-set-reps\"\n type=\"number\"\n inputMode=\"numeric\"\n min={0}\n value={logForm.reps}\n onChange={(e) => setLogForm((f) => ({ ...f, reps: e.target.value }))}\n placeholder=\"8\"\n />\n </div>\n <div className=\"space-y-1.5\">\n <Label htmlFor=\"myb-set-weight\">Weight (kg)</Label>\n <Input\n id=\"myb-set-weight\"\n type=\"number\"\n inputMode=\"decimal\"\n min={0}\n step=\"0.5\"\n value={logForm.weight}\n onChange={(e) => setLogForm((f) => ({ ...f, weight: e.target.value }))}\n placeholder=\"60\"\n />\n </div>\n <div className=\"space-y-1.5\">\n <Label htmlFor=\"myb-set-distance\">Distance (m)</Label>\n <Input\n id=\"myb-set-distance\"\n type=\"number\"\n inputMode=\"numeric\"\n min={0}\n value={logForm.distanceM}\n onChange={(e) => setLogForm((f) => ({ ...f, distanceM: e.target.value }))}\n placeholder=\"Optional\"\n />\n </div>\n <div className=\"space-y-1.5\">\n <Label htmlFor=\"myb-set-duration\">Duration (sec)</Label>\n <Input\n id=\"myb-set-duration\"\n type=\"number\"\n inputMode=\"numeric\"\n min={0}\n value={logForm.durationSec}\n onChange={(e) => setLogForm((f) => ({ ...f, durationSec: e.target.value }))}\n placeholder=\"Optional\"\n />\n </div>\n </div>\n\n <div className=\"flex items-center justify-between gap-3 rounded-xl bg-bg-sunken/60 p-3\">\n <div className=\"flex items-center gap-2\">\n <Gauge className=\"h-4 w-4 text-accent\" />\n <div>\n <Label htmlFor=\"myb-set-pr\" className=\"cursor-pointer\">\n Personal record\n </Label>\n <p className=\"text-xs text-text-tertiary\">Flag this set as a new PR.</p>\n </div>\n </div>\n <Switch\n id=\"myb-set-pr\"\n checked={logForm.isPersonalRecord}\n onCheckedChange={(v) => setLogForm((f) => ({ ...f, isPersonalRecord: v }))}\n />\n </div>\n\n {logError && <p className=\"text-sm text-status-error-text\">{logError}</p>}\n </div>\n\n <ResponsiveDialogFooter>\n <Button variant=\"outline\" onClick={() => setLogOpen(false)}>\n Done\n </Button>\n <Button onClick={submitLog} disabled={logSet.isPending}>\n {logSet.isPending ? 'Logging…' : 'Log set'}\n </Button>\n </ResponsiveDialogFooter>\n </ResponsiveDialogContent>\n </ResponsiveDialog>\n\n {/* Complete session dialog */}\n <ResponsiveDialog open={completeOpen} onOpenChange={setCompleteOpen}>\n <ResponsiveDialogContent>\n <ResponsiveDialogHeader>\n <ResponsiveDialogTitle>Complete session</ResponsiveDialogTitle>\n <ResponsiveDialogDescription>\n Wrap up this workout and record how it went.\n </ResponsiveDialogDescription>\n </ResponsiveDialogHeader>\n\n <div className=\"space-y-4 px-1\">\n {sets.length === 0 && (\n <div className=\"flex items-start gap-2.5 rounded-xl border border-status-warning-text/40 bg-status-warning-bg-subtle p-3\">\n <AlertTriangle className=\"mt-0.5 h-4 w-4 shrink-0 text-status-warning-text\" />\n <p className=\"text-sm text-text-secondary\">\n <span className=\"font-medium text-text-primary\">No sets logged.</span> You can\n still complete this session, but nothing was recorded for it.\n </p>\n </div>\n )}\n <div className=\"grid grid-cols-2 gap-3\">\n <div className=\"space-y-1.5\">\n <Label htmlFor=\"myb-complete-calories\">Calories burned</Label>\n <Input\n id=\"myb-complete-calories\"\n type=\"number\"\n inputMode=\"numeric\"\n min={0}\n value={completeForm.caloriesBurned}\n onChange={(e) =>\n setCompleteForm((f) => ({ ...f, caloriesBurned: e.target.value }))\n }\n placeholder=\"Optional\"\n />\n </div>\n <div className=\"space-y-1.5\">\n <Label htmlFor=\"myb-complete-rpe\">Perceived exertion (1–10)</Label>\n <Input\n id=\"myb-complete-rpe\"\n type=\"number\"\n inputMode=\"numeric\"\n min={1}\n max={10}\n value={completeForm.perceivedExertion}\n onChange={(e) =>\n setCompleteForm((f) => ({ ...f, perceivedExertion: e.target.value }))\n }\n placeholder=\"Optional\"\n />\n </div>\n </div>\n <div className=\"space-y-1.5\">\n <Label htmlFor=\"myb-complete-notes\">Notes</Label>\n <Textarea\n id=\"myb-complete-notes\"\n rows={3}\n value={completeForm.notes}\n onChange={(e) => setCompleteForm((f) => ({ ...f, notes: e.target.value }))}\n placeholder=\"How did the session feel?\"\n />\n </div>\n\n {completeError && <p className=\"text-sm text-status-error-text\">{completeError}</p>}\n </div>\n\n <ResponsiveDialogFooter>\n <Button variant=\"outline\" onClick={() => setCompleteOpen(false)}>\n Cancel\n </Button>\n <Button onClick={submitComplete} disabled={completeSession.isPending}>\n {completeSession.isPending ? 'Completing…' : 'Complete session'}\n </Button>\n </ResponsiveDialogFooter>\n </ResponsiveDialogContent>\n </ResponsiveDialog>\n </PageLayout>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"SessionDetailPage.js","names":[],"sources":["../../../../src/mybodyshield/pages/train/SessionDetailPage.tsx"],"sourcesContent":["/**\n * Train — workout session detail & live logging.\n * @module mybodyshield/pages/train\n *\n * Renders a single workout session (real `mybSession`, including its `sets`).\n * While a session is IN_PROGRESS you can log sets and complete it; completed /\n * scheduled sessions render read-only. Sets are grouped by exercise. No mock\n * data — everything comes from the myb* hooks.\n */\n\nimport { useMemo, useState } from 'react';\nimport { motion, useReducedMotion } from 'framer-motion';\nimport { useParams } from 'react-router-dom';\nimport {\n ArrowLeft,\n Plus,\n CheckCircle2,\n Dumbbell,\n Weight,\n Timer,\n Flame,\n Ruler,\n Gauge,\n AlertTriangle,\n} from 'lucide-react';\nimport {\n Button,\n GlassCard,\n Label,\n Input,\n Textarea,\n Switch,\n ResponsiveDialog,\n ResponsiveDialogContent,\n ResponsiveDialogHeader,\n ResponsiveDialogTitle,\n ResponsiveDialogDescription,\n ResponsiveDialogFooter,\n} from '@burdenoff/fe-libs/ui';\nimport {\n PageLayout,\n MetricsCard,\n StatusBadge,\n EmptyState,\n LoadingView,\n ErrorView,\n MybDiscussion,\n} from '../../components';\nimport { IconChip } from '../_shared/visuals';\nimport { useMyBodyShield } from '../../context';\nimport {\n useMybSession,\n useMybLogSet,\n useMybCompleteSession,\n useMyBodyShieldAnalytics,\n} from '../../hooks';\nimport {\n formatDateTime,\n formatRelativeTime,\n formatNumber,\n formatWeight,\n formatKcal,\n formatDuration,\n} from '../../utils/formatters';\nimport type { MybSessionSet } from '../../types';\n\n/** Shared entrance easing — a soft, decelerating cubic-bezier. */\nconst MOTION_EASE: [number, number, number, number] = [0.16, 1, 0.3, 1];\n\n/** Stagger container + rise-in child variants for grouped card entrances. */\nconst STAGGER_CONTAINER = {\n hidden: {},\n show: { transition: { staggerChildren: 0.06 } },\n};\nconst RISE_ITEM = {\n hidden: { opacity: 0, y: 12 },\n show: { opacity: 1, y: 0, transition: { duration: 0.35, ease: MOTION_EASE } },\n};\n\n/** Parse an optional numeric string into a number, or undefined when blank. */\nfunction numOrUndef(value: string): number | undefined {\n const trimmed = value.trim();\n if (!trimmed) return undefined;\n const n = Number(trimmed);\n return Number.isFinite(n) ? n : undefined;\n}\n\ninterface LogSetForm {\n exerciseName: string;\n setNumber: string;\n reps: string;\n weight: string;\n distanceM: string;\n durationSec: string;\n isPersonalRecord: boolean;\n}\n\nconst EMPTY_LOG_FORM: LogSetForm = {\n exerciseName: '',\n setNumber: '',\n reps: '',\n weight: '',\n distanceM: '',\n durationSec: '',\n isPersonalRecord: false,\n};\n\ninterface CompleteForm {\n caloriesBurned: string;\n perceivedExertion: string;\n notes: string;\n}\n\nconst EMPTY_COMPLETE_FORM: CompleteForm = { caloriesBurned: '', perceivedExertion: '', notes: '' };\n\nexport function SessionDetailPage() {\n const { navigateTo, workspaceId } = useMyBodyShield();\n const reduce = useReducedMotion();\n const { id } = useParams<{ id: string }>();\n const analytics = useMyBodyShieldAnalytics();\n\n const session = useMybSession(id);\n const logSet = useMybLogSet();\n const completeSession = useMybCompleteSession();\n\n const [logOpen, setLogOpen] = useState(false);\n const [logForm, setLogForm] = useState<LogSetForm>(EMPTY_LOG_FORM);\n const [logError, setLogError] = useState<string | null>(null);\n\n const [completeOpen, setCompleteOpen] = useState(false);\n const [completeForm, setCompleteForm] = useState<CompleteForm>(EMPTY_COMPLETE_FORM);\n const [completeError, setCompleteError] = useState<string | null>(null);\n\n const data = session.data;\n const sets = useMemo<MybSessionSet[]>(() => data?.sets ?? [], [data?.sets]);\n\n const groups = useMemo(() => {\n const map = new Map<string, MybSessionSet[]>();\n for (const st of sets) {\n const arr = map.get(st.exerciseName) ?? [];\n arr.push(st);\n map.set(st.exerciseName, arr);\n }\n return Array.from(map.entries()).map(([name, list]) => ({\n name,\n sets: list.slice().sort((a, b) => a.setNumber - b.setNumber),\n }));\n }, [sets]);\n\n const totalVolume = useMemo(() => sets.reduce((acc, st) => acc + st.reps * st.weight, 0), [sets]);\n\n const startedAt = data?.startedAt;\n const completedAt = data?.completedAt;\n const durationSec = useMemo(() => {\n if (!startedAt || !completedAt) return undefined;\n const start = new Date(startedAt).getTime();\n const end = new Date(completedAt).getTime();\n if (!Number.isFinite(start) || !Number.isFinite(end) || end < start) return undefined;\n return (end - start) / 1000;\n }, [startedAt, completedAt]);\n\n if (!id) {\n return (\n <PageLayout title=\"Workout session\">\n <ErrorView message=\"No session was specified.\" onRetry={() => navigateTo('train')} />\n </PageLayout>\n );\n }\n\n if (session.isLoading) {\n return (\n <PageLayout title=\"Workout session\">\n <LoadingView label=\"Loading session…\" />\n </PageLayout>\n );\n }\n\n if (session.isError || !data) {\n return (\n <PageLayout title=\"Workout session\">\n <ErrorView\n title=\"Session not found\"\n message=\"This workout session may have been removed, or you don't have access to it.\"\n onRetry={() => session.refetch()}\n />\n </PageLayout>\n );\n }\n\n const isLive = data.status === 'IN_PROGRESS';\n\n const summary = data.completedAt\n ? `Completed ${formatRelativeTime(data.completedAt)}`\n : data.startedAt\n ? `Started ${formatRelativeTime(data.startedAt)}`\n : data.scheduledFor\n ? `Scheduled ${formatRelativeTime(data.scheduledFor)}`\n : `Created ${formatRelativeTime(data.createdAt)}`;\n\n const openLog = () => {\n setLogForm(EMPTY_LOG_FORM);\n setLogError(null);\n setLogOpen(true);\n };\n\n const submitLog = async () => {\n setLogError(null);\n const exerciseName = logForm.exerciseName.trim();\n if (!exerciseName) {\n setLogError('Exercise name is required.');\n return;\n }\n try {\n const created = await logSet.mutateAsync({\n sessionId: id,\n exerciseName,\n setNumber: numOrUndef(logForm.setNumber),\n reps: numOrUndef(logForm.reps),\n weight: numOrUndef(logForm.weight),\n distanceM: numOrUndef(logForm.distanceM),\n durationSec: numOrUndef(logForm.durationSec),\n isPersonalRecord: logForm.isPersonalRecord,\n });\n // Keep the dialog open for rapid multi-set entry: preserve the exercise and\n // pre-fill the next set number, clearing the per-set measurements.\n setLogForm({\n ...EMPTY_LOG_FORM,\n exerciseName,\n setNumber: String(created.setNumber + 1),\n });\n } catch (e) {\n setLogError(e instanceof Error ? e.message : 'Failed to log the set.');\n }\n };\n\n const openComplete = () => {\n setCompleteForm(EMPTY_COMPLETE_FORM);\n setCompleteError(null);\n setCompleteOpen(true);\n };\n\n const submitComplete = async () => {\n setCompleteError(null);\n try {\n await completeSession.mutateAsync({\n id,\n input: {\n caloriesBurned: numOrUndef(completeForm.caloriesBurned),\n perceivedExertion: numOrUndef(completeForm.perceivedExertion),\n notes: completeForm.notes.trim() ? completeForm.notes.trim() : undefined,\n },\n });\n setCompleteOpen(false);\n } catch (e) {\n setCompleteError(e instanceof Error ? e.message : 'Failed to complete the session.');\n }\n };\n\n const actions = isLive ? (\n <>\n <Button variant=\"outline\" onClick={openLog}>\n <Plus className=\"h-4 w-4\" /> Log set\n </Button>\n <Button onClick={openComplete}>\n <CheckCircle2 className=\"h-4 w-4\" /> Complete\n </Button>\n </>\n ) : undefined;\n\n return (\n <PageLayout title=\"Workout session\" description={summary} actions={actions}>\n <button\n type=\"button\"\n onClick={() => navigateTo('train')}\n className=\"mb-4 inline-flex items-center gap-1.5 text-sm font-medium text-text-secondary hover:text-text-primary\"\n >\n <ArrowLeft className=\"h-4 w-4\" /> Back to sessions\n </button>\n\n {/* Header card */}\n <motion.div\n initial={reduce ? false : { opacity: 0, y: 10 }}\n animate={{ opacity: 1, y: 0 }}\n transition={reduce ? { duration: 0 } : { duration: 0.35, ease: MOTION_EASE }}\n >\n <GlassCard treatment=\"glass\" glow={isLive} className=\"p-6\">\n <div className=\"flex flex-wrap items-start justify-between gap-3\">\n <div className=\"flex items-center gap-3\">\n <IconChip\n icon={isLive ? <Flame className=\"h-5 w-5\" /> : <Dumbbell className=\"h-5 w-5\" />}\n tint={isLive ? 'var(--color-accent-teal)' : 'var(--color-accent-primary)'}\n />\n <div>\n <div className=\"flex items-center gap-2\">\n <StatusBadge status={data.status} />\n </div>\n <p className=\"mt-1 text-sm text-text-secondary\">{summary}</p>\n </div>\n </div>\n </div>\n\n <div className=\"mt-5 grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3\">\n {data.scheduledFor && (\n <div>\n <p className=\"text-xs text-text-tertiary\">Scheduled for</p>\n <p className=\"mt-0.5 text-sm font-medium text-text-primary\">\n {formatDateTime(data.scheduledFor)}\n </p>\n </div>\n )}\n {data.startedAt && (\n <div>\n <p className=\"text-xs text-text-tertiary\">Started</p>\n <p className=\"mt-0.5 text-sm font-medium text-text-primary\">\n {formatDateTime(data.startedAt)}\n </p>\n </div>\n )}\n {data.completedAt && (\n <div>\n <p className=\"text-xs text-text-tertiary\">Completed</p>\n <p className=\"mt-0.5 text-sm font-medium text-text-primary\">\n {formatDateTime(data.completedAt)}\n </p>\n </div>\n )}\n {data.perceivedExertion != null && (\n <div>\n <p className=\"text-xs text-text-tertiary\">Perceived exertion</p>\n <p className=\"mt-0.5 text-sm font-medium tabular-nums text-text-primary\">\n {data.perceivedExertion}/10 RPE\n </p>\n </div>\n )}\n {data.caloriesBurned > 0 && (\n <div>\n <p className=\"text-xs text-text-tertiary\">Calories burned</p>\n <p className=\"mt-0.5 text-sm font-medium tabular-nums text-text-primary\">\n {formatKcal(data.caloriesBurned)}\n </p>\n </div>\n )}\n </div>\n\n {data.notes && (\n <div className=\"mt-5 rounded-xl bg-bg-sunken/60 p-4\">\n <p className=\"text-xs text-text-tertiary\">Notes</p>\n <p className=\"mt-1 whitespace-pre-wrap text-sm text-text-secondary\">{data.notes}</p>\n </div>\n )}\n </GlassCard>\n </motion.div>\n\n {/* Stat cards */}\n <motion.div\n className=\"mt-6 grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-4\"\n variants={reduce ? undefined : STAGGER_CONTAINER}\n initial={reduce ? false : 'hidden'}\n animate=\"show\"\n >\n <motion.div variants={reduce ? undefined : RISE_ITEM}>\n <MetricsCard\n icon={\n <span className=\"text-action-primary-bg\">\n <Dumbbell className=\"h-5 w-5\" />\n </span>\n }\n value={formatNumber(sets.length)}\n label=\"Total sets\"\n />\n </motion.div>\n <motion.div variants={reduce ? undefined : RISE_ITEM}>\n <MetricsCard\n icon={\n <span className=\"text-action-primary-bg\">\n <Weight className=\"h-5 w-5\" />\n </span>\n }\n value={`${formatNumber(totalVolume)} kg`}\n label=\"Total volume\"\n />\n </motion.div>\n <motion.div variants={reduce ? undefined : RISE_ITEM}>\n <MetricsCard\n icon={\n <span className=\"text-action-primary-bg\">\n <Timer className=\"h-5 w-5\" />\n </span>\n }\n value={durationSec != null ? formatDuration(durationSec) : '—'}\n label=\"Duration\"\n />\n </motion.div>\n <motion.div variants={reduce ? undefined : RISE_ITEM}>\n <MetricsCard\n icon={\n <span className=\"text-action-primary-bg\">\n <Flame className=\"h-5 w-5\" />\n </span>\n }\n value={data.caloriesBurned > 0 ? formatKcal(data.caloriesBurned) : '—'}\n label=\"Calories burned\"\n />\n </motion.div>\n </motion.div>\n\n {/* Logged sets */}\n <div className=\"mt-8\">\n <div className=\"mb-3 flex items-end justify-between gap-3\">\n <div>\n <h2 className=\"text-base font-semibold text-text-primary\">Logged sets</h2>\n <p className=\"mt-0.5 text-sm text-text-secondary\">\n Every set recorded during this session, grouped by exercise.\n </p>\n </div>\n {isLive && (\n <Button variant=\"outline\" size=\"sm\" onClick={openLog} className=\"shrink-0\">\n <Plus className=\"h-4 w-4\" /> Log set\n </Button>\n )}\n </div>\n\n {groups.length === 0 ? (\n <EmptyState\n illustration=\"empty-data\"\n icon={<Dumbbell className=\"h-10 w-10\" />}\n title=\"No sets logged yet\"\n description={\n isLive\n ? 'Log your first set to start tracking this workout.'\n : 'No sets were recorded for this session.'\n }\n action={\n isLive ? (\n <Button onClick={openLog}>\n <Plus className=\"h-4 w-4\" /> Log set\n </Button>\n ) : undefined\n }\n />\n ) : (\n <motion.div\n className=\"space-y-4\"\n variants={reduce ? undefined : STAGGER_CONTAINER}\n initial={reduce ? false : 'hidden'}\n animate=\"show\"\n >\n {groups.map((group) => {\n const prCount = group.sets.filter((st) => st.isPersonalRecord).length;\n return (\n <motion.div key={group.name} variants={reduce ? undefined : RISE_ITEM}>\n <GlassCard treatment=\"plain\" className=\"p-4 transition-shadow hover:shadow-float\">\n <div className=\"mb-3 flex items-center justify-between gap-2\">\n <div className=\"flex min-w-0 items-center gap-2.5\">\n <IconChip icon={<Dumbbell className=\"h-4 w-4\" />} />\n <h3 className=\"truncate text-sm font-semibold text-text-primary\">\n {group.name}\n </h3>\n {prCount > 0 && (\n <span className=\"inline-flex items-center rounded-full bg-status-success-bg-subtle px-2 py-0.5 text-[11px] font-semibold text-status-success-text shadow-[0_0_0_3px_color-mix(in_oklab,var(--color-status-success-text)_14%,transparent)]\">\n {prCount} PR{prCount === 1 ? '' : 's'}\n </span>\n )}\n </div>\n <span className=\"shrink-0 text-xs tabular-nums text-text-tertiary\">\n {formatNumber(group.sets.length)} {group.sets.length === 1 ? 'set' : 'sets'}\n </span>\n </div>\n <ul className=\"divide-y divide-border-seam\">\n {group.sets.map((st) => {\n const isCardio = st.durationSec > 0 || st.distanceM > 0;\n return (\n <li\n key={st.id}\n className={\n 'flex flex-wrap items-center justify-between gap-2 rounded-lg px-2 py-2 transition-colors' +\n (st.isPersonalRecord\n ? ' bg-[color-mix(in_oklab,var(--color-status-success-text)_9%,transparent)]'\n : ' hover:bg-bg-sunken/40')\n }\n >\n <div className=\"flex items-center gap-2\">\n <span className=\"text-sm font-medium text-text-primary tabular-nums\">\n Set {st.setNumber}: {formatNumber(st.reps)} ×{' '}\n {formatWeight(st.weight)}\n </span>\n {st.isPersonalRecord && (\n <span className=\"inline-flex rounded-full shadow-[0_0_0_3px_color-mix(in_oklab,var(--color-status-success-text)_16%,transparent)]\">\n <StatusBadge status=\"PR\" />\n </span>\n )}\n </div>\n <div className=\"flex flex-wrap items-center gap-x-3 gap-y-1 text-xs text-text-secondary\">\n {isCardio && st.durationSec > 0 && (\n <span className=\"inline-flex items-center gap-1 tabular-nums\">\n <Timer className=\"h-3.5 w-3.5 text-accent\" />\n {formatDuration(st.durationSec)}\n </span>\n )}\n {isCardio && st.distanceM > 0 && (\n <span className=\"inline-flex items-center gap-1 tabular-nums\">\n <Ruler className=\"h-3.5 w-3.5 text-accent\" />\n {formatNumber(st.distanceM)} m\n </span>\n )}\n </div>\n </li>\n );\n })}\n </ul>\n </GlassCard>\n </motion.div>\n );\n })}\n </motion.div>\n )}\n </div>\n\n {/* Coach feedback / discussion — available for any session */}\n <div className=\"mt-8\">\n <MybDiscussion\n entityType=\"mybodyshield-session\"\n entityId={data.id}\n title=\"Coach feedback\"\n description=\"Discuss form, cues and this session's results with your coach and team.\"\n />\n </div>\n\n {/* Log set dialog */}\n <ResponsiveDialog open={logOpen} onOpenChange={setLogOpen}>\n <ResponsiveDialogContent>\n <ResponsiveDialogHeader>\n <ResponsiveDialogTitle>Log a set</ResponsiveDialogTitle>\n <ResponsiveDialogDescription>\n Record reps and load for strength work, or duration and distance for cardio. The\n dialog stays open so you can log sets back-to-back.\n </ResponsiveDialogDescription>\n </ResponsiveDialogHeader>\n\n <div className=\"space-y-4 px-1\">\n <div className=\"space-y-1.5\">\n <Label htmlFor=\"myb-set-exercise\">Exercise</Label>\n <Input\n id=\"myb-set-exercise\"\n value={logForm.exerciseName}\n onChange={(e) => setLogForm((f) => ({ ...f, exerciseName: e.target.value }))}\n placeholder=\"e.g. Back Squat\"\n />\n </div>\n\n <div className=\"grid grid-cols-2 gap-3\">\n <div className=\"space-y-1.5\">\n <Label htmlFor=\"myb-set-number\">Set number</Label>\n <Input\n id=\"myb-set-number\"\n type=\"number\"\n inputMode=\"numeric\"\n min={1}\n value={logForm.setNumber}\n onChange={(e) => setLogForm((f) => ({ ...f, setNumber: e.target.value }))}\n placeholder=\"1\"\n />\n </div>\n <div className=\"space-y-1.5\">\n <Label htmlFor=\"myb-set-reps\">Reps</Label>\n <Input\n id=\"myb-set-reps\"\n type=\"number\"\n inputMode=\"numeric\"\n min={0}\n value={logForm.reps}\n onChange={(e) => setLogForm((f) => ({ ...f, reps: e.target.value }))}\n placeholder=\"8\"\n />\n </div>\n <div className=\"space-y-1.5\">\n <Label htmlFor=\"myb-set-weight\">Weight (kg)</Label>\n <Input\n id=\"myb-set-weight\"\n type=\"number\"\n inputMode=\"decimal\"\n min={0}\n step=\"0.5\"\n value={logForm.weight}\n onChange={(e) => setLogForm((f) => ({ ...f, weight: e.target.value }))}\n placeholder=\"60\"\n />\n </div>\n <div className=\"space-y-1.5\">\n <Label htmlFor=\"myb-set-distance\">Distance (m)</Label>\n <Input\n id=\"myb-set-distance\"\n type=\"number\"\n inputMode=\"numeric\"\n min={0}\n value={logForm.distanceM}\n onChange={(e) => setLogForm((f) => ({ ...f, distanceM: e.target.value }))}\n placeholder=\"Optional\"\n />\n </div>\n <div className=\"space-y-1.5\">\n <Label htmlFor=\"myb-set-duration\">Duration (sec)</Label>\n <Input\n id=\"myb-set-duration\"\n type=\"number\"\n inputMode=\"numeric\"\n min={0}\n value={logForm.durationSec}\n onChange={(e) => setLogForm((f) => ({ ...f, durationSec: e.target.value }))}\n placeholder=\"Optional\"\n />\n </div>\n </div>\n\n <div className=\"flex items-center justify-between gap-3 rounded-xl bg-bg-sunken/60 p-3\">\n <div className=\"flex items-center gap-2\">\n <Gauge className=\"h-4 w-4 text-accent\" />\n <div>\n <Label htmlFor=\"myb-set-pr\" className=\"cursor-pointer\">\n Personal record\n </Label>\n <p className=\"text-xs text-text-tertiary\">Flag this set as a new PR.</p>\n </div>\n </div>\n <Switch\n id=\"myb-set-pr\"\n checked={logForm.isPersonalRecord}\n onCheckedChange={(v) => setLogForm((f) => ({ ...f, isPersonalRecord: v }))}\n />\n </div>\n\n {logError && <p className=\"text-sm text-status-error-text\">{logError}</p>}\n </div>\n\n <ResponsiveDialogFooter>\n <Button variant=\"outline\" onClick={() => setLogOpen(false)}>\n Done\n </Button>\n <Button onClick={submitLog} disabled={logSet.isPending}>\n {logSet.isPending ? 'Logging…' : 'Log set'}\n </Button>\n </ResponsiveDialogFooter>\n </ResponsiveDialogContent>\n </ResponsiveDialog>\n\n {/* Complete session dialog */}\n <ResponsiveDialog open={completeOpen} onOpenChange={setCompleteOpen}>\n <ResponsiveDialogContent>\n <ResponsiveDialogHeader>\n <ResponsiveDialogTitle>Complete session</ResponsiveDialogTitle>\n <ResponsiveDialogDescription>\n Wrap up this workout and record how it went.\n </ResponsiveDialogDescription>\n </ResponsiveDialogHeader>\n\n <div className=\"space-y-4 px-1\">\n {sets.length === 0 && (\n <div className=\"flex items-start gap-2.5 rounded-xl border border-status-warning-text/40 bg-status-warning-bg-subtle p-3\">\n <AlertTriangle className=\"mt-0.5 h-4 w-4 shrink-0 text-status-warning-text\" />\n <p className=\"text-sm text-text-secondary\">\n <span className=\"font-medium text-text-primary\">No sets logged.</span> You can\n still complete this session, but nothing was recorded for it.\n </p>\n </div>\n )}\n <div className=\"grid grid-cols-2 gap-3\">\n <div className=\"space-y-1.5\">\n <Label htmlFor=\"myb-complete-calories\">Calories burned</Label>\n <Input\n id=\"myb-complete-calories\"\n type=\"number\"\n inputMode=\"numeric\"\n min={0}\n value={completeForm.caloriesBurned}\n onChange={(e) =>\n setCompleteForm((f) => ({ ...f, caloriesBurned: e.target.value }))\n }\n placeholder=\"Optional\"\n />\n </div>\n <div className=\"space-y-1.5\">\n <Label htmlFor=\"myb-complete-rpe\">Perceived exertion (1–10)</Label>\n <Input\n id=\"myb-complete-rpe\"\n type=\"number\"\n inputMode=\"numeric\"\n min={1}\n max={10}\n value={completeForm.perceivedExertion}\n onChange={(e) =>\n setCompleteForm((f) => ({ ...f, perceivedExertion: e.target.value }))\n }\n placeholder=\"Optional\"\n />\n </div>\n </div>\n <div className=\"space-y-1.5\">\n <Label htmlFor=\"myb-complete-notes\">Notes</Label>\n <Textarea\n id=\"myb-complete-notes\"\n rows={3}\n value={completeForm.notes}\n onChange={(e) => setCompleteForm((f) => ({ ...f, notes: e.target.value }))}\n placeholder=\"How did the session feel?\"\n />\n </div>\n\n {completeError && <p className=\"text-sm text-status-error-text\">{completeError}</p>}\n </div>\n\n <ResponsiveDialogFooter>\n <Button variant=\"outline\" onClick={() => setCompleteOpen(false)}>\n Cancel\n </Button>\n <Button onClick={submitComplete} disabled={completeSession.isPending}>\n {completeSession.isPending ? 'Completing…' : 'Complete session'}\n </Button>\n </ResponsiveDialogFooter>\n </ResponsiveDialogContent>\n </ResponsiveDialog>\n </PageLayout>\n );\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Train — live workout sessions.
|
|
3
|
+
* @module mybodyshield/pages/train
|
|
4
|
+
*
|
|
5
|
+
* Lists the member's workout sessions (real `mybListSessions`) filtered by
|
|
6
|
+
* status, and lets you start a new live session (optionally attached to an
|
|
7
|
+
* active program). In-progress sessions are highlighted with an accent ring and
|
|
8
|
+
* a "Resume" affordance. No mock data — everything comes from the myb* hooks.
|
|
9
|
+
*/
|
|
10
|
+
export declare function SessionsPage(): import("react").JSX.Element;
|
|
11
|
+
//# sourceMappingURL=SessionsPage.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SessionsPage.d.ts","sourceRoot":"","sources":["../../../../src/mybodyshield/pages/train/SessionsPage.tsx"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAkIH,wBAAgB,YAAY,gCAqQ3B"}
|