refactor: split large page components + taxonomy/HeatBadge/FutureAvailability improvements

- Taxonomy: merge VERIFIED_PORTFOLIO + EXTERNAL_MARKET display → 'Plattform' (dark blue) across all surfaces
- HeatBadge: new flame indicator for hot properties (grid, list, pipeline views)
- FutureAvailabilityContextPanel: richer detail page with AI summary, strategic assessment, sources
- Refactor Pipeline.tsx (630→152 lines) → pipeline/PipelineCard, PipelineColumn, PipelineDetailPanel, pipelineConstants, pipelineUtils
- Refactor IntelligenceMatchCard.tsx (483→179 lines) → FutureAvailabilityCard extracted
- Refactor MatchDetail.tsx (559→464 lines) → useMatchDetailData hook, MatchDetailPropertyDetails
- Refactor Compare.tsx (638→485 lines) → compareUtils, CompareCriteriaCard extracted

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Benjamin Sutter
2026-05-23 23:36:03 +02:00
parent 72e4f08900
commit 22c195b4a5
28 changed files with 1615 additions and 1282 deletions
+3 -3
View File
@@ -66,9 +66,9 @@ export const ASSET_TYPE_LABELS: Record<string, string> = {
// Result type display labels
export const RESULT_TYPE_LABELS: Record<string, string> = {
VERIFIED_PORTFOLIO: 'Verified Portfolio',
EXTERNAL_MARKET: 'Direktinserat',
MAISON_WORK: 'Maison Work',
VERIFIED_PORTFOLIO: 'Plattform',
EXTERNAL_MARKET: 'Plattform',
MAISON_WORK: 'Maison Work',
FUTURE_AVAILABILITY: 'Zukunftssignal',
}
+1 -1
View File
@@ -7,7 +7,7 @@ import { CONF_HIGH, CONF_MEDIUM, DQ_HIGH, DQ_MEDIUM } from './constants'
export const DS_COLORS = {
resultType: {
VERIFIED_PORTFOLIO: { bg: 'rgba(30,58,95,0.10)', fg: '#1e3a5f' },
EXTERNAL_MARKET: { bg: 'rgba(180,83,9,0.10)', fg: '#b45309' },
EXTERNAL_MARKET: { bg: 'rgba(30,58,95,0.10)', fg: '#1e3a5f' },
MAISON_WORK: { bg: 'rgba(3,105,161,0.10)', fg: '#0369a1' },
FUTURE_AVAILABILITY: { bg: 'rgba(109,40,217,0.10)', fg: '#6d28d9' },
},
+42
View File
@@ -0,0 +1,42 @@
// Mock demand-heat data per property.
// In production: aggregated from cross-user pipeline additions, search impressions, and view counts.
export interface PropertyHeat {
searchCount: number // distinct active needs that matched this property
pipelineCount: number // pipeline entries across all users
viewCount: number // total detail-page opens
}
export const PROPERTY_HEAT: Record<string, PropertyHeat> = {
'prop-001': { searchCount: 7, pipelineCount: 4, viewCount: 52 },
'prop-007': { searchCount: 5, pipelineCount: 3, viewCount: 38 },
'prop-043': { searchCount: 9, pipelineCount: 2, viewCount: 61 },
'prop-012': { searchCount: 4, pipelineCount: 3, viewCount: 29 },
'prop-015': { searchCount: 6, pipelineCount: 2, viewCount: 44 },
'prop-003': { searchCount: 3, pipelineCount: 2, viewCount: 21 },
'prop-042': { searchCount: 4, pipelineCount: 1, viewCount: 33 },
'prop-044': { searchCount: 8, pipelineCount: 2, viewCount: 57 },
'prop-040': { searchCount: 5, pipelineCount: 2, viewCount: 31 },
'prop-002': { searchCount: 3, pipelineCount: 2, viewCount: 18 },
}
export type HeatLevel = 'HOT' | 'VERY_HOT' | null
export function getHeatLevel(propertyId: string | undefined): HeatLevel {
if (!propertyId) return null
const h = PROPERTY_HEAT[propertyId]
if (!h) return null
if (h.pipelineCount >= 3 || h.searchCount >= 7) return 'VERY_HOT'
if (h.pipelineCount >= 2 || h.searchCount >= 4) return 'HOT'
return null
}
export function heatTooltip(propertyId: string): string {
const h = PROPERTY_HEAT[propertyId]
if (!h) return ''
const parts: string[] = []
if (h.searchCount > 0) parts.push(`${h.searchCount} aktive Suchen`)
if (h.pipelineCount > 0) parts.push(`${h.pipelineCount}× in Pipeline`)
if (h.viewCount > 0) parts.push(`${h.viewCount} Aufrufe`)
return parts.join(' · ')
}