feat: role-aware UX, market intelligence, score fix & layout scroll

- Role-based workspace access: Property Manager gets Supply+Demand,
  Operations restricted to Super Admin + Reviewer only
- Root redirect routes each persona to their first workspace
- Match Center: replaced 3-panel with auto-sorted flat list + drawer
- AI Search: unified form with dual-action (Jetzt suchen / Als Suchprofil speichern)
- CompareTray hidden on non-Demand routes; Vergleichen removed from Supply
- LocationIntelligencePanel: city KPIs, rent trends, soft factors, comparables
- NegotiationInsightsPanel: price positioning, active demand, selling arguments
- scoreCalculator: cap hardMatchScore and softFactorScore to max 100
- Layout: add display:flex to overflow:hidden wrappers so inner scroll works
  (MatchCenter drawer, MarketIntelligence, SourceMonitoring, SignalPipeline)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Benjamin Sutter
2026-05-17 00:58:10 +02:00
parent e13fe470fb
commit efc406ace9
37 changed files with 4871 additions and 459 deletions
+9 -7
View File
@@ -12,6 +12,7 @@ import {
Typography,
} from '@mui/material'
import { X, ExternalLink } from 'lucide-react'
import { NegotiationInsightsPanel } from './NegotiationInsightsPanel'
import type { Property } from '../../domain/property'
import type { Match } from '../../domain/match'
import type { FutureSignal } from '../../domain/futureSignal'
@@ -411,7 +412,7 @@ function SignalsPanel({ signals }: { signals: FutureSignal[] }) {
// ── Main component ────────────────────────────────────────────────────────────
const TABS = ['Übersicht', 'Hard Facts', 'Soft Factors', 'Matchability', 'Datenqualität', 'Quelle', 'Signale'] as const
const TABS = ['Übersicht', 'Verhandlung & Markt', 'Hard Facts', 'Soft Factors', 'Matchability', 'Datenqualität', 'Quelle', 'Signale'] as const
export function PropertyDetailView({ propertyId, onClose }: PropertyDetailViewProps) {
const [tab, setTab] = useState(0)
@@ -486,12 +487,13 @@ export function PropertyDetailView({ propertyId, onClose }: PropertyDetailViewPr
{/* Tab content */}
<Box sx={{ flex: 1, overflowY: 'auto', p: 2.5 }}>
{tab === 0 && <OverviewPanel p={property} />}
{tab === 1 && <HardFactsPanel p={property} />}
{tab === 2 && <SoftFactorsPanel p={property} />}
{tab === 3 && <MatchabilityPanel matches={matches} />}
{tab === 4 && <DataQualityPanel p={property} />}
{tab === 5 && <SourcePanel p={property} />}
{tab === 6 && <SignalsPanel signals={signals} />}
{tab === 1 && <NegotiationInsightsPanel property={property} />}
{tab === 2 && <HardFactsPanel p={property} />}
{tab === 3 && <SoftFactorsPanel p={property} />}
{tab === 4 && <MatchabilityPanel matches={matches} />}
{tab === 5 && <DataQualityPanel p={property} />}
{tab === 6 && <SourcePanel p={property} />}
{tab === 7 && <SignalsPanel signals={signals} />}
</Box>
</Box>
)