Kündigungsdatum: Cursor bleibt beim Tippen im Feld

Bug: bei Eingabe der Jahreszahl im Kündigungsbestätigungs-Datum
sprang der Fokus raus und die Seite scrollte hoch. Ursache:
<input type=date> onChange feuert bei jedem Tastendruck. Sobald
"18.08.0002" ein gültiges Datum ergab, feuerte der Mutation-Aufruf
eine PUT-Request, die Server-Antwort re-renderte den Input und
der Cursor landete am Feldanfang – der Rest der Jahreszahl kam
im nächsten Feld an.

Fix: neue kleine AutosaveDateInput-Komponente – hält den Wert
während der Eingabe lokal, feuert onSave erst bei onBlur oder
Enter. Escape verwirft die Änderung. Kein Save bei unverändertem
Wert.

Angewendet auf beide betroffenen Stellen in ContractDetail
(Bestätigung erhalten am – Kündigungsschreiben + Options-Variante).

Andere Datumsfelder der App laufen entweder über react-hook-form
(batched, save auf Submit) oder halten den Wert lokal – die sind
vom Bug nicht betroffen.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
2026-07-11 15:32:25 +02:00
co-authored by Claude Opus 4.7
parent f2703ed6b7
commit 70724e35dc
2 changed files with 84 additions and 14 deletions
@@ -18,6 +18,7 @@ import { Edit, Trash2, Copy, Eye, EyeOff, ArrowLeft, ArrowRight, Download, Exter
import JpgToPdfModal from '../../components/ui/JpgToPdfModal';
import { calculateConsumption, calculateCosts, calculateMultiMeterConsumption } from '../../utils/energyCalculations';
import CopyButton, { CopyableBlock } from '../../components/ui/CopyButton';
import AutosaveDateInput from '../../components/ui/AutosaveDateInput';
import { formatDate } from '../../utils/dateFormat';
import { useProviderSettings } from '../../hooks/useProviderSettings';
import type { ContractType, ContractStatus, SimCard, MeterReading, ContractTask, ContractTaskSubtask, ContractMeter, ContractDocument } from '../../types';
@@ -2325,14 +2326,9 @@ export default function ContractDetail() {
<div className="mt-2">
<label className="text-xs text-gray-500 block mb-1">Bestätigung erhalten am</label>
<div className="flex items-center gap-2">
<input
type="date"
<AutosaveDateInput
value={c.cancellationConfirmationDate ? c.cancellationConfirmationDate.split('T')[0] : ''}
onChange={(e) => {
const value = e.target.value || null;
updateCancellationDateMutation.mutate(value);
}}
className="block w-full max-w-[180px] px-2 py-1 text-sm border border-gray-300 rounded focus:outline-none focus:ring-2 focus:ring-blue-500"
onSave={(value) => updateCancellationDateMutation.mutate(value)}
/>
{c.cancellationConfirmationDate && (
<button
@@ -2463,14 +2459,9 @@ export default function ContractDetail() {
<div className="mt-2">
<label className="text-xs text-gray-500 block mb-1">Bestätigung erhalten am</label>
<div className="flex items-center gap-2">
<input
type="date"
<AutosaveDateInput
value={c.cancellationConfirmationOptionsDate ? c.cancellationConfirmationOptionsDate.split('T')[0] : ''}
onChange={(e) => {
const value = e.target.value || null;
updateCancellationOptionsDateMutation.mutate(value);
}}
className="block w-full max-w-[180px] px-2 py-1 text-sm border border-gray-300 rounded focus:outline-none focus:ring-2 focus:ring-blue-500"
onSave={(value) => updateCancellationOptionsDateMutation.mutate(value)}
/>
{c.cancellationConfirmationOptionsDate && (
<button