27c53f3af1
- Single scoring system: MockupNeedProvider rewrites matches via calculateScore exclusively — allFactors always populated, no more dual-system (computeScore removed), weights from weightingProfile reflected in every breakdown - ScoreInlineBreakdown: new component shows hard/soft criteria with importance labels (Entscheidend/Sehr wichtig/…) and formula on compact + expanded cards - MatchCardAdapter: passes scoreBreakdown + allFactors to ViewModel - MatchDetail: 'Zukunftssignal' label replaced with 'Future Availability' - aiService budget parser: values < 100 treated as monthly and multiplied by 12 to produce correct annual CHF/m²/year value — fixes 0-result searches Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
120 lines
3.6 KiB
TypeScript
120 lines
3.6 KiB
TypeScript
import { Alert, Box, Card, Divider, Typography } from '@mui/material'
|
|
import { MapPin } from 'lucide-react'
|
|
import { MatchCardHeader } from './MatchCardHeader'
|
|
import { MatchReasonList } from './MatchReasonList'
|
|
import { TradeoffList } from './TradeoffList'
|
|
import { MatchDataQualitySummary } from './MatchDataQualitySummary'
|
|
import { MatchActionToolbar } from './MatchActionToolbar'
|
|
import { MatchCardRestrictedState } from './MatchCardRestrictedState'
|
|
import { ScoreInlineBreakdown } from './ScoreInlineBreakdown'
|
|
import type { MatchCardViewModel } from './MatchCardViewModel'
|
|
|
|
interface Props {
|
|
vm: MatchCardViewModel
|
|
}
|
|
|
|
export function MatchCardCompact({ vm }: Props) {
|
|
if (vm.isRestricted) return <MatchCardRestrictedState />
|
|
|
|
const borderColor = vm.isCompareSelected
|
|
? '#7c3aed'
|
|
: vm.isSelected
|
|
? '#1e3a5f'
|
|
: 'transparent'
|
|
|
|
return (
|
|
<Card
|
|
sx={{
|
|
p: 2.5,
|
|
mb: 1.5,
|
|
border: `2px solid ${borderColor}`,
|
|
opacity: vm.isStaleData ? 0.75 : 1,
|
|
transition: 'border-color 0.15s',
|
|
}}
|
|
>
|
|
{/* FUTURE_AVAILABILITY disclaimer — mandatory, non-dismissable */}
|
|
{vm.disclaimer && (
|
|
<Alert severity="warning" sx={{ mb: 1.5, py: 0.5 }}>
|
|
{vm.disclaimer}
|
|
</Alert>
|
|
)}
|
|
|
|
{vm.isReviewRequired && (
|
|
<Alert severity="info" sx={{ mb: 1.5, py: 0.5 }}>
|
|
Manuelle Überprüfung erforderlich
|
|
</Alert>
|
|
)}
|
|
|
|
{/* Header: score → type → confidence → availability → risk */}
|
|
<MatchCardHeader vm={vm} compact />
|
|
|
|
{/* Title + location (max 2 lines) */}
|
|
<Box sx={{ mt: 1.25, mb: 1.25 }}>
|
|
<Typography variant="subtitle1" sx={{ fontWeight: 600 }} noWrap>
|
|
{vm.title}
|
|
</Typography>
|
|
{vm.propertySubtitle && (
|
|
<Typography variant="caption" sx={{ display: 'block', color: '#64748b', fontWeight: 500, mt: 0.125 }} noWrap>
|
|
{vm.propertySubtitle}
|
|
</Typography>
|
|
)}
|
|
<Box sx={{ display: 'flex', alignItems: 'center', gap: 0.5, mt: 0.25 }}>
|
|
<MapPin size={13} color="#64748b" />
|
|
<Typography variant="body2" color="text.secondary">
|
|
{vm.locationLabel}
|
|
</Typography>
|
|
</Box>
|
|
{vm.explainabilitySummary && (
|
|
<Typography
|
|
variant="body2"
|
|
color="text.secondary"
|
|
sx={{
|
|
mt: 0.5,
|
|
overflow: 'hidden',
|
|
display: '-webkit-box',
|
|
WebkitLineClamp: 2,
|
|
WebkitBoxOrient: 'vertical',
|
|
}}
|
|
>
|
|
{vm.explainabilitySummary}
|
|
</Typography>
|
|
)}
|
|
</Box>
|
|
|
|
<Divider sx={{ mb: 1.25 }} />
|
|
|
|
{/* Score formula — always visible */}
|
|
{vm.scoreBreakdown && (
|
|
<Box sx={{ mb: 1.25 }}>
|
|
<ScoreInlineBreakdown scoreBreakdown={vm.scoreBreakdown} allFactors={vm.allFactors} compact />
|
|
</Box>
|
|
)}
|
|
|
|
{/* Top reason only */}
|
|
{vm.reasons.length > 0 && (
|
|
<Box sx={{ mb: 1 }}>
|
|
<MatchReasonList reasons={vm.reasons.slice(0, 1)} />
|
|
</Box>
|
|
)}
|
|
|
|
{/* Top tradeoff only (compact) */}
|
|
{vm.tradeoffs.length > 0 && (
|
|
<Box sx={{ mb: 1 }}>
|
|
<TradeoffList tradeoffs={vm.tradeoffs.slice(0, 1)} compact />
|
|
</Box>
|
|
)}
|
|
|
|
{/* Data quality — only critical warning in compact mode */}
|
|
<MatchDataQualitySummary
|
|
dataQualityScore={vm.dataQualityScore}
|
|
missingData={vm.missingData}
|
|
compact
|
|
/>
|
|
|
|
<Box sx={{ mt: 1.25 }}>
|
|
<MatchActionToolbar actions={vm.actions} compact />
|
|
</Box>
|
|
</Card>
|
|
)
|
|
}
|