Files
property-match/src/components/new-listing/TechnicalDetailsSection.tsx
T
Benjamin Sutter b2530f9e20 feat: Reale Jahresbelastung, must-have fixes, fitOut data coverage
Reale Jahresbelastung (Change 6):
- FitOutCostPanel zeigt Jahresmiete + amortisierte Ausbaukosten für alle fitOut-Werte
- FULL/PREMIUM: Ausbau CHF 0 (bezugsfertig), SHELL/BASIC: CRB/BKP-Richtwerte amortisiert über 5 J.
- Match-Card-Chip zeigt geschätzte Investition (orange wenn >100k)
- FitOutInvestment-Typ + calcFitOutInvestment() in fitOutUtils.ts
- BackendAIService + MockAIService mit generateFitOutAdvice (IAIService-Interface)

Must-have Kriterien (Nicht prüfbar Fix):
- ÖV-Anbindung: Minutengrenze aus Freitext extrahiert, gegen publicTransportMinutes geprüft
- Mindestfläche: m²-Wert aus Freitext extrahiert, gegen areaSqm geprüft
- Ausbaugrad: neues Keyword-Rule für FULL/PREMIUM

fitOut-Datenpflege:
- fitOut-Werte zu 32 fehlenden Properties ergänzt (Logistik=SHELL, Standard=BASIC, Modern=FULL)
- MAB-Werte (200/150/250 CHF/m²) zu 3 BASIC-Objekten hinzugefügt

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-06 20:09:55 +02:00

103 lines
3.6 KiB
TypeScript

import { Box, Card, FormControlLabel, MenuItem, Switch, TextField, Typography } from '@mui/material'
import { FIT_OUT_OPTIONS } from '../../pages/supply/newListingConstants'
interface Props {
floor: string
onFloorChange: (v: string) => void
fitOut: string
onFitOutChange: (v: string) => void
parking: string
onParkingChange: (v: string) => void
ceilingHeight: string
onCeilingHeightChange: (v: string) => void
mieterausbaubeitrag: string
onMieterausbaubeitragChange: (v: string) => void
isFlexible: boolean
onIsFlexibleChange: (v: boolean) => void
minLettableSqm: string
onMinLettableSqmChange: (v: string) => void
}
export function TechnicalDetailsSection({
floor, onFloorChange,
fitOut, onFitOutChange,
parking, onParkingChange,
ceilingHeight, onCeilingHeightChange,
mieterausbaubeitrag, onMieterausbaubeitragChange,
isFlexible, onIsFlexibleChange,
minLettableSqm, onMinLettableSqmChange,
}: Props) {
return (
<Card sx={{ p: 3, mb: 3 }}>
<Typography variant="subtitle2" sx={{ fontWeight: 700, mb: 2 }}>Technische Details (optional)</Typography>
<Box sx={{ display: 'grid', gridTemplateColumns: '1fr 1fr 1fr 1fr', gap: 2 }}>
<TextField
label="Stockwerk" value={floor}
onChange={e => onFloorChange(e.target.value)}
size="small" type="number" fullWidth placeholder="0 = EG"
/>
<TextField
select label="Ausbaustandard" value={fitOut}
onChange={e => onFitOutChange(e.target.value)} size="small" fullWidth
>
{FIT_OUT_OPTIONS.map(o => (
<MenuItem key={o.value} value={o.value}>{o.label}</MenuItem>
))}
</TextField>
<TextField
label="Mieterausbaubeitrag (CHF/m²)"
value={mieterausbaubeitrag}
onChange={e => onMieterausbaubeitragChange(e.target.value)}
size="small" type="number" fullWidth
slotProps={{ htmlInput: { min: 0, max: 1000, step: 25 } }}
helperText="Beitrag des Vermieters"
/>
<TextField
label="Parkplätze" value={parking}
onChange={e => onParkingChange(e.target.value)}
size="small" type="number" slotProps={{ htmlInput: { min: 0 } }} fullWidth
/>
<TextField
label="Deckenhöhe (m)" value={ceilingHeight}
onChange={e => onCeilingHeightChange(e.target.value)}
size="small" type="number" slotProps={{ htmlInput: { step: 0.1, min: 2 } }} fullWidth
/>
</Box>
{/* Divisibility */}
<Box sx={{ mt: 2.5, pt: 2, borderTop: '1px solid #f1f5f9', display: 'flex', alignItems: 'center', gap: 2 }}>
<FormControlLabel
control={
<Switch
checked={isFlexible}
onChange={e => onIsFlexibleChange(e.target.checked)}
size="small"
/>
}
label={
<Box>
<Typography variant="body2" sx={{ fontWeight: 600 }}>Fläche ist teilbar</Typography>
<Typography variant="caption" color="text.secondary">
Mieter können auch nur einen Teil der Fläche mieten
</Typography>
</Box>
}
sx={{ m: 0, flex: 1 }}
/>
{isFlexible && (
<TextField
label="Mindesteinheit (m²)"
value={minLettableSqm}
onChange={e => onMinLettableSqmChange(e.target.value)}
size="small"
type="number"
sx={{ width: 180 }}
slotProps={{ htmlInput: { min: 10, step: 10 } }}
helperText="Kleinste vermietbare Einheit"
/>
)}
</Box>
</Card>
)
}