feat: unit-first architecture — floor + street as primary card title
Every VERIFIED_PORTFOLIO property now has explicit units in mock data (added to prop-002, prop-008, prop-009, prop-010, prop-011, prop-014). PropertyUnit extracted to domain/unit.ts with formatFloorLabel, formatUnitTitle, formatMultiUnitFloors helpers; re-exported from property.ts so all existing imports are unaffected. Cards now show floor + street as the primary title: - Specific unit match: "1.OG Nord · Zollstrasse 12" - Multi-unit (whole building): "1.OG–3.OG · Zollstrasse 12" - EG retail: "EG Verkauf · Löwenplatz 3" Building name (e.g. "Bürofläche Zollstrasse 12") appears as subtitle. Both IntelligenceMatchCard (grid) and MatchCardCompact (list) updated. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -392,39 +392,28 @@ export function IntelligenceMatchCard({ vm, imageUrl, lat, lng, cityLabel }: Pro
|
||||
|
||||
{/* ── Card body ── */}
|
||||
<Box sx={{ p: 2, flex: 1, display: 'flex', flexDirection: 'column', gap: 0 }}>
|
||||
{/* Unit-first title (floor + street) */}
|
||||
<Typography variant="subtitle1" sx={{ fontWeight: 700, lineHeight: 1.3 }} noWrap>
|
||||
{vm.title}
|
||||
</Typography>
|
||||
{/* Building name as subtitle when a unit or floor range is in the title */}
|
||||
{vm.propertySubtitle && (
|
||||
<Typography variant="caption" sx={{ display: 'block', mt: 0.125, color: '#475569', fontWeight: 500 }} noWrap>
|
||||
{vm.propertySubtitle}
|
||||
</Typography>
|
||||
)}
|
||||
<Typography variant="caption" color="text.secondary" sx={{ display: 'block', mt: 0.25 }}>
|
||||
{[vm.locationLabel, vm.availabilityLabel].filter(Boolean).join(' · ')}
|
||||
</Typography>
|
||||
|
||||
{/* Specific named unit */}
|
||||
{vm.preMarketUnit?.unitLabel && (
|
||||
<Box sx={{ display: 'flex', alignItems: 'center', gap: 0.75, mt: 0.5 }}>
|
||||
<Chip
|
||||
size="small"
|
||||
label={`${floorLabel(vm.preMarketUnit.floorLevel)} · ${vm.preMarketUnit.unitLabel}`}
|
||||
sx={{ height: 18, fontSize: '0.62rem', bgcolor: '#f1f5f9', color: '#374151', border: '1px solid #e2e8f0' }}
|
||||
/>
|
||||
<Typography variant="caption" sx={{ color: '#64748b', fontSize: '0.68rem' }}>
|
||||
{vm.preMarketUnit.areaSqm.toLocaleString('de-CH')} m²
|
||||
</Typography>
|
||||
</Box>
|
||||
)}
|
||||
|
||||
{/* Multi-unit property: no specific unit matched — show aggregate summary */}
|
||||
{!vm.preMarketUnit && (vm.preMarketAllUnits?.length ?? 0) > 1 && (
|
||||
<Box sx={{ display: 'flex', alignItems: 'center', gap: 0.75, mt: 0.5 }}>
|
||||
<Chip
|
||||
size="small"
|
||||
label={`${vm.preMarketAllUnits!.length} Einheiten`}
|
||||
sx={{ height: 18, fontSize: '0.62rem', bgcolor: '#eff6ff', color: '#1e40af', border: '1px solid #bfdbfe' }}
|
||||
/>
|
||||
<Typography variant="caption" sx={{ color: '#64748b', fontSize: '0.68rem' }}>
|
||||
total {vm.preMarketAllUnits!.reduce((s, u) => s + u.areaSqm, 0).toLocaleString('de-CH')} m²
|
||||
</Typography>
|
||||
</Box>
|
||||
{/* Unit area + rent when a specific unit is matched */}
|
||||
{vm.preMarketUnit && (
|
||||
<Typography variant="caption" sx={{ color: '#64748b', fontSize: '0.68rem', mt: 0.25 }}>
|
||||
{vm.preMarketUnit.areaSqm.toLocaleString('de-CH')} m²
|
||||
{vm.preMarketUnit.rentPricePerSqm
|
||||
? ` · CHF ${Math.round(vm.preMarketUnit.rentPricePerSqm / 12).toLocaleString('de-CH')}/m²/Mt.`
|
||||
: ''}
|
||||
</Typography>
|
||||
)}
|
||||
|
||||
{/* Regular explainability summary */}
|
||||
|
||||
Reference in New Issue
Block a user