// Desktop Mietvorgänge — master list + detail pane + new/edit dialog. // ── Blocked-customer helpers ── // Match by name OR phone OR email (any normalized match counts as the same person). function _normKey(s) { return (s || '').toString().trim().toLowerCase().replace(/\s+/g, ' '); } function _normPhone(s) { return (s || '').toString().replace(/[^\d+]/g, ''); } function findBlockEntry(name, phone, email, blocked) { if (!blocked || !blocked.length) return null; const nk = _normKey(name), pk = _normPhone(phone), ek = _normKey(email); return blocked.find((b) => (nk && _normKey(b.name) === nk) || (pk && pk.length >= 4 && _normPhone(b.phone) === pk) || (ek && _normKey(b.email) === ek) ) || null; } window.findBlockEntry = findBlockEntry; // Reusable block toggle + reason editor used inside the rental dialog. function BlockToggleCard({ form, blocked, setBlocked }) { const t = useTheme(); const trimmed = (form.tenantName || '').trim(); const be = trimmed ? findBlockEntry(form.tenantName, form.phone, form.email, blocked) : null; const isBlocked = !!be; const [reasonDraft, setReasonDraft] = useState(null); // Reset draft when the entry identity changes (different customer / unblocked). useEffect(() => { setReasonDraft(null); }, [be ? be.id : null]); const currentReason = reasonDraft != null ? reasonDraft : (be && be.reason) || ''; const toggle = () => { if (!setBlocked || !trimmed) return; if (isBlocked) { setBlocked((prev) => prev.filter((b) => b.id !== be.id)); setReasonDraft(null); } else { const entry = { id: 'bl-' + Date.now(), name: trimmed, phone: form.phone || '', email: form.email || '', reason: (reasonDraft || '').trim(), blockedAt: todayISO() }; setBlocked((prev) => [entry, ...prev]); } }; const saveReason = () => { if (!isBlocked || reasonDraft == null) return; const newReason = reasonDraft.trim(); setBlocked((prev) => prev.map((b) => b.id === be.id ? { ...b, reason: newReason } : b)); setReasonDraft(null); }; const dirty = isBlocked && reasonDraft != null && reasonDraft !== (be.reason || ''); return ( <>