import { Box, Chip, Paper, Typography } from '@mui/material'
import { CheckCircle2, XCircle, Minus } from 'lucide-react'
import type { Match } from '../../domain/match'
import type { Property } from '../../domain/property'
import type { Need } from '../../domain/need'
type FitStatus = 'MATCH' | 'NO_MATCH' | 'PARTIAL' | 'UNKNOWN'
interface AlignmentRow {
label: string
needValue: string
resultValue: string
fit: FitStatus
}
function fitIcon(fit: FitStatus) {
if (fit === 'MATCH') return
if (fit === 'NO_MATCH') return
if (fit === 'PARTIAL') return
return
}
function fitColor(fit: FitStatus): string {
if (fit === 'MATCH') return '#f0fdf4'
if (fit === 'NO_MATCH') return '#fef2f2'
if (fit === 'PARTIAL') return '#fffbeb'
return '#f8fafc'
}
function buildRows(need: Need, property: Property): AlignmentRow[] {
const rows: AlignmentRow[] = []
// Area
const areaSqm = property.areaSqm
const areaFit: FitStatus = areaSqm >= need.requiredArea.min && areaSqm <= need.requiredArea.max
? 'MATCH'
: areaSqm >= need.requiredArea.min * 0.85
? 'PARTIAL'
: 'NO_MATCH'
rows.push({
label: 'Fläche',
needValue: `${need.requiredArea.min}–${need.requiredArea.max} m²`,
resultValue: `${areaSqm} m²`,
fit: areaFit,
})
// Location
const locationFit: FitStatus = need.preferredLocations.some(
l => l.toLowerCase() === property.location.city.toLowerCase() ||
l.toLowerCase() === property.location.district?.toLowerCase()
) ? 'MATCH' : 'PARTIAL'
rows.push({
label: 'Standort',
needValue: need.preferredLocations.join(', ') || '–',
resultValue: property.location.city,
fit: locationFit,
})
// Budget
const budgetFit: FitStatus = property.rentPricePerSqm <= need.budgetRange.maxPerSqm
? 'MATCH'
: property.rentPricePerSqm <= need.budgetRange.maxPerSqm * 1.1
? 'PARTIAL'
: 'NO_MATCH'
rows.push({
label: 'Budget',
needValue: `max. CHF ${need.budgetRange.maxPerSqm}/m²`,
resultValue: `CHF ${property.rentPricePerSqm}/m²`,
fit: budgetFit,
})
// Timing
const availDate = property.availabilityDate
const latestMoveIn = need.timing.latestMoveIn
const timingFit: FitStatus = !availDate ? 'UNKNOWN'
: availDate <= latestMoveIn ? 'MATCH' : 'PARTIAL'
rows.push({
label: 'Verfügbarkeit',
needValue: `bis ${need.timing.latestMoveIn}`,
resultValue: availDate || 'unbekannt',
fit: timingFit,
})
return rows
}
interface Props {
match: Match
need: Need | null
property: Property | null
}
export function NeedAlignmentPanel({ match: _match, need, property }: Props) {
if (!need || !property) return null
const rows = buildRows(need, property)
const mustHaves = need.mustHaveCriteria ?? []
return (
Need-Alignment
Gesucht: {need.companyName} · {need.assetType}
{/* Comparison table */}
Kriterium
Gesucht
Objekt
Fit
{rows.map((row, i) => (
{row.label}
{row.needValue}
{row.resultValue}
{fitIcon(row.fit)}
))}
{/* Must-haves */}
{mustHaves.length > 0 && (
Must-have Kriterien
{mustHaves.map((m, i) => (
))}
)}
)
}