refactor: split PropertyDetail, Anfragen, AISearch god components
PropertyDetail.tsx: 565→118 lines - Removed duplicate constants (import from MatchDetailPropertyDetails) - PropertyDetailPublicSections: Preis/Hauptangaben/Eigenschaften/Wegzeit/Einheiten/Beschreibung/Quelle sections - PropertyContactForm: Verwaltung kontaktieren form Anfragen.tsx: 481→320 lines - anfragenKiDetection.ts: STAGE_ORDER, STAGE_LABELS, KI_RULES, detectKiStage - AnfragenMessageBubble: chat message bubble component - AnfragenInquiryItem: inquiry list row component AISearch.tsx: 398→342 lines - needSearchMapper.ts: generateSummary + buildNeedInput pure functions Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,56 @@
|
||||
import { AssetType } from '../../domain/enums'
|
||||
import type { ParsedNeedCriteria, WeightingKey } from '../../domain/needBuilder'
|
||||
import type { CreateNeedInput } from '../../domain/need'
|
||||
|
||||
const ASSET_LABELS_TEXT: Record<string, string> = {
|
||||
OFFICE: 'Bürofläche', RETAIL: 'Retail-Fläche', LOGISTICS: 'Logistikfläche',
|
||||
PRODUCTION: 'Produktionsfläche', LIGHT_INDUSTRIAL: 'Gewerbefläche', MIXED: 'gemischte Fläche',
|
||||
}
|
||||
|
||||
export function generateSummary(c: ParsedNeedCriteria): string {
|
||||
const parts: string[] = []
|
||||
if (c.assetType) parts.push(`Suche ${ASSET_LABELS_TEXT[c.assetType] ?? c.assetType}`)
|
||||
if (c.areaRange && (c.areaRange.min > 0 || c.areaRange.max > 0))
|
||||
parts.push(`${c.areaRange.min}–${c.areaRange.max} m²`)
|
||||
if (c.preferredLocations?.length) parts.push(`in ${c.preferredLocations.join(', ')}`)
|
||||
if (c.budgetRange?.maxPerSqm) parts.push(`Budget max. CHF ${c.budgetRange.maxPerSqm}/m²`)
|
||||
if (c.timing?.earliestMoveIn) parts.push(`ab ${c.timing.earliestMoveIn}`)
|
||||
if (c.mustHaveCriteria?.length) parts.push(`Must-haves: ${c.mustHaveCriteria.join(', ')}`)
|
||||
return parts.join(', ')
|
||||
}
|
||||
|
||||
export function buildNeedInput(
|
||||
criteria: ParsedNeedCriteria,
|
||||
weights: Record<WeightingKey, number>,
|
||||
needTitle: string,
|
||||
overallConfidence: number,
|
||||
status: 'DRAFT' | 'ACTIVE',
|
||||
): CreateNeedInput {
|
||||
return {
|
||||
companyName: needTitle || criteria.companyName || 'Neue Suche',
|
||||
assetType: criteria.assetType ?? AssetType.UNKNOWN,
|
||||
requiredArea: criteria.areaRange ?? { min: 0, max: 0 },
|
||||
preferredLocations: criteria.preferredLocations ?? [],
|
||||
budgetRange: criteria.budgetRange ?? { maxPerSqm: 0, currency: 'CHF' },
|
||||
timing: {
|
||||
earliestMoveIn: criteria.timing?.earliestMoveIn ?? '',
|
||||
latestMoveIn: criteria.timing?.latestMoveIn ?? criteria.timing?.earliestMoveIn ?? '',
|
||||
contractDurationMonths: criteria.timing?.contractDurationMonths,
|
||||
flexibleTiming: criteria.timing?.flexibleTiming ?? true,
|
||||
},
|
||||
weightingProfile: weights,
|
||||
confidenceInCriteria: overallConfidence,
|
||||
status,
|
||||
mustCriteriaText: criteria.mustHaveCriteria ?? [],
|
||||
requireGroundFloor: criteria.requireGroundFloor,
|
||||
requiredFitOut: criteria.requiredFitOut,
|
||||
requiredParkingMin: criteria.requiredParkingMin,
|
||||
requireAirConditioning: criteria.requireAirConditioning,
|
||||
requireLoadingDock: criteria.requireLoadingDock,
|
||||
requireBarrierFree: criteria.requireBarrierFree,
|
||||
minCeilingHeightM: criteria.minCeilingHeightM,
|
||||
minContractDurationMonths: criteria.minContractDurationMonths,
|
||||
notes: criteria.notes,
|
||||
extractedFromText: undefined,
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user