refactor: consolidate duplicated UI score/color/badge logic into lib/

- Add matchScoreHex(), criterionScoreColor(), criterionScoreTextColor() to lib/utils.ts
- Add RESULT_TYPE_META (labels + colors) to lib/ds.ts as single source of truth
- Remove 5 local scoreColor() functions: StrongMatchMiniCard, MatchListCard,
  pipelineUtils (re-exported as matchScoreHex), CriterionRow, ScoreBreakdownPanel,
  ScoreInlineBreakdown
- Remove local RESULT_TYPE_META/TYPE_META from MatchCardHeader, ResultTypeBadge;
  remove RESULT_TYPE_LABEL/COLOR from pipelineConstants — all now use lib/ds.ts
- Replace local confidenceColor() in MatchCardHeader, ConfidenceFieldBadge,
  ReliabilityScorePanel with confidenceHex() from lib/utils.ts
- Replace local qualityColor() in propertyHelpers, DataQualityWidget with
  dataQualityColor() from lib/utils.ts
- Fix FUTURE_AVAILABILITY label inconsistency ('Future'/'Zukunft' → 'Zukunftssignal')
- Fix EXTERNAL_MARKET label inconsistency ('Direktinserat' → 'Plattform')
- tsc --noEmit passes with zero errors

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Benjamin Sutter
2026-05-24 01:47:08 +02:00
parent 5d53f35dea
commit 86bdf142b4
16 changed files with 60 additions and 138 deletions
+3 -10
View File
@@ -1,19 +1,12 @@
import { Box, LinearProgress, Typography } from '@mui/material'
import type { ScoreFactor } from '../../domain/match'
import { factorLabel, importanceLabel } from './scoreBreakdownConstants'
function scoreColor(v: number): 'success' | 'warning' | 'error' {
return v >= 70 ? 'success' : v >= 50 ? 'warning' : 'error'
}
function scoreTextColor(v: number): string {
return v >= 70 ? '#1a7a4a' : v >= 50 ? '#d97706' : '#c0392b'
}
import { criterionScoreColor, criterionScoreTextColor } from '../../lib/utils'
export function CriterionRow({ factor, maxWeight }: { factor: ScoreFactor; maxWeight: number }) {
const label = factorLabel(factor.criterion)
const pct = Math.round(factor.weight * 100)
const color = scoreColor(factor.score)
const color = criterionScoreColor(factor.score)
const imp = importanceLabel(factor.weight, maxWeight)
return (
@@ -34,7 +27,7 @@ export function CriterionRow({ factor, maxWeight }: { factor: ScoreFactor; maxWe
</Typography>
</Box>
<Box sx={{ display: 'flex', alignItems: 'baseline', gap: 1 }}>
<Typography variant="caption" sx={{ fontWeight: 700, color: scoreTextColor(factor.score) }}>
<Typography variant="caption" sx={{ fontWeight: 700, color: criterionScoreTextColor(factor.score) }}>
{factor.score}/100
</Typography>
<Typography variant="caption" sx={{ color: '#64748b', fontSize: '0.68rem', minWidth: 44, textAlign: 'right' }}>
@@ -5,16 +5,7 @@ import type { Match } from '../../domain/match'
import type { FutureSignal } from '../../domain/futureSignal'
import { CREDIBILITY_LABELS, HARD_KEYS, factorLabel } from './scoreBreakdownConstants'
import { CriterionRow } from './CriterionRow'
// ── Shared helpers ─────────────────────────────────────────────────────────────
function scoreColor(v: number): 'success' | 'warning' | 'error' {
return v >= 70 ? 'success' : v >= 50 ? 'warning' : 'error'
}
function scoreTextColor(v: number): string {
return v >= 70 ? '#1a7a4a' : v >= 50 ? '#d97706' : '#c0392b'
}
import { criterionScoreColor, criterionScoreTextColor } from '../../lib/utils'
// ── Standard breakdown (VERIFIED_PORTFOLIO / EXTERNAL / MAISON) ──────────────
@@ -135,7 +126,7 @@ function StandardBreakdown({ match, taxCalculatorUrl }: StandardBreakdownProps)
<Typography variant="subtitle1" sx={{ fontWeight: 700 }}>Gesamt-Score</Typography>
<Typography
variant="h4"
sx={{ fontWeight: 800, color: scoreTextColor(Math.round(baseSum)) }}
sx={{ fontWeight: 800, color: criterionScoreTextColor(Math.round(baseSum)) }}
>
{baseSum}/100
</Typography>
@@ -188,13 +179,13 @@ function SignalScoreDerivation({ match, signal }: SignalScoreDerivationProps) {
}
<Box sx={{ flex: 1, display: 'flex', justifyContent: 'space-between', alignItems: 'baseline' }}>
<Typography variant="caption" sx={{ fontWeight: 600, color: '#1e293b' }}>{factorLabel(f.criterion)}</Typography>
<Typography variant="caption" sx={{ fontWeight: 700, color: scoreTextColor(f.score), ml: 1 }}>{f.score}/100</Typography>
<Typography variant="caption" sx={{ fontWeight: 700, color: criterionScoreTextColor(f.score), ml: 1 }}>{f.score}/100</Typography>
</Box>
</Box>
<LinearProgress
variant="determinate"
value={f.score}
color={scoreColor(f.score)}
color={criterionScoreColor(f.score)}
sx={{ height: 5, borderRadius: 3, mb: 0.35, ml: 2.25 }}
/>
<Typography variant="caption" color="text.secondary" sx={{ display: 'block', ml: 2.25, lineHeight: 1.3 }}>
@@ -266,7 +257,7 @@ function SignalScoreDerivation({ match, signal }: SignalScoreDerivationProps) {
<Typography variant="subtitle1" sx={{ fontWeight: 700 }}>Gesamt-Score</Typography>
<Typography
variant="h4"
sx={{ fontWeight: 800, color: scoreTextColor(sb.totalScore) }}
sx={{ fontWeight: 800, color: criterionScoreTextColor(sb.totalScore) }}
>
{sb.totalScore}/100
</Typography>