fix: resolve all MUI v9 TypeScript build errors

- Move system props (fontWeight, lineHeight, display, alignItems, etc.) into sx
- Fix Lucide icon color prop (no sx support)
- Merge duplicate sx attributes
- Remove unused variables (location, _needId, v)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Benjamin Sutter
2026-05-15 10:37:07 +02:00
parent 67e4baf860
commit e20e0e9a2e
12 changed files with 164 additions and 183 deletions
+22 -28
View File
@@ -53,7 +53,7 @@ export default function AISearch() {
<Box>
{/* Page Header */}
<Box sx={{ bgcolor: 'white', borderBottom: '1px solid #e2e8f0', px: 3, py: 2 }}>
<Typography variant="h5" fontWeight={700} color="text.primary">
<Typography variant="h5" sx={{ fontWeight: 700 }} color="text.primary">
AI Bedarfsanalyse
</Typography>
<Typography variant="body2" color="text.secondary">
@@ -66,7 +66,7 @@ export default function AISearch() {
{step === 'input' && (
<Box>
<Card sx={{ maxWidth: 680, mx: 'auto', p: 3 }}>
<Typography variant="subtitle1" fontWeight={600} mb={2}>
<Typography variant="subtitle1" sx={{ fontWeight: 600, mb: 2 }}>
Flächenbedarf beschreiben
</Typography>
<TextField
@@ -76,10 +76,10 @@ export default function AISearch() {
placeholder="Beispiel: Wir suchen 8001.000 m² Bürofläche in Zürich-West, verfügbar ab September 2025, Budget max. 45 CHF/m². Wichtig: gute ÖV-Anbindung, moderne Infrastruktur."
value={inputText}
onChange={e => setInputText(e.target.value)}
inputProps={{ maxLength: 2000 }}
slotProps={{ htmlInput: { maxLength: 2000 } }}
sx={{ mb: 1 }}
/>
<Typography variant="caption" color="text.secondary" display="block" textAlign="right" mb={2}>
<Typography variant="caption" color="text.secondary" sx={{ display: 'block', textAlign: 'right', mb: 2 }}>
{inputText.length}/2000
</Typography>
<Button
@@ -92,17 +92,17 @@ export default function AISearch() {
>
Analysieren
</Button>
<Typography variant="caption" color="text.secondary" display="block" textAlign="center">
<Typography variant="caption" color="text.secondary" sx={{ display: 'block', textAlign: 'center' }}>
Die KI extrahiert automatisch Kriterien, Standortpräferenzen und Budget aus Ihrer Beschreibung.
</Typography>
</Card>
{/* Example Queries */}
<Box sx={{ maxWidth: 680, mx: 'auto', mt: 2 }}>
<Typography variant="caption" color="text.secondary" display="block" mb={1}>
<Typography variant="caption" color="text.secondary" sx={{ display: 'block', mb: 1 }}>
Beispiele:
</Typography>
<Stack direction="row" spacing={1} flexWrap="wrap" gap={1}>
<Stack direction="row" spacing={1} sx={{ flexWrap: 'wrap', gap: 1 }}>
{EXAMPLE_QUERIES.map(q => (
<Chip
key={q}
@@ -135,7 +135,7 @@ export default function AISearch() {
<Box className="grid grid-cols-2 gap-4" sx={{ mb: 3 }}>
{/* Left: Extracted Criteria */}
<Card sx={{ p: 3 }}>
<Typography variant="subtitle1" fontWeight={600} mb={2}>
<Typography variant="subtitle1" sx={{ fontWeight: 600, mb: 2 }}>
Extrahierte Kriterien
</Typography>
@@ -161,8 +161,7 @@ export default function AISearch() {
<Box>
<Typography
variant="caption"
fontWeight={600}
sx={{ color: ConfidenceColor(extractedCriteria.confidence) }}
sx={{ fontWeight: 600, color: ConfidenceColor(extractedCriteria.confidence) }}
>
Flächenbedarf
</Typography>
@@ -177,8 +176,7 @@ export default function AISearch() {
<Box>
<Typography
variant="caption"
fontWeight={600}
sx={{ color: ConfidenceColor(extractedCriteria.confidence) }}
sx={{ fontWeight: 600, color: ConfidenceColor(extractedCriteria.confidence) }}
>
Budget
</Typography>
@@ -193,8 +191,7 @@ export default function AISearch() {
<Box>
<Typography
variant="caption"
fontWeight={600}
sx={{ color: ConfidenceColor(0.5) }}
sx={{ fontWeight: 600, color: ConfidenceColor(0.5) }}
>
Unternehmen
</Typography>
@@ -208,8 +205,7 @@ export default function AISearch() {
<Box>
<Typography
variant="caption"
fontWeight={600}
sx={{ color: ConfidenceColor(0.85) }}
sx={{ fontWeight: 600, color: ConfidenceColor(0.85) }}
>
Standort
</Typography>
@@ -223,8 +219,7 @@ export default function AISearch() {
<Box>
<Typography
variant="caption"
fontWeight={600}
sx={{ color: ConfidenceColor(0.85) }}
sx={{ fontWeight: 600, color: ConfidenceColor(0.85) }}
>
Verfügbarkeit
</Typography>
@@ -238,8 +233,7 @@ export default function AISearch() {
<Box>
<Typography
variant="caption"
fontWeight={600}
sx={{ color: ConfidenceColor(0.85) }}
sx={{ fontWeight: 600, color: ConfidenceColor(0.85) }}
>
Objekttyp
</Typography>
@@ -252,8 +246,8 @@ export default function AISearch() {
{/* Assumptions */}
{extractedCriteria.assumptions.length > 0 && (
<Box mt={3}>
<Typography variant="caption" fontWeight={600} color="text.secondary" display="block" mb={1}>
<Box sx={{ mt: 3 }}>
<Typography variant="caption" sx={{ fontWeight: 600, display: 'block', mb: 1 }} color="text.secondary">
Annahmen der KI
</Typography>
<Stack spacing={0.5}>
@@ -268,11 +262,11 @@ export default function AISearch() {
{/* Missing Fields */}
{extractedCriteria.missingFields.length > 0 && (
<Box mt={2}>
<Typography variant="caption" fontWeight={600} color="text.secondary" display="block" mb={1}>
<Box sx={{ mt: 2 }}>
<Typography variant="caption" sx={{ fontWeight: 600, display: 'block', mb: 1 }} color="text.secondary">
Fehlende Informationen
</Typography>
<Stack direction="row" spacing={0.5} flexWrap="wrap" gap={0.5}>
<Stack direction="row" spacing={0.5} sx={{ flexWrap: 'wrap', gap: 0.5 }}>
{extractedCriteria.missingFields.map(f => (
<Chip
key={f}
@@ -289,17 +283,17 @@ export default function AISearch() {
{/* Right: Follow-up Questions */}
<Card sx={{ p: 3 }}>
<Typography variant="subtitle1" fontWeight={600} mb={0.5}>
<Typography variant="subtitle1" sx={{ fontWeight: 600, mb: 0.5 }}>
Rückfragen der KI
</Typography>
<Typography variant="caption" color="text.secondary" display="block" mb={2}>
<Typography variant="caption" color="text.secondary" sx={{ display: 'block', mb: 2 }}>
Diese Fragen sind optional verbessern jedoch die Trefferqualität.
</Typography>
<Stack spacing={3}>
{extractedCriteria.followUpQuestions.map((q, i) => (
<Box key={i}>
<Typography variant="body2" fontWeight={500} mb={1}>
<Typography variant="body2" sx={{ fontWeight: 500, mb: 1 }}>
{i + 1}. {q}
</Typography>
<TextField
+9 -11
View File
@@ -107,7 +107,7 @@ export default function Compare() {
return (
<Box>
<Box sx={{ bgcolor: 'white', borderBottom: '1px solid #e2e8f0', px: 3, py: 2 }}>
<Typography variant="h5" fontWeight={700}>Vergleich</Typography>
<Typography variant="h5" sx={{ fontWeight: 700 }}>Vergleich</Typography>
</Box>
<Box sx={{ px: 3, py: 3 }}>
<EmptyState
@@ -149,14 +149,13 @@ export default function Compare() {
{
label: 'Datenqualität',
getValue: p => p.dataQuality.score,
format: (v, p) => (
format: (_v, p) => (
<Box sx={{ display: 'flex', alignItems: 'center', gap: 1 }}>
<Box sx={{ width: 80 }}>
<LinearProgress
variant="determinate"
value={p.dataQuality.score * 100}
sx={{ height: 6, borderRadius: 3 }}
color={p.dataQuality.score >= 0.8 ? 'success' : p.dataQuality.score >= 0.6 ? 'warning' : 'error'}
sx={{ height: 6, borderRadius: 3, color: p.dataQuality.score >= 0.8 ? 'success' : p.dataQuality.score >= 0.6 ? 'warning' : 'error' }}
/>
</Box>
<Typography variant="caption">{Math.round(p.dataQuality.score * 100)}%</Typography>
@@ -173,9 +172,8 @@ export default function Compare() {
{
label: 'Risiko',
getValue: p => p.riskLevel ?? null,
format: (v, p) => (
<Chip
label={getRiskLabel(p.riskLevel)}
format: (_v, p) => (
<Chip label={getRiskLabel(p.riskLevel)}
size="small"
color={getRiskColor(p.riskLevel)}
variant="outlined"
@@ -213,7 +211,7 @@ export default function Compare() {
{/* Page Header */}
<Box sx={{ bgcolor: 'white', borderBottom: '1px solid #e2e8f0', px: 3, py: 2, display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
<Box sx={{ display: 'flex', alignItems: 'center', gap: 2 }}>
<Typography variant="h5" fontWeight={700}>Vergleich</Typography>
<Typography variant="h5" sx={{ fontWeight: 700 }}>Vergleich</Typography>
<Chip label={`${orderedProperties.length} Objekte`} size="small" />
</Box>
<Button variant="outlined" size="small" color="error" onClick={clearCompare}>
@@ -233,7 +231,7 @@ export default function Compare() {
<TableCell key={p.id} sx={{ borderLeft: '1px solid #f1f5f9', minWidth: 220 }}>
<Box sx={{ display: 'flex', alignItems: 'flex-start', justifyContent: 'space-between', gap: 1 }}>
<Box>
<Typography variant="body2" fontWeight={600}>{p.title}</Typography>
<Typography variant="body2" sx={{ fontWeight: 600 }}>{p.title}</Typography>
<Chip
label={getResultTypeLabel(p.resultType)}
size="small"
@@ -302,9 +300,9 @@ export default function Compare() {
{/* Add more prompt */}
{orderedProperties.length < 3 && (
<Card sx={{ p: 2.5, mt: 2, border: '2px dashed #e2e8f0', boxShadow: 'none' }}>
<Stack direction="row" alignItems="center" justifyContent="space-between">
<Stack direction="row" sx={{ alignItems: 'center', justifyContent: 'space-between' }}>
<Box>
<Typography variant="subtitle2" fontWeight={600}>Weiteres Objekt hinzufügen</Typography>
<Typography variant="subtitle2" sx={{ fontWeight: 600 }}>Weiteres Objekt hinzufügen</Typography>
<Typography variant="caption" color="text.secondary">
Bis zu {3 - orderedProperties.length} weitere{orderedProperties.length < 2 ? 's' : ''} Objekt{orderedProperties.length < 2 ? '' : 'e'} möglich
</Typography>
+17 -22
View File
@@ -20,7 +20,7 @@ import {
Columns2,
} from 'lucide-react'
import { useQuery } from '@tanstack/react-query'
import { useNavigate, useLocation } from 'react-router'
import { useNavigate } from 'react-router'
import { propertyService } from '../../services/propertyService'
import { matchService } from '../../services/matchService'
import { needService } from '../../services/needService'
@@ -104,12 +104,12 @@ function ResultCard({ property, match, onCompare, isInCompare }: ResultCardProps
fontSize: 11,
}}
/>
<Typography variant="h6" fontWeight={600}>
<Typography variant="h6" sx={{ fontWeight: 600 }}>
{property.title}
</Typography>
</Box>
<Box sx={{ display: 'flex', alignItems: 'baseline', gap: 0.5 }}>
<Typography variant="h4" fontWeight={800} sx={{ color: scoreColor }}>
<Typography variant="h4" sx={{ fontWeight: 800, color: scoreColor }}>
{match.matchScore}
</Typography>
<Typography variant="body2" color="text.secondary">/100</Typography>
@@ -117,7 +117,7 @@ function ResultCard({ property, match, onCompare, isInCompare }: ResultCardProps
</Box>
{/* Property details row */}
<Stack direction="row" spacing={2.5} sx={{ mb: 1.5 }} flexWrap="wrap">
<Stack direction="row" spacing={2.5} sx={{ mb: 1.5, flexWrap: 'wrap' }}>
<Box sx={{ display: 'flex', alignItems: 'center', gap: 0.5 }}>
<MapPin size={14} color="#64748b" />
<Typography variant="body2" color="text.secondary">
@@ -150,10 +150,10 @@ function ResultCard({ property, match, onCompare, isInCompare }: ResultCardProps
{match.positiveFactors.length > 0 && (
<Box sx={{ mb: 1 }}>
<Typography variant="caption" fontWeight={600} color="text.secondary" display="block" mb={0.5}>
<Typography variant="caption" sx={{ fontWeight: 600, display: 'block', mb: 0.5 }} color="text.secondary">
Positive Faktoren
</Typography>
<Stack direction="row" spacing={0.5} flexWrap="wrap" gap={0.5}>
<Stack direction="row" spacing={0.5} sx={{ flexWrap: 'wrap', gap: 0.5 }}>
{match.positiveFactors.slice(0, 3).map((f, i) => (
<Chip
key={i}
@@ -168,9 +168,9 @@ function ResultCard({ property, match, onCompare, isInCompare }: ResultCardProps
{match.tradeoffs.length > 0 && (
<Alert severity="warning" sx={{ py: 0.5, px: 1.5, mb: 1, '& .MuiAlert-message': { fontSize: 12 } }}>
<Typography variant="caption" fontWeight={600} display="block" mb={0.5}>Abwägungen</Typography>
<Typography variant="caption" sx={{ fontWeight: 600, display: 'block', mb: 0.5 }}>Abwägungen</Typography>
{match.tradeoffs.slice(0, 2).map((t, i) => (
<Typography key={i} variant="caption" display="block">
<Typography key={i} variant="caption" sx={{ display: 'block' }}>
{t.criterion}: {t.concern}
</Typography>
))}
@@ -178,7 +178,7 @@ function ResultCard({ property, match, onCompare, isInCompare }: ResultCardProps
)}
{/* Confidence + Quality row */}
<Stack direction="row" spacing={2.5} alignItems="center" sx={{ mb: 1.5 }} flexWrap="wrap">
<Stack direction="row" spacing={2.5} sx={{ alignItems: 'center', mb: 1.5, flexWrap: 'wrap' }}>
<Typography variant="caption">
<span style={{ color: '#64748b' }}>Konfidenz </span>
<strong style={{ color: match.confidenceLevel >= 0.8 ? '#1a7a4a' : match.confidenceLevel >= 0.6 ? '#d97706' : '#c0392b' }}>
@@ -191,11 +191,9 @@ function ResultCard({ property, match, onCompare, isInCompare }: ResultCardProps
<LinearProgress
variant="determinate"
value={property.dataQuality.score * 100}
sx={{ height: 6, borderRadius: 3 }}
color={
sx={{ height: 6, borderRadius: 3, color:
property.dataQuality.score >= 0.8 ? 'success' :
property.dataQuality.score >= 0.6 ? 'warning' : 'error'
}
property.dataQuality.score >= 0.6 ? 'warning' : 'error' }}
/>
</Box>
<Typography variant="caption" color="text.secondary">
@@ -203,8 +201,7 @@ function ResultCard({ property, match, onCompare, isInCompare }: ResultCardProps
</Typography>
</Box>
{property.riskLevel && (
<Chip
label={getRiskLabel(property.riskLevel)}
<Chip label={getRiskLabel(property.riskLevel)}
size="small"
color={getRiskChipColor(property.riskLevel)}
variant="outlined"
@@ -246,8 +243,6 @@ function ResultCard({ property, match, onCompare, isInCompare }: ResultCardProps
export default function Results() {
const navigate = useNavigate()
const location = useLocation()
const _needId = (location.state as { needId?: string } | null)?.needId ?? 'need-001'
const [filterSource, setFilterSource] = useState<FilterSource>('ALL')
const [sortBy, setSortBy] = useState<SortBy>('score')
@@ -320,7 +315,7 @@ export default function Results() {
{/* Page Header */}
<Box sx={{ bgcolor: 'white', borderBottom: '1px solid #e2e8f0', px: 3, py: 2, display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
<Box>
<Typography variant="h5" fontWeight={700} color="text.primary">
<Typography variant="h5" sx={{ fontWeight: 700 }} color="text.primary">
{sorted.length} Treffer gefunden
</Typography>
<Typography variant="body2" color="text.secondary">
@@ -335,7 +330,7 @@ export default function Results() {
<Card sx={{ bgcolor: '#eff6ff', p: 2, mb: 2, border: '1px solid #bfdbfe' }}>
<Box sx={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
<Box>
<Typography variant="subtitle2" fontWeight={600} color="#1e3a5f">
<Typography variant="subtitle2" sx={{ fontWeight: 600 }} color="#1e3a5f">
Aktive Suche: {activeNeed.companyName}
</Typography>
<Typography variant="caption" color="text.secondary">
@@ -358,7 +353,7 @@ export default function Results() {
{/* Filter/Sort bar */}
<Card sx={{ p: 1.5, mb: 2 }}>
<Box sx={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', flexWrap: 'wrap', gap: 1 }}>
<Stack direction="row" spacing={0.5} flexWrap="wrap" gap={0.5}>
<Stack direction="row" spacing={0.5} sx={{ flexWrap: 'wrap', gap: 0.5 }}>
{(['ALL', ResultType.VERIFIED_PORTFOLIO, ResultType.EXTERNAL_MARKET, ResultType.FUTURE_AVAILABILITY] as FilterSource[]).map(source => {
const labels: Record<FilterSource, string> = {
ALL: 'Alle',
@@ -390,7 +385,7 @@ export default function Results() {
})}
</Stack>
<Stack direction="row" spacing={0.5} alignItems="center">
<Stack direction="row" spacing={0.5} sx={{ alignItems: 'center' }}>
<Typography variant="caption" color="text.secondary">Sortierung:</Typography>
{([['score', 'Relevanz'], ['area', 'Fläche'], ['rent', 'Mietpreis']] as [SortBy, string][]).map(([val, label]) => (
<Chip
@@ -448,7 +443,7 @@ export default function Results() {
boxShadow: '0 -4px 12px rgba(0,0,0,0.15)',
}}
>
<Typography variant="body2" fontWeight={600}>
<Typography variant="body2" sx={{ fontWeight: 600 }}>
{compareTray.length} Objekte zum Vergleich ausgewählt
</Typography>
<Stack direction="row" spacing={1}>
+4 -5
View File
@@ -62,7 +62,7 @@ export default function Shortlists() {
}}
>
<Box>
<Typography variant="h5" fontWeight={700} color="text.primary">
<Typography variant="h5" sx={{ fontWeight: 700 }} color="text.primary">
Shortlists
</Typography>
<Typography variant="body2" color="text.secondary">
@@ -94,7 +94,7 @@ export default function Shortlists() {
}}
>
<Box>
<Typography variant="subtitle1" fontWeight={700}>
<Typography variant="subtitle1" sx={{ fontWeight: 700 }}>
{sl.title}
</Typography>
<Typography variant="body2" color="text.secondary">
@@ -135,8 +135,7 @@ export default function Shortlists() {
}}
/>
<ListItemText
primary={prop}
primaryTypographyProps={{ variant: 'body2' }}
primary={<Typography variant="body2">{prop}</Typography>}
/>
</ListItem>
))}
@@ -163,7 +162,7 @@ export default function Shortlists() {
bgcolor: '#fafafa',
}}
>
<Typography variant="body2" color="text.secondary" textAlign="center">
<Typography variant="body2" color="text.secondary" sx={{ textAlign: 'center' }}>
Objekte aus den Suchergebnissen zur Shortlist hinzufügen
</Typography>
</Card>