Versicherung/Steuer: Wortlaut-Feinschliff und Vertrag komplett editierbar
Mein-Audi-Kachel "Versicherung/Steuer" (vAudi()) und Kfz-Steuer-Detail (vSteuer()): "Zusammen" heisst jetzt "Summe", die Fusszeile "feste Kosten im Jahr" darunter entfaellt ersatzlos. Die Kfz-Steuer-Zeile zeigt "im Jahr" statt des rohen Datenwerts "jaehrlich", deckungsgleich mit der Versicherungs-Zeile darueber - nur wenn steuer.zeitraum tatsaechlich "jaehrlich" ist. Der gespeicherte Wert und die "jaehrlich"/"halbjaehrlich"-Auswahl in vSteuerBearbeiten() bleiben unveraendert, das war ein reiner Anzeige-Fix, keine Datenmodell- Aenderung. companion-app hatte an keiner der beiden Stellen ein Gegenstueck (kein "Zusammen"-Tile, keine Nur-Lese-Anzeige des Zeitraums) - dokumentiert als vorbestehende strukturelle Luecke statt kommentarlos uebersprungen. Vertrag-Kachel: war komplett nur lesbar (Gesellschaft, Umfang, Vertragsnummer, Selbstbeteiligung, Schadenfreiheitsklasse). Neue vVertragBearbeiten()-Ansicht (Panel, Route "vertrag") ueber ein neues Zahnrad auf der Vertrag-Kachel - alle Felder editierbar, Selbstbeteiligung zusaetzlich mit Hinzufuegen/Loeschen pro Zeile (neue .zeile-loeschen-Klasse, 44x44pt-Tippflaeche wie .km-edit). Die aktuelle Schadenfreiheitsklasse bleibt bewusst nur ueber "Beitrag anpassen" editierbar (Querverweis statt Duplikat), nur "zuvor" (sfAlt) ist neu in der Vertrag-Ansicht. companion-app: neue Vertrag()-Seite (Route "vertrag", eigene NaviKachel auf der Versicherungs-Seite) nach dem dortigen etablierten Muster (lokaler Entwurf-State + expliziter Speichern-Knopf statt Panel-Autosave pro Feld - gleiches Verhalten, eigenes Idiom). Die bisherige Nur-Lese-Selbstbeteiligung in Vertragsdetails() entfaellt, da sie jetzt (editierbar) in Vertrag() lebt. Schadenfreiheitsklasse wird in companion-app bewusst nicht ergaenzt: das Feld war dort noch nie sichtbar, auch nicht lesend - eine komplette neue UI-Sektion dafuer waere kein "Zeile editierbar machen" mehr, sondern ein neues Feature; als Luecke dokumentiert statt still uebergangen. tsc --noEmit sauber, companion-app-Tests 100/100 (inkl. dem Alle-Seiten-Rendertest, der jetzt auch "vertrag" abdeckt), vite build erfolgreich. Panel live im Docker-Testcontainer geprueft: Zeile hinzufuegen/bearbeiten/loeschen, Daten bleiben nach Re-Render erhalten. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -23,6 +23,7 @@ export type SeitenName =
|
||||
| "reifen"
|
||||
| "vers"
|
||||
| "beitrag"
|
||||
| "vertrag"
|
||||
| "vertragsdetails"
|
||||
| "schutz"
|
||||
| "notruf"
|
||||
@@ -54,6 +55,7 @@ export const ZURUECK: Partial<Record<SeitenName, SeitenName>> = {
|
||||
battverlauf: "audi",
|
||||
vers: "audi",
|
||||
beitrag: "vers",
|
||||
vertrag: "vers",
|
||||
vertragsdetails: "vers",
|
||||
schutz: "vertragsdetails",
|
||||
steuer: "vers",
|
||||
@@ -80,6 +82,7 @@ export const TITEL: Record<SeitenName, string> = {
|
||||
reifen: "Reifen",
|
||||
vers: "Versicherung & Steuer",
|
||||
beitrag: "Beitrag",
|
||||
vertrag: "Vertrag",
|
||||
vertragsdetails: "Vertragsdetails",
|
||||
schutz: "Schutzbrief",
|
||||
notruf: "Notruf",
|
||||
|
||||
@@ -56,6 +56,11 @@ export function Versicherung({ geheZu }: { geheZu: (name: SeitenName, id?: strin
|
||||
|
||||
<div className="dm-raster">
|
||||
<NaviKachel titel="Beitrag" wert="Einzelposten bearbeiten" beiKlick={() => geheZu("beitrag")} />
|
||||
<NaviKachel
|
||||
titel="Vertrag"
|
||||
wert="Gesellschaft, Nummer, Selbstbeteiligung"
|
||||
beiKlick={() => geheZu("vertrag")}
|
||||
/>
|
||||
<NaviKachel
|
||||
titel="Vertragsdetails"
|
||||
wert="Leistungen und Schutzbrief"
|
||||
@@ -155,13 +160,115 @@ export function Beitrag() {
|
||||
)
|
||||
}
|
||||
|
||||
export function Vertrag() {
|
||||
const { fahrzeug, profilSpeichern } = useDaten()
|
||||
const v = fahrzeug?.versicherung ?? {}
|
||||
const [gesellschaft, setzeGesellschaft] = useState((v["gesellschaft"] as string) ?? "")
|
||||
const [umfang, setzeUmfang] = useState((v["vertrag"] as string) ?? "")
|
||||
const [nummer, setzeNummer] = useState((v["nummer"] as string) ?? "")
|
||||
const [selbst, setzeSelbst] = useState<string[][]>(() =>
|
||||
((v["selbst"] as (string | number)[][]) ?? []).map(([b, w]) => [String(b ?? ""), String(w ?? "")]),
|
||||
)
|
||||
const [laeuft, setzeLaeuft] = useState(false)
|
||||
const [gespeichert, setzeGespeichert] = useState(false)
|
||||
|
||||
if (!fahrzeug) return null
|
||||
|
||||
const speichern = async () => {
|
||||
setzeLaeuft(true)
|
||||
setzeGespeichert(false)
|
||||
try {
|
||||
await profilSpeichern({
|
||||
fahrzeug: {
|
||||
...fahrzeug,
|
||||
versicherung: { ...v, gesellschaft, vertrag: umfang, nummer, selbst },
|
||||
},
|
||||
})
|
||||
setzeGespeichert(true)
|
||||
} finally {
|
||||
setzeLaeuft(false)
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<Tile>
|
||||
<span className="ads-eyebrow">Vertrag</span>
|
||||
<Feld label="Gesellschaft">
|
||||
<input
|
||||
className="dm-eingabe"
|
||||
value={gesellschaft}
|
||||
onChange={(e) => setzeGesellschaft(e.target.value)}
|
||||
/>
|
||||
</Feld>
|
||||
<Feld label="Umfang">
|
||||
<input className="dm-eingabe" value={umfang} onChange={(e) => setzeUmfang(e.target.value)} />
|
||||
</Feld>
|
||||
<Feld label="Vertragsnummer" last>
|
||||
<input className="dm-eingabe" value={nummer} onChange={(e) => setzeNummer(e.target.value)} />
|
||||
</Feld>
|
||||
</Tile>
|
||||
|
||||
<Tile>
|
||||
<span className="ads-eyebrow">Selbstbeteiligung</span>
|
||||
{selbst.map((zeile, i) => (
|
||||
<Feld key={i} label={`Position ${i + 1}`} last={i === selbst.length - 1}>
|
||||
<span className="dm-selbst-zeile">
|
||||
<input
|
||||
className="dm-eingabe"
|
||||
style={{ minWidth: 84, maxWidth: 110 }}
|
||||
placeholder="Bezeichnung"
|
||||
value={zeile[0]}
|
||||
onChange={(e) => {
|
||||
const wert = e.target.value
|
||||
setzeSelbst((alt) => alt.map((z, idx) => (idx === i ? [wert, z[1] ?? ""] : z)))
|
||||
}}
|
||||
/>
|
||||
<input
|
||||
className="dm-eingabe"
|
||||
style={{ minWidth: 64, maxWidth: 90 }}
|
||||
placeholder="Betrag"
|
||||
value={zeile[1]}
|
||||
onChange={(e) => {
|
||||
const wert = e.target.value
|
||||
setzeSelbst((alt) => alt.map((z, idx) => (idx === i ? [z[0] ?? "", wert] : z)))
|
||||
}}
|
||||
/>
|
||||
<button
|
||||
type="button"
|
||||
className="dm-zeile-loeschen"
|
||||
aria-label={`Position ${i + 1} löschen`}
|
||||
onClick={() => setzeSelbst((alt) => alt.filter((_, idx) => idx !== i))}
|
||||
>
|
||||
×
|
||||
</button>
|
||||
</span>
|
||||
</Feld>
|
||||
))}
|
||||
{selbst.length === 0 && <p className="dm-fussnote">Keine Selbstbeteiligung hinterlegt.</p>}
|
||||
<div style={{ marginTop: 14 }}>
|
||||
<ActionButton onClick={() => setzeSelbst((alt) => [...alt, ["", ""]])}>
|
||||
+ Position hinzufügen
|
||||
</ActionButton>
|
||||
</div>
|
||||
</Tile>
|
||||
|
||||
{gespeichert && <p className="dm-erfolg">Gespeichert.</p>}
|
||||
<div style={{ marginTop: 14 }}>
|
||||
<ActionButton onClick={() => void speichern()} disabled={laeuft}>
|
||||
{laeuft ? "Speichere …" : "Speichern"}
|
||||
</ActionButton>
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export function Vertragsdetails({ geheZu }: { geheZu: (name: SeitenName, id?: string) => void }) {
|
||||
const { fahrzeug } = useDaten()
|
||||
if (!fahrzeug) return null
|
||||
|
||||
const v = fahrzeug.versicherung
|
||||
const leistungen = (v["leistungen"] ?? []) as { bez?: string; wert?: string }[]
|
||||
const selbst = (v["selbst"] ?? []) as (string | number)[][]
|
||||
|
||||
return (
|
||||
<>
|
||||
@@ -178,17 +285,6 @@ export function Vertragsdetails({ geheZu }: { geheZu: (name: SeitenName, id?: st
|
||||
)}
|
||||
</Tile>
|
||||
|
||||
{selbst.length > 0 && (
|
||||
<Tile>
|
||||
<span className="ads-eyebrow">Selbstbeteiligung</span>
|
||||
<Werteliste
|
||||
kinder={selbst.map((zeile, i) => (
|
||||
<Wertzeile key={i} label={String(zeile[0] ?? "")} wert={String(zeile[1] ?? "")} />
|
||||
))}
|
||||
/>
|
||||
</Tile>
|
||||
)}
|
||||
|
||||
<NaviKachel
|
||||
titel="Schutzbrief"
|
||||
wert="Bedingungen im Detail"
|
||||
|
||||
@@ -25,6 +25,7 @@ import {
|
||||
Schutzbrief,
|
||||
Steuer,
|
||||
Versicherung,
|
||||
Vertrag,
|
||||
Vertragsdetails,
|
||||
} from "./Versicherung"
|
||||
|
||||
@@ -78,6 +79,8 @@ export function SeiteFuer(props: SeitenProps) {
|
||||
return <Versicherung geheZu={geheZu} />
|
||||
case "beitrag":
|
||||
return <Beitrag />
|
||||
case "vertrag":
|
||||
return <Vertrag />
|
||||
case "vertragsdetails":
|
||||
return <Vertragsdetails geheZu={geheZu} />
|
||||
case "schutz":
|
||||
|
||||
@@ -24,6 +24,42 @@
|
||||
color: var(--fg3);
|
||||
}
|
||||
|
||||
/* Eine Zeile aus einer bearbeitbaren Liste (z. B. Selbstbeteiligung im
|
||||
Vertrag) - zwei Eingaben plus Löschen-Knopf in einer Reihe, deckungsgleich
|
||||
mit .feld/.zeile-loeschen im Panel (audi-dashboard.css). */
|
||||
.dm-selbst-zeile {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: var(--sp-2);
|
||||
}
|
||||
|
||||
.dm-zeile-loeschen {
|
||||
position: relative;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 22px;
|
||||
height: 22px;
|
||||
border: none;
|
||||
background: none;
|
||||
color: var(--fg3);
|
||||
font-size: 18px;
|
||||
line-height: 1;
|
||||
padding: 0;
|
||||
cursor: pointer;
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
|
||||
.dm-zeile-loeschen::before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
inset: -11px;
|
||||
}
|
||||
|
||||
.dm-zeile-loeschen:active {
|
||||
color: var(--bad);
|
||||
}
|
||||
|
||||
.dm-auswahl {
|
||||
text-align: right;
|
||||
appearance: none;
|
||||
|
||||
Reference in New Issue
Block a user