Files
property-match/src/components/match-card/MatchCardViewModel.ts
T
Benjamin Sutter beecf754d5 refactor: premium design polish — cards, results, grid view
- PropertyIntelligenceCard: aspect-ratio image, hover animation, compact
  data-completeness row, tighter body padding
- Results: replace verbose Card with compact active-search strip, remove
  DecisionContextPanel
- Properties: add 3/5/10 column toggle in grid view, persist to localStorage
- NeedInput, UnifiedResultCard/Feed, MatchCardViewModel: cleanup from
  earlier session

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-11 00:06:23 +02:00

108 lines
3.2 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 { ResultType } from '../../domain/enums'
import type { TradeOff, Risk, MissingDataItem, ScoreFactor } from '../../domain/match'
import type { PropertyUnit } from '../../domain/property'
import type { FitOutInvestment } from '../../lib/fitOutUtils'
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 // 01
dataQualityScore: number // 01
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
// Divisibility (Teilbarkeit)
isDivisible?: boolean
minDivisibleUnitSqm?: number
// Fit-out signal
fitOutLabel?: string // e.g. "FULL — bezugsfertig", "BASIC + CHF 200 MAB"
fitOutViable?: boolean // true when budget bridges the gap
fitOutInvestment?: FitOutInvestment
// 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
// Key metrics for compact display (Ginesta-style metric line)
areaSqm?: number
rentPerSqm?: number
// Score transparency
scoreBreakdown?: {
hardMatchScore: number
softFactorScore: number
totalScore: number
}
allFactors?: ScoreFactor[]
// States
isSelected?: boolean
isCompareSelected?: boolean
isRestricted?: boolean
isReviewRequired?: boolean
isStaleData?: boolean
}