fix: replace separate h/m number inputs with single HH:MM time input in correction form

- Remove stale corrHoursInt/corrMins state (leftover from previous refactor)
- Use corrDuration (HH:MM string) parsed once and reuse totalHours in submit handler
- Single type="time" input + +/− toggle button matches TimerWidget style
- flex-1 on Date and Duration columns for equal width and consistent height alignment
This commit is contained in:
2026-02-24 21:49:54 +01:00
parent 2a5e6d4a22
commit 91d13b19db

View File

@@ -60,8 +60,7 @@ function ClientTargetPanel({
// Correction form state // Correction form state
const [showCorrectionForm, setShowCorrectionForm] = useState(false); const [showCorrectionForm, setShowCorrectionForm] = useState(false);
const [corrDate, setCorrDate] = useState(''); const [corrDate, setCorrDate] = useState('');
const [corrHoursInt, setCorrHoursInt] = useState(''); const [corrDuration, setCorrDuration] = useState('');
const [corrMins, setCorrMins] = useState('');
const [corrNegative, setCorrNegative] = useState(false); const [corrNegative, setCorrNegative] = useState(false);
const [corrDesc, setCorrDesc] = useState(''); const [corrDesc, setCorrDesc] = useState('');
const [corrError, setCorrError] = useState<string | null>(null); const [corrError, setCorrError] = useState<string | null>(null);
@@ -154,31 +153,28 @@ function ClientTargetPanel({
e.preventDefault(); e.preventDefault();
setCorrError(null); setCorrError(null);
if (!target) return; if (!target) return;
const h = parseInt(corrHoursInt || '0', 10); if (!corrDuration) {
const m = parseInt(corrMins || '0', 10); setCorrError('Enter a duration');
if (isNaN(h) || isNaN(m) || h < 0 || m < 0 || m > 59 || (h === 0 && m === 0)) {
setCorrError('Enter a valid duration (at least 1 minute)');
return; return;
} }
const totalHours = h + m / 60; const [hPart, mPart] = corrDuration.split(':').map(Number);
if (totalHours > 1000) { const h = isNaN(hPart) ? 0 : hPart;
setCorrError('Duration cannot exceed 1000 hours'); const m = isNaN(mPart) ? 0 : mPart;
if (h === 0 && m === 0) {
setCorrError('Duration must be at least 1 minute');
return; return;
} }
const totalHours = (h + m / 60) * (corrNegative ? -1 : 1);
if (!corrDate) { if (!corrDate) {
setCorrError('Please select a date'); setCorrError('Please select a date');
return; return;
} }
setCorrSaving(true); setCorrSaving(true);
try { try {
const h = parseInt(corrHoursInt || '0', 10); const input: CreateCorrectionInput = { date: corrDate, hours: totalHours, description: corrDesc || undefined };
const m = parseInt(corrMins || '0', 10);
const hours = (h + m / 60) * (corrNegative ? -1 : 1);
const input: CreateCorrectionInput = { date: corrDate, hours, description: corrDesc || undefined };
await addCorrection.mutateAsync({ targetId: target.id, input }); await addCorrection.mutateAsync({ targetId: target.id, input });
setCorrDate(''); setCorrDate('');
setCorrHoursInt(''); setCorrDuration('');
setCorrMins('');
setCorrNegative(false); setCorrNegative(false);
setCorrDesc(''); setCorrDesc('');
setShowCorrectionForm(false); setShowCorrectionForm(false);
@@ -398,13 +394,13 @@ function ClientTargetPanel({
required required
/> />
</div> </div>
<div> <div className="flex-1">
<label className="block text-xs text-gray-500 mb-0.5">Duration</label> <label className="block text-xs text-gray-500 mb-0.5">Duration</label>
<div className="flex items-center gap-1"> <div className="flex gap-1">
<button <button
type="button" type="button"
onClick={() => setCorrNegative(v => !v)} onClick={() => setCorrNegative(v => !v)}
className={`text-xs px-1.5 py-1 rounded border font-mono font-bold transition-colors ${ className={`input text-xs py-1 px-2 font-mono font-bold w-8 shrink-0 text-center transition-colors ${
corrNegative corrNegative
? 'bg-red-50 border-red-300 text-red-600' ? 'bg-red-50 border-red-300 text-red-600'
: 'bg-green-50 border-green-300 text-green-600' : 'bg-green-50 border-green-300 text-green-600'
@@ -414,25 +410,11 @@ function ClientTargetPanel({
{corrNegative ? '' : '+'} {corrNegative ? '' : '+'}
</button> </button>
<input <input
type="number" type="time"
value={corrHoursInt} value={corrDuration}
onChange={e => setCorrHoursInt(e.target.value)} onChange={e => setCorrDuration(e.target.value)}
className="input text-xs py-1 w-14 text-center" className="input text-xs py-1 flex-1 min-w-0"
placeholder="0h" required
min="0"
max="999"
step="1"
/>
<span className="text-xs text-gray-400">:</span>
<input
type="number"
value={corrMins}
onChange={e => setCorrMins(e.target.value)}
className="input text-xs py-1 w-14 text-center"
placeholder="00m"
min="0"
max="59"
step="1"
/> />
</div> </div>
</div> </div>