647493bf3c
- 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>
99 lines
3.5 KiB
TypeScript
99 lines
3.5 KiB
TypeScript
import { AssetType, AvailabilityStatus, ResultType } from '../../domain/enums'
|
|
import type { CreatePropertyInput } from '../../domain/property'
|
|
import { ASSET_TYPE_LABELS, LEVEL_TO_SCORE } from './newListingConstants'
|
|
|
|
export function buildCreatePropertyInput(fields: {
|
|
assetType: string
|
|
street: string
|
|
houseNumber: string
|
|
postalCode: string
|
|
city: string
|
|
areaSqm: number
|
|
rentPerSqm: number
|
|
availableFrom: string
|
|
description: string
|
|
softLevels: Record<string, string>
|
|
floor: string
|
|
fitOut: string
|
|
fitOutByLandlord?: boolean
|
|
parking: string
|
|
ceilingHeight: string
|
|
images: string[]
|
|
floorPlanUrl: string
|
|
mieterausbaubeitrag?: string
|
|
isFlexible?: boolean
|
|
minLettableSqm?: string
|
|
}): CreatePropertyInput {
|
|
const {
|
|
assetType, street, houseNumber, postalCode, city,
|
|
areaSqm, rentPerSqm, availableFrom, description,
|
|
softLevels, floor, fitOut, fitOutByLandlord, parking, ceilingHeight, images, floorPlanUrl,
|
|
mieterausbaubeitrag, isFlexible, minLettableSqm,
|
|
} = fields
|
|
|
|
const sf = {
|
|
prestigeScore: LEVEL_TO_SCORE[softLevels.prestige ?? ''],
|
|
commuterAccessScore: LEVEL_TO_SCORE[softLevels.accessibility ?? ''],
|
|
visibilityScore: LEVEL_TO_SCORE[softLevels.visibility ?? ''],
|
|
footfallScore: LEVEL_TO_SCORE[softLevels.footfall ?? ''],
|
|
talentAccessScore: LEVEL_TO_SCORE[softLevels.talentAccess ?? ''],
|
|
esgScore: LEVEL_TO_SCORE[softLevels.esg ?? ''],
|
|
flexibilityScore: LEVEL_TO_SCORE[softLevels.flexibility ?? ''],
|
|
expansionPotentialScore: LEVEL_TO_SCORE[softLevels.expansionPotential ?? ''],
|
|
taxEnvironmentScore: LEVEL_TO_SCORE[softLevels.taxEnvironment ?? ''],
|
|
}
|
|
|
|
const hf = {
|
|
floor: floor ? parseInt(floor) : undefined,
|
|
fitOut: (fitOut || undefined) as 'SHELL' | 'BASIC' | 'FULL' | 'PREMIUM' | undefined,
|
|
fitOutByLandlord,
|
|
// MAB nur relevant, wenn der Mieter ausbaut — sonst nicht speichern
|
|
mieterausbaubeitragPerSqm: !fitOutByLandlord && mieterausbaubeitrag ? parseInt(mieterausbaubeitrag) : undefined,
|
|
parking: parking ? parseInt(parking) : undefined,
|
|
ceilingHeightM: ceilingHeight ? parseFloat(ceilingHeight) : undefined,
|
|
}
|
|
|
|
return {
|
|
title: `${ASSET_TYPE_LABELS[assetType] ?? assetType} · ${city}`,
|
|
assetType: assetType as typeof AssetType[keyof typeof AssetType],
|
|
resultType: ResultType.VERIFIED_PORTFOLIO,
|
|
sourceType: 'DIRECT',
|
|
location: { city, country: 'CH' },
|
|
address: {
|
|
street: street.trim(),
|
|
houseNumber: houseNumber.trim(),
|
|
postalCode: postalCode.trim(),
|
|
city: city.trim(),
|
|
country: 'CH',
|
|
},
|
|
areaSqm,
|
|
rentPricePerSqm: rentPerSqm,
|
|
availabilityDate: availableFrom || new Date().toISOString().slice(0, 10),
|
|
availabilityStatus: availableFrom ? AvailabilityStatus.AVAILABLE_SOON : AvailabilityStatus.AVAILABLE_NOW,
|
|
confidenceScore: 1.0,
|
|
description: description.trim() || undefined,
|
|
softFactors: sf,
|
|
hardFacts: hf,
|
|
images: images.length > 0 ? images : undefined,
|
|
floorPlanUrl: floorPlanUrl.trim() || undefined,
|
|
dataQuality: {
|
|
score: 1.0,
|
|
missingCriticalFields: [],
|
|
missingOptionalFields: [],
|
|
freshness: 'FRESH',
|
|
warnings: [],
|
|
},
|
|
status: 'ACTIVE',
|
|
units: isFlexible ? [{
|
|
id: `unit-listing-${Date.now()}`,
|
|
propertyId: '',
|
|
floorLevel: hf.floor ?? 0,
|
|
areaSqm,
|
|
available: true,
|
|
rentPricePerSqm: rentPerSqm,
|
|
isFlexible: true,
|
|
minLettableSqm: minLettableSqm ? parseInt(minLettableSqm) : undefined,
|
|
}] : undefined,
|
|
}
|
|
}
|