f487435a94
- NeedAlignmentPanel: display budget row in monthly (CHF/m²/Mt.) to match the Preis section, use exact division (no Math.round) to avoid 13×12≠152 - MatchDetailPropertySections + PropertyDetailPublicSections: replace Math.round(rentPricePerSqm/12) with exact division; show 2 decimal places when monthly is not a whole number (e.g. CHF 12.67 instead of CHF 13) - Add /Jahr suffix to all 15 displays showing rentPricePerSqm or maxPerSqm without a time unit across results, compare, match-detail, supply, and anfragencenter components Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
68 lines
3.0 KiB
TypeScript
68 lines
3.0 KiB
TypeScript
import { Box, Chip, Paper, Typography } from '@mui/material'
|
||
import { Banknote, Calendar, MapPin, Maximize2, Tag } from 'lucide-react'
|
||
import type { Match } from '../../domain/match'
|
||
import type { Property } from '../../domain/property'
|
||
import type { FutureSignal } from '../../domain/futureSignal'
|
||
|
||
interface FactRowProps {
|
||
icon: React.ReactNode
|
||
label: string
|
||
value: string
|
||
}
|
||
|
||
function FactRow({ icon, label, value }: FactRowProps) {
|
||
return (
|
||
<Box sx={{ display: 'flex', alignItems: 'center', gap: 1.5, py: 1, borderBottom: '1px solid #f1f5f9' }}>
|
||
<Box sx={{ color: '#64748b', flexShrink: 0 }}>{icon}</Box>
|
||
<Typography variant="body2" color="text.secondary" sx={{ minWidth: 140 }}>{label}</Typography>
|
||
<Typography variant="body2" sx={{ fontWeight: 500 }}>{value}</Typography>
|
||
</Box>
|
||
)
|
||
}
|
||
|
||
interface Props {
|
||
match: Match
|
||
property: Property | null
|
||
signal: FutureSignal | null
|
||
}
|
||
|
||
export function PropertyOverviewPanel({ match, property, signal }: Props) {
|
||
if (!property && !signal) return null
|
||
|
||
const isFuture = match.resultType === 'FUTURE_AVAILABILITY'
|
||
|
||
const rows: FactRowProps[] = isFuture ? [
|
||
{ icon: <MapPin size={15} />, label: 'Standorthinweis', value: signal?.locationHint ?? '–' },
|
||
{ icon: <Maximize2 size={15} />, label: 'Flächenschätzung', value: signal?.areaSqmEstimate ? `~${signal.areaSqmEstimate} m²` : 'unbekannt' },
|
||
{ icon: <Calendar size={15} />, label: 'Zeithorizont', value: signal?.timeHorizonMonths ? `~${signal.timeHorizonMonths} Monate` : '–' },
|
||
{ icon: <Tag size={15} />, label: 'Wahrscheinlichkeit', value: signal?.probability ? `${Math.round(signal.probability * 100)}%` : '–' },
|
||
] : [
|
||
{ icon: <MapPin size={15} />, label: 'Standort', value: property ? `${property.location.city}${property.location.district ? `, ${property.location.district}` : ''}` : '–' },
|
||
{ icon: <Maximize2 size={15} />, label: 'Nutzfläche', value: property ? `${property.areaSqm} m²` : '–' },
|
||
{ icon: <Banknote size={15} />, label: 'Mietpreis', value: property?.rentPricePerSqm ? `CHF ${property.rentPricePerSqm}/m²/Jahr` : '–' },
|
||
{ icon: <Calendar size={15} />, label: 'Verfügbar ab', value: property?.availabilityDate ?? '–' },
|
||
{ icon: <Tag size={15} />, label: 'Objekttyp', value: property?.assetType ?? '–' },
|
||
]
|
||
|
||
return (
|
||
<Paper sx={{ p: 2.5, mb: 2 }}>
|
||
<Box sx={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', mb: 1.5 }}>
|
||
<Typography variant="h6" sx={{ fontWeight: 700 }}>
|
||
{isFuture ? 'Signal-Übersicht' : 'Objekt-Übersicht'}
|
||
</Typography>
|
||
{property?.status && (
|
||
<Chip label={property.status} size="small" variant="outlined" />
|
||
)}
|
||
</Box>
|
||
{rows.map((row, i) => (
|
||
<FactRow key={i} {...row} />
|
||
))}
|
||
{property?.description && (
|
||
<Typography variant="body2" color="text.secondary" sx={{ mt: 1.5, fontStyle: 'italic' }}>
|
||
{property.description}
|
||
</Typography>
|
||
)}
|
||
</Paper>
|
||
)
|
||
}
|