Fix upload auto-refresh, health data refresh, and HR zone recalculation
- UploadPage now polls task status every 2s and invalidates activity, health-summary, and health-metrics queries on completion so new activities and health data appear without a hard refresh - Garmin and Strava export endpoints now return a task_id for polling - Updating max HR in Profile triggers a background Celery task to recalculate hr_zones for all existing activities; profile page shows a confirmation note when this is queued - Add CLAUDE.md with repo architecture and dev commands Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import { useState, useEffect } from 'react'
|
||||
import { useState, useEffect, useRef } from 'react'
|
||||
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'
|
||||
import api from '../utils/api'
|
||||
import { useAuthStore } from '../hooks/useAuth'
|
||||
@@ -59,6 +59,8 @@ export default function ProfilePage() {
|
||||
// HR / measurements form
|
||||
const [hrForm, setHrForm] = useState({ max_heart_rate: '', resting_heart_rate: '', birth_year: '', height_cm: '' })
|
||||
const [hrSaved, setHrSaved] = useState(false)
|
||||
const [hrZoneRecalc, setHrZoneRecalc] = useState(false)
|
||||
const maxHrChangedRef = useRef(false)
|
||||
useEffect(() => {
|
||||
if (profile) setHrForm({
|
||||
max_heart_rate: profile.max_heart_rate || '',
|
||||
@@ -70,7 +72,16 @@ export default function ProfilePage() {
|
||||
|
||||
const updateProfile = useMutation({
|
||||
mutationFn: data => api.patch('/profile/', data).then(r => r.data),
|
||||
onSuccess: () => { qc.invalidateQueries({ queryKey: ['profile'] }); setHrSaved(true); setTimeout(() => setHrSaved(false), 3000) },
|
||||
onSuccess: () => {
|
||||
qc.invalidateQueries({ queryKey: ['profile'] })
|
||||
setHrSaved(true)
|
||||
setTimeout(() => setHrSaved(false), 3000)
|
||||
if (maxHrChangedRef.current) {
|
||||
setHrZoneRecalc(true)
|
||||
setTimeout(() => setHrZoneRecalc(false), 6000)
|
||||
maxHrChangedRef.current = false
|
||||
}
|
||||
},
|
||||
})
|
||||
|
||||
// Weight log
|
||||
@@ -149,12 +160,19 @@ export default function ProfilePage() {
|
||||
</div>
|
||||
|
||||
<SaveButton
|
||||
onClick={() => updateProfile.mutate(Object.fromEntries(
|
||||
Object.entries(hrForm).filter(([,v]) => v !== '').map(([k,v]) => [k, parseFloat(v)])
|
||||
))}
|
||||
onClick={() => {
|
||||
const data = Object.fromEntries(
|
||||
Object.entries(hrForm).filter(([,v]) => v !== '').map(([k,v]) => [k, parseFloat(v)])
|
||||
)
|
||||
maxHrChangedRef.current = data.max_heart_rate !== undefined && data.max_heart_rate !== profile?.max_heart_rate
|
||||
updateProfile.mutate(data)
|
||||
}}
|
||||
loading={updateProfile.isPending}
|
||||
saved={hrSaved}
|
||||
/>
|
||||
{hrZoneRecalc && (
|
||||
<p className="text-xs text-blue-400 mt-1">HR zones are being recalculated for your existing activities.</p>
|
||||
)}
|
||||
</Section>
|
||||
|
||||
{/* Weight log */}
|
||||
|
||||
Reference in New Issue
Block a user