Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 5 additions & 3 deletions apps/web/src/pages/EntityDetail/ActivityChart.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ interface ActivityChartProps {
}

const CHART_HEIGHT = 260
const MARGIN = { bottom: 30, left: 50, right: 60, top: 10 }
const MARGIN = { bottom: 30, left: 50, right: 110, top: 10 }

/** Hypnogram Y-axis labels in display order (top to bottom). */
const HYPNOGRAM_LABELS = ['Awake', 'REM', 'Light', 'Deep']
Expand Down Expand Up @@ -95,12 +95,14 @@ const drawLineOverlay = (
unit: string,
axisSide: 'left' | 'right',
axisOffset: number = 0,
forceZeroMin: boolean = false,
) => {
const yExtent = d3.extent(data, (d) => d[1]) as [number, number]
const padding = (yExtent[1] - yExtent[0]) * 0.1 || 5
const yMin = forceZeroMin && yExtent[0] >= 0 ? 0 : yExtent[0] - padding
const yScale = d3
.scaleLinear()
.domain([yExtent[0] - padding, yExtent[1] + padding])
.domain([yMin, yExtent[1] + padding])
.range([innerHeight, 0])

if (axisSide === 'right') {
Expand Down Expand Up @@ -223,7 +225,7 @@ export const ActivityChart = ({
const hrVisible = hasData(hrData)
const axisSide = hrVisible || hasHypnogram ? 'right' : 'left'
const offset = axisSide === 'right' && hrVisible ? 45 : 0
drawLineOverlay(g, xScale, innerWidth, innerHeight, hrvData, '#14b8a6', 'ms', axisSide, offset)
drawLineOverlay(g, xScale, innerWidth, innerHeight, hrvData, '#14b8a6', 'ms', axisSide, offset, true)
}

// Tooltip crosshair and interaction overlay
Expand Down
21 changes: 10 additions & 11 deletions apps/web/src/pages/EntityDetail/EditableActivityFields.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -75,17 +75,16 @@ export const EditableActivityFields = ({
<span class="field-label">{durationLabel}</span>
<span class="field-value">{draftDuration}</span>
</div>
<div class="field-row">
<span class="field-label">Notes</span>
<span class="field-value">
<textarea
class="edit-notes-input"
value={draft.notes}
onInput={(e) => onDraftChange({ ...draft, notes: (e.target as HTMLTextAreaElement).value })}
rows={3}
/>
</span>
</div>
</div>

<div class="edit-notes-block">
<span class="field-label">Notes</span>
<textarea
class="edit-notes-input"
value={draft.notes}
onInput={(e) => onDraftChange({ ...draft, notes: (e.target as HTMLTextAreaElement).value })}
rows={3}
/>
</div>
</>
)
Expand Down
25 changes: 23 additions & 2 deletions apps/web/src/pages/EntityDetail/ExerciseDetail.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
/**
* Exercise-specific detail view with HR chart and HR zone bar.
*/
import { Activity } from '../../state/api'
import { useQuery } from '@tanstack/react-query'
import { Activity, fetchMetricTimeSeries } from '../../state/api'
import { ActivityChart } from './ActivityChart'
import { type ActivityDraft, EditableActivityFields } from './EditableActivityFields'

Expand Down Expand Up @@ -64,6 +65,17 @@ export const ExerciseDetail = ({
| string
| undefined

const caloriesQuery = useQuery({
queryFn: () => fetchMetricTimeSeries('calories_active', displayStart, displayEnd),
queryKey: ['detail-calories', displayStart.toISOString(), displayEnd.toISOString()],
staleTime: 5 * 60 * 1000,
})

const totalCalories =
caloriesQuery.data && caloriesQuery.data.length > 0 ?
Math.round(caloriesQuery.data.reduce((sum, [, val]) => sum + val, 0))
: undefined

return (
<>
<div class="entity-info">
Expand All @@ -82,6 +94,15 @@ export const ExerciseDetail = ({
onDraftChange={onDraftChange}
/>

{!isEditing && totalCalories !== undefined && (
<div class="entity-fields">
<div class="field-row">
<span class="field-label">Active Calories</span>
<span class="field-value">{totalCalories} kcal</span>
</div>
</div>
)}

{!isEditing && activity.avg_hrv !== undefined && (
<div class="entity-fields">
<div class="field-row">
Expand All @@ -96,7 +117,7 @@ export const ExerciseDetail = ({

{/* HR chart with overlays */}
<div class="detail-grid-full">
<ActivityChart start={displayStart} end={displayEnd} showHrDefault={true} />
<ActivityChart start={displayStart} end={displayEnd} showHrDefault={true} showHrvDefault={true} />
</div>
</>
)
Expand Down
6 changes: 3 additions & 3 deletions apps/web/src/pages/EntityDetail/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -312,7 +312,7 @@
}
}

const EntityContent = ({ entityType, entityId }: { entityType: EntityType; entityId: string }) => {

Check warning on line 315 in apps/web/src/pages/EntityDetail/index.tsx

View workflow job for this annotation

GitHub Actions / Node (test, check, build)

Arrow function has a complexity of 20. Maximum allowed is 15
const queryClient = useQueryClient()

// Strip merged: prefix for raw operations (delete/restore/notes write)
Expand Down Expand Up @@ -449,9 +449,9 @@
return (
<div class="entity-detail-page">
<div class="entity-detail-header">
<a href="/day" class="back-link">
Back to Day View
</a>
<button type="button" class="back-link back-link-btn" onClick={() => history.back()}>
Back
</button>
</div>
<EntityContent entityType={entityType} entityId={entityId} />
</div>
Expand Down
15 changes: 15 additions & 0 deletions apps/web/src/pages/EntityDetail/style.css
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,14 @@
text-decoration: underline;
}

.back-link-btn {
background: none;
border: none;
padding: 0;
cursor: pointer;
font: inherit;
}

/* Deleted banner */
.deleted-banner {
display: flex;
Expand Down Expand Up @@ -617,6 +625,13 @@
box-shadow: 0 0 0 2px rgba(103, 58, 184, 0.2);
}

.edit-notes-block {
margin-top: 0.5rem;
display: flex;
flex-direction: column;
gap: 0.25rem;
}

.edit-notes-input {
width: 100%;
padding: 0.375rem 0.5rem;
Expand Down
Loading