feat: Verwaltungszugang refactor — lease data, 3-tab detail, market signals

- Dashboard: remove QuickActionPanel, StrongMatchOverview, FutureSignalWidget,
  DataQualityWidget, header buttons, Marktchancen nav; KpiGrid → 4 cards
- Property domain: 9 new fields (leaseTerm, leaseStartDate/End, breakoutOption,
  currentTenant, importedFrom, importedAt, lastUpdatedAt)
- Mock data: annual CHF/m²/Jahr prices (×12), Swiss images, tenant/lease data
  for all 10 VERIFIED_PORTFOLIO properties; need budgets updated to annual
- PropertyTable: swap columns — add Aktueller Mieter, Mietlaufzeit,
  Breakoutoption, Breakoutoption Zeitpunkt; remove Verfügbarkeit, Konfidenz, Quelle
- PropertyDetailView: 3 tabs (Übersicht, Matchability, Marktsignale) with
  inline edit mode, NeedMatchCard list, PropertyMarketSignalsTab
- New: marketReport domain + mock data + service, NeedMatchCard,
  PropertyMarketSignalsTab with 4 sections + PDF button
- matchService: getNeedMatchesForProperty(propertyId, {minScore})

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Benjamin Sutter
2026-05-19 15:43:52 +02:00
parent 52a2693cad
commit 920ce8eb09
17 changed files with 1036 additions and 476 deletions
+5 -5
View File
@@ -25,10 +25,10 @@ const AREA_PRESETS = [
]
const BUDGET_PRESETS = [
{ label: '25 CHF/m²', value: 25 },
{ label: '45 CHF/m²', value: 45 },
{ label: '65 CHF/m²', value: 65 },
{ label: '100 CHF/m²', value: 100 },
{ label: '300 CHF/m²/J', value: 300 },
{ label: '420 CHF/m²/J', value: 420 },
{ label: '540 CHF/m²/J', value: 540 },
{ label: '780 CHF/m²/J', value: 780 },
]
const LOCATION_PRESETS = ['Zürich', 'Zürich-West', 'Zürich-Nord', 'Bern', 'Basel', 'Luzern']
@@ -163,7 +163,7 @@ export function NeedInput({ criteria: c, onCriteriaChange: set }: Props) {
<Box sx={{ mb: (c.preferredLocations?.filter(l => !LOCATION_PRESETS.includes(l)).length ?? 0) > 0 ? 0 : 2.5 }} />
{/* Budget */}
<FieldLabel>Budget (max CHF/m²)</FieldLabel>
<FieldLabel>Budget (max CHF/m²/Jahr)</FieldLabel>
<Stack direction="row" spacing={0.5} sx={{ flexWrap: 'wrap', gap: 0.5, mb: 0.75 }}>
{BUDGET_PRESETS.map(p => (
<Chip