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:
@@ -15,6 +15,8 @@ function validate(fields: {
|
||||
city: string
|
||||
areaSqm: string
|
||||
rentPerSqm: string
|
||||
fitOut: string
|
||||
fitOutByLandlord: boolean | undefined
|
||||
}): string | null {
|
||||
if (!fields.street.trim()) return 'Strasse erforderlich'
|
||||
if (!fields.postalCode.trim()) return 'PLZ erforderlich'
|
||||
@@ -23,6 +25,9 @@ function validate(fields: {
|
||||
|| Number(fields.areaSqm) <= 0) return 'Gültige Fläche eingeben'
|
||||
if (!fields.rentPerSqm || isNaN(Number(fields.rentPerSqm))
|
||||
|| Number(fields.rentPerSqm) <= 0) return 'Gültigen Mietpreis eingeben'
|
||||
// Bei Rohbau/Edelrohbau muss der Ausbau-Träger aktiv gewählt werden
|
||||
if ((fields.fitOut === 'SHELL' || fields.fitOut === 'BASIC')
|
||||
&& fields.fitOutByLandlord === undefined) return 'Bitte wählen, wer den Ausbau trägt (Vermieter oder Mieter)'
|
||||
return null
|
||||
}
|
||||
|
||||
@@ -43,7 +48,7 @@ export interface NewListingFormState {
|
||||
// Technical
|
||||
floor: string
|
||||
fitOut: string
|
||||
fitOutByLandlord: boolean
|
||||
fitOutByLandlord: boolean | undefined
|
||||
parking: string
|
||||
ceilingHeight: string
|
||||
mieterausbaubeitrag: string
|
||||
@@ -81,7 +86,7 @@ export interface NewListingFormHandlers {
|
||||
setSoftLevel: (key: string, value: string) => void
|
||||
setFloor: (v: string) => void
|
||||
setFitOut: (v: string) => void
|
||||
setFitOutByLandlord: (v: boolean) => void
|
||||
setFitOutByLandlord: (v: boolean | undefined) => void
|
||||
setParking: (v: string) => void
|
||||
setCeilingHeight: (v: string) => void
|
||||
setMieterausbaubeitrag: (v: string) => void
|
||||
@@ -119,7 +124,7 @@ export function useNewListingForm(pre: Prefill): NewListingFormState & NewListin
|
||||
const [softLevels, setSoftLevels] = useState<Record<string, string>>(() => ({ ...emptySoftLevels(), ...pre.softLevels }))
|
||||
const [floor, setFloor] = useState(pre.floor ?? '')
|
||||
const [fitOut, setFitOut] = useState(pre.fitOut ?? '')
|
||||
const [fitOutByLandlord, setFitOutByLandlord] = useState(pre.fitOutByLandlord ?? false)
|
||||
const [fitOutByLandlord, setFitOutByLandlord] = useState<boolean | undefined>(pre.fitOutByLandlord)
|
||||
const [parking, setParking] = useState(pre.parking != null ? String(pre.parking) : '')
|
||||
const [ceilingHeight, setCeilingHeight]= useState(pre.ceilingHeight != null ? String(pre.ceilingHeight) : '')
|
||||
const [mieterausbaubeitrag, setMieterausbaubeitrag] = useState(pre.mieterausbaubeitragPerSqm != null ? String(pre.mieterausbaubeitragPerSqm) : '')
|
||||
@@ -164,7 +169,7 @@ export function useNewListingForm(pre: Prefill): NewListingFormState & NewListin
|
||||
}
|
||||
|
||||
function handleSubmit() {
|
||||
const err = validate({ street, postalCode, city, areaSqm, rentPerSqm })
|
||||
const err = validate({ street, postalCode, city, areaSqm, rentPerSqm, fitOut, fitOutByLandlord })
|
||||
if (err) { setError(err); return }
|
||||
setError(null)
|
||||
createProperty.mutate(
|
||||
@@ -188,7 +193,7 @@ export function useNewListingForm(pre: Prefill): NewListingFormState & NewListin
|
||||
setAreaSqm(''); setRentPerSqm(''); setAvailableFrom(''); setDescription('')
|
||||
setContactName(''); setContactEmail(''); setContactPhone('')
|
||||
setSoftLevels(emptySoftLevels())
|
||||
setFloor(''); setFitOut(''); setFitOutByLandlord(false); setParking(''); setCeilingHeight('')
|
||||
setFloor(''); setFitOut(''); setFitOutByLandlord(undefined); setParking(''); setCeilingHeight('')
|
||||
setMieterausbaubeitrag(''); setIsFlexible(false); setMinLettableSqm('')
|
||||
setImages([]); setImageInput(''); setFloorPlanUrl('')
|
||||
setAiText(''); setAiApplied(false)
|
||||
|
||||
Reference in New Issue
Block a user