Vertriebsunterstützung an Reisezeit koppeln

- Reisezeit 0 -> Vertriebsunterstützung 0
- Reisezeit < 2h -> Vertriebsunterstützung = Reisezeit (Feld gesperrt)
- Reisezeit >= 2h -> Vertriebsunterstützung 2h, aber editierbar
- Regel zentral in lib/calc.ts (applyVertriebsregel), im Formular interaktiv
  und in der API-Validierung erzwungen

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-22 10:23:07 +02:00
parent 9ee78d2dcf
commit 1e221a3c2c
3 changed files with 54 additions and 7 deletions
+32 -5
View File
@@ -2,7 +2,14 @@
import { useState } from 'react';
import { ORTE, ARBEITSZEIT_KUNDE_FIX, type ArbeitszeitEintrag } from '@/types/arbeitszeit';
import { toDecimalHours, mehrarbeit, weekdayName, formatHours, hatZeiten } from '@/lib/calc';
import {
toDecimalHours,
mehrarbeit,
weekdayName,
formatHours,
hatZeiten,
vertriebEditierbar,
} from '@/lib/calc';
import CustomSelect from './CustomSelect';
import TimeInput from './TimeInput';
@@ -25,6 +32,11 @@ function toNum(raw: string): number {
return isNaN(n) ? 0 : n;
}
// Zahl als deutscher Dezimalstring (Komma)
function numToStr(n: number): string {
return String(n).replace('.', ',');
}
export default function ArbeitszeitForm({ editEntry, pause, onSaved, onCancel }: Props) {
// Diese Komponente wird beim Wechsel von editEntry über `key` neu gemountet,
// daher genügt eine einmalige Initialisierung aus editEntry (kein Sync-Effekt nötig).
@@ -32,8 +44,8 @@ export default function ArbeitszeitForm({ editEntry, pause, onSaved, onCancel }:
const [ort, setOrt] = useState<string>(editEntry?.ort ?? ORTE[0]);
const [beginn, setBeginn] = useState(editEntry?.beginn ?? '');
const [ende, setEnde] = useState(editEntry?.ende ?? '');
const [reisezeit, setReisezeit] = useState(editEntry ? String(editEntry.reisezeit) : '0');
const [vertrieb, setVertrieb] = useState(editEntry ? String(editEntry.vertriebsunterstuetzung) : '2');
const [reisezeit, setReisezeit] = useState(editEntry ? numToStr(editEntry.reisezeit) : '0');
const [vertrieb, setVertrieb] = useState(editEntry ? numToStr(editEntry.vertriebsunterstuetzung) : '0');
const [kommentar, setKommentar] = useState(editEntry?.kommentar ?? '');
const [saving, setSaving] = useState(false);
const [error, setError] = useState('');
@@ -42,6 +54,19 @@ export default function ArbeitszeitForm({ editEntry, pause, onSaved, onCancel }:
const zeiten = hatZeiten(beginn, ende);
const arbeitszeit = toDecimalHours(beginn, ende);
const mehr = mehrarbeit(arbeitszeit, pause);
const vertriebFrei = vertriebEditierbar(toNum(reisezeit));
// Vertriebsunterstützung an die Reisezeit koppeln (siehe applyVertriebsregel):
// =0 ⇒ 0, <2 ⇒ = Reisezeit, ≥2 ⇒ 2 beim Überschreiten der Schwelle, danach frei änderbar.
function handleReisezeit(raw: string) {
const alt = toNum(reisezeit);
const neu = toNum(raw);
setReisezeit(raw);
if (neu <= 0) setVertrieb('0');
else if (neu < 2) setVertrieb(numToStr(neu));
else if (alt < 2) setVertrieb('2'); // Schwelle 2h überschritten → Standard 2h
// neu ≥ 2 und alt ≥ 2: bestehenden (ggf. geänderten) Wert beibehalten
}
async function handleSubmit(e: React.FormEvent) {
e.preventDefault();
@@ -145,7 +170,7 @@ export default function ArbeitszeitForm({ editEntry, pause, onSaved, onCancel }:
type="text"
inputMode="decimal"
value={reisezeit}
onChange={(e) => setReisezeit(e.target.value)}
onChange={(e) => handleReisezeit(e.target.value)}
className={numCls}
/>
</div>
@@ -156,7 +181,9 @@ export default function ArbeitszeitForm({ editEntry, pause, onSaved, onCancel }:
inputMode="decimal"
value={vertrieb}
onChange={(e) => setVertrieb(e.target.value)}
className={numCls}
disabled={!vertriebFrei}
title={vertriebFrei ? undefined : 'Wird automatisch aus der Reisezeit berechnet (< 2 h)'}
className={`${numCls} disabled:bg-gray-100 disabled:text-gray-500`}
/>
</div>
</div>