Files
property-match/src/components/compare/compareUtils.tsx
T
Benjamin Sutter 7f090a48ff refactor: replace hardcoded hex colors with design tokens across priority components
- Add DS_COLORS.heat, DS_COLORS.futureCard, INQUIRY_STATUS_META tokens to ds.ts
- Eliminate 4 duplicate RESULT_TYPE_META / TYPE_META constants (now all use ds.ts)
- Eliminate 3 duplicate scoreColor / SCORE_COLOR functions (now all use matchScoreHex)
- HeatBadge: use DS_COLORS.heat.VERY_HOT / HOT tokens
- FutureAvailabilityCard: use DS_COLORS.futureCard.controlled / signal tokens
- IntelligenceMatchCard: import RESULT_TYPE_META from ds.ts, remove primary override
- MatchScoreDisplay: replace local scoreColor() with matchScoreHex()
- CompareColumnHeader: remove local TYPE_META + SCORE_COLOR, use ds.ts + utils.ts
- CompareTableBody: import RESULT_TYPE_META + matchScoreHex, fix #7c3aed → token
- compareUtils: remove TYPE_META + SCORE_COLOR, use dataQualityHex in scoreBar
- Anfragen + AnfragenInquiryItem: deduplicate STATUS_CONFIG → INQUIRY_STATUS_META
- Anfragen: #1e3a5f → 'primary.main', KI alert → futureCard.controlled tokens
- AnfragenMessageBubble: own-message bubble → 'primary.main', AI bubble → tokens
- ScoreBreakdownPanel: #1e3a5f → 'primary.main', #6d28d9 → futureCard.controlled
- ESLint: add warn rule against new hex colors in component sx props

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-24 13:02:01 +02:00

85 lines
3.5 KiB
TypeScript

import type { ReactNode } from 'react'
import { Box, LinearProgress, Typography } from '@mui/material'
import type { WeightingKey } from '../../domain/needBuilder'
import type { UnifiedMatchResult, VerifiedPortfolioResult, ExternalMarketResult, FutureAvailabilityResult } from '../../domain/unifiedResult'
import { dataQualityHex } from '../../lib/utils'
// ── Helpers ───────────────────────────────────────────────────────────────────
export const HARD_CRITERIA = new Set(['area', 'location', 'budget', 'timing'])
export function getProp(item: UnifiedMatchResult) {
return item.resultType !== 'FUTURE_AVAILABILITY'
? (item as VerifiedPortfolioResult | ExternalMarketResult).property
: null
}
export function getSig(item: UnifiedMatchResult) {
return item.resultType === 'FUTURE_AVAILABILITY'
? (item as FutureAvailabilityResult).signal
: null
}
export const RISK_LEVEL_ORDER: Record<string, number> = { CRITICAL: 0, HIGH: 1, MEDIUM: 2, LOW: 3 }
export const CRITERION_ALIASES: Record<WeightingKey, string[]> = {
area: ['area', 'Fläche', 'fläche'],
location: ['location', 'Standort', 'standort'],
budget: ['budget', 'Budget', 'Mietpreis', 'mietpreis'],
timing: ['timing', 'Verfügbarkeit', 'verfügbarkeit'],
prestige: ['prestige', 'Prestige'],
accessibility: ['accessibility', 'ÖV-Anbindung', 'ÖV', 'Erreichbarkeit'],
expansionPotential:['expansionPotential', 'Expansionspotenzial'],
flexibility: ['flexibility', 'Flexibilität'],
visibility: ['visibility', 'Sichtbarkeit', 'visibilityScore'],
footfall: ['footfall', 'Passantenfrequenz', 'passerbyFrequency'],
talentAccess: ['talentAccess', 'Talent-Zugang', 'Talente'],
esg: ['esg', 'ESG', 'Nachhaltigkeit'],
taxEnvironment: ['taxEnvironment', 'Steuerlast', 'Steuerumfeld'],
}
export function getTitle(item: UnifiedMatchResult): string {
const prop = getProp(item)
const sig = getSig(item)
return prop?.title ?? sig?.companyName ?? sig?.locationHint ?? item.matchId.slice(0, 8)
}
// ── Row label cell ────────────────────────────────────────────────────────────
export const LABEL_SX = {
position: 'sticky' as const,
left: 0,
bgcolor: 'white',
zIndex: 1,
width: 200,
minWidth: 200,
color: '#64748b',
fontSize: 13,
fontWeight: 600,
borderRight: '1px solid #e2e8f0',
verticalAlign: 'top',
py: 1.5,
}
export const DATA_SX = {
borderLeft: '1px solid #f1f5f9',
minWidth: 220,
verticalAlign: 'top',
py: 1.5,
}
// ── Score bar helper ──────────────────────────────────────────────────────────
export function scoreBar(value: number, label?: string): ReactNode {
const color = dataQualityHex(value)
return (
<Box sx={{ display: 'flex', alignItems: 'center', gap: 1 }}>
<Box sx={{ width: 70 }}>
<LinearProgress variant="determinate" value={value * 100}
sx={{ height: 6, borderRadius: 3, '& .MuiLinearProgress-bar': { bgcolor: color } }} />
</Box>
<Typography variant="caption" sx={{ color }}>{label ?? `${Math.round(value * 100)}%`}</Typography>
</Box>
)
}