feat(supply): per-unit price/availability editor + mandatory fit-out cost-bearer for shell/edelrohbau

- unit.availableFrom: explicit per-unit availability date
- UnitStructurePanel: inline expandable editor (pencil) for per-unit price + availability via useUpdateUnit
- fitOutByLandlord now boolean|undefined ("not chosen"); toggle has no default for SHELL/BASIC
- NewListing: validate() blocks save until cost-bearer chosen for Rohbau/Edelrohbau
- PropertyDetailView.saveEdit: same guard for existing listings; required asterisk + hint in both forms
- newListingMapper persists explicit tenant(false) choice (was collapsed to undefined)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Benjamin Sutter
2026-06-20 23:26:45 +02:00
parent 5d26dd4a6c
commit 647493bf3c
7 changed files with 102 additions and 22 deletions
@@ -39,7 +39,7 @@ export function PropertyDetailOverview({ p, editing, draft, onDraftChange }: Pro
// Effektive (Draft-überlagerte) hardFacts für den Bearbeiten-Modus
const hf = draft.hardFacts ?? p.hardFacts ?? {}
const editFitOut = hf.fitOut ?? ''
const editByLandlord = hf.fitOutByLandlord ?? false
const editByLandlord = hf.fitOutByLandlord
const showBuildResponsibility = FIT_OUT_NEEDS_BUILD.has(editFitOut)
const patchHF = (patch: Partial<NonNullable<Property['hardFacts']>>) =>
onDraftChange({ ...draft, hardFacts: { ...hf, ...patch } })
@@ -187,17 +187,24 @@ export function PropertyDetailOverview({ p, editing, draft, onDraftChange }: Pro
{showBuildResponsibility && (
<Box sx={{ mt: 1.5 }}>
<Typography variant="caption" color="text.secondary" sx={{ display: 'block', mb: 0.5 }}>Wer baut aus?</Typography>
<Typography variant="caption" color="text.secondary" sx={{ display: 'block', mb: 0.5 }}>
Wer baut aus? <Box component="span" sx={{ color: '#dc2626' }}>*</Box>
</Typography>
<Box sx={{ display: 'flex', gap: 1.5, alignItems: 'center', flexWrap: 'wrap' }}>
<ToggleButtonGroup
exclusive size="small"
value={editByLandlord ? 'landlord' : 'tenant'}
value={editByLandlord === undefined ? null : editByLandlord ? 'landlord' : 'tenant'}
onChange={(_, v) => { if (v) patchHF({ fitOutByLandlord: v === 'landlord', ...(v === 'landlord' ? { mieterausbaubeitragPerSqm: undefined } : {}) }) }}
>
<ToggleButton value="landlord" sx={{ textTransform: 'none' }}>Vermieter übernimmt</ToggleButton>
<ToggleButton value="tenant" sx={{ textTransform: 'none' }}>Mieter baut aus</ToggleButton>
</ToggleButtonGroup>
{!editByLandlord && (
{editByLandlord === undefined && (
<Typography variant="caption" sx={{ color: '#b45309' }}>
Pflichtangabe bei Rohbau/Edelrohbau
</Typography>
)}
{editByLandlord === false && (
<TextField
label="Mieterausbaubeitrag (CHF/m²)"
size="small" type="number" sx={{ width: 240 }}