// Log tab — wired to /api/workout-intention, /api/brain-dump, /api/drinks, // /api/log-event. All saves call onUpdate to refresh /api/today. const { api } = window.HC_DATA; function TimeBtn({ children, selected, onClick, disabled, theme }) { const p = theme.palette; return ( ); } function LogTab({ today, onUpdate }) { const theme = window.HC_THEME.useHCTheme(); const p = theme.palette; const d = theme.density; const Card = window.HCCard; const workoutIntention = today.workout_intention || {}; const brainDump = today.brain_dump || {}; const drinksToday = today.drinks_today || {}; const habits = today.habits || {}; const training = today.training || {}; const comeback = !!training.comeback_mode; const daysSince = training.days_since_training; const [workoutBusy, setWorkoutBusy] = React.useState(false); const [brainText, setBrainText] = React.useState(''); const [drinkText, setDrinkText] = React.useState(''); const [busy, setBusy] = React.useState({ brain: false, drink: false }); const [eventOpen, setEventOpen] = React.useState(false); const [eventText, setEventText] = React.useState(''); const [eventSaved, setEventSaved] = React.useState(null); const [eventBusy, setEventBusy] = React.useState(false); const [habitBusy, setHabitBusy] = React.useState(null); async function toggleHabit(key) { if (habitBusy) return; setHabitBusy(key); const undo = !!habits[key]; try { await api('/api/habit', { method: 'POST', body: JSON.stringify({ habit: key, undo }), }); await onUpdate(); } catch (e) { console.error('habit toggle failed', e); } finally { setHabitBusy(null); } } const txAreaStyle = { width: '100%', boxSizing: 'border-box', padding: 10, fontFamily: 'DM Sans', fontSize: 14, color: p.text, border: `1px solid ${p.border}`, borderRadius: 8, resize: 'none', outline: 'none', background: p.inputBg, }; async function setWorkout(time) { setWorkoutBusy(true); try { await api('/api/workout-intention', { method: 'POST', body: JSON.stringify({ time }), }); await onUpdate(); } catch (e) { console.error('workout save failed', e); } finally { setWorkoutBusy(false); } } async function saveBrain() { const text = brainText.trim(); if (!text || busy.brain) return; setBusy((b) => ({ ...b, brain: true })); try { await api('/api/brain-dump', { method: 'POST', body: JSON.stringify({ text }) }); setBrainText(''); await onUpdate(); } catch (e) { console.error('brain dump save failed', e); } finally { setBusy((b) => ({ ...b, brain: false })); } } async function saveDrink() { const text = drinkText.trim(); if (!text || busy.drink) return; setBusy((b) => ({ ...b, drink: true })); try { await api('/api/drinks', { method: 'POST', body: JSON.stringify({ text }) }); setDrinkText(''); await onUpdate(); } catch (e) { console.error('drink save failed', e); } finally { setBusy((b) => ({ ...b, drink: false })); } } async function saveEvent() { const label = eventText.trim(); if (!label || eventBusy) return; setEventBusy(true); try { await api('/api/log-event', { method: 'POST', body: JSON.stringify({ label }) }); setEventSaved(label); setEventOpen(false); setEventText(''); } catch (e) { console.error('event save failed', e); } finally { setEventBusy(false); } } const workoutDone = !!workoutIntention.time; const brainDone = !!brainDump.done; const workoutOptions = comeback ? [{ label: 'walk only', value: 'walk' }, { label: 'skip', value: 'skip' }] : [ { label: '17:00', value: '17:00' }, { label: '17:30', value: '17:30' }, { label: '18:00', value: '18:00' }, { label: 'walk', value: 'walk' }, { label: 'skip', value: 'skip' }, ]; return (
{comeback && daysSince != null && (
day {daysSince} · re-entry when ready
)} {/* Workout */}
Workout
{workoutDone ? (
{workoutIntention.time === 'skip' ? 'skip ✓' : workoutIntention.time === 'walk' ? 'walk only ✓' : `${workoutIntention.time} ✓`}
) : ( <>
{comeback ? 'first session back: 20-min walk, no load' : "when's your workout?"}
{workoutOptions.map((o) => ( setWorkout(o.value)} disabled={workoutBusy}>{o.label} ))}
)}
{/* Brain dump */}
Brain dump
{brainDone ? (
{brainDump.text}
done ✓
) : ( <>