import { memo, useCallback, useMemo, useState } from 'react' import { Alert, Box, Button, Chip, Divider, TextField, Typography } from '@mui/material' import { Building2, CheckCircle2, Copy, MapPin, Ruler } from 'lucide-react' import type { MarktHinweis } from '../../domain/marktHinweis' import type { Property } from '../../domain/property' import { useProperties } from '../../hooks/useProperties' import { ASSET_TYPE_LABELS } from '../../lib/constants' import { areaFitPct } from '../market-leads' import { OWN_VERWALTUNG_ID, QUELLE_LABELS, buildAnschreiben, formatDate } from './hinweisHelpers' import { DS_ACCENT, DS_NEUTRAL, DS_SLATE } from '../../lib/ds' /** * Der Netzwerk-Bereich der Nora-Seite: menschlich erfasste Marktinformationen. * * Ausgezogen aus `MarketIntelligence.tsx`, die mit über 1100 Zeilen zwei * eigenständige Funktionsbereiche in einer Datei führte — bei einem harten * Limit von 300 Zeilen je Seite. */ // ── Netzwerk: HinweisPropertyCard ──────────────────────────────────────────── const HinweisPropertyCard = memo(function HinweisPropertyCard({ p, hinweis, }: { p: Property hinweis: MarktHinweis }) { const [open, setOpen] = useState(false) const [copied, setCopied] = useState(false) const companyName = hinweis.isAnonymized ? 'Interessent' : (hinweis.companyName ?? 'Interessent') const areaEstimate = hinweis.areaSqmMax ?? hinweis.areaSqmMin const [draft, setDraft] = useState(() => buildAnschreiben(companyName, hinweis.locationHint, p, areaEstimate) ) const fit = areaEstimate != null ? areaFitPct(p.areaSqm, areaEstimate) : null const handleCopy = useCallback(() => { navigator.clipboard.writeText(draft) setCopied(true) setTimeout(() => setCopied(false), 2000) }, [draft]) return ( {/* Property header */} {p.title} {p.location.city} · {p.areaSqm.toLocaleString('de-CH')} m² · CHF {p.rentPricePerSqm}/m²/J {fit !== null && ( = 75 ? '#dcfce7' : fit >= 50 ? '#fef9c3' : '#fee2e2', color: fit >= 75 ? '#16a34a' : fit >= 50 ? '#92400e' : '#dc2626', }} /> )} {/* Anschreiben toggle */} {/* Anschreiben composer */} {open && ( Anschreiben-Entwurf setDraft(e.target.value)} sx={{ '& .MuiOutlinedInput-root': { fontSize: '0.8rem', bgcolor: 'white' }, '& textarea': { lineHeight: 1.6 }, }} /> Text bearbeitbar — dann kopieren und per E-Mail versenden )} ) }) // ── Netzwerk: HinweisDetail ────────────────────────────────────────────────── function HinweisDetail({ hinweis }: { hinweis: MarktHinweis }) { const { data: properties = [] } = useProperties() const matchingProperties = useMemo( () => properties.filter(p => p.assetType === hinweis.assetType).slice(0, 3), [properties, hinweis.assetType], ) const displayName = !hinweis.isAnonymized && hinweis.companyName ? hinweis.companyName : 'Anonym' const areaStr = useMemo(() => { if (hinweis.areaSqmMin != null && hinweis.areaSqmMax != null && hinweis.areaSqmMin !== hinweis.areaSqmMax) { return `${hinweis.areaSqmMin}–${hinweis.areaSqmMax} m²` } if (hinweis.areaSqmMax != null) return `${hinweis.areaSqmMax} m²` if (hinweis.areaSqmMin != null) return `${hinweis.areaSqmMin} m²` return null }, [hinweis.areaSqmMin, hinweis.areaSqmMax]) return ( {/* Header */} {displayName} {/* Badge row */} {hinweis.direction === 'SUCHE' ? : } {hinweis.visibility === 'INTERN' ? : hinweis.verwaltungId === OWN_VERWALTUNG_ID ? : } {/* Stat chips */} } label={hinweis.locationHint} size="small" sx={{ bgcolor: DS_SLATE[100], color: DS_SLATE[600], fontSize: '0.75rem' }} /> {areaStr && } label={areaStr} size="small" sx={{ bgcolor: DS_SLATE[100], color: DS_SLATE[600], fontSize: '0.75rem' }} />} {/* Quelle row */} Quelle: {QUELLE_LABELS[hinweis.quelle] ?? hinweis.quelle} {' · '}{hinweis.createdBy} {' · '}{formatDate(hinweis.createdAt)} {/* Body */} {hinweis.note && ( Notiz {hinweis.note} )} {hinweis.direction === 'SUCHE' ? ( Passende Objekte im Portfolio ({matchingProperties.length}) {matchingProperties.length === 0 ? ( Kein passendes Portfolioobjekt gefunden ) : ( matchingProperties.map(p => ( )) )} ) : ( Verfügbarkeitssignal — wird auf der Plattform für andere Verwaltungen sichtbar gemacht )} ) } export { HinweisPropertyCard, HinweisDetail }