/* Powermieter — Vertrags-Lifecycle: Fristen & Kündigung · Mieterwechsel · Automatisierung */ const { useState: useLcS } = React; /* ---- Status für Lifecycle ---- */ const LC_STATUS = { aktiv: { label: 'Aktiv', tone: 'positive', dot: 'var(--positive-500)' }, verlaengert: { label: 'Verlängert', tone: 'positive', dot: 'var(--positive)' }, auslaufend: { label: 'Läuft bald aus', tone: 'warn', dot: 'var(--warn-500)' }, gekuendigt: { label: 'Gekündigt', tone: 'gray', dot: 'var(--text-3)' }, wechsel: { label: 'In Mieterwechsel', tone: 'accent', dot: 'var(--accent)' }, }; function LcBadge({ s }) { const st = LC_STATUS[s] || LC_STATUS.aktiv; return {st.label}; } /* ---- Vertragsfristen (Mock) ---- */ const LC_CONTRACTS = [ { whg: 'W01', name: 'Anna Berger', modell: 'Mieterstrom', start: '01.06.2024', laufzeit: '24 Mon.', ende: '31.05.2026', frist: '3 Mon.', auto: true, status: 'verlaengert', tageBis: 320 }, { whg: 'W02', name: 'Familie Çelik', modell: 'Mieterstrom', start: '01.07.2024', laufzeit: '24 Mon.', ende: '30.06.2026', frist: '3 Mon.', auto: true, status: 'aktiv', tageBis: 371 }, { whg: 'W04', name: 'Max Mustermann', modell: 'Mieterstrom', start: '15.07.2024', laufzeit: '12 Mon.', ende: '14.07.2026', frist: '6 Wochen', auto: false, status: 'auslaufend', tageBis: 20 }, { whg: 'W07', name: 'Hr. & Fr. Yılmaz',modell: 'gGV', start: '01.05.2024', laufzeit: '24 Mon.', ende: '30.04.2026', frist: '3 Mon.', auto: true, status: 'aktiv', tageBis: 310 }, { whg: 'W08', name: 'Clara Hoffmann', modell: 'Mieterstrom', start: '20.05.2024', laufzeit: '12 Mon.', ende: '19.05.2026', frist: '6 Wochen', auto: false, status: 'auslaufend', tageBis: 45 }, { whg: 'W09', name: 'Jonas Krüger', modell: 'Mieterstrom', start: '10.08.2024', laufzeit: '24 Mon.', ende: '09.08.2026', frist: '3 Mon.', auto: true, status: 'wechsel', tageBis: 410 }, { whg: 'W11', name: 'Mara Schulz', modell: 'gGV', start: '01.03.2024', laufzeit: '12 Mon.', ende: '28.02.2026', frist: '6 Wochen', auto: false, status: 'gekuendigt', tageBis: -60 }, ]; function FristenView() { const auslaufend = LC_CONTRACTS.filter(c => c.status === 'auslaufend').length; const autoRenew = LC_CONTRACTS.filter(c => c.auto).length; const gekuendigt = LC_CONTRACTS.filter(c => c.status === 'gekuendigt').length; const radar = [...LC_CONTRACTS].filter(c => c.tageBis >= 0 && c.tageBis < 120).sort((a, b) => a.tageBis - b.tageBis); return (
} value={LC_CONTRACTS.length} label="Laufende Verträge" sub="im Objekt" /> } value={auslaufend} label="Laufen bald aus" tone={auslaufend ? 'warn' : 'positive'} sub="innerhalb der Frist" /> } value={autoRenew} label="Auto-Verlängerung" tone="accent" sub="aktiv geschaltet" /> } value={gekuendigt} label="Gekündigt" sub="in Abwicklung" />
{/* Fristen-Radar */}

Fristen-Radar · nächste 120 Tage

{radar.map(c => { const urgent = c.tageBis <= 30; return (
{c.tageBis}
Tage
{c.whg} · {c.name} — Vertragsende {c.ende} · Kündigungsfrist {c.frist}
{c.auto ? verlängert autom. : }
); })}
{/* Vertragsfristen-Tabelle */}
Einheit
Modell
Laufzeit
Vertragsende
Kündigungsfrist
Verlängerung
Status
{LC_CONTRACTS.map(c => (
{c.whg}{c.name}
{c.modell}
{c.laufzeit}
{c.ende}
{c.frist}
{c.auto ? automatisch : manuell}
))}

Fristen, Laufzeiten & Kündigungen werden je Vertrag in contract_obligations geführt; jede Verlängerung erzeugt ein revisionssicheres contract_event mit eingefrorener Tarifversion.

); } /* ---- Mieterwechsel (Mock) ---- */ const WECHSEL_STEPS = ['Auszug gemeldet', 'Schlussabrechnung', 'Vertrag beendet', 'Nachmieter eingeladen', 'Nachmieter aktiv']; const WECHSEL_CASES = [ { whg: 'W09', alt: 'Jonas Krüger', neu: 'Pending — Einladung offen', auszug: '31.07.2026', stage: 1, modell: 'Mieterstrom' }, { whg: 'W03', alt: 'Tobias Wolf', neu: 'Elif Demir', auszug: '30.06.2026', stage: 3, modell: 'Mieterstrom' }, { whg: 'W05', alt: 'Sofia Russo', neu: 'Niklas Brandt', auszug: '15.06.2026', stage: 4, modell: 'gGV' }, ]; function MieterwechselView() { const [sel, setSel] = useLcS(WECHSEL_CASES[0]); return (
} value={WECHSEL_CASES.length} label="Aktive Wechsel" sub="in Bearbeitung" tone="accent" /> } value={1} label="Schlussabrechnung offen" tone="warn" sub="zu erstellen" /> } value={2} label="Nachmieter onboarding" sub="läuft" tone="positive" />
{/* Fall-Liste */}

Wechsel-Fälle

{WECHSEL_CASES.map(c => ( ))}
{/* Detail-Flow */}

Ablauf · {sel.whg}

{sel.modell}
Auszug
{sel.alt}
Nachmieter
{sel.neu}
{WECHSEL_STEPS.map((s, i) => { const state = i < sel.stage ? 'done' : i === sel.stage ? 'active' : 'todo'; return (
{state === 'done' ? : state === 'active' ? : i + 1} {i < WECHSEL_STEPS.length - 1 && }
{s}{state === 'active' && aktuell}
{[ 'Mieter meldet Auszugsdatum — Vertrag wird zur Beendigung vorgemerkt.', 'Verbrauch bis Auszug abgelesen, Schlussrechnung erzeugt & versendet.', 'Altvertrag beendet, Dokumente archiviert (contract_events).', 'Nachmieter erhält QR-Einladung ins Objekt-Onboarding.', 'Nachmieter hat unterzeichnet — Belieferung nahtlos übernommen.', ][i]}
); })}
); } /* ---- Automatisierung (Mock) ---- */ const AUTO_RULES_INIT = [ { id: 'gen', icon: 'spark', name: 'Auto-Vertragserzeugung bei Registrierung', desc: 'Erzeugt automatisch die passende Vertragsstrecke je Modell (§ 42a / § 42b), sobald sich ein Bewohner registriert.', on: true }, { id: 'renew', icon: 'refresh', name: 'Automatische Verlängerung', desc: 'Verträge ohne fristgerechte Kündigung 3 Monate vor Ablauf um die Laufzeit verlängern — mit eingefrorener Tarifversion.', on: true }, { id: 'remind', icon: 'calendar', name: 'Fristen-Erinnerung', desc: 'Hausverwaltung 90 / 60 / 30 Tage vor Vertragsende benachrichtigen.', on: true }, { id: 'final', icon: 'receipt', name: 'Auto-Schlussabrechnung bei Auszug', desc: 'Bei gemeldetem Auszug Verbrauch ablesen und Schlussrechnung automatisch erzeugen.', on: false }, { id: 'tariff', icon: 'bolt', name: 'Tarifwechsel zum Jahreswechsel', desc: 'Neue Tarifversion automatisch zum 01.01. anwenden und Bewohner informieren.', on: false }, ]; const AUTO_LOG = [ { t: 'Vertrag W12 automatisch erzeugt (Mieterstrom v2.1)', when: 'Heute · 08:14', icon: 'spark', good: true }, { t: 'Erinnerung an HV: 3 Verträge laufen in < 60 Tagen aus', when: 'Gestern · 06:00', icon: 'calendar' }, { t: 'Vertrag W01 automatisch um 24 Monate verlängert', when: '21.06. · 00:01', icon: 'refresh', good: true }, { t: 'Schlussabrechnung W05 — manuell ausgelöst (Regel inaktiv)', when: '18.06. · 14:32', icon: 'receipt', warn: true }, ]; function AutomationView() { const [rules, setRules] = useLcS(AUTO_RULES_INIT); const toggle = id => setRules(rs => rs.map(r => r.id === id ? { ...r, on: !r.on } : r)); const onCount = rules.filter(r => r.on).length; return (
Automatisierung aktiv
{onCount} von {rules.length} Regeln laufen. Powermieter erzeugt, verlängert und überwacht Verträge je Tarifmodell — die Hausverwaltung greift nur bei Ausnahmen ein.
{onCount}/{rules.length}
Regeln aktiv
{/* Regeln */}

Automatisierungs-Regeln

{rules.map(r => (
{(I[r.icon] || I.dot)({ size: 18 })}
{r.name}
{r.desc}
))}
{/* Aktivitäts-Log */}

Automatisierungs-Log

{AUTO_LOG.map((e, i) => (
{(I[e.icon] || I.dot)({ size: 13 })}
{e.t}
{e.when}
))}

Jede automatische Aktion ist im Audit-Log nachvollziehbar — wer/was/wann, inkl. genutzter Vertrags- und Tarifversion.

); } /* ---- Lifecycle-Container mit Tabs ---- */ function Lifecycle({ initialTab = 'fristen' }) { const [tab, setTab] = useLcS(initialTab); return (
{[['fristen', 'Fristen & Kündigung', I.calendar], ['wechsel', 'Mieterwechsel', I.users], ['auto', 'Automatisierung', I.spark]].map(([v, l, Ic]) => ( ))}
{tab === 'fristen' && } {tab === 'wechsel' && } {tab === 'auto' && }
); } Object.assign(window, { Lifecycle });