@burdenoff/microfe-mybodyshield 2026.821.2 → 2026.830.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (90) hide show
  1. package/dist/mybodyshield/MyBodyShieldRoot.d.ts.map +1 -1
  2. package/dist/mybodyshield/MyBodyShieldRoot.js +54 -56
  3. package/dist/mybodyshield/MyBodyShieldRoot.js.map +1 -1
  4. package/dist/mybodyshield/MyBodyShieldRoutes.d.ts.map +1 -1
  5. package/dist/mybodyshield/MyBodyShieldRoutes.js +121 -62
  6. package/dist/mybodyshield/MyBodyShieldRoutes.js.map +1 -1
  7. package/dist/mybodyshield/components/EvidenceUpload.d.ts.map +1 -1
  8. package/dist/mybodyshield/components/EvidenceUpload.js +46 -45
  9. package/dist/mybodyshield/components/EvidenceUpload.js.map +1 -1
  10. package/dist/mybodyshield/components/FileLink.d.ts.map +1 -1
  11. package/dist/mybodyshield/components/FileLink.js +27 -18
  12. package/dist/mybodyshield/components/FileLink.js.map +1 -1
  13. package/dist/mybodyshield/components/MybDiscussion.d.ts +1 -1
  14. package/dist/mybodyshield/components/MybDiscussion.d.ts.map +1 -1
  15. package/dist/mybodyshield/components/MybDiscussion.js +59 -58
  16. package/dist/mybodyshield/components/MybDiscussion.js.map +1 -1
  17. package/dist/mybodyshield/components/MybTags.d.ts +1 -1
  18. package/dist/mybodyshield/components/MybTags.d.ts.map +1 -1
  19. package/dist/mybodyshield/components/MybTags.js +83 -74
  20. package/dist/mybodyshield/components/MybTags.js.map +1 -1
  21. package/dist/mybodyshield/components/PageDisabled.d.ts.map +1 -1
  22. package/dist/mybodyshield/components/PageDisabled.js +16 -11
  23. package/dist/mybodyshield/components/PageDisabled.js.map +1 -1
  24. package/dist/mybodyshield/components/Pagination.d.ts.map +1 -1
  25. package/dist/mybodyshield/components/Pagination.js +36 -27
  26. package/dist/mybodyshield/components/Pagination.js.map +1 -1
  27. package/dist/mybodyshield/components/StateViews.d.ts.map +1 -1
  28. package/dist/mybodyshield/components/StateViews.js +42 -34
  29. package/dist/mybodyshield/components/StateViews.js.map +1 -1
  30. package/dist/mybodyshield/components/UserSearchSelect.d.ts.map +1 -1
  31. package/dist/mybodyshield/components/UserSearchSelect.js +66 -68
  32. package/dist/mybodyshield/components/UserSearchSelect.js.map +1 -1
  33. package/dist/mybodyshield/hooks/index.d.ts +1 -0
  34. package/dist/mybodyshield/hooks/index.d.ts.map +1 -1
  35. package/dist/mybodyshield/hooks/index.js +1 -0
  36. package/dist/mybodyshield/hooks/useTr.d.ts +5 -0
  37. package/dist/mybodyshield/hooks/useTr.d.ts.map +1 -0
  38. package/dist/mybodyshield/hooks/useTr.js +12 -0
  39. package/dist/mybodyshield/hooks/useTr.js.map +1 -0
  40. package/dist/mybodyshield/pages/DashboardPage.d.ts.map +1 -1
  41. package/dist/mybodyshield/pages/DashboardPage.js +157 -136
  42. package/dist/mybodyshield/pages/DashboardPage.js.map +1 -1
  43. package/dist/mybodyshield/pages/SettingsPage.d.ts.map +1 -1
  44. package/dist/mybodyshield/pages/SettingsPage.js +50 -59
  45. package/dist/mybodyshield/pages/SettingsPage.js.map +1 -1
  46. package/dist/mybodyshield/pages/_shared/visuals.d.ts +2 -1
  47. package/dist/mybodyshield/pages/_shared/visuals.d.ts.map +1 -1
  48. package/dist/mybodyshield/pages/_shared/visuals.js +91 -81
  49. package/dist/mybodyshield/pages/_shared/visuals.js.map +1 -1
  50. package/dist/mybodyshield/pages/ai/AiControlsPage.d.ts.map +1 -1
  51. package/dist/mybodyshield/pages/ai/AiControlsPage.js +279 -231
  52. package/dist/mybodyshield/pages/ai/AiControlsPage.js.map +1 -1
  53. package/dist/mybodyshield/pages/coaching/CoachingPage.d.ts.map +1 -1
  54. package/dist/mybodyshield/pages/coaching/CoachingPage.js +349 -258
  55. package/dist/mybodyshield/pages/coaching/CoachingPage.js.map +1 -1
  56. package/dist/mybodyshield/pages/goals/GoalsPage.d.ts.map +1 -1
  57. package/dist/mybodyshield/pages/goals/GoalsPage.js +247 -251
  58. package/dist/mybodyshield/pages/goals/GoalsPage.js.map +1 -1
  59. package/dist/mybodyshield/pages/insights/InsightsCharts.d.ts.map +1 -1
  60. package/dist/mybodyshield/pages/insights/InsightsCharts.js +216 -213
  61. package/dist/mybodyshield/pages/insights/InsightsCharts.js.map +1 -1
  62. package/dist/mybodyshield/pages/insights/InsightsPage.d.ts.map +1 -1
  63. package/dist/mybodyshield/pages/insights/InsightsPage.js +327 -220
  64. package/dist/mybodyshield/pages/insights/InsightsPage.js.map +1 -1
  65. package/dist/mybodyshield/pages/nutrition/NutritionPage.d.ts.map +1 -1
  66. package/dist/mybodyshield/pages/nutrition/NutritionPage.js +575 -529
  67. package/dist/mybodyshield/pages/nutrition/NutritionPage.js.map +1 -1
  68. package/dist/mybodyshield/pages/programs/ProgramDetailPage.d.ts.map +1 -1
  69. package/dist/mybodyshield/pages/programs/ProgramDetailPage.js +333 -275
  70. package/dist/mybodyshield/pages/programs/ProgramDetailPage.js.map +1 -1
  71. package/dist/mybodyshield/pages/programs/ProgramsPage.d.ts.map +1 -1
  72. package/dist/mybodyshield/pages/programs/ProgramsPage.js +258 -253
  73. package/dist/mybodyshield/pages/programs/ProgramsPage.js.map +1 -1
  74. package/dist/mybodyshield/pages/progress/ProgressPage.d.ts.map +1 -1
  75. package/dist/mybodyshield/pages/progress/ProgressPage.js +271 -254
  76. package/dist/mybodyshield/pages/progress/ProgressPage.js.map +1 -1
  77. package/dist/mybodyshield/pages/recovery/RecoveryPage.d.ts.map +1 -1
  78. package/dist/mybodyshield/pages/recovery/RecoveryPage.js +206 -200
  79. package/dist/mybodyshield/pages/recovery/RecoveryPage.js.map +1 -1
  80. package/dist/mybodyshield/pages/train/SessionDetailPage.d.ts.map +1 -1
  81. package/dist/mybodyshield/pages/train/SessionDetailPage.js +327 -294
  82. package/dist/mybodyshield/pages/train/SessionDetailPage.js.map +1 -1
  83. package/dist/mybodyshield/pages/train/SessionsPage.d.ts.map +1 -1
  84. package/dist/mybodyshield/pages/train/SessionsPage.js +180 -163
  85. package/dist/mybodyshield/pages/train/SessionsPage.js.map +1 -1
  86. package/dist/mybodyshield/utils/i18n.d.ts +1 -2
  87. package/dist/mybodyshield/utils/i18n.d.ts.map +1 -1
  88. package/dist/mybodyshield/utils/i18n.js +15 -0
  89. package/dist/mybodyshield/utils/i18n.js.map +1 -0
  90. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"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 { useCallback, useEffect, useMemo, useState } from 'react';\nimport { motion, useReducedMotion } from 'framer-motion';\nimport { useParams } from 'react-router';\nimport {\n ArrowLeft,\n Plus,\n CheckCircle2,\n Dumbbell,\n Weight,\n Timer,\n Flame,\n Ruler,\n Gauge,\n AlertTriangle,\n ChevronLeft,\n ChevronRight,\n ListChecks,\n Trophy,\n WifiOff,\n X,\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 useMybWorkoutExercises,\n useMybExerciseBestSet,\n useMyBodyShieldAnalytics,\n} from '../../hooks';\nimport {\n listPendingActionsForSession,\n type PendingSessionAction,\n} from '../../lib/offlineSessionQueue';\nimport { useOfflineSessionSync } from '../../lib/useOfflineSessionSync';\nimport {\n formatDateTime,\n formatRelativeTime,\n formatNumber,\n formatWeight,\n formatKcal,\n formatDuration,\n formatEnumLabel,\n} from '../../utils/formatters';\nimport type { MybSessionSet, MybExercise } from '../../types';\n\n/**\n * Heuristic for \"this failure means we're offline, not that the request was\n * rejected\" (BOFF-4219). `graphqlFetch`'s underlying `fetch()` throws a\n * `TypeError` when the network is unreachable (no HTTP response at all);\n * a real GraphQL/backend error instead resolves with an `errors` array that\n * `mybQuery` turns into a plain `Error` with a server-authored message, so\n * checking `navigator.onLine` first and falling back to the error shape\n * keeps a genuine validation error (e.g. a deleted session) from being\n * mistaken for a connectivity gap and silently queued.\n */\nfunction isLikelyOffline(err: unknown): boolean {\n if (typeof navigator !== 'undefined' && !navigator.onLine) return true;\n if (err instanceof TypeError) return true;\n const msg = err instanceof Error ? err.message.toLowerCase() : '';\n return msg.includes('failed to fetch') || msg.includes('load failed') || msg.includes('network');\n}\n\n/** Render a queued (not-yet-synced) set the same shape as a real MybSessionSet for display. */\nfunction pendingActionToDisplaySet(action: PendingSessionAction, sessionId: string): MybSessionSet {\n const input = action.input as {\n exerciseName: string;\n setNumber?: number | null;\n reps?: number | null;\n weight?: number | null;\n distanceM?: number | null;\n durationSec?: number | null;\n isPersonalRecord?: boolean | null;\n };\n return {\n id: `pending-${action.clientActionId}`,\n workspaceId: '',\n sessionId,\n exerciseName: input.exerciseName,\n setNumber: input.setNumber ?? 1,\n reps: input.reps ?? 0,\n weight: input.weight ?? 0,\n distanceM: input.distanceM ?? 0,\n durationSec: input.durationSec ?? 0,\n isPersonalRecord: Boolean(input.isPersonalRecord),\n createdAt: action.capturedAt,\n updatedAt: action.capturedAt,\n };\n}\n\n/** Rest timer default when a set isn't part of a guided plan exercise. */\nconst DEFAULT_REST_SECONDS = 90;\n\n/** Stable empty-array reference so the \"no plan\" case never changes identity across renders. */\nconst NO_EXERCISES: readonly MybExercise[] = [];\n\n/**\n * Does a newly-logged `weight`/`reps` beat the member's prior best for this\n * exercise? Mirrors the backend's own ranking (weight desc, then reps desc).\n * `null`/`undefined` best (never logged before) is NOT treated as a record —\n * there is nothing yet to break — matching `mybExerciseBestSet`'s contract.\n */\nfunction beatsBest(weight: number, reps: number, best: MybSessionSet | null | undefined): boolean {\n if (!best) return false;\n if (weight > best.weight) return true;\n if (weight === best.weight && reps > best.reps) return true;\n return false;\n}\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 const exercisesQuery = useMybWorkoutExercises(session.data?.workoutId ?? undefined);\n\n // BOFF-4219: offline-first queue for logging sets / completing a session\n // that was started while online but hits a connectivity gap mid-workout.\n const offlineSync = useOfflineSessionSync(\n (input) => logSet.mutateAsync(input),\n (vars) => completeSession.mutateAsync(vars),\n () => session.refetch()\n );\n const [pendingActions, setPendingActions] = useState<PendingSessionAction[]>([]);\n const refreshPendingForSession = useCallback(() => {\n if (!id) return;\n void listPendingActionsForSession(id).then(setPendingActions);\n }, [id]);\n useEffect(() => {\n refreshPendingForSession();\n }, [refreshPendingForSession, offlineSync.pendingCount]);\n const pendingSets = useMemo(\n () =>\n id\n ? pendingActions\n .filter((a) => a.type === 'LOG_SET')\n .map((a) => pendingActionToDisplaySet(a, id))\n : [],\n [pendingActions, id]\n );\n const pendingComplete = pendingActions.some((a) => a.type === 'COMPLETE_SESSION');\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 const [prTouched, setPrTouched] = useState(false);\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 // Guided next-exercise stepper (BOFF-4096): `null` means \"auto-follow\" —\n // the active step tracks the first not-yet-fully-logged planned exercise;\n // an explicit index means the member manually paged away from that.\n const [manualExerciseIdx, setManualExerciseIdx] = useState<number | null>(null);\n const [prevWorkoutId, setPrevWorkoutId] = useState<string | null | undefined>(\n session.data?.workoutId\n );\n\n // Rest timer (BOFF-4096): a wall-clock deadline rather than a plain\n // countdown-in-state, so the remaining time stays correct even if the tab\n // was backgrounded and the 1s interval was throttled/paused.\n const [restEndsAt, setRestEndsAt] = useState<number | null>(null);\n const [restRemaining, setRestRemaining] = useState(0);\n\n const bestSet = useMybExerciseBestSet(logForm.exerciseName);\n\n const data = session.data;\n // BOFF-4219: sets queued offline aren't in the server-fetched `data.sets`\n // yet — merge them in so a member sees what they logged immediately,\n // even before the queue has had a chance to sync.\n const sets = useMemo<MybSessionSet[]>(\n () => [...(data?.sets ?? []), ...pendingSets],\n [data?.sets, pendingSets]\n );\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 const exercises = exercisesQuery.data ?? NO_EXERCISES;\n\n const loggedCountByExercise = useMemo(() => {\n const map = new Map<string, number>();\n for (const g of groups) map.set(g.name, g.sets.length);\n return map;\n }, [groups]);\n\n const autoExerciseIdx = useMemo(() => {\n if (exercises.length === 0) return 0;\n const idx = exercises.findIndex(\n (ex) => (loggedCountByExercise.get(ex.name) ?? 0) < Math.max(ex.sets, 1)\n );\n return idx === -1 ? exercises.length - 1 : idx;\n }, [exercises, loggedCountByExercise]);\n\n const activeExerciseIdx = Math.min(\n manualExerciseIdx ?? autoExerciseIdx,\n Math.max(exercises.length - 1, 0)\n );\n const activeExercise: MybExercise | undefined = exercises[activeExerciseIdx];\n const allExercisesDone =\n exercises.length > 0 &&\n exercises.every((ex) => (loggedCountByExercise.get(ex.name) ?? 0) >= Math.max(ex.sets, 1));\n\n // A different session's plan invalidates any manual stepper override. This\n // adjusts state during render (React's documented alternative to an\n // effect for \"reset state when a prop changes\") rather than an effect, so\n // it never causes the extra reset-then-settle render an effect would.\n if (session.data?.workoutId !== prevWorkoutId) {\n setPrevWorkoutId(session.data?.workoutId);\n setManualExerciseIdx(null);\n }\n\n // Tick the rest-timer countdown against the wall-clock deadline. The\n // effect only *subscribes* to the interval — every state update happens\n // inside the (deferred) tick callback, never synchronously in the effect\n // body itself, so starting/stopping the timer never forces an extra render.\n useEffect(() => {\n if (restEndsAt == null) return;\n const interval = window.setInterval(() => {\n const remaining = Math.max(0, Math.ceil((restEndsAt - Date.now()) / 1000));\n setRestRemaining(remaining);\n if (remaining <= 0) setRestEndsAt(null);\n }, 1000);\n return () => window.clearInterval(interval);\n }, [restEndsAt]);\n\n // Live auto-PR detection (BOFF-4096): derived at render time, not synced\n // via an effect — whether the in-progress reps/weight would beat the\n // member's historical best, unless they've manually overridden the switch\n // for this exercise.\n const weightNum = numOrUndef(logForm.weight) ?? 0;\n const repsNum = numOrUndef(logForm.reps) ?? 0;\n const autoPredictedPR =\n logForm.exerciseName.trim().length > 0 && beatsBest(weightNum, repsNum, bestSet.data);\n const effectiveIsPersonalRecord = prTouched ? logForm.isPersonalRecord : autoPredictedPR;\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 setPrTouched(false);\n setLogOpen(true);\n };\n\n /** Guided-stepper quick action: pre-fill the log dialog from a planned exercise. */\n const openLogForExercise = (exercise: MybExercise) => {\n const alreadyLogged = loggedCountByExercise.get(exercise.name) ?? 0;\n setLogForm({\n ...EMPTY_LOG_FORM,\n exerciseName: exercise.name,\n setNumber: String(alreadyLogged + 1),\n reps: exercise.reps > 0 ? String(exercise.reps) : '',\n weight: exercise.targetWeight > 0 ? String(exercise.targetWeight) : '',\n });\n setLogError(null);\n setPrTouched(false);\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 const input = {\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: effectiveIsPersonalRecord,\n };\n const advanceForm = (nextSetNumber: number) => {\n setLogForm({ ...EMPTY_LOG_FORM, exerciseName, setNumber: String(nextSetNumber) });\n setPrTouched(false);\n const restSeconds =\n activeExercise && activeExercise.name === exerciseName && activeExercise.restSeconds > 0\n ? activeExercise.restSeconds\n : DEFAULT_REST_SECONDS;\n setRestEndsAt(Date.now() + restSeconds * 1000);\n setRestRemaining(restSeconds);\n };\n // BOFF-4219: log offline-first — don't even attempt the network round-trip\n // when we already know we're offline, so the set is captured instantly.\n if (!offlineSync.isOnline) {\n await offlineSync.enqueueLogSet(id, input);\n refreshPendingForSession();\n advanceForm((numOrUndef(logForm.setNumber) ?? sets.length) + 1);\n return;\n }\n try {\n const created = await logSet.mutateAsync({ sessionId: id, ...input });\n advanceForm(created.setNumber + 1);\n } catch (e) {\n if (isLikelyOffline(e)) {\n await offlineSync.enqueueLogSet(id, input);\n refreshPendingForSession();\n advanceForm((numOrUndef(logForm.setNumber) ?? sets.length) + 1);\n return;\n }\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 const input = {\n caloriesBurned: numOrUndef(completeForm.caloriesBurned),\n perceivedExertion: numOrUndef(completeForm.perceivedExertion),\n notes: completeForm.notes.trim() ? completeForm.notes.trim() : undefined,\n };\n if (!offlineSync.isOnline) {\n await offlineSync.enqueueCompleteSession(id, input);\n refreshPendingForSession();\n setCompleteOpen(false);\n return;\n }\n try {\n await completeSession.mutateAsync({ id, input });\n setCompleteOpen(false);\n } catch (e) {\n if (isLikelyOffline(e)) {\n await offlineSync.enqueueCompleteSession(id, input);\n refreshPendingForSession();\n setCompleteOpen(false);\n return;\n }\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} disabled={pendingComplete}>\n <CheckCircle2 className=\"h-4 w-4\" /> {pendingComplete ? 'Pending sync…' : '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 {/* BOFF-4219: offline queue status — only shown when it's relevant, so\n nothing changes for a member who never leaves connectivity. */}\n {(!offlineSync.isOnline || pendingActions.length > 0) && (\n <div className=\"mb-4 flex items-center gap-2 rounded-xl border border-status-warning-text/40 bg-status-warning-bg-subtle px-4 py-2.5 text-sm text-text-primary\">\n <WifiOff className=\"h-4 w-4 shrink-0 text-status-warning-text\" />\n <span>\n {!offlineSync.isOnline\n ? `You're offline — logged sets and completion will sync automatically once you're back online${\n pendingActions.length > 0 ? ` (${pendingActions.length} queued)` : ''\n }.`\n : `Syncing ${pendingActions.length} queued ${pendingActions.length === 1 ? 'action' : 'actions'}…`}\n </span>\n {offlineSync.isOnline && pendingActions.length > 0 && (\n <Button\n variant=\"ghost\"\n onClick={offlineSync.syncNow}\n className=\"ml-auto h-7 px-2 text-xs\"\n >\n Retry now\n </Button>\n )}\n </div>\n )}\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 {/* Rest timer — appears after a set is logged, counts down to the next one */}\n {isLive && restRemaining > 0 && (\n <motion.div\n initial={reduce ? false : { opacity: 0, y: -6 }}\n animate={{ opacity: 1, y: 0 }}\n transition={reduce ? { duration: 0 } : { duration: 0.25, ease: MOTION_EASE }}\n className=\"mt-4\"\n >\n <GlassCard\n treatment=\"plain\"\n className=\"flex flex-wrap items-center justify-between gap-3 border border-accent/30 bg-accent/5 p-4\"\n >\n <div className=\"flex items-center gap-2.5\">\n <IconChip icon={<Timer className=\"h-4 w-4\" />} tint=\"var(--color-accent-teal)\" />\n <div>\n <p className=\"text-sm font-semibold text-text-primary\">Resting</p>\n <p className=\"text-xs tabular-nums text-text-secondary\">\n {formatDuration(restRemaining)} remaining\n </p>\n </div>\n </div>\n <div className=\"flex items-center gap-2\">\n <Button\n variant=\"outline\"\n size=\"sm\"\n onClick={() => {\n setRestEndsAt((prev) => (prev ? prev + 15_000 : prev));\n setRestRemaining((r) => r + 15);\n }}\n >\n +15s\n </Button>\n <Button\n variant=\"ghost\"\n size=\"sm\"\n onClick={() => {\n setRestEndsAt(null);\n setRestRemaining(0);\n }}\n >\n <X className=\"h-4 w-4\" /> Skip\n </Button>\n </div>\n </GlassCard>\n </motion.div>\n )}\n\n {/* Guided next-exercise stepper — only for sessions tied to a planned workout */}\n {isLive && exercises.length > 0 && (\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, delay: 0.05 }}\n className=\"mt-4\"\n >\n <GlassCard treatment=\"plain\" className=\"p-4\">\n <div className=\"mb-3 flex items-center justify-between gap-2\">\n <div className=\"flex items-center gap-2.5\">\n <IconChip icon={<ListChecks className=\"h-4 w-4\" />} />\n <div>\n <h3 className=\"text-sm font-semibold text-text-primary\">Guided workout</h3>\n <p className=\"text-xs text-text-secondary\">\n {allExercisesDone\n ? 'All planned exercises logged — nice work.'\n : `Exercise ${activeExerciseIdx + 1} of ${exercises.length}`}\n </p>\n </div>\n </div>\n <div className=\"flex items-center gap-1.5\">\n <Button\n variant=\"outline\"\n size=\"sm\"\n onClick={() => setManualExerciseIdx(Math.max(activeExerciseIdx - 1, 0))}\n disabled={activeExerciseIdx === 0}\n aria-label=\"Previous exercise\"\n >\n <ChevronLeft className=\"h-4 w-4\" />\n </Button>\n <Button\n variant=\"outline\"\n size=\"sm\"\n onClick={() =>\n setManualExerciseIdx(Math.min(activeExerciseIdx + 1, exercises.length - 1))\n }\n disabled={activeExerciseIdx >= exercises.length - 1}\n aria-label=\"Next exercise\"\n >\n <ChevronRight className=\"h-4 w-4\" />\n </Button>\n </div>\n </div>\n\n {activeExercise && (\n <div className=\"flex flex-wrap items-center justify-between gap-3 rounded-xl bg-bg-sunken/60 p-3\">\n <div>\n <p className=\"text-sm font-semibold text-text-primary\">{activeExercise.name}</p>\n <p className=\"mt-0.5 text-xs text-text-secondary\">\n {formatEnumLabel(activeExercise.muscleGroup)} · {activeExercise.sets} ×{' '}\n {activeExercise.reps} reps\n {activeExercise.targetWeight > 0\n ? ` @ ${formatWeight(activeExercise.targetWeight)}`\n : ''}\n {activeExercise.restSeconds > 0\n ? ` · ${formatDuration(activeExercise.restSeconds)} rest`\n : ''}\n </p>\n <p className=\"mt-0.5 text-xs tabular-nums text-text-tertiary\">\n {loggedCountByExercise.get(activeExercise.name) ?? 0} of{' '}\n {Math.max(activeExercise.sets, 1)} sets logged\n </p>\n </div>\n <Button size=\"sm\" onClick={() => openLogForExercise(activeExercise)}>\n <Plus className=\"h-4 w-4\" /> Log this exercise\n </Button>\n </div>\n )}\n </GlassCard>\n </motion.div>\n )}\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) => {\n const exerciseName = e.target.value;\n setLogForm((f) => ({ ...f, exerciseName }));\n // A different exercise has a different history — let auto-PR\n // detection recompute fresh instead of keeping a stale override.\n setPrTouched(false);\n }}\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 {effectiveIsPersonalRecord ? (\n <Trophy className=\"h-4 w-4 text-status-success-text\" />\n ) : (\n <Gauge className=\"h-4 w-4 text-accent\" />\n )}\n <div>\n <Label htmlFor=\"myb-set-pr\" className=\"cursor-pointer\">\n Personal record\n </Label>\n <p className=\"text-xs text-text-tertiary\">\n {bestSet.data\n ? `Auto-detected against your best: ${formatNumber(bestSet.data.reps)} × ${formatWeight(bestSet.data.weight)}.`\n : logForm.exerciseName.trim()\n ? 'First time logging this exercise — nothing to compare yet.'\n : 'Flag this set as a new PR.'}\n </p>\n </div>\n </div>\n <Switch\n id=\"myb-set-pr\"\n checked={effectiveIsPersonalRecord}\n onCheckedChange={(v) => {\n setPrTouched(true);\n setLogForm((f) => ({ ...f, isPersonalRecord: v }));\n }}\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":";;;;;;;;;;;;;;;;;;;;;;;;AA0FA,SAAS,GAAgB,GAAuB;AAE9C,KADI,OAAO,YAAc,OAAe,CAAC,UAAU,UAC/C,aAAe,UAAW,QAAO;CACrC,IAAM,IAAM,aAAe,QAAQ,EAAI,QAAQ,aAAa,GAAG;AAC/D,QAAO,EAAI,SAAS,kBAAkB,IAAI,EAAI,SAAS,cAAc,IAAI,EAAI,SAAS,UAAU;;AAIlG,SAAS,GAA0B,GAA8B,GAAkC;CACjG,IAAM,IAAQ,EAAO;AASrB,QAAO;EACL,IAAI,WAAW,EAAO;EACtB,aAAa;EACb;EACA,cAAc,EAAM;EACpB,WAAW,EAAM,aAAa;EAC9B,MAAM,EAAM,QAAQ;EACpB,QAAQ,EAAM,UAAU;EACxB,WAAW,EAAM,aAAa;EAC9B,aAAa,EAAM,eAAe;EAClC,kBAAkB,EAAQ,EAAM;EAChC,WAAW,EAAO;EAClB,WAAW,EAAO;EACnB;;AAIH,IAAM,KAAuB,IAGvB,KAAuC,EAAE;AAQ/C,SAAS,GAAU,GAAgB,GAAc,GAAiD;AAIhG,QAHK,IACD,IAAS,EAAK,UACd,MAAW,EAAK,UAAU,IAAO,EAAK,OAFxB;;AAOpB,IAAM,IAAgD;CAAC;CAAM;CAAG;CAAK;CAAE,EAGjE,KAAoB;CACxB,QAAQ,EAAE;CACV,MAAM,EAAE,YAAY,EAAE,iBAAiB,KAAM,EAAE;CAChD,EACK,IAAY;CAChB,QAAQ;EAAE,SAAS;EAAG,GAAG;EAAI;CAC7B,MAAM;EAAE,SAAS;EAAG,GAAG;EAAG,YAAY;GAAE,UAAU;GAAM,MAAM;GAAa;EAAE;CAC9E;AAGD,SAAS,EAAW,GAAmC;CACrD,IAAM,IAAU,EAAM,MAAM;AAC5B,KAAI,CAAC,EAAS;CACd,IAAM,IAAI,OAAO,EAAQ;AACzB,QAAO,OAAO,SAAS,EAAE,GAAG,IAAI,KAAA;;AAalC,IAAM,IAA6B;CACjC,cAAc;CACd,WAAW;CACX,MAAM;CACN,QAAQ;CACR,WAAW;CACX,aAAa;CACb,kBAAkB;CACnB,EAQK,KAAoC;CAAE,gBAAgB;CAAI,mBAAmB;CAAI,OAAO;CAAI;AAElG,SAAgB,IAAoB;CAClC,IAAM,EAAE,eAAY,oBAAgB,GAAiB,EAC/C,IAAS,IAAkB,EAC3B,EAAE,UAAO,IAA2B;AACxB,KAA0B;CAE5C,IAAM,IAAU,GAAc,EAAG,EAC3B,IAAS,IAAc,EACvB,IAAkB,IAAuB,EACzC,KAAiB,GAAuB,EAAQ,MAAM,aAAa,KAAA,EAAU,EAI7E,IAAc,IACjB,MAAU,EAAO,YAAY,EAAM,GACnC,MAAS,EAAgB,YAAY,EAAK,QACrC,EAAQ,SAAS,CACxB,EACK,CAAC,GAAgB,MAAqB,EAAiC,EAAE,CAAC,EAC1E,IAA2B,SAAkB;AAC5C,OACA,GAA6B,EAAG,CAAC,KAAK,GAAkB;IAC5D,CAAC,EAAG,CAAC;AACR,UAAgB;AACd,KAA0B;IACzB,CAAC,GAA0B,EAAY,aAAa,CAAC;CACxD,IAAM,KAAc,QAEhB,IACI,EACG,QAAQ,MAAM,EAAE,SAAS,UAAU,CACnC,KAAK,MAAM,GAA0B,GAAG,EAAG,CAAC,GAC/C,EAAE,EACR,CAAC,GAAgB,EAAG,CACrB,EACK,KAAkB,EAAe,MAAM,MAAM,EAAE,SAAS,mBAAmB,EAE3E,CAAC,IAAS,KAAc,EAAS,GAAM,EACvC,CAAC,GAAS,KAAc,EAAqB,EAAe,EAC5D,CAAC,IAAU,KAAe,EAAwB,KAAK,EACvD,CAAC,IAAW,KAAgB,EAAS,GAAM,EAE3C,CAAC,IAAc,KAAmB,EAAS,GAAM,EACjD,CAAC,GAAc,KAAmB,EAAuB,GAAoB,EAC7E,CAAC,IAAe,KAAoB,EAAwB,KAAK,EAKjE,CAAC,IAAmB,KAAwB,EAAwB,KAAK,EACzE,CAAC,IAAe,MAAoB,EACxC,EAAQ,MAAM,UACf,EAKK,CAAC,IAAY,KAAiB,EAAwB,KAAK,EAC3D,CAAC,IAAe,KAAoB,EAAS,EAAE,EAE/C,IAAU,GAAsB,EAAQ,aAAa,EAErD,IAAO,EAAQ,MAIf,IAAO,QACL,CAAC,GAAI,GAAM,QAAQ,EAAE,EAAG,GAAG,GAAY,EAC7C,CAAC,GAAM,MAAM,GAAY,CAC1B,EAEK,IAAS,QAAc;EAC3B,IAAM,oBAAM,IAAI,KAA8B;AAC9C,OAAK,IAAM,KAAM,GAAM;GACrB,IAAM,IAAM,EAAI,IAAI,EAAG,aAAa,IAAI,EAAE;AAE1C,GADA,EAAI,KAAK,EAAG,EACZ,EAAI,IAAI,EAAG,cAAc,EAAI;;AAE/B,SAAO,MAAM,KAAK,EAAI,SAAS,CAAC,CAAC,KAAK,CAAC,GAAM,QAAW;GACtD;GACA,MAAM,EAAK,OAAO,CAAC,MAAM,GAAG,MAAM,EAAE,YAAY,EAAE,UAAU;GAC7D,EAAE;IACF,CAAC,EAAK,CAAC,EAEJ,KAAc,QAAc,EAAK,QAAQ,GAAK,MAAO,IAAM,EAAG,OAAO,EAAG,QAAQ,EAAE,EAAE,CAAC,EAAK,CAAC,EAE3F,KAAY,GAAM,WAClB,KAAc,GAAM,aACpB,KAAc,QAAc;AAChC,MAAI,CAAC,MAAa,CAAC,GAAa;EAChC,IAAM,IAAQ,IAAI,KAAK,GAAU,CAAC,SAAS,EACrC,IAAM,IAAI,KAAK,GAAY,CAAC,SAAS;AACvC,SAAC,OAAO,SAAS,EAAM,IAAI,CAAC,OAAO,SAAS,EAAI,IAAI,IAAM,GAC9D,SAAQ,IAAM,KAAS;IACtB,CAAC,IAAW,GAAY,CAAC,EAEtB,IAAY,GAAe,QAAQ,IAEnC,IAAwB,QAAc;EAC1C,IAAM,oBAAM,IAAI,KAAqB;AACrC,OAAK,IAAM,KAAK,EAAQ,GAAI,IAAI,EAAE,MAAM,EAAE,KAAK,OAAO;AACtD,SAAO;IACN,CAAC,EAAO,CAAC,EAEN,KAAkB,QAAc;AACpC,MAAI,EAAU,WAAW,EAAG,QAAO;EACnC,IAAM,IAAM,EAAU,WACnB,OAAQ,EAAsB,IAAI,EAAG,KAAK,IAAI,KAAK,KAAK,IAAI,EAAG,MAAM,EAAE,CACzE;AACD,SAAO,MAAQ,KAAK,EAAU,SAAS,IAAI;IAC1C,CAAC,GAAW,EAAsB,CAAC,EAEhC,IAAoB,KAAK,IAC7B,MAAqB,IACrB,KAAK,IAAI,EAAU,SAAS,GAAG,EAAE,CAClC,EACK,IAA0C,EAAU,IACpD,KACJ,EAAU,SAAS,KACnB,EAAU,OAAO,OAAQ,EAAsB,IAAI,EAAG,KAAK,IAAI,MAAM,KAAK,IAAI,EAAG,MAAM,EAAE,CAAC;AAe5F,CATI,EAAQ,MAAM,cAAc,OAC9B,GAAiB,EAAQ,MAAM,UAAU,EACzC,EAAqB,KAAK,GAO5B,SAAgB;AACd,MAAI,MAAc,KAAM;EACxB,IAAM,IAAW,OAAO,kBAAkB;GACxC,IAAM,IAAY,KAAK,IAAI,GAAG,KAAK,MAAM,KAAa,KAAK,KAAK,IAAI,IAAK,CAAC;AAE1E,GADA,EAAiB,EAAU,EACvB,KAAa,KAAG,EAAc,KAAK;KACtC,IAAK;AACR,eAAa,OAAO,cAAc,EAAS;IAC1C,CAAC,GAAW,CAAC;CAMhB,IAAM,KAAY,EAAW,EAAQ,OAAO,IAAI,GAC1C,KAAU,EAAW,EAAQ,KAAK,IAAI,GACtC,KACJ,EAAQ,aAAa,MAAM,CAAC,SAAS,KAAK,GAAU,IAAW,IAAS,EAAQ,KAAK,EACjF,KAA4B,KAAY,EAAQ,mBAAmB;AAEzE,KAAI,CAAC,EACH,QACE,kBAAC,GAAD;EAAY,OAAM;YAChB,kBAAC,IAAD;GAAW,SAAQ;GAA4B,eAAe,EAAW,QAAQ;GAAI,CAAA;EAC1E,CAAA;AAIjB,KAAI,EAAQ,UACV,QACE,kBAAC,GAAD;EAAY,OAAM;YAChB,kBAAC,IAAD,EAAa,OAAM,oBAAqB,CAAA;EAC7B,CAAA;AAIjB,KAAI,EAAQ,WAAW,CAAC,EACtB,QACE,kBAAC,GAAD;EAAY,OAAM;YAChB,kBAAC,IAAD;GACE,OAAM;GACN,SAAQ;GACR,eAAe,EAAQ,SAAS;GAChC,CAAA;EACS,CAAA;CAIjB,IAAM,IAAS,EAAK,WAAW,eAEzB,KAAU,EAAK,cACjB,aAAa,EAAmB,EAAK,YAAY,KACjD,EAAK,YACH,WAAW,EAAmB,EAAK,UAAU,KAC7C,EAAK,eACH,aAAa,EAAmB,EAAK,aAAa,KAClD,WAAW,EAAmB,EAAK,UAAU,IAE/C,WAAgB;AAIpB,EAHA,EAAW,EAAe,EAC1B,EAAY,KAAK,EACjB,EAAa,GAAM,EACnB,EAAW,GAAK;IAIZ,MAAsB,MAA0B;EACpD,IAAM,IAAgB,EAAsB,IAAI,EAAS,KAAK,IAAI;AAUlE,EATA,EAAW;GACT,GAAG;GACH,cAAc,EAAS;GACvB,WAAW,OAAO,IAAgB,EAAE;GACpC,MAAM,EAAS,OAAO,IAAI,OAAO,EAAS,KAAK,GAAG;GAClD,QAAQ,EAAS,eAAe,IAAI,OAAO,EAAS,aAAa,GAAG;GACrE,CAAC,EACF,EAAY,KAAK,EACjB,EAAa,GAAM,EACnB,EAAW,GAAK;;AA+FlB,QACE,kBAAC,GAAD;EAAY,OAAM;EAAkB,aAAa;EAAkB,SAZrD,IACd,kBAAA,IAAA,EAAA,UAAA,CACE,kBAAC,GAAD;GAAQ,SAAQ;GAAU,SAAS;aAAnC,CACE,kBAAC,GAAD,EAAM,WAAU,WAAY,CAAA,EAAA,WACrB;MACT,kBAAC,GAAD;GAAQ,eAtCe;AAGzB,IAFA,EAAgB,GAAoB,EACpC,EAAiB,KAAK,EACtB,EAAgB,GAAK;;GAmCY,UAAU;aAAzC;IACE,kBAAC,IAAD,EAAc,WAAU,WAAY,CAAA;;IAAE,KAAkB,kBAAkB;IACnE;KACR,EAAA,CAAA,GACD,KAAA;YAGF;GACE,kBAAC,UAAD;IACE,MAAK;IACL,eAAe,EAAW,QAAQ;IAClC,WAAU;cAHZ,CAKE,kBAAC,IAAD,EAAW,WAAU,WAAY,CAAA,EAAA,oBAC1B;;IAIP,CAAC,EAAY,YAAY,EAAe,SAAS,MACjD,kBAAC,OAAD;IAAK,WAAU;cAAf;KACE,kBAAC,IAAD,EAAS,WAAU,6CAA8C,CAAA;KACjE,kBAAC,QAAD,EAAA,UACI,EAAY,WAIV,WAAW,EAAe,OAAO,UAAU,EAAe,WAAW,IAAI,WAAW,UAAU,KAH9F,8FACE,EAAe,SAAS,IAAI,KAAK,EAAe,OAAO,YAAY,GACpE,IAEA,CAAA;KACN,EAAY,YAAY,EAAe,SAAS,KAC/C,kBAAC,GAAD;MACE,SAAQ;MACR,SAAS,EAAY;MACrB,WAAU;gBACX;MAEQ,CAAA;KAEP;;GAIR,kBAAC,EAAO,KAAR;IACE,SAAS,IAAS,KAAQ;KAAE,SAAS;KAAG,GAAG;KAAI;IAC/C,SAAS;KAAE,SAAS;KAAG,GAAG;KAAG;IAC7B,YAAY,IAAS,EAAE,UAAU,GAAG,GAAG;KAAE,UAAU;KAAM,MAAM;KAAa;cAE5E,kBAAC,GAAD;KAAW,WAAU;KAAQ,MAAM;KAAQ,WAAU;eAArD;MACE,kBAAC,OAAD;OAAK,WAAU;iBACb,kBAAC,OAAD;QAAK,WAAU;kBAAf,CACE,kBAAC,GAAD;SACE,MAAe,EAAT,IAAU,KAAgC,GAAjC,EAAO,WAAU,WAAY,CAAmC;SAC/E,MAAM,IAAS,6BAA6B;SAC5C,CAAA,EACF,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,OAAD;SAAK,WAAU;mBACb,kBAAC,IAAD,EAAa,QAAQ,EAAK,QAAU,CAAA;SAChC,CAAA,EACN,kBAAC,KAAD;SAAG,WAAU;mBAAoC;SAAY,CAAA,CACzD,EAAA,CAAA,CACF;;OACF,CAAA;MAEN,kBAAC,OAAD;OAAK,WAAU;iBAAf;QACG,EAAK,gBACJ,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,KAAD;SAAG,WAAU;mBAA6B;SAAiB,CAAA,EAC3D,kBAAC,KAAD;SAAG,WAAU;mBACV,GAAe,EAAK,aAAa;SAChC,CAAA,CACA,EAAA,CAAA;QAEP,EAAK,aACJ,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,KAAD;SAAG,WAAU;mBAA6B;SAAW,CAAA,EACrD,kBAAC,KAAD;SAAG,WAAU;mBACV,GAAe,EAAK,UAAU;SAC7B,CAAA,CACA,EAAA,CAAA;QAEP,EAAK,eACJ,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,KAAD;SAAG,WAAU;mBAA6B;SAAa,CAAA,EACvD,kBAAC,KAAD;SAAG,WAAU;mBACV,GAAe,EAAK,YAAY;SAC/B,CAAA,CACA,EAAA,CAAA;QAEP,EAAK,qBAAqB,QACzB,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,KAAD;SAAG,WAAU;mBAA6B;SAAsB,CAAA,EAChE,kBAAC,KAAD;SAAG,WAAU;mBAAb,CACG,EAAK,mBAAkB,UACtB;WACA,EAAA,CAAA;QAEP,EAAK,iBAAiB,KACrB,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,KAAD;SAAG,WAAU;mBAA6B;SAAmB,CAAA,EAC7D,kBAAC,KAAD;SAAG,WAAU;mBACV,GAAW,EAAK,eAAe;SAC9B,CAAA,CACA,EAAA,CAAA;QAEJ;;MAEL,EAAK,SACJ,kBAAC,OAAD;OAAK,WAAU;iBAAf,CACE,kBAAC,KAAD;QAAG,WAAU;kBAA6B;QAAS,CAAA,EACnD,kBAAC,KAAD;QAAG,WAAU;kBAAwD,EAAK;QAAU,CAAA,CAChF;;MAEE;;IACD,CAAA;GAGZ,KAAU,KAAgB,KACzB,kBAAC,EAAO,KAAR;IACE,SAAS,IAAS,KAAQ;KAAE,SAAS;KAAG,GAAG;KAAI;IAC/C,SAAS;KAAE,SAAS;KAAG,GAAG;KAAG;IAC7B,YAAY,IAAS,EAAE,UAAU,GAAG,GAAG;KAAE,UAAU;KAAM,MAAM;KAAa;IAC5E,WAAU;cAEV,kBAAC,GAAD;KACE,WAAU;KACV,WAAU;eAFZ,CAIE,kBAAC,OAAD;MAAK,WAAU;gBAAf,CACE,kBAAC,GAAD;OAAU,MAAM,kBAAC,GAAD,EAAO,WAAU,WAAY,CAAA;OAAE,MAAK;OAA6B,CAAA,EACjF,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,KAAD;OAAG,WAAU;iBAA0C;OAAW,CAAA,EAClE,kBAAC,KAAD;OAAG,WAAU;iBAAb,CACG,EAAe,GAAc,EAAC,aAC7B;SACA,EAAA,CAAA,CACF;SACN,kBAAC,OAAD;MAAK,WAAU;gBAAf,CACE,kBAAC,GAAD;OACE,SAAQ;OACR,MAAK;OACL,eAAe;AAEb,QADA,GAAe,MAAU,KAAO,IAAO,KAAe,EACtD,GAAkB,MAAM,IAAI,GAAG;;iBAElC;OAEQ,CAAA,EACT,kBAAC,GAAD;OACE,SAAQ;OACR,MAAK;OACL,eAAe;AAEb,QADA,EAAc,KAAK,EACnB,EAAiB,EAAE;;iBALvB,CAQE,kBAAC,IAAD,EAAG,WAAU,WAAY,CAAA,EAAA,QAClB;SACL;QACI;;IACD,CAAA;GAId,KAAU,EAAU,SAAS,KAC5B,kBAAC,EAAO,KAAR;IACE,SAAS,IAAS,KAAQ;KAAE,SAAS;KAAG,GAAG;KAAI;IAC/C,SAAS;KAAE,SAAS;KAAG,GAAG;KAAG;IAC7B,YAAY,IAAS,EAAE,UAAU,GAAG,GAAG;KAAE,UAAU;KAAM,MAAM;KAAa,OAAO;KAAM;IACzF,WAAU;cAEV,kBAAC,GAAD;KAAW,WAAU;KAAQ,WAAU;eAAvC,CACE,kBAAC,OAAD;MAAK,WAAU;gBAAf,CACE,kBAAC,OAAD;OAAK,WAAU;iBAAf,CACE,kBAAC,GAAD,EAAU,MAAM,kBAAC,IAAD,EAAY,WAAU,WAAY,CAAA,EAAI,CAAA,EACtD,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,MAAD;QAAI,WAAU;kBAA0C;QAAmB,CAAA,EAC3E,kBAAC,KAAD;QAAG,WAAU;kBACV,KACG,8CACA,YAAY,IAAoB,EAAE,MAAM,EAAU;QACpD,CAAA,CACA,EAAA,CAAA,CACF;UACN,kBAAC,OAAD;OAAK,WAAU;iBAAf,CACE,kBAAC,GAAD;QACE,SAAQ;QACR,MAAK;QACL,eAAe,EAAqB,KAAK,IAAI,IAAoB,GAAG,EAAE,CAAC;QACvE,UAAU,MAAsB;QAChC,cAAW;kBAEX,kBAAC,IAAD,EAAa,WAAU,WAAY,CAAA;QAC5B,CAAA,EACT,kBAAC,GAAD;QACE,SAAQ;QACR,MAAK;QACL,eACE,EAAqB,KAAK,IAAI,IAAoB,GAAG,EAAU,SAAS,EAAE,CAAC;QAE7E,UAAU,KAAqB,EAAU,SAAS;QAClD,cAAW;kBAEX,kBAAC,IAAD,EAAc,WAAU,WAAY,CAAA;QAC7B,CAAA,CACL;SACF;SAEL,KACC,kBAAC,OAAD;MAAK,WAAU;gBAAf,CACE,kBAAC,OAAD,EAAA,UAAA;OACE,kBAAC,KAAD;QAAG,WAAU;kBAA2C,EAAe;QAAS,CAAA;OAChF,kBAAC,KAAD;QAAG,WAAU;kBAAb;SACG,GAAgB,EAAe,YAAY;SAAC;SAAI,EAAe;SAAK;SAAG;SACvE,EAAe;SAAK;SACpB,EAAe,eAAe,IAC3B,MAAM,EAAa,EAAe,aAAa,KAC/C;SACH,EAAe,cAAc,IAC1B,MAAM,EAAe,EAAe,YAAY,CAAC,SACjD;SACF;;OACJ,kBAAC,KAAD;QAAG,WAAU;kBAAb;SACG,EAAsB,IAAI,EAAe,KAAK,IAAI;SAAE;SAAI;SACxD,KAAK,IAAI,EAAe,MAAM,EAAE;SAAC;SAChC;;OACA,EAAA,CAAA,EACN,kBAAC,GAAD;OAAQ,MAAK;OAAK,eAAe,GAAmB,EAAe;iBAAnE,CACE,kBAAC,GAAD,EAAM,WAAU,WAAY,CAAA,EAAA,qBACrB;SACL;QAEE;;IACD,CAAA;GAIf,kBAAC,EAAO,KAAR;IACE,WAAU;IACV,UAAU,IAAS,KAAA,IAAY;IAC/B,SAAS,IAAS,KAAQ;IAC1B,SAAQ;cAJV;KAME,kBAAC,EAAO,KAAR;MAAY,UAAU,IAAS,KAAA,IAAY;gBACzC,kBAAC,GAAD;OACE,MACE,kBAAC,QAAD;QAAM,WAAU;kBACd,kBAAC,GAAD,EAAU,WAAU,WAAY,CAAA;QAC3B,CAAA;OAET,OAAO,EAAa,EAAK,OAAO;OAChC,OAAM;OACN,CAAA;MACS,CAAA;KACb,kBAAC,EAAO,KAAR;MAAY,UAAU,IAAS,KAAA,IAAY;gBACzC,kBAAC,GAAD;OACE,MACE,kBAAC,QAAD;QAAM,WAAU;kBACd,kBAAC,IAAD,EAAQ,WAAU,WAAY,CAAA;QACzB,CAAA;OAET,OAAO,GAAG,EAAa,GAAY,CAAC;OACpC,OAAM;OACN,CAAA;MACS,CAAA;KACb,kBAAC,EAAO,KAAR;MAAY,UAAU,IAAS,KAAA,IAAY;gBACzC,kBAAC,GAAD;OACE,MACE,kBAAC,QAAD;QAAM,WAAU;kBACd,kBAAC,GAAD,EAAO,WAAU,WAAY,CAAA;QACxB,CAAA;OAET,OAAO,MAAe,OAAqC,MAA9B,EAAe,GAAY;OACxD,OAAM;OACN,CAAA;MACS,CAAA;KACb,kBAAC,EAAO,KAAR;MAAY,UAAU,IAAS,KAAA,IAAY;gBACzC,kBAAC,GAAD;OACE,MACE,kBAAC,QAAD;QAAM,WAAU;kBACd,kBAAC,IAAD,EAAO,WAAU,WAAY,CAAA;QACxB,CAAA;OAET,OAAO,EAAK,iBAAiB,IAAI,GAAW,EAAK,eAAe,GAAG;OACnE,OAAM;OACN,CAAA;MACS,CAAA;KACF;;GAGb,kBAAC,OAAD;IAAK,WAAU;cAAf,CACE,kBAAC,OAAD;KAAK,WAAU;eAAf,CACE,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,MAAD;MAAI,WAAU;gBAA4C;MAAgB,CAAA,EAC1E,kBAAC,KAAD;MAAG,WAAU;gBAAqC;MAE9C,CAAA,CACA,EAAA,CAAA,EACL,KACC,kBAAC,GAAD;MAAQ,SAAQ;MAAU,MAAK;MAAK,SAAS;MAAS,WAAU;gBAAhE,CACE,kBAAC,GAAD,EAAM,WAAU,WAAY,CAAA,EAAA,WACrB;QAEP;QAEL,EAAO,WAAW,IACjB,kBAAC,IAAD;KACE,cAAa;KACb,MAAM,kBAAC,GAAD,EAAU,WAAU,aAAc,CAAA;KACxC,OAAM;KACN,aACE,IACI,uDACA;KAEN,QACE,IACE,kBAAC,GAAD;MAAQ,SAAS;gBAAjB,CACE,kBAAC,GAAD,EAAM,WAAU,WAAY,CAAA,EAAA,WACrB;UACP,KAAA;KAEN,CAAA,GAEF,kBAAC,EAAO,KAAR;KACE,WAAU;KACV,UAAU,IAAS,KAAA,IAAY;KAC/B,SAAS,IAAS,KAAQ;KAC1B,SAAQ;eAEP,EAAO,KAAK,MAAU;MACrB,IAAM,IAAU,EAAM,KAAK,QAAQ,MAAO,EAAG,iBAAiB,CAAC;AAC/D,aACE,kBAAC,EAAO,KAAR;OAA6B,UAAU,IAAS,KAAA,IAAY;iBAC1D,kBAAC,GAAD;QAAW,WAAU;QAAQ,WAAU;kBAAvC,CACE,kBAAC,OAAD;SAAK,WAAU;mBAAf,CACE,kBAAC,OAAD;UAAK,WAAU;oBAAf;WACE,kBAAC,GAAD,EAAU,MAAM,kBAAC,GAAD,EAAU,WAAU,WAAY,CAAA,EAAI,CAAA;WACpD,kBAAC,MAAD;YAAI,WAAU;sBACX,EAAM;YACJ,CAAA;WACJ,IAAU,KACT,kBAAC,QAAD;YAAM,WAAU;sBAAhB;aACG;aAAQ;aAAI,MAAY,IAAI,KAAK;aAC7B;;WAEL;aACN,kBAAC,QAAD;UAAM,WAAU;oBAAhB;WACG,EAAa,EAAM,KAAK,OAAO;WAAC;WAAE,EAAM,KAAK,WAAW,IAAI,QAAQ;WAChE;YACH;YACN,kBAAC,MAAD;SAAI,WAAU;mBACX,EAAM,KAAK,KAAK,MAAO;UACtB,IAAM,IAAW,EAAG,cAAc,KAAK,EAAG,YAAY;AACtD,iBACE,kBAAC,MAAD;WAEE,WACE,8FACC,EAAG,mBACA,8EACA;qBANR,CASE,kBAAC,OAAD;YAAK,WAAU;sBAAf,CACE,kBAAC,QAAD;aAAM,WAAU;uBAAhB;cAAqE;cAC9D,EAAG;cAAU;cAAG,EAAa,EAAG,KAAK;cAAC;cAAG;cAC7C,EAAa,EAAG,OAAO;cACnB;gBACN,EAAG,oBACF,kBAAC,QAAD;aAAM,WAAU;uBACd,kBAAC,IAAD,EAAa,QAAO,MAAO,CAAA;aACtB,CAAA,CAEL;eACN,kBAAC,OAAD;YAAK,WAAU;sBAAf,CACG,KAAY,EAAG,cAAc,KAC5B,kBAAC,QAAD;aAAM,WAAU;uBAAhB,CACE,kBAAC,GAAD,EAAO,WAAU,2BAA4B,CAAA,EAC5C,EAAe,EAAG,YAAY,CAC1B;gBAER,KAAY,EAAG,YAAY,KAC1B,kBAAC,QAAD;aAAM,WAAU;uBAAhB;cACE,kBAAC,IAAD,EAAO,WAAU,2BAA4B,CAAA;cAC5C,EAAa,EAAG,UAAU;cAAC;cACvB;eAEL;cACH;aAjCE,EAAG,GAiCL;WAEP;SACC,CAAA,CACK;;OACD,EA7DI,EAAM,KA6DV;OAEf;KACS,CAAA,CAEX;;GAGN,kBAAC,OAAD;IAAK,WAAU;cACb,kBAAC,IAAD;KACE,YAAW;KACX,UAAU,EAAK;KACf,OAAM;KACN,aAAY;KACZ,CAAA;IACE,CAAA;GAGN,kBAAC,IAAD;IAAkB,MAAM;IAAS,cAAc;cAC7C,kBAAC,IAAD,EAAA,UAAA;KACE,kBAAC,IAAD,EAAA,UAAA,CACE,kBAAC,IAAD,EAAA,UAAuB,aAAiC,CAAA,EACxD,kBAAC,IAAD,EAAA,UAA6B,wIAGC,CAAA,CACP,EAAA,CAAA;KAEzB,kBAAC,OAAD;MAAK,WAAU;gBAAf;OACE,kBAAC,OAAD;QAAK,WAAU;kBAAf,CACE,kBAAC,GAAD;SAAO,SAAQ;mBAAmB;SAAgB,CAAA,EAClD,kBAAC,GAAD;SACE,IAAG;SACH,OAAO,EAAQ;SACf,WAAW,MAAM;UACf,IAAM,IAAe,EAAE,OAAO;AAI9B,UAHA,GAAY,OAAO;WAAE,GAAG;WAAG;WAAc,EAAE,EAG3C,EAAa,GAAM;;SAErB,aAAY;SACZ,CAAA,CACE;;OAEN,kBAAC,OAAD;QAAK,WAAU;kBAAf;SACE,kBAAC,OAAD;UAAK,WAAU;oBAAf,CACE,kBAAC,GAAD;WAAO,SAAQ;qBAAiB;WAAkB,CAAA,EAClD,kBAAC,GAAD;WACE,IAAG;WACH,MAAK;WACL,WAAU;WACV,KAAK;WACL,OAAO,EAAQ;WACf,WAAW,MAAM,GAAY,OAAO;YAAE,GAAG;YAAG,WAAW,EAAE,OAAO;YAAO,EAAE;WACzE,aAAY;WACZ,CAAA,CACE;;SACN,kBAAC,OAAD;UAAK,WAAU;oBAAf,CACE,kBAAC,GAAD;WAAO,SAAQ;qBAAe;WAAY,CAAA,EAC1C,kBAAC,GAAD;WACE,IAAG;WACH,MAAK;WACL,WAAU;WACV,KAAK;WACL,OAAO,EAAQ;WACf,WAAW,MAAM,GAAY,OAAO;YAAE,GAAG;YAAG,MAAM,EAAE,OAAO;YAAO,EAAE;WACpE,aAAY;WACZ,CAAA,CACE;;SACN,kBAAC,OAAD;UAAK,WAAU;oBAAf,CACE,kBAAC,GAAD;WAAO,SAAQ;qBAAiB;WAAmB,CAAA,EACnD,kBAAC,GAAD;WACE,IAAG;WACH,MAAK;WACL,WAAU;WACV,KAAK;WACL,MAAK;WACL,OAAO,EAAQ;WACf,WAAW,MAAM,GAAY,OAAO;YAAE,GAAG;YAAG,QAAQ,EAAE,OAAO;YAAO,EAAE;WACtE,aAAY;WACZ,CAAA,CACE;;SACN,kBAAC,OAAD;UAAK,WAAU;oBAAf,CACE,kBAAC,GAAD;WAAO,SAAQ;qBAAmB;WAAoB,CAAA,EACtD,kBAAC,GAAD;WACE,IAAG;WACH,MAAK;WACL,WAAU;WACV,KAAK;WACL,OAAO,EAAQ;WACf,WAAW,MAAM,GAAY,OAAO;YAAE,GAAG;YAAG,WAAW,EAAE,OAAO;YAAO,EAAE;WACzE,aAAY;WACZ,CAAA,CACE;;SACN,kBAAC,OAAD;UAAK,WAAU;oBAAf,CACE,kBAAC,GAAD;WAAO,SAAQ;qBAAmB;WAAsB,CAAA,EACxD,kBAAC,GAAD;WACE,IAAG;WACH,MAAK;WACL,WAAU;WACV,KAAK;WACL,OAAO,EAAQ;WACf,WAAW,MAAM,GAAY,OAAO;YAAE,GAAG;YAAG,aAAa,EAAE,OAAO;YAAO,EAAE;WAC3E,aAAY;WACZ,CAAA,CACE;;SACF;;OAEN,kBAAC,OAAD;QAAK,WAAU;kBAAf,CACE,kBAAC,OAAD;SAAK,WAAU;mBAAf,CACG,KACC,kBAAC,IAAD,EAAQ,WAAU,oCAAqC,CAAA,GAEvD,kBAAC,IAAD,EAAO,WAAU,uBAAwB,CAAA,EAE3C,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,GAAD;UAAO,SAAQ;UAAa,WAAU;oBAAiB;UAE/C,CAAA,EACR,kBAAC,KAAD;UAAG,WAAU;oBACV,EAAQ,OACL,oCAAoC,EAAa,EAAQ,KAAK,KAAK,CAAC,KAAK,EAAa,EAAQ,KAAK,OAAO,CAAC,KAC3G,EAAQ,aAAa,MAAM,GACzB,+DACA;UACJ,CAAA,CACA,EAAA,CAAA,CACF;YACN,kBAAC,IAAD;SACE,IAAG;SACH,SAAS;SACT,kBAAkB,MAAM;AAEtB,UADA,EAAa,GAAK,EAClB,GAAY,OAAO;WAAE,GAAG;WAAG,kBAAkB;WAAG,EAAE;;SAEpD,CAAA,CACE;;OAEL,MAAY,kBAAC,KAAD;QAAG,WAAU;kBAAkC;QAAa,CAAA;OACrE;;KAEN,kBAAC,IAAD,EAAA,UAAA,CACE,kBAAC,GAAD;MAAQ,SAAQ;MAAU,eAAe,EAAW,GAAM;gBAAE;MAEnD,CAAA,EACT,kBAAC,GAAD;MAAQ,SAhnBA,YAAY;AAC5B,SAAY,KAAK;OACjB,IAAM,IAAe,EAAQ,aAAa,MAAM;AAChD,WAAI,CAAC,GAAc;AACjB,UAAY,6BAA6B;AACzC;;OAEF,IAAM,IAAQ;QACZ;QACA,WAAW,EAAW,EAAQ,UAAU;QACxC,MAAM,EAAW,EAAQ,KAAK;QAC9B,QAAQ,EAAW,EAAQ,OAAO;QAClC,WAAW,EAAW,EAAQ,UAAU;QACxC,aAAa,EAAW,EAAQ,YAAY;QAC5C,kBAAkB;QACnB,EACK,KAAe,MAA0B;AAE7C,QADA,EAAW;SAAE,GAAG;SAAgB;SAAc,WAAW,OAAO,EAAc;SAAE,CAAC,EACjF,EAAa,GAAM;QACnB,IAAM,IACJ,KAAkB,EAAe,SAAS,KAAgB,EAAe,cAAc,IACnF,EAAe,cACf;AAEN,QADA,EAAc,KAAK,KAAK,GAAG,IAAc,IAAK,EAC9C,EAAiB,EAAY;;AAI/B,WAAI,CAAC,EAAY,UAAU;AAGzB,QAFA,MAAM,EAAY,cAAc,GAAI,EAAM,EAC1C,GAA0B,EAC1B,GAAa,EAAW,EAAQ,UAAU,IAAI,EAAK,UAAU,EAAE;AAC/D;;AAEF,WAAI;AAEF,WADgB,MAAM,EAAO,YAAY;SAAE,WAAW;SAAI,GAAG;SAAO,CAAC,EACjD,YAAY,EAAE;gBAC3B,GAAG;AACV,YAAI,GAAgB,EAAE,EAAE;AAGtB,SAFA,MAAM,EAAY,cAAc,GAAI,EAAM,EAC1C,GAA0B,EAC1B,GAAa,EAAW,EAAQ,UAAU,IAAI,EAAK,UAAU,EAAE;AAC/D;;AAEF,UAAY,aAAa,QAAQ,EAAE,UAAU,yBAAyB;;;MAokBpC,UAAU,EAAO;gBAC1C,EAAO,YAAY,aAAa;MAC1B,CAAA,CACc,EAAA,CAAA;KACD,EAAA,CAAA;IACT,CAAA;GAGnB,kBAAC,IAAD;IAAkB,MAAM;IAAc,cAAc;cAClD,kBAAC,IAAD,EAAA,UAAA;KACE,kBAAC,IAAD,EAAA,UAAA,CACE,kBAAC,IAAD,EAAA,UAAuB,oBAAwC,CAAA,EAC/D,kBAAC,IAAD,EAAA,UAA6B,gDAEC,CAAA,CACP,EAAA,CAAA;KAEzB,kBAAC,OAAD;MAAK,WAAU;gBAAf;OACG,EAAK,WAAW,KACf,kBAAC,OAAD;QAAK,WAAU;kBAAf,CACE,kBAAC,IAAD,EAAe,WAAU,oDAAqD,CAAA,EAC9E,kBAAC,KAAD;SAAG,WAAU;mBAAb,CACE,kBAAC,QAAD;UAAM,WAAU;oBAAgC;UAAsB,CAAA,EAAA,yEAEpE;WACA;;OAER,kBAAC,OAAD;QAAK,WAAU;kBAAf,CACE,kBAAC,OAAD;SAAK,WAAU;mBAAf,CACE,kBAAC,GAAD;UAAO,SAAQ;oBAAwB;UAAuB,CAAA,EAC9D,kBAAC,GAAD;UACE,IAAG;UACH,MAAK;UACL,WAAU;UACV,KAAK;UACL,OAAO,EAAa;UACpB,WAAW,MACT,GAAiB,OAAO;WAAE,GAAG;WAAG,gBAAgB,EAAE,OAAO;WAAO,EAAE;UAEpE,aAAY;UACZ,CAAA,CACE;YACN,kBAAC,OAAD;SAAK,WAAU;mBAAf,CACE,kBAAC,GAAD;UAAO,SAAQ;oBAAmB;UAAiC,CAAA,EACnE,kBAAC,GAAD;UACE,IAAG;UACH,MAAK;UACL,WAAU;UACV,KAAK;UACL,KAAK;UACL,OAAO,EAAa;UACpB,WAAW,MACT,GAAiB,OAAO;WAAE,GAAG;WAAG,mBAAmB,EAAE,OAAO;WAAO,EAAE;UAEvE,aAAY;UACZ,CAAA,CACE;WACF;;OACN,kBAAC,OAAD;QAAK,WAAU;kBAAf,CACE,kBAAC,GAAD;SAAO,SAAQ;mBAAqB;SAAa,CAAA,EACjD,kBAAC,IAAD;SACE,IAAG;SACH,MAAM;SACN,OAAO,EAAa;SACpB,WAAW,MAAM,GAAiB,OAAO;UAAE,GAAG;UAAG,OAAO,EAAE,OAAO;UAAO,EAAE;SAC1E,aAAY;SACZ,CAAA,CACE;;OAEL,MAAiB,kBAAC,KAAD;QAAG,WAAU;kBAAkC;QAAkB,CAAA;OAC/E;;KAEN,kBAAC,IAAD,EAAA,UAAA,CACE,kBAAC,GAAD;MAAQ,SAAQ;MAAU,eAAe,EAAgB,GAAM;gBAAE;MAExD,CAAA,EACT,kBAAC,GAAD;MAAQ,SAtoBK,YAAY;AACjC,SAAiB,KAAK;OACtB,IAAM,IAAQ;QACZ,gBAAgB,EAAW,EAAa,eAAe;QACvD,mBAAmB,EAAW,EAAa,kBAAkB;QAC7D,OAAO,EAAa,MAAM,MAAM,GAAG,EAAa,MAAM,MAAM,GAAG,KAAA;QAChE;AACD,WAAI,CAAC,EAAY,UAAU;AAGzB,QAFA,MAAM,EAAY,uBAAuB,GAAI,EAAM,EACnD,GAA0B,EAC1B,EAAgB,GAAM;AACtB;;AAEF,WAAI;AAEF,QADA,MAAM,EAAgB,YAAY;SAAE;SAAI;SAAO,CAAC,EAChD,EAAgB,GAAM;gBACf,GAAG;AACV,YAAI,GAAgB,EAAE,EAAE;AAGtB,SAFA,MAAM,EAAY,uBAAuB,GAAI,EAAM,EACnD,GAA0B,EAC1B,EAAgB,GAAM;AACtB;;AAEF,UAAiB,aAAa,QAAQ,EAAE,UAAU,kCAAkC;;;MA+mB7C,UAAU,EAAgB;gBACxD,EAAgB,YAAY,gBAAgB;MACtC,CAAA,CACc,EAAA,CAAA;KACD,EAAA,CAAA;IACT,CAAA;GACR"}
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 { useCallback, useEffect, useMemo, useState } from 'react';\nimport { motion, useReducedMotion } from 'framer-motion';\nimport { useParams } from 'react-router';\nimport {\n ArrowLeft,\n Plus,\n CheckCircle2,\n Dumbbell,\n Weight,\n Timer,\n Flame,\n Ruler,\n Gauge,\n AlertTriangle,\n ChevronLeft,\n ChevronRight,\n ListChecks,\n Trophy,\n WifiOff,\n X,\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 useMybWorkoutExercises,\n useMybExerciseBestSet,\n useMyBodyShieldAnalytics,\n useTr,\n} from '../../hooks';\nimport {\n listPendingActionsForSession,\n type PendingSessionAction,\n} from '../../lib/offlineSessionQueue';\nimport { useOfflineSessionSync } from '../../lib/useOfflineSessionSync';\nimport {\n formatDateTime,\n formatRelativeTime,\n formatNumber,\n formatWeight,\n formatKcal,\n formatDuration,\n formatEnumLabel,\n} from '../../utils/formatters';\nimport type { MybSessionSet, MybExercise } from '../../types';\n\n/**\n * Heuristic for \"this failure means we're offline, not that the request was\n * rejected\" (BOFF-4219). `graphqlFetch`'s underlying `fetch()` throws a\n * `TypeError` when the network is unreachable (no HTTP response at all);\n * a real GraphQL/backend error instead resolves with an `errors` array that\n * `mybQuery` turns into a plain `Error` with a server-authored message, so\n * checking `navigator.onLine` first and falling back to the error shape\n * keeps a genuine validation error (e.g. a deleted session) from being\n * mistaken for a connectivity gap and silently queued.\n */\nfunction isLikelyOffline(err: unknown): boolean {\n if (typeof navigator !== 'undefined' && !navigator.onLine) return true;\n if (err instanceof TypeError) return true;\n const msg = err instanceof Error ? err.message.toLowerCase() : '';\n return msg.includes('failed to fetch') || msg.includes('load failed') || msg.includes('network');\n}\n\n/** Render a queued (not-yet-synced) set the same shape as a real MybSessionSet for display. */\nfunction pendingActionToDisplaySet(action: PendingSessionAction, sessionId: string): MybSessionSet {\n const input = action.input as {\n exerciseName: string;\n setNumber?: number | null;\n reps?: number | null;\n weight?: number | null;\n distanceM?: number | null;\n durationSec?: number | null;\n isPersonalRecord?: boolean | null;\n };\n return {\n id: `pending-${action.clientActionId}`,\n workspaceId: '',\n sessionId,\n exerciseName: input.exerciseName,\n setNumber: input.setNumber ?? 1,\n reps: input.reps ?? 0,\n weight: input.weight ?? 0,\n distanceM: input.distanceM ?? 0,\n durationSec: input.durationSec ?? 0,\n isPersonalRecord: Boolean(input.isPersonalRecord),\n createdAt: action.capturedAt,\n updatedAt: action.capturedAt,\n };\n}\n\n/** Rest timer default when a set isn't part of a guided plan exercise. */\nconst DEFAULT_REST_SECONDS = 90;\n\n/** Stable empty-array reference so the \"no plan\" case never changes identity across renders. */\nconst NO_EXERCISES: readonly MybExercise[] = [];\n\n/**\n * Does a newly-logged `weight`/`reps` beat the member's prior best for this\n * exercise? Mirrors the backend's own ranking (weight desc, then reps desc).\n * `null`/`undefined` best (never logged before) is NOT treated as a record —\n * there is nothing yet to break — matching `mybExerciseBestSet`'s contract.\n */\nfunction beatsBest(weight: number, reps: number, best: MybSessionSet | null | undefined): boolean {\n if (!best) return false;\n if (weight > best.weight) return true;\n if (weight === best.weight && reps > best.reps) return true;\n return false;\n}\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 t = useTr();\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 const exercisesQuery = useMybWorkoutExercises(session.data?.workoutId ?? undefined);\n\n // BOFF-4219: offline-first queue for logging sets / completing a session\n // that was started while online but hits a connectivity gap mid-workout.\n const offlineSync = useOfflineSessionSync(\n (input) => logSet.mutateAsync(input),\n (vars) => completeSession.mutateAsync(vars),\n () => session.refetch()\n );\n const [pendingActions, setPendingActions] = useState<PendingSessionAction[]>([]);\n const refreshPendingForSession = useCallback(() => {\n if (!id) return;\n void listPendingActionsForSession(id).then(setPendingActions);\n }, [id]);\n useEffect(() => {\n refreshPendingForSession();\n }, [refreshPendingForSession, offlineSync.pendingCount]);\n const pendingSets = useMemo(\n () =>\n id\n ? pendingActions\n .filter((a) => a.type === 'LOG_SET')\n .map((a) => pendingActionToDisplaySet(a, id))\n : [],\n [pendingActions, id]\n );\n const pendingComplete = pendingActions.some((a) => a.type === 'COMPLETE_SESSION');\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 const [prTouched, setPrTouched] = useState(false);\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 // Guided next-exercise stepper (BOFF-4096): `null` means \"auto-follow\" —\n // the active step tracks the first not-yet-fully-logged planned exercise;\n // an explicit index means the member manually paged away from that.\n const [manualExerciseIdx, setManualExerciseIdx] = useState<number | null>(null);\n const [prevWorkoutId, setPrevWorkoutId] = useState<string | null | undefined>(\n session.data?.workoutId\n );\n\n // Rest timer (BOFF-4096): a wall-clock deadline rather than a plain\n // countdown-in-state, so the remaining time stays correct even if the tab\n // was backgrounded and the 1s interval was throttled/paused.\n const [restEndsAt, setRestEndsAt] = useState<number | null>(null);\n const [restRemaining, setRestRemaining] = useState(0);\n\n const bestSet = useMybExerciseBestSet(logForm.exerciseName);\n\n const data = session.data;\n // BOFF-4219: sets queued offline aren't in the server-fetched `data.sets`\n // yet — merge them in so a member sees what they logged immediately,\n // even before the queue has had a chance to sync.\n const sets = useMemo<MybSessionSet[]>(\n () => [...(data?.sets ?? []), ...pendingSets],\n [data?.sets, pendingSets]\n );\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 const exercises = exercisesQuery.data ?? NO_EXERCISES;\n\n const loggedCountByExercise = useMemo(() => {\n const map = new Map<string, number>();\n for (const g of groups) map.set(g.name, g.sets.length);\n return map;\n }, [groups]);\n\n const autoExerciseIdx = useMemo(() => {\n if (exercises.length === 0) return 0;\n const idx = exercises.findIndex(\n (ex) => (loggedCountByExercise.get(ex.name) ?? 0) < Math.max(ex.sets, 1)\n );\n return idx === -1 ? exercises.length - 1 : idx;\n }, [exercises, loggedCountByExercise]);\n\n const activeExerciseIdx = Math.min(\n manualExerciseIdx ?? autoExerciseIdx,\n Math.max(exercises.length - 1, 0)\n );\n const activeExercise: MybExercise | undefined = exercises[activeExerciseIdx];\n const allExercisesDone =\n exercises.length > 0 &&\n exercises.every((ex) => (loggedCountByExercise.get(ex.name) ?? 0) >= Math.max(ex.sets, 1));\n\n // A different session's plan invalidates any manual stepper override. This\n // adjusts state during render (React's documented alternative to an\n // effect for \"reset state when a prop changes\") rather than an effect, so\n // it never causes the extra reset-then-settle render an effect would.\n if (session.data?.workoutId !== prevWorkoutId) {\n setPrevWorkoutId(session.data?.workoutId);\n setManualExerciseIdx(null);\n }\n\n // Tick the rest-timer countdown against the wall-clock deadline. The\n // effect only *subscribes* to the interval — every state update happens\n // inside the (deferred) tick callback, never synchronously in the effect\n // body itself, so starting/stopping the timer never forces an extra render.\n useEffect(() => {\n if (restEndsAt == null) return;\n const interval = window.setInterval(() => {\n const remaining = Math.max(0, Math.ceil((restEndsAt - Date.now()) / 1000));\n setRestRemaining(remaining);\n if (remaining <= 0) setRestEndsAt(null);\n }, 1000);\n return () => window.clearInterval(interval);\n }, [restEndsAt]);\n\n // Live auto-PR detection (BOFF-4096): derived at render time, not synced\n // via an effect — whether the in-progress reps/weight would beat the\n // member's historical best, unless they've manually overridden the switch\n // for this exercise.\n const weightNum = numOrUndef(logForm.weight) ?? 0;\n const repsNum = numOrUndef(logForm.reps) ?? 0;\n const autoPredictedPR =\n logForm.exerciseName.trim().length > 0 && beatsBest(weightNum, repsNum, bestSet.data);\n const effectiveIsPersonalRecord = prTouched ? logForm.isPersonalRecord : autoPredictedPR;\n\n if (!id) {\n return (\n <PageLayout title={t('mybodyshield.pages.sessionDetail.title', 'Workout session')}>\n <ErrorView\n message={t(\n 'mybodyshield.pages.sessionDetail.noSessionSpecified',\n 'No session was specified.'\n )}\n onRetry={() => navigateTo('train')}\n />\n </PageLayout>\n );\n }\n\n if (session.isLoading) {\n return (\n <PageLayout title={t('mybodyshield.pages.sessionDetail.title', 'Workout session')}>\n <LoadingView label={t('mybodyshield.pages.sessionDetail.loading', 'Loading session…')} />\n </PageLayout>\n );\n }\n\n if (session.isError || !data) {\n return (\n <PageLayout title={t('mybodyshield.pages.sessionDetail.title', 'Workout session')}>\n <ErrorView\n title={t('mybodyshield.pages.sessionDetail.notFound', 'Session not found')}\n message={t(\n 'mybodyshield.pages.sessionDetail.notFoundDescription',\n \"This workout session may have been removed, or you don't have access to it.\"\n )}\n onRetry={() => session.refetch()}\n />\n </PageLayout>\n );\n }\n\n const isLive = data.status === 'IN_PROGRESS';\n\n const summary = data.completedAt\n ? t('mybodyshield.pages.sessionDetail.completedAgo', 'Completed {{time}}', {\n time: formatRelativeTime(data.completedAt),\n })\n : data.startedAt\n ? t('mybodyshield.pages.sessionDetail.startedAgo', 'Started {{time}}', {\n time: formatRelativeTime(data.startedAt),\n })\n : data.scheduledFor\n ? t('mybodyshield.pages.sessionDetail.scheduledAgo', 'Scheduled {{time}}', {\n time: formatRelativeTime(data.scheduledFor),\n })\n : t('mybodyshield.pages.sessionDetail.createdAgo', 'Created {{time}}', {\n time: formatRelativeTime(data.createdAt),\n });\n\n const openLog = () => {\n setLogForm(EMPTY_LOG_FORM);\n setLogError(null);\n setPrTouched(false);\n setLogOpen(true);\n };\n\n /** Guided-stepper quick action: pre-fill the log dialog from a planned exercise. */\n const openLogForExercise = (exercise: MybExercise) => {\n const alreadyLogged = loggedCountByExercise.get(exercise.name) ?? 0;\n setLogForm({\n ...EMPTY_LOG_FORM,\n exerciseName: exercise.name,\n setNumber: String(alreadyLogged + 1),\n reps: exercise.reps > 0 ? String(exercise.reps) : '',\n weight: exercise.targetWeight > 0 ? String(exercise.targetWeight) : '',\n });\n setLogError(null);\n setPrTouched(false);\n setLogOpen(true);\n };\n\n const submitLog = async () => {\n setLogError(null);\n const exerciseName = logForm.exerciseName.trim();\n if (!exerciseName) {\n setLogError(\n t('mybodyshield.pages.sessionDetail.exerciseNameRequired', 'Exercise name is required.')\n );\n return;\n }\n const input = {\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: effectiveIsPersonalRecord,\n };\n const advanceForm = (nextSetNumber: number) => {\n setLogForm({ ...EMPTY_LOG_FORM, exerciseName, setNumber: String(nextSetNumber) });\n setPrTouched(false);\n const restSeconds =\n activeExercise && activeExercise.name === exerciseName && activeExercise.restSeconds > 0\n ? activeExercise.restSeconds\n : DEFAULT_REST_SECONDS;\n setRestEndsAt(Date.now() + restSeconds * 1000);\n setRestRemaining(restSeconds);\n };\n // BOFF-4219: log offline-first — don't even attempt the network round-trip\n // when we already know we're offline, so the set is captured instantly.\n if (!offlineSync.isOnline) {\n await offlineSync.enqueueLogSet(id, input);\n refreshPendingForSession();\n advanceForm((numOrUndef(logForm.setNumber) ?? sets.length) + 1);\n return;\n }\n try {\n const created = await logSet.mutateAsync({ sessionId: id, ...input });\n advanceForm(created.setNumber + 1);\n } catch (e) {\n if (isLikelyOffline(e)) {\n await offlineSync.enqueueLogSet(id, input);\n refreshPendingForSession();\n advanceForm((numOrUndef(logForm.setNumber) ?? sets.length) + 1);\n return;\n }\n setLogError(\n e instanceof Error\n ? e.message\n : t('mybodyshield.pages.sessionDetail.failedToLogSet', 'Failed to log the set.')\n );\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 const input = {\n caloriesBurned: numOrUndef(completeForm.caloriesBurned),\n perceivedExertion: numOrUndef(completeForm.perceivedExertion),\n notes: completeForm.notes.trim() ? completeForm.notes.trim() : undefined,\n };\n if (!offlineSync.isOnline) {\n await offlineSync.enqueueCompleteSession(id, input);\n refreshPendingForSession();\n setCompleteOpen(false);\n return;\n }\n try {\n await completeSession.mutateAsync({ id, input });\n setCompleteOpen(false);\n } catch (e) {\n if (isLikelyOffline(e)) {\n await offlineSync.enqueueCompleteSession(id, input);\n refreshPendingForSession();\n setCompleteOpen(false);\n return;\n }\n setCompleteError(\n e instanceof Error\n ? e.message\n : t(\n 'mybodyshield.pages.sessionDetail.failedToComplete',\n 'Failed to complete the session.'\n )\n );\n }\n };\n\n const actions = isLive ? (\n <>\n <Button variant=\"outline\" onClick={openLog}>\n <Plus className=\"h-4 w-4\" /> {t('mybodyshield.pages.sessionDetail.logSet', 'Log set')}\n </Button>\n <Button onClick={openComplete} disabled={pendingComplete}>\n <CheckCircle2 className=\"h-4 w-4\" />{' '}\n {pendingComplete\n ? t('mybodyshield.pages.sessionDetail.pendingSync', 'Pending sync…')\n : t('mybodyshield.pages.sessionDetail.complete', 'Complete')}\n </Button>\n </>\n ) : undefined;\n\n return (\n <PageLayout\n title={t('mybodyshield.pages.sessionDetail.title', 'Workout session')}\n description={summary}\n actions={actions}\n >\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\" />{' '}\n {t('mybodyshield.pages.sessionDetail.backToSessions', 'Back to sessions')}\n </button>\n\n {/* BOFF-4219: offline queue status — only shown when it's relevant, so\n nothing changes for a member who never leaves connectivity. */}\n {(!offlineSync.isOnline || pendingActions.length > 0) && (\n <div className=\"mb-4 flex items-center gap-2 rounded-xl border border-status-warning-text/40 bg-status-warning-bg-subtle px-4 py-2.5 text-sm text-text-primary\">\n <WifiOff className=\"h-4 w-4 shrink-0 text-status-warning-text\" />\n <span>\n {!offlineSync.isOnline\n ? t(\n 'mybodyshield.pages.sessionDetail.offlineBanner',\n \"You're offline — logged sets and completion will sync automatically once you're back online{{queue}}.\",\n {\n queue:\n pendingActions.length > 0\n ? ` (${pendingActions.length} ${t(\n 'mybodyshield.pages.sessionDetail.queued',\n 'queued'\n )})`\n : '',\n }\n )\n : t(\n 'mybodyshield.pages.sessionDetail.syncingBanner',\n 'Syncing {{count}} queued {{actions}}…',\n {\n count: pendingActions.length,\n actions: t(\n pendingActions.length === 1\n ? 'mybodyshield.pages.sessionDetail.action'\n : 'mybodyshield.pages.sessionDetail.actions',\n pendingActions.length === 1 ? 'action' : 'actions'\n ),\n }\n )}\n </span>\n {offlineSync.isOnline && pendingActions.length > 0 && (\n <Button\n variant=\"ghost\"\n onClick={offlineSync.syncNow}\n className=\"ml-auto h-7 px-2 text-xs\"\n >\n {t('mybodyshield.pages.sessionDetail.retryNow', 'Retry now')}\n </Button>\n )}\n </div>\n )}\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\">\n {t('mybodyshield.pages.sessionDetail.scheduledFor', 'Scheduled for')}\n </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\">\n {t('mybodyshield.pages.sessionDetail.started', 'Started')}\n </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\">\n {t('mybodyshield.pages.sessionDetail.completed', 'Completed')}\n </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\">\n {t('mybodyshield.pages.sessionDetail.perceivedExertion', 'Perceived exertion')}\n </p>\n <p className=\"mt-0.5 text-sm font-medium tabular-nums text-text-primary\">\n {t('mybodyshield.pages.sessionDetail.rpeValue', '{{rpe}}/10 RPE', {\n rpe: data.perceivedExertion,\n })}\n </p>\n </div>\n )}\n {data.caloriesBurned > 0 && (\n <div>\n <p className=\"text-xs text-text-tertiary\">\n {t('mybodyshield.pages.sessionDetail.caloriesBurned', 'Calories burned')}\n </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\">\n {t('mybodyshield.common.notes', 'Notes')}\n </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 {/* Rest timer — appears after a set is logged, counts down to the next one */}\n {isLive && restRemaining > 0 && (\n <motion.div\n initial={reduce ? false : { opacity: 0, y: -6 }}\n animate={{ opacity: 1, y: 0 }}\n transition={reduce ? { duration: 0 } : { duration: 0.25, ease: MOTION_EASE }}\n className=\"mt-4\"\n >\n <GlassCard\n treatment=\"plain\"\n className=\"flex flex-wrap items-center justify-between gap-3 border border-accent/30 bg-accent/5 p-4\"\n >\n <div className=\"flex items-center gap-2.5\">\n <IconChip icon={<Timer className=\"h-4 w-4\" />} tint=\"var(--color-accent-teal)\" />\n <div>\n <p className=\"text-sm font-semibold text-text-primary\">\n {t('mybodyshield.pages.sessionDetail.resting', 'Resting')}\n </p>\n <p className=\"text-xs tabular-nums text-text-secondary\">\n {t('mybodyshield.pages.sessionDetail.remaining', '{{time}} remaining', {\n time: formatDuration(restRemaining),\n })}\n </p>\n </div>\n </div>\n <div className=\"flex items-center gap-2\">\n <Button\n variant=\"outline\"\n size=\"sm\"\n onClick={() => {\n setRestEndsAt((prev) => (prev ? prev + 15_000 : prev));\n setRestRemaining((r) => r + 15);\n }}\n >\n {t('mybodyshield.pages.sessionDetail.add15s', '+15s')}\n </Button>\n <Button\n variant=\"ghost\"\n size=\"sm\"\n onClick={() => {\n setRestEndsAt(null);\n setRestRemaining(0);\n }}\n >\n <X className=\"h-4 w-4\" /> {t('mybodyshield.pages.sessionDetail.skipRest', 'Skip')}\n </Button>\n </div>\n </GlassCard>\n </motion.div>\n )}\n\n {/* Guided next-exercise stepper — only for sessions tied to a planned workout */}\n {isLive && exercises.length > 0 && (\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, delay: 0.05 }}\n className=\"mt-4\"\n >\n <GlassCard treatment=\"plain\" className=\"p-4\">\n <div className=\"mb-3 flex items-center justify-between gap-2\">\n <div className=\"flex items-center gap-2.5\">\n <IconChip icon={<ListChecks className=\"h-4 w-4\" />} />\n <div>\n <h3 className=\"text-sm font-semibold text-text-primary\">\n {t('mybodyshield.pages.sessionDetail.guidedWorkout', 'Guided workout')}\n </h3>\n <p className=\"text-xs text-text-secondary\">\n {allExercisesDone\n ? t(\n 'mybodyshield.pages.sessionDetail.allExercisesDone',\n 'All planned exercises logged — nice work.'\n )\n : t(\n 'mybodyshield.pages.sessionDetail.exerciseProgress',\n 'Exercise {{current}} of {{total}}',\n {\n current: activeExerciseIdx + 1,\n total: exercises.length,\n }\n )}\n </p>\n </div>\n </div>\n <div className=\"flex items-center gap-1.5\">\n <Button\n variant=\"outline\"\n size=\"sm\"\n onClick={() => setManualExerciseIdx(Math.max(activeExerciseIdx - 1, 0))}\n disabled={activeExerciseIdx === 0}\n aria-label={t(\n 'mybodyshield.pages.sessionDetail.previousExercise',\n 'Previous exercise'\n )}\n >\n <ChevronLeft className=\"h-4 w-4\" />\n </Button>\n <Button\n variant=\"outline\"\n size=\"sm\"\n onClick={() =>\n setManualExerciseIdx(Math.min(activeExerciseIdx + 1, exercises.length - 1))\n }\n disabled={activeExerciseIdx >= exercises.length - 1}\n aria-label={t('mybodyshield.pages.sessionDetail.nextExercise', 'Next exercise')}\n >\n <ChevronRight className=\"h-4 w-4\" />\n </Button>\n </div>\n </div>\n\n {activeExercise && (\n <div className=\"flex flex-wrap items-center justify-between gap-3 rounded-xl bg-bg-sunken/60 p-3\">\n <div>\n <p className=\"text-sm font-semibold text-text-primary\">{activeExercise.name}</p>\n <p className=\"mt-0.5 text-xs text-text-secondary\">\n {formatEnumLabel(activeExercise.muscleGroup)} · {activeExercise.sets} ×{' '}\n {activeExercise.reps} {t('mybodyshield.pages.sessionDetail.reps', 'reps')}\n {activeExercise.targetWeight > 0\n ? ` @ ${formatWeight(activeExercise.targetWeight)}`\n : ''}\n {activeExercise.restSeconds > 0\n ? ` · ${formatDuration(activeExercise.restSeconds)} ${t(\n 'mybodyshield.pages.sessionDetail.rest',\n 'rest'\n )}`\n : ''}\n </p>\n <p className=\"mt-0.5 text-xs tabular-nums text-text-tertiary\">\n {loggedCountByExercise.get(activeExercise.name) ?? 0}{' '}\n {t('mybodyshield.pages.sessionDetail.ofSets', 'of')}{' '}\n {Math.max(activeExercise.sets, 1)}{' '}\n {t('mybodyshield.pages.sessionDetail.setsLogged', 'sets logged')}\n </p>\n </div>\n <Button size=\"sm\" onClick={() => openLogForExercise(activeExercise)}>\n <Plus className=\"h-4 w-4\" />{' '}\n {t('mybodyshield.pages.sessionDetail.logThisExercise', 'Log this exercise')}\n </Button>\n </div>\n )}\n </GlassCard>\n </motion.div>\n )}\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={t(\n sets.length === 1\n ? 'mybodyshield.pages.sessionDetail.totalSet'\n : 'mybodyshield.pages.sessionDetail.totalSets',\n sets.length === 1 ? 'Total set' : 'Total sets'\n )}\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={t('mybodyshield.pages.sessionDetail.volumeKg', '{{volume}} kg', {\n volume: formatNumber(totalVolume),\n })}\n label={t('mybodyshield.pages.sessionDetail.totalVolume', '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={t('mybodyshield.pages.sessionDetail.duration', '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={t('mybodyshield.pages.sessionDetail.caloriesBurned', '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\">\n {t('mybodyshield.pages.sessionDetail.loggedSets', 'Logged sets')}\n </h2>\n <p className=\"mt-0.5 text-sm text-text-secondary\">\n {t(\n 'mybodyshield.pages.sessionDetail.loggedSetsDescription',\n 'Every set recorded during this session, grouped by exercise.'\n )}\n </p>\n </div>\n {isLive && (\n <Button variant=\"outline\" size=\"sm\" onClick={openLog} className=\"shrink-0\">\n <Plus className=\"h-4 w-4\" /> {t('mybodyshield.pages.sessionDetail.logSet', '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={t('mybodyshield.pages.sessionDetail.noSetsLogged', 'No sets logged yet')}\n description={t(\n isLive\n ? 'mybodyshield.pages.sessionDetail.noSetsLoggedLive'\n : 'mybodyshield.pages.sessionDetail.noSetsLoggedReadonly',\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\" />{' '}\n {t('mybodyshield.pages.sessionDetail.logSet', '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}{' '}\n {t(\n prCount === 1\n ? 'mybodyshield.pages.sessionDetail.prSingular'\n : 'mybodyshield.pages.sessionDetail.prPlural',\n prCount === 1 ? 'PR' : 'PRs'\n )}\n </span>\n )}\n </div>\n <span className=\"shrink-0 text-xs tabular-nums text-text-tertiary\">\n {formatNumber(group.sets.length)}{' '}\n {t(\n group.sets.length === 1\n ? 'mybodyshield.pages.sessionDetail.set'\n : 'mybodyshield.pages.sessionDetail.sets',\n group.sets.length === 1 ? 'set' : 'sets'\n )}\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 {t(\n 'mybodyshield.pages.sessionDetail.setRow',\n 'Set {{number}}: {{reps}} × {{weight}}',\n {\n number: st.setNumber,\n reps: formatNumber(st.reps),\n weight: formatWeight(st.weight),\n }\n )}\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 {t(\n 'mybodyshield.pages.sessionDetail.distanceM',\n '{{distance}} m',\n {\n distance: formatNumber(st.distanceM),\n }\n )}\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={t('mybodyshield.pages.sessionDetail.coachFeedback', 'Coach feedback')}\n description={t(\n 'mybodyshield.pages.sessionDetail.coachFeedbackDescription',\n \"Discuss form, cues and this session's results with your coach and team.\"\n )}\n />\n </div>\n\n {/* Log set dialog */}\n <ResponsiveDialog open={logOpen} onOpenChange={setLogOpen}>\n <ResponsiveDialogContent>\n <ResponsiveDialogHeader>\n <ResponsiveDialogTitle>\n {t('mybodyshield.pages.sessionDetail.logSetDialogTitle', 'Log a set')}\n </ResponsiveDialogTitle>\n <ResponsiveDialogDescription>\n {t(\n 'mybodyshield.pages.sessionDetail.logSetDialogDescription',\n 'Record reps and load for strength work, or duration and distance for cardio. The dialog stays open so you can log sets back-to-back.'\n )}\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\">\n {t('mybodyshield.pages.sessionDetail.exerciseLabel', 'Exercise')}\n </Label>\n <Input\n id=\"myb-set-exercise\"\n value={logForm.exerciseName}\n onChange={(e) => {\n const exerciseName = e.target.value;\n setLogForm((f) => ({ ...f, exerciseName }));\n // A different exercise has a different history — let auto-PR\n // detection recompute fresh instead of keeping a stale override.\n setPrTouched(false);\n }}\n placeholder={t(\n 'mybodyshield.pages.sessionDetail.exercisePlaceholder',\n 'e.g. Back Squat'\n )}\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\">\n {t('mybodyshield.pages.sessionDetail.setNumberLabel', 'Set number')}\n </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={t('mybodyshield.pages.sessionDetail.setNumberPlaceholder', '1')}\n />\n </div>\n <div className=\"space-y-1.5\">\n <Label htmlFor=\"myb-set-reps\">\n {t('mybodyshield.pages.sessionDetail.repsLabel', 'Reps')}\n </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={t('mybodyshield.pages.sessionDetail.repsPlaceholder', '8')}\n />\n </div>\n <div className=\"space-y-1.5\">\n <Label htmlFor=\"myb-set-weight\">\n {t('mybodyshield.pages.sessionDetail.weightLabel', 'Weight (kg)')}\n </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={t('mybodyshield.pages.sessionDetail.weightPlaceholder', '60')}\n />\n </div>\n <div className=\"space-y-1.5\">\n <Label htmlFor=\"myb-set-distance\">\n {t('mybodyshield.pages.sessionDetail.distanceLabel', 'Distance (m)')}\n </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={t(\n 'mybodyshield.pages.sessionDetail.optionalPlaceholder',\n 'Optional'\n )}\n />\n </div>\n <div className=\"space-y-1.5\">\n <Label htmlFor=\"myb-set-duration\">\n {t('mybodyshield.pages.sessionDetail.durationLabel', 'Duration (sec)')}\n </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={t(\n 'mybodyshield.pages.sessionDetail.optionalPlaceholder',\n 'Optional'\n )}\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 {effectiveIsPersonalRecord ? (\n <Trophy className=\"h-4 w-4 text-status-success-text\" />\n ) : (\n <Gauge className=\"h-4 w-4 text-accent\" />\n )}\n <div>\n <Label htmlFor=\"myb-set-pr\" className=\"cursor-pointer\">\n {t('mybodyshield.pages.sessionDetail.personalRecord', 'Personal record')}\n </Label>\n <p className=\"text-xs text-text-tertiary\">\n {bestSet.data\n ? t(\n 'mybodyshield.pages.sessionDetail.prAutoDetected',\n 'Auto-detected against your best: {{reps}} × {{weight}}.',\n {\n reps: formatNumber(bestSet.data.reps),\n weight: formatWeight(bestSet.data.weight),\n }\n )\n : logForm.exerciseName.trim()\n ? t(\n 'mybodyshield.pages.sessionDetail.prFirstTime',\n 'First time logging this exercise — nothing to compare yet.'\n )\n : t(\n 'mybodyshield.pages.sessionDetail.prFlagHint',\n 'Flag this set as a new PR.'\n )}\n </p>\n </div>\n </div>\n <Switch\n id=\"myb-set-pr\"\n checked={effectiveIsPersonalRecord}\n onCheckedChange={(v) => {\n setPrTouched(true);\n setLogForm((f) => ({ ...f, isPersonalRecord: v }));\n }}\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 {t('mybodyshield.common.close', 'Close')}\n </Button>\n <Button onClick={submitLog} disabled={logSet.isPending}>\n {logSet.isPending\n ? t('mybodyshield.common.logging', 'Logging…')\n : t('mybodyshield.pages.sessionDetail.logSet', '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>\n {t('mybodyshield.pages.sessionDetail.completeDialogTitle', 'Complete session')}\n </ResponsiveDialogTitle>\n <ResponsiveDialogDescription>\n {t(\n 'mybodyshield.pages.sessionDetail.completeDialogDescription',\n 'Wrap up this workout and record how it went.'\n )}\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\">\n {t('mybodyshield.pages.sessionDetail.noSetsWarning', 'No sets logged.')}\n </span>{' '}\n {t(\n 'mybodyshield.pages.sessionDetail.noSetsWarningDetail',\n 'You can still complete this session, but nothing was recorded for it.'\n )}\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\">\n {t('mybodyshield.pages.sessionDetail.caloriesBurned', 'Calories burned')}\n </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={t(\n 'mybodyshield.pages.sessionDetail.optionalPlaceholder',\n 'Optional'\n )}\n />\n </div>\n <div className=\"space-y-1.5\">\n <Label htmlFor=\"myb-complete-rpe\">\n {t('mybodyshield.pages.sessionDetail.rpeLabel', 'Perceived exertion (1–10)')}\n </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={t(\n 'mybodyshield.pages.sessionDetail.optionalPlaceholder',\n 'Optional'\n )}\n />\n </div>\n </div>\n <div className=\"space-y-1.5\">\n <Label htmlFor=\"myb-complete-notes\">{t('mybodyshield.common.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={t(\n 'mybodyshield.pages.sessionDetail.completeNotesPlaceholder',\n 'How did the session feel?'\n )}\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 {t('mybodyshield.common.cancel', 'Cancel')}\n </Button>\n <Button onClick={submitComplete} disabled={completeSession.isPending}>\n {completeSession.isPending\n ? t('mybodyshield.common.completing', 'Completing…')\n : t('mybodyshield.pages.sessionDetail.completeSession', 'Complete session')}\n </Button>\n </ResponsiveDialogFooter>\n </ResponsiveDialogContent>\n </ResponsiveDialog>\n </PageLayout>\n );\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"SessionsPage.d.ts","sourceRoot":"","sources":["../../../../src/mybodyshield/pages/train/SessionsPage.tsx"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AA0IH,wBAAgB,YAAY,gCA0S3B"}
1
+ {"version":3,"file":"SessionsPage.d.ts","sourceRoot":"","sources":["../../../../src/mybodyshield/pages/train/SessionsPage.tsx"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAwJH,wBAAgB,YAAY,gCAwW3B"}