This commit is contained in:
2026-02-24 21:57:21 +01:00
parent 924b83eb4d
commit 7677fdd73d

View File

@@ -61,8 +61,6 @@ function ClientTargetPanel({
const [showCorrectionForm, setShowCorrectionForm] = useState(false); const [showCorrectionForm, setShowCorrectionForm] = useState(false);
const [corrDate, setCorrDate] = useState(''); const [corrDate, setCorrDate] = useState('');
const [corrHours, setCorrHours] = useState(''); const [corrHours, setCorrHours] = useState('');
const [corrMins, setCorrMins] = useState('');
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);
const [corrSaving, setCorrSaving] = useState(false); const [corrSaving, setCorrSaving] = useState(false);
@@ -154,25 +152,21 @@ function ClientTargetPanel({
e.preventDefault(); e.preventDefault();
setCorrError(null); setCorrError(null);
if (!target) return; if (!target) return;
const h = parseInt(corrHours || '0', 10); const hours = parseFloat(corrHours);
const m = parseInt(corrMins || '0', 10); if (isNaN(hours) || hours < -1000 || hours > 1000) {
if (h === 0 && m === 0) { setCorrError('Hours must be between -1000 and 1000');
setCorrError('Duration must be at least 1 minute');
return; return;
} }
if (!corrDate) { if (!corrDate) {
setCorrError('Please select a date'); setCorrError('Please select a date');
return; return;
} }
const totalHours = (h + m / 60) * (corrNegative ? -1 : 1);
setCorrSaving(true); setCorrSaving(true);
try { try {
const input: CreateCorrectionInput = { date: corrDate, hours: totalHours, description: corrDesc || undefined }; 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('');
setCorrHours(''); setCorrHours('');
setCorrMins('');
setCorrNegative(false);
setCorrDesc(''); setCorrDesc('');
setShowCorrectionForm(false); setShowCorrectionForm(false);
} catch (err) { } catch (err) {
@@ -365,7 +359,7 @@ function ClientTargetPanel({
</div> </div>
<div className="flex items-center gap-1.5"> <div className="flex items-center gap-1.5">
<span className={`text-xs font-semibold ${c.hours >= 0 ? 'text-green-600' : 'text-red-600'}`}> <span className={`text-xs font-semibold ${c.hours >= 0 ? 'text-green-600' : 'text-red-600'}`}>
{c.hours >= 0 ? '+' : ''}{formatDurationHoursMinutes(Math.abs(c.hours) * 3600)} {c.hours >= 0 ? '+' : ''}{c.hours}h
</span> </span>
<button <button
onClick={() => handleDeleteCorrection(c.id)} onClick={() => handleDeleteCorrection(c.id)}
@@ -391,41 +385,17 @@ function ClientTargetPanel({
required required
/> />
</div> </div>
<div className="flex-1"> <div className="w-24">
<label className="block text-xs text-gray-500 mb-0.5">Duration</label> <label className="block text-xs text-gray-500 mb-0.5">Hours</label>
<div className="flex gap-1">
<button
type="button"
onClick={() => setCorrNegative(v => !v)}
className={`input text-xs py-1 px-2 font-mono font-bold w-8 shrink-0 text-center transition-colors ${
corrNegative
? 'bg-red-50 border-red-300 text-red-600'
: 'bg-green-50 border-green-300 text-green-600'
}`}
title="Toggle positive / negative"
>
{corrNegative ? '' : '+'}
</button>
<input <input
type="number" type="number"
min={0}
value={corrHours} value={corrHours}
onChange={e => setCorrHours(e.target.value)} onChange={e => setCorrHours(e.target.value)}
className="input text-xs py-1 w-12 min-w-0 text-center" className="input text-xs py-1"
placeholder="h" placeholder="+8 / -4"
step="0.5"
required
/> />
<span className="text-xs text-gray-400 self-center">h</span>
<input
type="number"
min={0}
max={59}
value={corrMins}
onChange={e => setCorrMins(e.target.value)}
className="input text-xs py-1 w-12 min-w-0 text-center"
placeholder="m"
/>
<span className="text-xs text-gray-400 self-center">m</span>
</div>
</div> </div>
</div> </div>
<div> <div>