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:
@@ -19,10 +19,6 @@ import type { PropertyTableFilters } from './PropertyFilterBar'
|
||||
import {
|
||||
getAssetTypeColor,
|
||||
getAssetTypeLabel,
|
||||
getAvailabilityChipColor,
|
||||
getAvailabilityLabel,
|
||||
getResultTypeColor,
|
||||
getResultTypeLabel,
|
||||
qualityColor,
|
||||
} from './propertyHelpers'
|
||||
|
||||
@@ -38,8 +34,9 @@ interface PropertyTableProps {
|
||||
}
|
||||
|
||||
const COL_HEADERS = [
|
||||
'Objekt', 'Typ', 'Standort', 'Fläche', 'Miete/m²',
|
||||
'Verfügbarkeit', 'Konfidenz', 'Datenqualität', 'Quelle', 'Aktionen',
|
||||
'Objekt', 'Typ', 'Standort', 'Fläche', 'Miete CHF/m²/Jahr',
|
||||
'Aktueller Mieter', 'Mietlaufzeit', 'Breakoutoption', 'Breakoutoption Zeitpunkt',
|
||||
'Datenqualität', 'Aktionen',
|
||||
]
|
||||
|
||||
function LoadingRows() {
|
||||
@@ -108,11 +105,12 @@ export function PropertyTable({
|
||||
<TableCell><Typography variant="caption" sx={{ fontWeight: 600 }}>Typ</Typography></TableCell>
|
||||
<TableCell><Typography variant="caption" sx={{ fontWeight: 600 }}>Standort</Typography></TableCell>
|
||||
<TableCell><SortableHeader field="area" label="Fläche (m²)" /></TableCell>
|
||||
<TableCell><SortableHeader field="rent" label="Miete/m²" /></TableCell>
|
||||
<TableCell><SortableHeader field="availability" label="Verfügbarkeit" /></TableCell>
|
||||
<TableCell><SortableHeader field="confidence" label="Konfidenz" /></TableCell>
|
||||
<TableCell><SortableHeader field="rent" label="Miete CHF/m²/Jahr" /></TableCell>
|
||||
<TableCell><Typography variant="caption" sx={{ fontWeight: 600 }}>Aktueller Mieter</Typography></TableCell>
|
||||
<TableCell><Typography variant="caption" sx={{ fontWeight: 600 }}>Mietlaufzeit</Typography></TableCell>
|
||||
<TableCell><Typography variant="caption" sx={{ fontWeight: 600 }}>Breakoutoption</Typography></TableCell>
|
||||
<TableCell><Typography variant="caption" sx={{ fontWeight: 600 }}>Breakoutoption Zeitpunkt</Typography></TableCell>
|
||||
<TableCell><SortableHeader field="dataQuality" label="Datenqualität" /></TableCell>
|
||||
<TableCell><Typography variant="caption" sx={{ fontWeight: 600 }}>Quelle</Typography></TableCell>
|
||||
<TableCell><Typography variant="caption" sx={{ fontWeight: 600 }}>Aktionen</Typography></TableCell>
|
||||
</TableRow>
|
||||
</TableHead>
|
||||
@@ -121,7 +119,7 @@ export function PropertyTable({
|
||||
<LoadingRows />
|
||||
) : properties.length === 0 ? (
|
||||
<TableRow>
|
||||
<TableCell colSpan={10}>
|
||||
<TableCell colSpan={11}>
|
||||
<Typography variant="body2" sx={{ color: 'text.secondary', textAlign: 'center', py: 4 }}>
|
||||
Keine Objekte gefunden.
|
||||
</Typography>
|
||||
@@ -184,30 +182,47 @@ export function PropertyTable({
|
||||
{/* Miete */}
|
||||
<TableCell>
|
||||
<Typography variant="body2">
|
||||
{p.rentPricePerSqm > 0 ? `CHF ${p.rentPricePerSqm}` : <span style={{ color: '#94a3b8' }}>k.A.</span>}
|
||||
{p.rentPricePerSqm > 0 ? `CHF ${p.rentPricePerSqm.toLocaleString('de-CH')}` : <span style={{ color: '#94a3b8' }}>k.A.</span>}
|
||||
</Typography>
|
||||
</TableCell>
|
||||
|
||||
{/* Verfügbarkeit */}
|
||||
{/* Aktueller Mieter */}
|
||||
<TableCell>
|
||||
<Chip
|
||||
label={getAvailabilityLabel(p.availabilityStatus)}
|
||||
size="small"
|
||||
color={getAvailabilityChipColor(p.availabilityStatus)}
|
||||
variant="outlined"
|
||||
/>
|
||||
<Typography variant="body2" sx={{ whiteSpace: 'nowrap' }}>
|
||||
{p.currentTenant ?? <span style={{ color: '#94a3b8' }}>–</span>}
|
||||
</Typography>
|
||||
</TableCell>
|
||||
|
||||
{/* Konfidenz */}
|
||||
{/* Mietlaufzeit */}
|
||||
<TableCell>
|
||||
<Typography
|
||||
variant="body2"
|
||||
sx={{
|
||||
fontWeight: 600,
|
||||
color: p.confidenceScore >= 0.85 ? '#1a7a4a' : p.confidenceScore >= 0.65 ? '#1e3a5f' : '#d97706',
|
||||
}}
|
||||
>
|
||||
{Math.round(p.confidenceScore * 100)}%
|
||||
<Typography variant="body2">
|
||||
{p.leaseTerm ?? <span style={{ color: '#94a3b8' }}>–</span>}
|
||||
</Typography>
|
||||
</TableCell>
|
||||
|
||||
{/* Breakoutoption */}
|
||||
<TableCell>
|
||||
{p.breakoutOption == null
|
||||
? <Typography variant="body2" sx={{ color: '#94a3b8' }}>–</Typography>
|
||||
: <Chip
|
||||
label={p.breakoutOption ? 'Ja' : 'Nein'}
|
||||
size="small"
|
||||
sx={{
|
||||
bgcolor: p.breakoutOption ? '#dcfce7' : '#f1f5f9',
|
||||
color: p.breakoutOption ? '#166534' : '#64748b',
|
||||
fontSize: '0.68rem',
|
||||
}}
|
||||
/>
|
||||
}
|
||||
</TableCell>
|
||||
|
||||
{/* Breakoutoption Zeitpunkt */}
|
||||
<TableCell>
|
||||
<Typography variant="body2">
|
||||
{p.breakoutOptionDate
|
||||
? new Date(p.breakoutOptionDate).toLocaleDateString('de-CH')
|
||||
: <span style={{ color: '#94a3b8' }}>–</span>
|
||||
}
|
||||
</Typography>
|
||||
</TableCell>
|
||||
|
||||
@@ -231,15 +246,6 @@ export function PropertyTable({
|
||||
</Tooltip>
|
||||
</TableCell>
|
||||
|
||||
{/* Quelle */}
|
||||
<TableCell>
|
||||
<Chip
|
||||
label={getResultTypeLabel(p.resultType)}
|
||||
size="small"
|
||||
sx={{ bgcolor: getResultTypeColor(p.resultType), color: 'white', fontSize: '0.68rem' }}
|
||||
/>
|
||||
</TableCell>
|
||||
|
||||
{/* Aktionen */}
|
||||
<TableCell onClick={e => e.stopPropagation()}>
|
||||
<Box sx={{ display: 'flex', gap: 0.25 }}>
|
||||
|
||||
Reference in New Issue
Block a user