fix: resolve all TypeScript errors and refactor oversized components

- Fix MUI v9 API: PaperProps/InputLabelProps/inputProps → slotProps in 6 components
- Add ExternalMarketResult alias, PropertyUnit import, OPERATIONS workspace config
- Fix TradeOff.description → .concern, ScoreFactor.label → .criterion
- Make schattenmarktRelease.leadTimeMonths optional, fix mock-data enum values
- Fix useMatchDetailData query typing, weightingService missing WeightProfile keys
- Split Pipeline/Compare/MatchDetail/IntelligenceMatchCard into sub-components
- Fix all test fixtures (CreateNeedInput, CreatePropertyInput, TradeOffInput, etc.)
- Add vercel.json for deployment, zero tsc errors

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Benjamin Sutter
2026-05-26 00:08:35 +02:00
parent 98d2770054
commit 36570c5bdc
52 changed files with 269 additions and 143 deletions
@@ -123,7 +123,6 @@ export function InquiryReplyComposer({
display: 'flex',
alignItems: 'center',
gap: 0.75,
bgcolor: 'white',
border: '1px solid',
borderColor: a.generated ? '#bfdbfe' : '#cbd5e1',
borderRadius: 1,
@@ -104,7 +104,7 @@ export function OfferCreationWizard({ inquiryId, propertyId, tenantName, onClose
}
return (
<Dialog open fullWidth maxWidth="lg" PaperProps={{ sx: { height: '90vh', display: 'flex', flexDirection: 'column' } }}>
<Dialog open fullWidth maxWidth="lg" slotProps={{ paper: { sx: { height: '90vh', display: 'flex', flexDirection: 'column' } } }}>
<Box sx={{ px: 3, pt: 2.5, pb: 1.5, borderBottom: '1px solid #e2e8f0', display: 'flex', alignItems: 'center', justifyContent: 'space-between', flexShrink: 0 }}>
<Typography variant="h6" sx={{ fontWeight: 700 }}>Angebot erstellen</Typography>
<Button size="small" onClick={onClose} sx={{ minWidth: 0, p: 0.5 }}><X size={18} /></Button>
@@ -187,7 +187,7 @@ export function OfferCreationWizard({ inquiryId, propertyId, tenantName, onClose
size="small"
value={a.date}
onChange={e => updateAppointment(a.id, 'date', e.target.value)}
InputLabelProps={{ shrink: true }}
slotProps={{ inputLabel: { shrink: true } }}
sx={{ width: 160 }}
/>
<TextField
@@ -228,7 +228,7 @@ export function OfferCreationWizard({ inquiryId, propertyId, tenantName, onClose
progress={progress}
ready={ready}
draft={draft}
property={property}
property={property ?? undefined}
onDownload={() => showToast('PDF wird heruntergeladen…', 'info')}
onAttach={() => {
const label = `Angebot_${property?.title ?? 'Objekt'}.pdf`
@@ -48,12 +48,14 @@ export function OfferWizard() {
fullScreen={fullScreen}
maxWidth="lg"
fullWidth
PaperProps={{
sx: {
height: fullScreen ? '100vh' : '85vh',
display: 'flex',
flexDirection: 'column',
overflow: 'hidden',
slotProps={{
paper: {
sx: {
height: fullScreen ? '100vh' : '85vh',
display: 'flex',
flexDirection: 'column',
overflow: 'hidden',
},
},
}}
>
@@ -6,7 +6,6 @@ import {
} from '@mui/material'
import { Download, Send, X } from 'lucide-react'
import type { Inquiry } from '../../domain/inquiry'
import type { Property } from '../../domain/property'
import type { InquiryPreparationReportDraft, ReportObjectFieldSelection } from '../../domain/inquiryReport'
import { useCreateInquiryReport, useUpdateInquiryReport, useFinalizeInquiryReport } from '../../hooks/useInquiryReport'
import { useToastStore } from '../../stores/toastStore'
@@ -40,10 +39,6 @@ export function PreparationWizard({ inquiryId, inquiry, onClose }: Props) {
const portfolioProps = allProperties.filter(p => p.resultType === ResultType.VERIFIED_PORTFOLIO)
const selectedProperties = draft?.selectedPropertyIds
.map(id => allProperties.find(p => p.id === id))
.filter((p): p is Property => !!p) ?? []
const toggleProperty = (id: string) => {
setSelectedIds(prev =>
prev.includes(id) ? prev.filter(x => x !== id) : [...prev, id],
@@ -112,7 +107,7 @@ export function PreparationWizard({ inquiryId, inquiry, onClose }: Props) {
}
return (
<Dialog open fullWidth maxWidth="lg" PaperProps={{ sx: { height: '90vh', display: 'flex', flexDirection: 'column' } }}>
<Dialog open fullWidth maxWidth="lg" slotProps={{ paper: { sx: { height: '90vh', display: 'flex', flexDirection: 'column' } } }}>
<Box sx={{ px: 3, pt: 2.5, pb: 1.5, borderBottom: '1px solid #e2e8f0', display: 'flex', alignItems: 'center', justifyContent: 'space-between', flexShrink: 0 }}>
<Typography variant="h6" sx={{ fontWeight: 700 }}>Vorbereitung starten</Typography>
<Button size="small" onClick={onClose} sx={{ minWidth: 0, p: 0.5 }}><X size={18} /></Button>
@@ -82,8 +82,6 @@ const FIELD_GROUPS: FieldGroup[] = [
},
]
const MANDATORY: ReportObjectFieldKey[] = ['title', 'location', 'mapImageUrl', 'images']
export function ReportObjectFieldSelector({ propertyTitle, value, onChange }: Props) {
const isSelected = (key: ReportObjectFieldKey) =>
value.selectedOptionalFields.includes(key)
@@ -115,7 +113,6 @@ export function ReportObjectFieldSelector({ propertyTitle, value, onChange }: Pr
{FIELD_GROUPS.map(group => {
const groupKeys = group.fields.map(f => f.key)
const allSelected = groupKeys.every(k => value.selectedOptionalFields.includes(k))
return (
<Accordion key={group.label} disableGutters elevation={0} sx={{ border: '1px solid #e2e8f0', mb: 0.5, '&:before': { display: 'none' } }}>
<AccordionSummary expandIcon={<ChevronDown size={16} />} sx={{ minHeight: 40, '& .MuiAccordionSummary-content': { my: 0.5 } }}>