Files
property-match/src/domain/property.ts
T
Benjamin Sutter 36570c5bdc 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>
2026-05-26 00:08:35 +02:00

190 lines
5.7 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import type {
AssetType, ResultType, AvailabilityStatus, AvailabilityType,
FreshnessStatus, RiskLevel, SourceType, DataQualityLevel,
} from './enums'
import { AvailabilityStatus as AS } from './enums'
import type { PropertyUnit } from './unit'
// Re-export unit types so all existing imports from 'property' continue to work
export type { PropertyUnit, UnitBundle, UnitNeedMatch } from './unit'
// ── Location / Address ────────────────────────────────────────────────────────
export interface Location {
city: string
district?: string
canton?: string
region?: string
country: string
coordinates?: { lat: number; lng: number }
}
export interface Address {
street: string
houseNumber: string
postalCode: string
city: string
country: string
}
// ── Source Metadata ───────────────────────────────────────────────────────────
export interface SourceMeta {
sourceType: SourceType | string
sourceLabel?: string
sourceUrl?: string
sourceUpdatedAt?: string
externalId?: string
}
// ── Data Quality ──────────────────────────────────────────────────────────────
export interface DataQuality {
score: number
qualityLevel?: DataQualityLevel
missingCriticalFields: string[]
missingOptionalFields: string[]
lastVerifiedAt?: string
freshness: FreshnessStatus
warnings: string[]
}
// ── Hard Facts ────────────────────────────────────────────────────────────────
export interface PropertyHardFacts {
floor?: number
fitOut?: 'SHELL' | 'BASIC' | 'FULL' | 'PREMIUM'
parking?: number
publicTransportScore?: number
usageType?: string
ceilingHeightM?: number
loadingDocksCount?: number
powerSupplyKva?: number
hasServerRoom?: boolean
isBarrierFree?: boolean
hasAirConditioning?: boolean
hasStorefront?: boolean
}
// ── Soft Factors ──────────────────────────────────────────────────────────────
export interface SoftFactors {
prestigeScore?: number
visibilityScore?: number
footfallScore?: number
commuterAccessScore?: number
talentAccessScore?: number
esgScore?: number
flexibilityScore?: number
expansionPotentialScore?: number
taxEnvironmentScore?: number
// Legacy aliases kept for mock-data backward compatibility
prestige?: number
accessibility?: number
talentAccess?: number
esgRating?: string
passerbyFrequency?: 'LOW' | 'MEDIUM' | 'HIGH' | 'VERY_HIGH'
parkingSpots?: number
publicTransportMinutes?: number
infrastructureNotes?: string
}
// ── Property ──────────────────────────────────────────────────────────────────
export interface Property {
id: string
organizationId?: string
title: string
assetType: AssetType
resultType: ResultType
location: Location
address: Address
areaSqm: number
areaSqmMin?: number
areaSqmMax?: number
rentPricePerSqm: number
rentChfSqmYear?: number
totalRentMonthly?: number
ancillaryCosts?: number
availabilityDate: string
availabilityStatus: AvailabilityStatus
availabilityType?: AvailabilityType
sourceType: string
sourceLabel?: string
sourceUrl?: string
sourceUpdatedAt?: string
sourceMeta?: SourceMeta
confidenceScore: number
dataQuality: DataQuality
softFactors?: SoftFactors
hardFacts?: PropertyHardFacts
// Legacy fields — kept for backward compat
floorLevel?: number
expansionPotentialSqm?: number
contractDurationMonths?: number
riskLevel?: RiskLevel
description?: string
images?: string[]
floorPlanUrl?: string
leaseContractUrl?: string // link to the signed lease document
leaseContractName?: string // display label, e.g. "Mietvertrag 20212026"
propertyNumber?: string
units?: PropertyUnit[]
mapImageUrl?: string
leaseTerm?: string
leaseStartDate?: string
leaseEndDate?: string
breakoutOption?: boolean
breakoutOptionDate?: string
currentTenant?: string
importedFrom?: string
importedAt?: string
lastUpdatedAt?: string
schattenmarktRelease?: { enabled: boolean; leadTimeMonths?: number }
status?: 'ACTIVE' | 'INACTIVE' | 'DRAFT' | 'ARCHIVED'
lastReviewedAt?: string
createdAt: string
updatedAt: string
}
export type CreatePropertyInput = Omit<Property, 'id' | 'createdAt' | 'updatedAt'>
export type UpdatePropertyInput = Partial<CreatePropertyInput>
/**
* Returns the rentable units of a property.
* For properties without explicit units, synthesises one unit from property-level data
* so that all matching logic can operate uniformly at unit level.
*/
export function getEffectiveUnits(p: Property): PropertyUnit[] {
if (p.units && p.units.length > 0) return p.units
return [{
id: p.id,
propertyId: p.id,
floorLevel: p.hardFacts?.floor ?? p.floorLevel ?? 0,
unitLabel: undefined,
areaSqm: p.areaSqm,
available: p.availabilityStatus === AS.AVAILABLE_NOW || p.availabilityStatus === AS.AVAILABLE_SOON,
rentPricePerSqm: p.rentPricePerSqm,
currentTenant: p.currentTenant,
leaseTerm: p.leaseTerm,
leaseEndDate: p.leaseEndDate,
schattenmarktRelease: p.schattenmarktRelease?.enabled
? { enabled: true, availableFrom: p.leaseEndDate }
: undefined,
}]
}