Zeilenenden der 24 verbliebenen Dateien normalisieren

Ausschliesslich Zeilenenden. Nachgewiesen mit
"git diff --cached --ignore-cr-at-eol": Der Diff ist leer, es hat sich
kein Zeichen Inhalt geaendert.

Deshalb ein eigener Commit: 7448 geaenderte Zeilen in einem Commit mit
echten Aenderungen zu verstecken, macht die Historie an dieser Stelle
unlesbar. So laesst er sich beim Durchsehen ueberspringen.

Refs #26
This commit is contained in:
Florian Wilde
2026-08-23 23:37:02 +02:00
parent 6a0db51e3b
commit 1ed19eb76e
24 changed files with 7448 additions and 7448 deletions
+310 -310
View File
@@ -1,310 +1,310 @@
'use client'
import { useActionState, useState } from 'react'
import { Feld, Feldgruppe } from '@/components/feld'
import { Rechtshinweis } from '@/components/rechtshinweis'
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'
import { Input } from '@/components/ui/input'
import { Select } from '@/components/ui/select'
import { Textarea } from '@/components/ui/textarea'
import { Absenden, Meldung } from '@/components/sozialhilfe/bausteine'
import { MONATSNAMEN } from '@/lib/sozialhilfe/heimkosten'
import { heimkostenSpeichern, type Formularzustand } from '@/server/actions/sozialhilfe'
export type HeimkostenWerte = {
jahr: number
monat: number
pflegeEigenanteil: string
unterkunftVerpflegung: string
investitionskosten: string
ausbildungsumlage: string
zusatzleistungen: string
pflegekasse: string
leistungszuschlagProzent: number
leistungszuschlag: string
rente: string
sonstigeEinkuenfte: string
sozialhilfe: string
eigenmittel: string
barbetrag: string
bekleidungspauschale: string
abwesenheitstage: number
bemerkung: string
}
/**
* Ein Monat der Gegenüberstellung.
*
* Die Reihenfolge folgt der Heimrechnung: erst die vier Bausteine der
* Kosten, dann die Deckungsquellen, dann das, was der betreuten Person
* verbleiben muss. Wer von oben nach unten abtippt, findet alles an der
* Stelle, an der es auf der Rechnung steht.
*/
export function HeimkostenFormular({
werte,
jahre,
hinweisPflegekasse,
vorschlagBarbetrag,
}: {
werte: HeimkostenWerte
jahre: number[]
/**
* Erklaerung zum Feld "Leistung der Pflegekasse". Bewusst KEIN
* Uebernehmen-Knopf: Unter der Lesart dieses Moduls ist der
* Eigenanteil bereits um die Pauschale gekuerzt, das Feld gehoert
* deshalb auf 0. Siehe src/lib/sozialhilfe/heimkosten.ts.
*/
hinweisPflegekasse: string
vorschlagBarbetrag: { betrag: string; text: string }
}) {
const [zustand, aktion] = useActionState<Formularzustand, FormData>(heimkostenSpeichern, {})
const [barbetrag, setBarbetrag] = useState(werte.barbetrag)
return (
<form action={aktion} className="space-y-6">
<Meldung zustand={zustand} />
<Card>
<CardHeader>
<CardTitle>Monat erfassen</CardTitle>
<CardDescription>
Beträge wie auf der Heimrechnung, z.B. 1.234,56. Ein bereits erfasster Monat wird
überschrieben.
</CardDescription>
</CardHeader>
<CardContent className="space-y-6">
<div className="grid gap-4 sm:grid-cols-2">
<Feld id="jahr" beschriftung="Jahr" pflicht fehler={zustand.felder?.jahr}>
<Select name="jahr" defaultValue={String(werte.jahr)}>
{jahre.map((j) => (
<option key={j} value={j}>
{j}
</option>
))}
</Select>
</Feld>
<Feld id="monat" beschriftung="Monat" pflicht fehler={zustand.felder?.monat}>
<Select name="monat" defaultValue={String(werte.monat)}>
{MONATSNAMEN.map((name, i) => (
<option key={name} value={i + 1}>
{name}
</option>
))}
</Select>
</Feld>
</div>
<Feldgruppe
titel="Kosten"
beschreibung="Die vier Bausteine der Heimrechnung, dazu Zusatzleistungen."
>
<Feld
id="pflegeEigenanteil"
beschriftung="Einrichtungseinheitlicher Eigenanteil"
fehler={zustand.felder?.pflegeEigenanteil}
erklaerung="Der pflegebedingte Anteil (EEE), genau wie er auf der Heimrechnung steht — also bereits abzüglich der Pauschale der Pflegekasse (§ 43 Abs. 2 SGB XI). In jedem Pflegegrad gleich hoch. Nur auf ihn wirkt der Leistungszuschlag."
>
<Input
name="pflegeEigenanteil"
inputMode="decimal"
defaultValue={werte.pflegeEigenanteil}
/>
</Feld>
<Feld
id="unterkunftVerpflegung"
beschriftung="Unterkunft und Verpflegung"
fehler={zustand.felder?.unterkunftVerpflegung}
>
<Input
name="unterkunftVerpflegung"
inputMode="decimal"
defaultValue={werte.unterkunftVerpflegung}
/>
</Feld>
<Feld
id="investitionskosten"
beschriftung="Investitionskosten"
fehler={zustand.felder?.investitionskosten}
erklaerung="Gebäude und Instandhaltung. Laufen auch bei Abwesenheit weiter."
>
<Input
name="investitionskosten"
inputMode="decimal"
defaultValue={werte.investitionskosten}
/>
</Feld>
<Feld
id="ausbildungsumlage"
beschriftung="Ausbildungsumlage"
fehler={zustand.felder?.ausbildungsumlage}
>
<Input
name="ausbildungsumlage"
inputMode="decimal"
defaultValue={werte.ausbildungsumlage}
/>
</Feld>
<Feld
id="zusatzleistungen"
beschriftung="Zusatzleistungen"
fehler={zustand.felder?.zusatzleistungen}
erklaerung="Friseur, Komfortleistungen. Der Träger übernimmt sie in aller Regel nicht — sie gehen vom Barbetrag ab."
>
<Input
name="zusatzleistungen"
inputMode="decimal"
defaultValue={werte.zusatzleistungen}
/>
</Feld>
</Feldgruppe>
<Feldgruppe titel="Deckung" beschreibung="Wer zahlt welchen Teil?">
<Feld
id="pflegekasse"
beschriftung="Leistung der Pflegekasse (nachrichtlich)"
fehler={zustand.felder?.pflegekasse}
erklaerung={hinweisPflegekasse}
>
<Input name="pflegekasse" inputMode="decimal" defaultValue={werte.pflegekasse} />
</Feld>
<Feld
id="leistungszuschlagProzent"
beschriftung="Leistungszuschlag in Prozent"
fehler={zustand.felder?.leistungszuschlagProzent}
erklaerung="§ 43c SGB XI: 15 / 30 / 50 / 75 Prozent nach Verweildauer. Steht auf der Heimrechnung."
>
<Input
name="leistungszuschlagProzent"
type="number"
min={0}
max={100}
defaultValue={werte.leistungszuschlagProzent}
/>
</Feld>
<Feld
id="leistungszuschlag"
beschriftung="Leistungszuschlag in Euro"
fehler={zustand.felder?.leistungszuschlag}
erklaerung="Nur auf den pflegebedingten Eigenanteil, nicht auf die ganze Rechnung."
>
<Input
name="leistungszuschlag"
inputMode="decimal"
defaultValue={werte.leistungszuschlag}
/>
</Feld>
<Feld id="rente" beschriftung="Rente" fehler={zustand.felder?.rente}>
<Input name="rente" inputMode="decimal" defaultValue={werte.rente} />
</Feld>
<Feld
id="sonstigeEinkuenfte"
beschriftung="Sonstige Einkünfte"
fehler={zustand.felder?.sonstigeEinkuenfte}
erklaerung="Betriebsrente, Mieteinnahmen, Zinsen."
>
<Input
name="sonstigeEinkuenfte"
inputMode="decimal"
defaultValue={werte.sonstigeEinkuenfte}
/>
</Feld>
<Feld
id="sozialhilfe"
beschriftung="Anteil der Sozialhilfe"
fehler={zustand.felder?.sozialhilfe}
erklaerung="Was der Bezirk laut Bescheid übernimmt."
>
<Input name="sozialhilfe" inputMode="decimal" defaultValue={werte.sozialhilfe} />
</Feld>
<Feld
id="eigenmittel"
beschriftung="Eigenmittel"
fehler={zustand.felder?.eigenmittel}
erklaerung="Was aus dem eigenen Vermögen zugeschossen wurde."
>
<Input name="eigenmittel" inputMode="decimal" defaultValue={werte.eigenmittel} />
</Feld>
</Feldgruppe>
<Feldgruppe
titel="Was verbleiben muss"
beschreibung="Barbetrag und Bekleidungspauschale sind Teil des Bedarfs, nicht Rest."
>
<Feld
id="barbetrag"
beschriftung="Barbetrag"
fehler={zustand.felder?.barbetrag}
erklaerung={
<>
{vorschlagBarbetrag.text}{' '}
<button
type="button"
onClick={() => setBarbetrag(vorschlagBarbetrag.betrag)}
className="font-medium text-primary underline-offset-4 hover:underline"
>
Wert übernehmen
</button>
</>
}
>
<Input
name="barbetrag"
inputMode="decimal"
value={barbetrag}
onChange={(e) => setBarbetrag(e.target.value)}
/>
</Feld>
<Feld
id="bekleidungspauschale"
beschriftung="Bekleidungspauschale"
fehler={zustand.felder?.bekleidungspauschale}
erklaerung="Höhe legt der Träger fest (§ 27b Abs. 1 SGB XII) — übernimm den Betrag aus dem Bescheid."
>
<Input
name="bekleidungspauschale"
inputMode="decimal"
defaultValue={werte.bekleidungspauschale}
/>
</Feld>
<Feld
id="abwesenheitstage"
beschriftung="Abwesenheitstage"
fehler={zustand.felder?.abwesenheitstage}
erklaerung="Krankenhaus, Reha, Urlaub. Die ersten drei Tage sind voll zu zahlen; ab dem vierten mindert sich das Entgelt nach dem Rahmenvertrag — die Anwendung schätzt das nur, maßgeblich ist die Heimrechnung."
>
<Input
name="abwesenheitstage"
type="number"
min={0}
max={31}
defaultValue={werte.abwesenheitstage}
/>
</Feld>
</Feldgruppe>
<Feld id="bemerkung" beschriftung="Bemerkung" fehler={zustand.felder?.bemerkung}>
<Textarea name="bemerkung" defaultValue={werte.bemerkung} rows={2} />
</Feld>
</CardContent>
</Card>
<Rechtshinweis rechtsgrundlage="§ 43 SGB XI, § 43c SGB XI, § 27b SGB XII" />
<Absenden>Monat speichern</Absenden>
</form>
)
}
'use client'
import { useActionState, useState } from 'react'
import { Feld, Feldgruppe } from '@/components/feld'
import { Rechtshinweis } from '@/components/rechtshinweis'
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'
import { Input } from '@/components/ui/input'
import { Select } from '@/components/ui/select'
import { Textarea } from '@/components/ui/textarea'
import { Absenden, Meldung } from '@/components/sozialhilfe/bausteine'
import { MONATSNAMEN } from '@/lib/sozialhilfe/heimkosten'
import { heimkostenSpeichern, type Formularzustand } from '@/server/actions/sozialhilfe'
export type HeimkostenWerte = {
jahr: number
monat: number
pflegeEigenanteil: string
unterkunftVerpflegung: string
investitionskosten: string
ausbildungsumlage: string
zusatzleistungen: string
pflegekasse: string
leistungszuschlagProzent: number
leistungszuschlag: string
rente: string
sonstigeEinkuenfte: string
sozialhilfe: string
eigenmittel: string
barbetrag: string
bekleidungspauschale: string
abwesenheitstage: number
bemerkung: string
}
/**
* Ein Monat der Gegenüberstellung.
*
* Die Reihenfolge folgt der Heimrechnung: erst die vier Bausteine der
* Kosten, dann die Deckungsquellen, dann das, was der betreuten Person
* verbleiben muss. Wer von oben nach unten abtippt, findet alles an der
* Stelle, an der es auf der Rechnung steht.
*/
export function HeimkostenFormular({
werte,
jahre,
hinweisPflegekasse,
vorschlagBarbetrag,
}: {
werte: HeimkostenWerte
jahre: number[]
/**
* Erklaerung zum Feld "Leistung der Pflegekasse". Bewusst KEIN
* Uebernehmen-Knopf: Unter der Lesart dieses Moduls ist der
* Eigenanteil bereits um die Pauschale gekuerzt, das Feld gehoert
* deshalb auf 0. Siehe src/lib/sozialhilfe/heimkosten.ts.
*/
hinweisPflegekasse: string
vorschlagBarbetrag: { betrag: string; text: string }
}) {
const [zustand, aktion] = useActionState<Formularzustand, FormData>(heimkostenSpeichern, {})
const [barbetrag, setBarbetrag] = useState(werte.barbetrag)
return (
<form action={aktion} className="space-y-6">
<Meldung zustand={zustand} />
<Card>
<CardHeader>
<CardTitle>Monat erfassen</CardTitle>
<CardDescription>
Beträge wie auf der Heimrechnung, z.B. 1.234,56. Ein bereits erfasster Monat wird
überschrieben.
</CardDescription>
</CardHeader>
<CardContent className="space-y-6">
<div className="grid gap-4 sm:grid-cols-2">
<Feld id="jahr" beschriftung="Jahr" pflicht fehler={zustand.felder?.jahr}>
<Select name="jahr" defaultValue={String(werte.jahr)}>
{jahre.map((j) => (
<option key={j} value={j}>
{j}
</option>
))}
</Select>
</Feld>
<Feld id="monat" beschriftung="Monat" pflicht fehler={zustand.felder?.monat}>
<Select name="monat" defaultValue={String(werte.monat)}>
{MONATSNAMEN.map((name, i) => (
<option key={name} value={i + 1}>
{name}
</option>
))}
</Select>
</Feld>
</div>
<Feldgruppe
titel="Kosten"
beschreibung="Die vier Bausteine der Heimrechnung, dazu Zusatzleistungen."
>
<Feld
id="pflegeEigenanteil"
beschriftung="Einrichtungseinheitlicher Eigenanteil"
fehler={zustand.felder?.pflegeEigenanteil}
erklaerung="Der pflegebedingte Anteil (EEE), genau wie er auf der Heimrechnung steht — also bereits abzüglich der Pauschale der Pflegekasse (§ 43 Abs. 2 SGB XI). In jedem Pflegegrad gleich hoch. Nur auf ihn wirkt der Leistungszuschlag."
>
<Input
name="pflegeEigenanteil"
inputMode="decimal"
defaultValue={werte.pflegeEigenanteil}
/>
</Feld>
<Feld
id="unterkunftVerpflegung"
beschriftung="Unterkunft und Verpflegung"
fehler={zustand.felder?.unterkunftVerpflegung}
>
<Input
name="unterkunftVerpflegung"
inputMode="decimal"
defaultValue={werte.unterkunftVerpflegung}
/>
</Feld>
<Feld
id="investitionskosten"
beschriftung="Investitionskosten"
fehler={zustand.felder?.investitionskosten}
erklaerung="Gebäude und Instandhaltung. Laufen auch bei Abwesenheit weiter."
>
<Input
name="investitionskosten"
inputMode="decimal"
defaultValue={werte.investitionskosten}
/>
</Feld>
<Feld
id="ausbildungsumlage"
beschriftung="Ausbildungsumlage"
fehler={zustand.felder?.ausbildungsumlage}
>
<Input
name="ausbildungsumlage"
inputMode="decimal"
defaultValue={werte.ausbildungsumlage}
/>
</Feld>
<Feld
id="zusatzleistungen"
beschriftung="Zusatzleistungen"
fehler={zustand.felder?.zusatzleistungen}
erklaerung="Friseur, Komfortleistungen. Der Träger übernimmt sie in aller Regel nicht — sie gehen vom Barbetrag ab."
>
<Input
name="zusatzleistungen"
inputMode="decimal"
defaultValue={werte.zusatzleistungen}
/>
</Feld>
</Feldgruppe>
<Feldgruppe titel="Deckung" beschreibung="Wer zahlt welchen Teil?">
<Feld
id="pflegekasse"
beschriftung="Leistung der Pflegekasse (nachrichtlich)"
fehler={zustand.felder?.pflegekasse}
erklaerung={hinweisPflegekasse}
>
<Input name="pflegekasse" inputMode="decimal" defaultValue={werte.pflegekasse} />
</Feld>
<Feld
id="leistungszuschlagProzent"
beschriftung="Leistungszuschlag in Prozent"
fehler={zustand.felder?.leistungszuschlagProzent}
erklaerung="§ 43c SGB XI: 15 / 30 / 50 / 75 Prozent nach Verweildauer. Steht auf der Heimrechnung."
>
<Input
name="leistungszuschlagProzent"
type="number"
min={0}
max={100}
defaultValue={werte.leistungszuschlagProzent}
/>
</Feld>
<Feld
id="leistungszuschlag"
beschriftung="Leistungszuschlag in Euro"
fehler={zustand.felder?.leistungszuschlag}
erklaerung="Nur auf den pflegebedingten Eigenanteil, nicht auf die ganze Rechnung."
>
<Input
name="leistungszuschlag"
inputMode="decimal"
defaultValue={werte.leistungszuschlag}
/>
</Feld>
<Feld id="rente" beschriftung="Rente" fehler={zustand.felder?.rente}>
<Input name="rente" inputMode="decimal" defaultValue={werte.rente} />
</Feld>
<Feld
id="sonstigeEinkuenfte"
beschriftung="Sonstige Einkünfte"
fehler={zustand.felder?.sonstigeEinkuenfte}
erklaerung="Betriebsrente, Mieteinnahmen, Zinsen."
>
<Input
name="sonstigeEinkuenfte"
inputMode="decimal"
defaultValue={werte.sonstigeEinkuenfte}
/>
</Feld>
<Feld
id="sozialhilfe"
beschriftung="Anteil der Sozialhilfe"
fehler={zustand.felder?.sozialhilfe}
erklaerung="Was der Bezirk laut Bescheid übernimmt."
>
<Input name="sozialhilfe" inputMode="decimal" defaultValue={werte.sozialhilfe} />
</Feld>
<Feld
id="eigenmittel"
beschriftung="Eigenmittel"
fehler={zustand.felder?.eigenmittel}
erklaerung="Was aus dem eigenen Vermögen zugeschossen wurde."
>
<Input name="eigenmittel" inputMode="decimal" defaultValue={werte.eigenmittel} />
</Feld>
</Feldgruppe>
<Feldgruppe
titel="Was verbleiben muss"
beschreibung="Barbetrag und Bekleidungspauschale sind Teil des Bedarfs, nicht Rest."
>
<Feld
id="barbetrag"
beschriftung="Barbetrag"
fehler={zustand.felder?.barbetrag}
erklaerung={
<>
{vorschlagBarbetrag.text}{' '}
<button
type="button"
onClick={() => setBarbetrag(vorschlagBarbetrag.betrag)}
className="font-medium text-primary underline-offset-4 hover:underline"
>
Wert übernehmen
</button>
</>
}
>
<Input
name="barbetrag"
inputMode="decimal"
value={barbetrag}
onChange={(e) => setBarbetrag(e.target.value)}
/>
</Feld>
<Feld
id="bekleidungspauschale"
beschriftung="Bekleidungspauschale"
fehler={zustand.felder?.bekleidungspauschale}
erklaerung="Höhe legt der Träger fest (§ 27b Abs. 1 SGB XII) — übernimm den Betrag aus dem Bescheid."
>
<Input
name="bekleidungspauschale"
inputMode="decimal"
defaultValue={werte.bekleidungspauschale}
/>
</Feld>
<Feld
id="abwesenheitstage"
beschriftung="Abwesenheitstage"
fehler={zustand.felder?.abwesenheitstage}
erklaerung="Krankenhaus, Reha, Urlaub. Die ersten drei Tage sind voll zu zahlen; ab dem vierten mindert sich das Entgelt nach dem Rahmenvertrag — die Anwendung schätzt das nur, maßgeblich ist die Heimrechnung."
>
<Input
name="abwesenheitstage"
type="number"
min={0}
max={31}
defaultValue={werte.abwesenheitstage}
/>
</Feld>
</Feldgruppe>
<Feld id="bemerkung" beschriftung="Bemerkung" fehler={zustand.felder?.bemerkung}>
<Textarea name="bemerkung" defaultValue={werte.bemerkung} rows={2} />
</Feld>
</CardContent>
</Card>
<Rechtshinweis rechtsgrundlage="§ 43 SGB XI, § 43c SGB XI, § 27b SGB XII" />
<Absenden>Monat speichern</Absenden>
</form>
)
}
+237 -237
View File
@@ -1,237 +1,237 @@
'use client'
import { useActionState, useState } from 'react'
import type { SozialhilfeBewertung, VertragArt } from '@prisma/client'
import { Input } from '@/components/ui/input'
import { Select } from '@/components/ui/select'
import { Textarea } from '@/components/ui/textarea'
import { Feld, Feldgruppe } from '@/components/feld'
import { Rechtshinweis } from '@/components/rechtshinweis'
import { Absendeknopf, Zustandsmeldung } from '@/components/substanz-formular'
import {
BEWERTUNG_BESCHRIFTUNG,
BEWERTUNG_ERKLAERUNG,
RHYTHMUS_BESCHRIFTUNG,
VERTRAG_ART_BESCHRIFTUNG,
VERTRAG_STATUS_BESCHRIFTUNG,
} from '@/lib/vertraege/konstanten'
import { BEWERTUNGEN, VERTRAG_ARTEN, VERTRAG_STATUS, ZAHL_RHYTHMEN } from '@/lib/validierung/vertraege'
import { vertragSpeichern } from '@/server/actions/vertraege'
import type { Formularzustand } from '@/lib/validierung/substanz'
export type VertragWerte = {
id?: string
bezeichnung: string
gesellschaft: string
art: string
status: string
vertragsnummer: string
beginnAm: string
endeAm: string
kuendigungsfristMonate: string
kuendigungZum: string
gekuendigtAm: string
beitrag: string
rhythmus: string
bewertungSozialhilfe: string
bewertungBegruendung: string
notizen: string
}
export const LEERER_VERTRAG: VertragWerte = {
bezeichnung: '',
gesellschaft: '',
art: 'LEBENSVERSICHERUNG',
status: 'AKTIV',
vertragsnummer: '',
beginnAm: '',
endeAm: '',
kuendigungsfristMonate: '3',
kuendigungZum: '',
gekuendigtAm: '',
beitrag: '',
rhythmus: 'MONATLICH',
bewertungSozialhilfe: 'UNGEPRUEFT',
bewertungBegruendung: '',
notizen: '',
}
export function VertragFormular({
betreuteId,
werte,
}: {
betreuteId: string
werte: VertragWerte
}) {
const [zustand, aktion] = useActionState<Formularzustand, FormData>(vertragSpeichern, {})
const [bewertung, setBewertung] = useState(werte.bewertungSozialhilfe)
const istNeu = !werte.id
return (
<form action={aktion} className="space-y-8" noValidate>
<input type="hidden" name="betreuteId" value={betreuteId} />
{werte.id && <input type="hidden" name="vertragId" value={werte.id} />}
<Zustandsmeldung zustand={zustand} />
<Feldgruppe titel="Vertrag" beschreibung="Wer, was und unter welcher Nummer.">
<Feld
id="bezeichnung"
beschriftung="Bezeichnung"
erklaerung="Ein Name, unter dem du den Vertrag wiedererkennst."
fehler={zustand.felder?.bezeichnung}
pflicht
>
<Input name="bezeichnung" defaultValue={werte.bezeichnung} required maxLength={150} />
</Feld>
<Feld id="gesellschaft" beschriftung="Gesellschaft" fehler={zustand.felder?.gesellschaft}>
<Input name="gesellschaft" defaultValue={werte.gesellschaft} maxLength={150} />
</Feld>
<Feld id="art" beschriftung="Art" fehler={zustand.felder?.art} pflicht>
<Select name="art" defaultValue={werte.art}>
{VERTRAG_ARTEN.map((a) => (
<option key={a} value={a}>
{VERTRAG_ART_BESCHRIFTUNG[a as VertragArt]}
</option>
))}
</Select>
</Feld>
<Feld id="status" beschriftung="Status" fehler={zustand.felder?.status}>
<Select name="status" defaultValue={werte.status}>
{VERTRAG_STATUS.map((s) => (
<option key={s} value={s}>
{VERTRAG_STATUS_BESCHRIFTUNG[s]}
</option>
))}
</Select>
</Feld>
<Feld
id="vertragsnummer"
beschriftung="Vertragsnummer"
erklaerung="Wird verschlüsselt gespeichert. Ohne sie ordnet die Gesellschaft kein Schreiben zu."
fehler={zustand.felder?.vertragsnummer}
className="sm:col-span-2"
>
<Input name="vertragsnummer" defaultValue={werte.vertragsnummer} maxLength={80} />
</Feld>
</Feldgruppe>
<Feldgruppe
titel="Laufzeit und Kündigung"
beschreibung="Aus diesen Angaben rechnet die App den nächstmöglichen Kündigungstermin und den spätesten Absendetag."
>
<Feld id="beginnAm" beschriftung="Laufzeitbeginn" fehler={zustand.felder?.beginnAm}>
<Input name="beginnAm" type="date" defaultValue={werte.beginnAm} />
</Feld>
<Feld
id="endeAm"
beschriftung="Vereinbartes Ende"
erklaerung="Nur bei fester Ablaufzeit, z. B. einer Kapitallebensversicherung. Steht hier ein Datum, ergibt sich daraus zugleich die Laufzeit, um die sich der Vertrag verlängert — sonst wird mit einem Jahr gerechnet."
fehler={zustand.felder?.endeAm}
>
<Input name="endeAm" type="date" defaultValue={werte.endeAm} />
</Feld>
<Feld
id="kuendigungsfristMonate"
beschriftung="Kündigungsfrist in Monaten"
erklaerung="Wie lange vor dem Ende muss die Kündigung zugehen? Bei Versicherungen meist drei Monate."
fehler={zustand.felder?.kuendigungsfristMonate}
>
<Input
name="kuendigungsfristMonate"
inputMode="numeric"
defaultValue={werte.kuendigungsfristMonate}
/>
</Feld>
<Feld
id="kuendigungZum"
beschriftung="Gekündigt zum"
fehler={zustand.felder?.kuendigungZum}
>
<Input name="kuendigungZum" type="date" defaultValue={werte.kuendigungZum} />
</Feld>
<Feld id="gekuendigtAm" beschriftung="Kündigung versandt am" fehler={zustand.felder?.gekuendigtAm}>
<Input name="gekuendigtAm" type="date" defaultValue={werte.gekuendigtAm} />
</Feld>
</Feldgruppe>
<Feldgruppe titel="Beitrag" beschreibung="Grundlage für den Jahresbeitrag in der Übersicht.">
<Feld id="beitrag" beschriftung="Beitrag" fehler={zustand.felder?.beitrag}>
<Input name="beitrag" inputMode="decimal" defaultValue={werte.beitrag} placeholder="25,40" />
</Feld>
<Feld id="rhythmus" beschriftung="Rhythmus" fehler={zustand.felder?.rhythmus}>
<Select name="rhythmus" defaultValue={werte.rhythmus}>
<option value="">— nicht angegeben —</option>
{ZAHL_RHYTHMEN.map((r) => (
<option key={r} value={r}>
{RHYTHMUS_BESCHRIFTUNG[r]}
</option>
))}
</Select>
</Feld>
</Feldgruppe>
<Feldgruppe
titel="Bewertung fürs Sozialamt"
beschreibung="Deine Einordnung und deine Argumentation — keine Rechtsauskunft."
>
<Feld
id="bewertungSozialhilfe"
beschriftung="Einordnung"
erklaerung={BEWERTUNG_ERKLAERUNG[bewertung as SozialhilfeBewertung]}
fehler={zustand.felder?.bewertungSozialhilfe}
>
<Select
name="bewertungSozialhilfe"
value={bewertung}
onChange={(e) => setBewertung(e.target.value)}
>
{BEWERTUNGEN.map((b) => (
<option key={b} value={b}>
{BEWERTUNG_BESCHRIFTUNG[b]}
</option>
))}
</Select>
</Feld>
<Feld
id="bewertungBegruendung"
beschriftung="Begründung"
erklaerung="Wird verschlüsselt gespeichert. Diese Zeilen stehen im Zweifel Jahre später im Widerspruchsverfahren."
fehler={zustand.felder?.bewertungBegruendung}
pflicht={bewertung !== 'UNGEPRUEFT'}
className="sm:col-span-2"
>
<Textarea
name="bewertungBegruendung"
defaultValue={werte.bewertungBegruendung}
rows={4}
maxLength={4000}
/>
</Feld>
</Feldgruppe>
<Feld
id="notizen"
beschriftung="Notizen"
erklaerung="Wird verschlüsselt gespeichert."
fehler={zustand.felder?.notizen}
>
<Textarea name="notizen" defaultValue={werte.notizen} rows={4} maxLength={4000} />
</Feld>
<Rechtshinweis rechtsgrundlage="§ 90 Abs. 3 SGB XII" kurz />
<Absendeknopf>{istNeu ? 'Vertrag anlegen' : 'Änderungen speichern'}</Absendeknopf>
</form>
)
}
'use client'
import { useActionState, useState } from 'react'
import type { SozialhilfeBewertung, VertragArt } from '@prisma/client'
import { Input } from '@/components/ui/input'
import { Select } from '@/components/ui/select'
import { Textarea } from '@/components/ui/textarea'
import { Feld, Feldgruppe } from '@/components/feld'
import { Rechtshinweis } from '@/components/rechtshinweis'
import { Absendeknopf, Zustandsmeldung } from '@/components/substanz-formular'
import {
BEWERTUNG_BESCHRIFTUNG,
BEWERTUNG_ERKLAERUNG,
RHYTHMUS_BESCHRIFTUNG,
VERTRAG_ART_BESCHRIFTUNG,
VERTRAG_STATUS_BESCHRIFTUNG,
} from '@/lib/vertraege/konstanten'
import { BEWERTUNGEN, VERTRAG_ARTEN, VERTRAG_STATUS, ZAHL_RHYTHMEN } from '@/lib/validierung/vertraege'
import { vertragSpeichern } from '@/server/actions/vertraege'
import type { Formularzustand } from '@/lib/validierung/substanz'
export type VertragWerte = {
id?: string
bezeichnung: string
gesellschaft: string
art: string
status: string
vertragsnummer: string
beginnAm: string
endeAm: string
kuendigungsfristMonate: string
kuendigungZum: string
gekuendigtAm: string
beitrag: string
rhythmus: string
bewertungSozialhilfe: string
bewertungBegruendung: string
notizen: string
}
export const LEERER_VERTRAG: VertragWerte = {
bezeichnung: '',
gesellschaft: '',
art: 'LEBENSVERSICHERUNG',
status: 'AKTIV',
vertragsnummer: '',
beginnAm: '',
endeAm: '',
kuendigungsfristMonate: '3',
kuendigungZum: '',
gekuendigtAm: '',
beitrag: '',
rhythmus: 'MONATLICH',
bewertungSozialhilfe: 'UNGEPRUEFT',
bewertungBegruendung: '',
notizen: '',
}
export function VertragFormular({
betreuteId,
werte,
}: {
betreuteId: string
werte: VertragWerte
}) {
const [zustand, aktion] = useActionState<Formularzustand, FormData>(vertragSpeichern, {})
const [bewertung, setBewertung] = useState(werte.bewertungSozialhilfe)
const istNeu = !werte.id
return (
<form action={aktion} className="space-y-8" noValidate>
<input type="hidden" name="betreuteId" value={betreuteId} />
{werte.id && <input type="hidden" name="vertragId" value={werte.id} />}
<Zustandsmeldung zustand={zustand} />
<Feldgruppe titel="Vertrag" beschreibung="Wer, was und unter welcher Nummer.">
<Feld
id="bezeichnung"
beschriftung="Bezeichnung"
erklaerung="Ein Name, unter dem du den Vertrag wiedererkennst."
fehler={zustand.felder?.bezeichnung}
pflicht
>
<Input name="bezeichnung" defaultValue={werte.bezeichnung} required maxLength={150} />
</Feld>
<Feld id="gesellschaft" beschriftung="Gesellschaft" fehler={zustand.felder?.gesellschaft}>
<Input name="gesellschaft" defaultValue={werte.gesellschaft} maxLength={150} />
</Feld>
<Feld id="art" beschriftung="Art" fehler={zustand.felder?.art} pflicht>
<Select name="art" defaultValue={werte.art}>
{VERTRAG_ARTEN.map((a) => (
<option key={a} value={a}>
{VERTRAG_ART_BESCHRIFTUNG[a as VertragArt]}
</option>
))}
</Select>
</Feld>
<Feld id="status" beschriftung="Status" fehler={zustand.felder?.status}>
<Select name="status" defaultValue={werte.status}>
{VERTRAG_STATUS.map((s) => (
<option key={s} value={s}>
{VERTRAG_STATUS_BESCHRIFTUNG[s]}
</option>
))}
</Select>
</Feld>
<Feld
id="vertragsnummer"
beschriftung="Vertragsnummer"
erklaerung="Wird verschlüsselt gespeichert. Ohne sie ordnet die Gesellschaft kein Schreiben zu."
fehler={zustand.felder?.vertragsnummer}
className="sm:col-span-2"
>
<Input name="vertragsnummer" defaultValue={werte.vertragsnummer} maxLength={80} />
</Feld>
</Feldgruppe>
<Feldgruppe
titel="Laufzeit und Kündigung"
beschreibung="Aus diesen Angaben rechnet die App den nächstmöglichen Kündigungstermin und den spätesten Absendetag."
>
<Feld id="beginnAm" beschriftung="Laufzeitbeginn" fehler={zustand.felder?.beginnAm}>
<Input name="beginnAm" type="date" defaultValue={werte.beginnAm} />
</Feld>
<Feld
id="endeAm"
beschriftung="Vereinbartes Ende"
erklaerung="Nur bei fester Ablaufzeit, z. B. einer Kapitallebensversicherung. Steht hier ein Datum, ergibt sich daraus zugleich die Laufzeit, um die sich der Vertrag verlängert — sonst wird mit einem Jahr gerechnet."
fehler={zustand.felder?.endeAm}
>
<Input name="endeAm" type="date" defaultValue={werte.endeAm} />
</Feld>
<Feld
id="kuendigungsfristMonate"
beschriftung="Kündigungsfrist in Monaten"
erklaerung="Wie lange vor dem Ende muss die Kündigung zugehen? Bei Versicherungen meist drei Monate."
fehler={zustand.felder?.kuendigungsfristMonate}
>
<Input
name="kuendigungsfristMonate"
inputMode="numeric"
defaultValue={werte.kuendigungsfristMonate}
/>
</Feld>
<Feld
id="kuendigungZum"
beschriftung="Gekündigt zum"
fehler={zustand.felder?.kuendigungZum}
>
<Input name="kuendigungZum" type="date" defaultValue={werte.kuendigungZum} />
</Feld>
<Feld id="gekuendigtAm" beschriftung="Kündigung versandt am" fehler={zustand.felder?.gekuendigtAm}>
<Input name="gekuendigtAm" type="date" defaultValue={werte.gekuendigtAm} />
</Feld>
</Feldgruppe>
<Feldgruppe titel="Beitrag" beschreibung="Grundlage für den Jahresbeitrag in der Übersicht.">
<Feld id="beitrag" beschriftung="Beitrag" fehler={zustand.felder?.beitrag}>
<Input name="beitrag" inputMode="decimal" defaultValue={werte.beitrag} placeholder="25,40" />
</Feld>
<Feld id="rhythmus" beschriftung="Rhythmus" fehler={zustand.felder?.rhythmus}>
<Select name="rhythmus" defaultValue={werte.rhythmus}>
<option value="">— nicht angegeben —</option>
{ZAHL_RHYTHMEN.map((r) => (
<option key={r} value={r}>
{RHYTHMUS_BESCHRIFTUNG[r]}
</option>
))}
</Select>
</Feld>
</Feldgruppe>
<Feldgruppe
titel="Bewertung fürs Sozialamt"
beschreibung="Deine Einordnung und deine Argumentation — keine Rechtsauskunft."
>
<Feld
id="bewertungSozialhilfe"
beschriftung="Einordnung"
erklaerung={BEWERTUNG_ERKLAERUNG[bewertung as SozialhilfeBewertung]}
fehler={zustand.felder?.bewertungSozialhilfe}
>
<Select
name="bewertungSozialhilfe"
value={bewertung}
onChange={(e) => setBewertung(e.target.value)}
>
{BEWERTUNGEN.map((b) => (
<option key={b} value={b}>
{BEWERTUNG_BESCHRIFTUNG[b]}
</option>
))}
</Select>
</Feld>
<Feld
id="bewertungBegruendung"
beschriftung="Begründung"
erklaerung="Wird verschlüsselt gespeichert. Diese Zeilen stehen im Zweifel Jahre später im Widerspruchsverfahren."
fehler={zustand.felder?.bewertungBegruendung}
pflicht={bewertung !== 'UNGEPRUEFT'}
className="sm:col-span-2"
>
<Textarea
name="bewertungBegruendung"
defaultValue={werte.bewertungBegruendung}
rows={4}
maxLength={4000}
/>
</Feld>
</Feldgruppe>
<Feld
id="notizen"
beschriftung="Notizen"
erklaerung="Wird verschlüsselt gespeichert."
fehler={zustand.felder?.notizen}
>
<Textarea name="notizen" defaultValue={werte.notizen} rows={4} maxLength={4000} />
</Feld>
<Rechtshinweis rechtsgrundlage="§ 90 Abs. 3 SGB XII" kurz />
<Absendeknopf>{istNeu ? 'Vertrag anlegen' : 'Änderungen speichern'}</Absendeknopf>
</form>
)
}