// screens-detail.jsx — Listing detail + AI evaluation full screen function mobileRentalPersonalizationEnabled(user) { const value = user?.rental_profile?.personalized_inquiry_enabled; return !(value === false || value === 'false' || value === 0 || value === '0'); } // ─── LISTING DETAIL ──────────────────────────────────────────────────── function ListingDetailScreen({ ctx, id, publicMode = false }) { const { listings = [], evaluations = {}, navigate = () => {}, back = () => { window.location.href = '/'; }, favs = new Set(), toggleFav = () => {}, contactAd = async () => {}, toggleSharing = () => {}, evaluateAd = () => {}, scrapeAdDetails = () => {}, inquiryPreview = null, busy = false, } = ctx; const idKey = String(id ?? ''); const investorItems = [ ...(ctx.investor?.evaluations || []), ...(ctx.investor?.compare?.items || []), ...(ctx.portfolioAnalytics?.items || []), ]; const investorItem = investorItems.find(item => { const li = item?.listing || {}; return String(item?.adId ?? '') === idKey || String(item?.id ?? '') === idKey || String(li.id ?? '') === idKey || String(li.adId ?? '') === idKey; }); const l = listings.find(x => String(x.id) === idKey || String(x.adId) === idKey) || investorItem?.listing; const eval_ = evaluations[idKey] || evaluations[id] || window.AI_EVALS?.[idKey] || window.AI_EVALS?.[id] || investorItem?.evaluation; const [shared, setShared] = React.useState(!!l?.sharingEnabled); const [shareUrl, setShareUrl] = React.useState(l?.shareUrl || null); const [shareOpen, setShareOpen] = React.useState(false); const [contactOpen, setContactOpen] = React.useState(false); const isKauf = l?.type === 'kauf'; const personalizedInquiryEnabled = !isKauf && mobileRentalPersonalizationEnabled(ctx.user); const messageKey = `immobot.mobile.contactMessage.${isKauf ? 'purchase' : 'rental'}`; const cachedInquiryMessage = (!isKauf && personalizedInquiryEnabled) ? (l?.rentalInquiryMessage || '') : ''; const standardMessage = isKauf ? 'Sehr geehrte Damen und Herren,\n\nich habe Interesse an dieser Immobilie und möchte gerne einen Besichtigungstermin vereinbaren.' : (ctx.user?.default_reply_message || 'Sehr geehrte Damen und Herren,\n\nich habe Interesse an dieser Mietwohnung und möchte gerne einen Besichtigungstermin vereinbaren.'); const defaultMessage = cachedInquiryMessage || standardMessage; const [message, setMessage] = React.useState(() => cachedInquiryMessage || (isKauf ? localStorage.getItem(messageKey) : null) || standardMessage); const [previewLoading, setPreviewLoading] = React.useState(false); const pricePerArea = l?.pricePerSqm ? `${Number(l.pricePerSqm).toLocaleString('de-DE')} €/m²` : (l?.area ? `${Math.round(l.price / l.area).toLocaleString('de-DE')} €/m²` : '€/m² nicht verfügbar'); React.useEffect(() => { if (!l) return; if (!isKauf && personalizedInquiryEnabled) return; localStorage.setItem(messageKey, message); }, [l, isKauf, personalizedInquiryEnabled, messageKey, message]); React.useEffect(() => { if (!contactOpen || isKauf || personalizedInquiryEnabled) return; setPreviewLoading(false); setMessage(localStorage.getItem(messageKey) || defaultMessage); }, [contactOpen, isKauf, personalizedInquiryEnabled, messageKey, defaultMessage]); React.useEffect(() => { setShared(!!l?.sharingEnabled); setShareUrl(l?.shareUrl || null); }, [l?.id, l?.sharingEnabled, l?.shareUrl]); React.useEffect(() => { if (!contactOpen || !l || isKauf || !personalizedInquiryEnabled || !inquiryPreview) return undefined; if (cachedInquiryMessage) { setMessage(cachedInquiryMessage); setPreviewLoading(false); return undefined; } let active = true; setMessage(''); setPreviewLoading(true); inquiryPreview(l.task_id, l.adId || l.id) .then(result => { if (active && result?.message) setMessage(result.message); }) .catch(() => { if (active) setMessage(defaultMessage); }) .finally(() => { if (active) setPreviewLoading(false); }); return () => { active = false; }; }, [contactOpen, l?.task_id, l?.adId, l?.id, isKauf, personalizedInquiryEnabled, inquiryPreview, defaultMessage, cachedInquiryMessage]); if (!l) return
Nicht gefunden
; const isFav = !publicMode && favs.has(l.id); const shareDataFor = (url) => ({ title: l.title || 'ImmoBot Anzeige', text: `Schau dir diese Immobilie an: ${l.title || 'ImmoBot Anzeige'}`, url, }); const copyShareLink = async (url) => { if (!url) return; try { await navigator.clipboard?.writeText(url); alert('Share-Link wurde kopiert.'); } catch (error) { const input = document.createElement('textarea'); input.value = url; input.style.position = 'fixed'; input.style.left = '-9999px'; document.body.appendChild(input); input.focus(); input.select(); document.execCommand('copy'); document.body.removeChild(input); alert('Share-Link wurde kopiert.'); } }; const openInquirySettings = () => { sessionStorage.setItem('immobotScrollInquiryProfile', '1'); setContactOpen(false); navigate('profile'); }; const openContactSheet = () => { if (!isKauf && personalizedInquiryEnabled && cachedInquiryMessage) { setMessage(cachedInquiryMessage); setPreviewLoading(false); } else if (!isKauf && personalizedInquiryEnabled && inquiryPreview) { setMessage(''); setPreviewLoading(true); } else { setPreviewLoading(false); } setContactOpen(true); }; const nativeShare = async (url) => { if (!url || !navigator.share) return false; await navigator.share(shareDataFor(url)); return true; }; const ensureShareUrl = async () => { if (shareUrl || l.shareUrl) return shareUrl || l.shareUrl; const result = await toggleSharing(l.task_id, l.adId || l.id); const url = result.share_url || l.shareUrl || shareUrl; setShared(!!result.sharing_enabled); setShareUrl(url); return url; }; const shareListing = async () => { try { const alreadyShareable = !!(shareUrl || l.shareUrl); const url = await ensureShareUrl(); if (!url) return; if (alreadyShareable) { try { if (await nativeShare(url)) return; } catch (error) { if (error?.name === 'AbortError') return; } } setShareOpen(true); } catch (error) { const url = shareUrl || l.shareUrl; if (url) setShareOpen(true); } }; const generatingText = previewLoading && personalizedInquiryEnabled && !isKauf; return (
{/* Photo gallery with overlay back */}
{/* Back / fav buttons */}
{!publicMode &&
}
{/* Body */}
{l.provisionsfrei && Provisionsfrei} {fmtRelative(l.posted)}

{l.title}

{l.address}, {l.plz} {l.city} · {l.district}
{/* Price block */}
{isKauf ? 'Kaufpreis' : 'Warmmiete / Monat'}
{fmtPrice(l.price)}
{isKauf ? pricePerArea : `inkl. ${l.nebenkosten} € NK · kalt ${l.kaltmiete} €` }
{l.aiScore !== null && l.aiScore !== undefined && }
{/* Specs grid */}
} label="Wohnfläche" value={fmtArea(l.area)} /> } label="Zimmer" value={`${l.rooms} Zi.`} /> } label="Baujahr" value={l.baujahr} /> } label="Energie" value={`Klasse ${l.energieklasse}`} /> {isKauf && l.nebenkosten && } label="Hausgeld" value={`${l.nebenkosten} €/Mt.`} />} {!isKauf && } label="Kaltmiete" value={`${l.kaltmiete} €`} />} } label="Etage" value={l.floor} />
{/* AI evaluation card (if available) */} {eval_ && (
!publicMode && navigate('aiEval', { id: l.id })} style={{ marginTop: 20, padding: 16, borderRadius: 16, cursor: publicMode ? 'default' : 'pointer', background: 'linear-gradient(135deg, var(--primary-soft) 0%, #FCEEDE 100%)', border: '1px solid var(--primary-soft)', display: 'flex', alignItems: 'center', gap: 14, }} >
KI-Bewertung
{eval_.recommendation} · Note {eval_.grade}
{eval_.summary}
{!publicMode && }
)} {isKauf && !eval_ && !publicMode && (
Noch nicht bewertet
KI-Analyse jetzt starten
)} {/* Description */}
Beschreibung

{l.description}

{/* Features */}
Ausstattung
{l.features.map(f => ( {f} ))}
{/* Source */}
Quelle
{l.sourceUrl}
{/* Footer CTA */} {!publicMode &&
{eval_ && ( )}
} {!publicMode && setShareOpen(false)} title="Anzeige teilen" height="46%">

Diese Anzeige ist jetzt öffentlich teilbar. Sende den Link direkt an Freunde oder kopiere ihn.

{navigator.share && } Per WhatsApp teilen Per Telegram teilen
} {!publicMode && setContactOpen(false)} title="Anbieter kontaktieren" height="58%">
Die Nachricht wird kopiert. Der Versand erfolgt bewusst auf der Quellplattform.
{}} />