lewtun's picture
lewtun HF Staff
Replace injury tracking dropdown with checkboxes for left/right knee
7b3fdb0
import { useState } from 'react';
import './RunForm.css';
const INJURY_LOCATIONS = [
{ key: 'left_knee', label: 'Left Knee' },
{ key: 'right_knee', label: 'Right Knee' },
];
const RPE_DESCRIPTIONS = {
1: { label: 'Very easy', detail: 'Gentle warm-up, recovery jog' },
2: { label: 'Very easy', detail: 'Full conversation easy' },
3: { label: 'Easy', detail: 'Easy run, full sentences' },
4: { label: 'Comfortable', detail: 'Can talk in full sentences' },
5: { label: 'Moderate', detail: 'Talking becomes slightly harder' },
6: { label: 'Comfortably hard', detail: 'Tempo effort, short sentences only' },
7: { label: 'Hard', detail: 'Threshold pace, conversation difficult' },
8: { label: 'Very hard', detail: 'Interval pace, a few words at a time' },
9: { label: 'Extremely hard', detail: 'Near max, sustain only briefly' },
10: { label: 'All-out', detail: 'Max sprint, lasts only seconds' },
};
function RunForm({ onAddRun }) {
const today = new Date().toISOString().split('T')[0];
const [date, setDate] = useState(today);
const [distance, setDistance] = useState('');
const [time, setTime] = useState('');
const [rpe, setRpe] = useState(5);
const [notes, setNotes] = useState('');
const [injuries, setInjuries] = useState(
Object.fromEntries(INJURY_LOCATIONS.map((loc) => [loc.key, { enabled: false, during: '', after: '' }]))
);
function handleSubmit(e) {
e.preventDefault();
const dist = parseFloat(distance);
const mins = parseFloat(time);
if (!date || isNaN(dist) || dist <= 0 || isNaN(mins) || mins <= 0) return;
const runData = {
date,
distance_km: dist,
time_minutes: mins,
rpe: Number(rpe),
notes: notes.trim(),
};
for (const loc of INJURY_LOCATIONS) {
const inj = injuries[loc.key];
if (inj.enabled) {
runData[`${loc.key}_during`] = inj.during ? Number(inj.during) : null;
runData[`${loc.key}_after`] = inj.after ? Number(inj.after) : null;
}
}
onAddRun(runData);
setDistance('');
setTime('');
setRpe(5);
setNotes('');
setInjuries(
Object.fromEntries(INJURY_LOCATIONS.map((loc) => [loc.key, { enabled: false, during: '', after: '' }]))
);
}
return (
<form className="run-form card" onSubmit={handleSubmit}>
<h2>Log a Run</h2>
<div className="form-group">
<label htmlFor="run-date">Date</label>
<input
id="run-date"
type="date"
value={date}
onChange={(e) => setDate(e.target.value)}
required
/>
</div>
<div className="form-group">
<label htmlFor="run-distance">Distance (km)</label>
<input
id="run-distance"
type="number"
step="0.01"
min="0.01"
placeholder="e.g. 5.25"
value={distance}
onChange={(e) => setDistance(e.target.value)}
required
/>
</div>
<div className="form-group">
<label htmlFor="run-time">Time (minutes)</label>
<input
id="run-time"
type="number"
step="0.01"
min="0.01"
placeholder="e.g. 30"
value={time}
onChange={(e) => setTime(e.target.value)}
required
/>
</div>
<div className="form-group">
<label htmlFor="run-rpe">Effort (RPE): <strong>{rpe}</strong></label>
<input
id="run-rpe"
type="range"
min="1"
max="10"
value={rpe}
onChange={(e) => setRpe(e.target.value)}
/>
<div className="rpe-labels">
<span>Easy</span>
<span>Max</span>
</div>
<div className="rpe-description">
<span className="rpe-effort">{RPE_DESCRIPTIONS[rpe].label}</span>
<span className="rpe-detail">{RPE_DESCRIPTIONS[rpe].detail}</span>
</div>
</div>
<div className="form-group">
<label>Injury Tracking</label>
<div className="injury-checkboxes">
{INJURY_LOCATIONS.map((loc) => (
<label key={loc.key} className="injury-checkbox-label">
<input
type="checkbox"
checked={injuries[loc.key].enabled}
onChange={(e) =>
setInjuries((prev) => ({
...prev,
[loc.key]: { ...prev[loc.key], enabled: e.target.checked, ...(!e.target.checked && { during: '', after: '' }) },
}))
}
/>
{loc.label}
</label>
))}
</div>
</div>
{INJURY_LOCATIONS.filter((loc) => injuries[loc.key].enabled).map((loc) => (
<div key={loc.key} className="pain-inputs">
<span className="pain-location-label">{loc.label}</span>
<div className="form-group pain-field">
<label htmlFor={`pain-during-${loc.key}`}>Pain During (1–10)</label>
<input
id={`pain-during-${loc.key}`}
type="number" min="1" max="10" step="1" placeholder="1–10"
value={injuries[loc.key].during}
onChange={(e) =>
setInjuries((prev) => ({
...prev,
[loc.key]: { ...prev[loc.key], during: e.target.value },
}))
}
/>
</div>
<div className="form-group pain-field">
<label htmlFor={`pain-after-${loc.key}`}>Pain After (1–10)</label>
<input
id={`pain-after-${loc.key}`}
type="number" min="1" max="10" step="1" placeholder="1–10"
value={injuries[loc.key].after}
onChange={(e) =>
setInjuries((prev) => ({
...prev,
[loc.key]: { ...prev[loc.key], after: e.target.value },
}))
}
/>
</div>
</div>
))}
<div className="form-group">
<label htmlFor="run-notes">Notes</label>
<textarea
id="run-notes"
placeholder="How did it feel? Any observations..."
value={notes}
onChange={(e) => setNotes(e.target.value)}
rows="3"
/>
</div>
<button type="submit" className="btn-primary">Add Run</button>
</form>
);
}
export default RunForm;