feat(kontrolle): Ablaufdatum als nur Monat/Jahr erfassbar
CI / backend-tests (push) Failing after 2m6s
CI / frontend-build (push) Successful in 19s

Charge zeigt teils nur MM/JJJJ. Checkbox schaltet Eingabe auf Monat um, gespeichert wird Monatsende.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CVgbozhYmuEhiEJHffRXCV
This commit is contained in:
2026-09-07 00:50:53 +02:00
co-authored by Claude Sonnet 5
parent 1c2f2d38e0
commit 9b2701e220
+34 -14
View File
@@ -1,3 +1,5 @@
import { useState } from "react";
import { StatusBadge } from "./StatusBadge"; import { StatusBadge } from "./StatusBadge";
import type { PositionZustand } from "./types"; import type { PositionZustand } from "./types";
@@ -8,6 +10,11 @@ interface Props {
onErneutVersuchen: (materialId: number, zustand: PositionZustand) => void; onErneutVersuchen: (materialId: number, zustand: PositionZustand) => void;
} }
function letzterTagDesMonats(monatswert: string): string {
const [jahr, monat] = monatswert.split("-").map(Number);
return new Date(jahr, monat, 0).toISOString().slice(0, 10);
}
/** /**
* Nutzer-Vorgabe: Ablauf/Charge/SN gehören zur Kontroll-Erfassung dazu, wie * Nutzer-Vorgabe: Ablauf/Charge/SN gehören zur Kontroll-Erfassung dazu, wie
* die Menge - kein separater Admin-Schritt. Felder erscheinen nur, wenn der * die Menge - kein separater Admin-Schritt. Felder erscheinen nur, wenn der
@@ -34,6 +41,7 @@ function rahmenFarbe(status: PositionZustand["status"], passt: boolean): string
export function PositionCard({ zustand, onEingabeAendern, onSenden, onErneutVersuchen }: Props) { export function PositionCard({ zustand, onEingabeAendern, onSenden, onErneutVersuchen }: Props) {
const materialtyp = zustand.material?.materialtyp; const materialtyp = zustand.material?.materialtyp;
const passt = zustand.eingabe === zustand.position.sollmenge_effektiv; const passt = zustand.eingabe === zustand.position.sollmenge_effektiv;
const [nurMonat, setNurMonat] = useState(false);
return ( return (
<div className="card" style={{ borderLeft: `4px solid ${rahmenFarbe(zustand.status, passt)}` }}> <div className="card" style={{ borderLeft: `4px solid ${rahmenFarbe(zustand.status, passt)}` }}>
@@ -61,20 +69,32 @@ export function PositionCard({ zustand, onEingabeAendern, onSenden, onErneutVers
</button> </button>
</div> </div>
{materialtyp === "ablauf_charge" && ( {materialtyp === "ablauf_charge" && (
<div className="row" style={{ marginTop: "0.5rem" }}> <div style={{ marginTop: "0.5rem" }}>
<input <div className="row">
type="date" <input
className="input" type={nurMonat ? "month" : "date"}
value={zustand.ablaufdatum} className="input"
onChange={(e) => onEingabeAendern(zustand.position.material_id, "ablaufdatum", e.target.value)} value={nurMonat ? zustand.ablaufdatum.slice(0, 7) : zustand.ablaufdatum}
style={{ borderColor: ablaufFarbe(zustand.ablaufdatum), color: ablaufFarbe(zustand.ablaufdatum) }} onChange={(e) =>
/> onEingabeAendern(
<input zustand.position.material_id,
className="input" "ablaufdatum",
placeholder="Chargennummer" nurMonat && e.target.value ? letzterTagDesMonats(e.target.value) : e.target.value
value={zustand.chargennummer} )
onChange={(e) => onEingabeAendern(zustand.position.material_id, "chargennummer", e.target.value)} }
/> style={{ borderColor: ablaufFarbe(zustand.ablaufdatum), color: ablaufFarbe(zustand.ablaufdatum) }}
/>
<input
className="input"
placeholder="Chargennummer"
value={zustand.chargennummer}
onChange={(e) => onEingabeAendern(zustand.position.material_id, "chargennummer", e.target.value)}
/>
</div>
<label className="text-muted" style={{ display: "flex", alignItems: "center", gap: "0.3rem", marginTop: "0.3rem" }}>
<input type="checkbox" checked={nurMonat} onChange={(e) => setNurMonat(e.target.checked)} />
Nur Monat/Jahr auf Charge (gilt bis Monatsende)
</label>
</div> </div>
)} )}
{materialtyp === "geraet_sn" && ( {materialtyp === "geraet_sn" && (