27c53f3af1
- Single scoring system: MockupNeedProvider rewrites matches via calculateScore exclusively — allFactors always populated, no more dual-system (computeScore removed), weights from weightingProfile reflected in every breakdown - ScoreInlineBreakdown: new component shows hard/soft criteria with importance labels (Entscheidend/Sehr wichtig/…) and formula on compact + expanded cards - MatchCardAdapter: passes scoreBreakdown + allFactors to ViewModel - MatchDetail: 'Zukunftssignal' label replaced with 'Future Availability' - aiService budget parser: values < 100 treated as monthly and multiplied by 12 to produce correct annual CHF/m²/year value — fixes 0-result searches Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
94 lines
2.7 KiB
TypeScript
94 lines
2.7 KiB
TypeScript
import type { ResultType } from '../../domain/enums'
|
||
import type { TradeOff, Risk, MissingDataItem, ScoreFactor } from '../../domain/match'
|
||
import type { PropertyUnit } from '../../domain/property'
|
||
|
||
export type MatchCardVariant = 'compact' | 'expanded' | 'review' | 'compare-mini'
|
||
|
||
export type MatchCardActionType =
|
||
| 'OPEN_DETAIL'
|
||
| 'ADD_COMPARE'
|
||
| 'SAVE_SHORTLIST'
|
||
| 'SEND_REVIEW'
|
||
| 'APPROVE'
|
||
| 'REJECT'
|
||
| 'REQUEST_DATA'
|
||
|
||
export interface MatchCardAction {
|
||
id: string
|
||
label: string
|
||
actionType: MatchCardActionType
|
||
variant?: 'primary' | 'secondary' | 'danger'
|
||
disabled?: boolean
|
||
onClick: () => void
|
||
}
|
||
|
||
export interface MatchCardReason {
|
||
type: 'HARD_FACT' | 'SOFT_FACTOR' | 'STRATEGIC'
|
||
label: string
|
||
explanation: string
|
||
score: number
|
||
}
|
||
|
||
export interface MatchCardViewModel {
|
||
id: string
|
||
title: string
|
||
resultType: ResultType
|
||
assetType?: string
|
||
matchScore: number
|
||
confidenceScore: number // 0–1
|
||
dataQualityScore: number // 0–1
|
||
locationLabel: string
|
||
availabilityLabel?: string
|
||
sourceLabel?: string
|
||
externalUrl?: string
|
||
reasons: MatchCardReason[] // max 3: HARD_FACT, SOFT_FACTOR, STRATEGIC
|
||
tradeoffs: TradeOff[]
|
||
risks: Risk[]
|
||
missingData: MissingDataItem[]
|
||
actions: MatchCardAction[]
|
||
disclaimer?: string // required for FUTURE_AVAILABILITY
|
||
explainabilitySummary?: string
|
||
taxCalculatorUrl?: string // deeplink to cantonal tax calculator
|
||
|
||
// Schattenmarkt / FUTURE_AVAILABILITY signal fields
|
||
signalSourceType?: 'PRESS' | 'CONSTRUCTION_PERMIT' | 'JOB_POSTING' | 'COMPANY_REPORT' | 'MARKET_DATA' | 'MANUAL' | 'LEASE_CONTRACT'
|
||
signalSourceUrl?: string
|
||
signalSourceCredibility?: 'LOW' | 'MEDIUM' | 'HIGH'
|
||
signalProbability?: number
|
||
signalMarketIndicator?: string
|
||
signalType?: string
|
||
signalIsVerified?: boolean
|
||
aiSignalSummary?: string
|
||
signalQuality?: 'HIGH' | 'MEDIUM' | 'LOW'
|
||
signalMarketIndicators?: string[]
|
||
signalStrategicInterpretation?: string
|
||
signalConfirmedFacts?: string[]
|
||
signalUnconfirmedFacts?: string[]
|
||
signalIsControlled?: boolean
|
||
signalAreaSqmEstimate?: number
|
||
|
||
// Unit-first display (primary)
|
||
propertySubtitle?: string // building name shown below the unit title
|
||
|
||
// Property / unit reference (for FUTURE_AVAILABILITY with a backing property)
|
||
propertyId?: string
|
||
unitId?: string
|
||
preMarketUnit?: PropertyUnit // specific unit being released pre-market
|
||
preMarketAllUnits?: PropertyUnit[] // all units of the backing property
|
||
|
||
// Score transparency
|
||
scoreBreakdown?: {
|
||
hardMatchScore: number
|
||
softFactorScore: number
|
||
totalScore: number
|
||
}
|
||
allFactors?: ScoreFactor[]
|
||
|
||
// States
|
||
isSelected?: boolean
|
||
isCompareSelected?: boolean
|
||
isRestricted?: boolean
|
||
isReviewRequired?: boolean
|
||
isStaleData?: boolean
|
||
}
|