refactor: split AppShell, match-detail panels, extract useCompareData
AppShell.tsx: 627→116 lines - appShellConfig.ts: NavItem/WorkspaceConfig types, WORKSPACE_CONFIG, nav helpers - AppShellSidebar.tsx: Sidebar component with visual constants - AppShellTopBar.tsx: TopBar component Match-detail panels: - ScoreBreakdownPanel: 377→303 lines (scoreBreakdownConstants.ts + CriterionRow.tsx extracted) - LocationIntelligencePanel: 383→333 lines (SoftFactorBar.tsx extracted) - FutureAvailabilityContextPanel: 386→351 lines (futureAvailabilityConstants.tsx extracted) Compare.tsx: 485→441 lines - useCompareData hook: all queries and derived state extracted to hooks/useCompareData.ts Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,81 @@
|
||||
import { useQuery } from '@tanstack/react-query'
|
||||
import type { UnifiedMatchResult } from '../domain/unifiedResult'
|
||||
import { WEIGHTING_KEYS, WEIGHTING_LABELS } from '../domain/needBuilder'
|
||||
import type { WeightingKey } from '../domain/needBuilder'
|
||||
import { aiService } from '../services/aiService'
|
||||
import { needService } from '../services/needService'
|
||||
import { CRITERION_ALIASES, getProp } from '../components/compare/compareUtils'
|
||||
|
||||
export function useCompareData(compareItems: UnifiedMatchResult[]) {
|
||||
const { data: aiSummary, isLoading: aiLoading } = useQuery({
|
||||
queryKey: ['ai-compare', compareItems.map(i => i.matchId)],
|
||||
queryFn: () => aiService.summarizeComparison(compareItems),
|
||||
enabled: compareItems.length >= 2,
|
||||
select: r => r.data,
|
||||
staleTime: Infinity,
|
||||
})
|
||||
|
||||
const { data: needsData } = useQuery({
|
||||
queryKey: ['needs'],
|
||||
queryFn: () => needService.getAll(),
|
||||
select: r => r.data,
|
||||
})
|
||||
|
||||
const activeNeed = needsData
|
||||
? [...needsData].sort((a, b) => new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime())[0]
|
||||
: undefined
|
||||
|
||||
const relevantCriteria = activeNeed
|
||||
? WEIGHTING_KEYS
|
||||
.map(key => ({ key, label: WEIGHTING_LABELS[key], weight: activeNeed.weightingProfile[key] ?? 0 }))
|
||||
.filter(c => c.weight > 0)
|
||||
.sort((a, b) => b.weight - a.weight)
|
||||
: []
|
||||
|
||||
const weightedTotals = compareItems.map(item =>
|
||||
relevantCriteria.reduce((sum, { key, weight }) => {
|
||||
const factor = [...item.match.positiveFactors, ...item.match.negativeFactors]
|
||||
.find(f => CRITERION_ALIASES[key as WeightingKey].some(a => a.toLowerCase() === f.criterion.toLowerCase()))
|
||||
return sum + (factor?.score ?? 50) * weight
|
||||
}, 0)
|
||||
)
|
||||
const maxWeightedTotal = Math.max(...weightedTotals)
|
||||
const overallWinnerIdx = compareItems.length > 1 && weightedTotals.filter(t => t === maxWeightedTotal).length === 1
|
||||
? weightedTotals.indexOf(maxWeightedTotal)
|
||||
: -1
|
||||
|
||||
const bestScoreIdx = compareItems.length > 0
|
||||
? compareItems.reduce(
|
||||
(best, item, i) => item.matchScore > compareItems[best].matchScore ? i : best, 0
|
||||
)
|
||||
: -1
|
||||
|
||||
const worstConfIdx = compareItems.length > 0
|
||||
? compareItems.reduce(
|
||||
(worst, item, i) => item.match.confidenceLevel < compareItems[worst].match.confidenceLevel ? i : worst, 0
|
||||
)
|
||||
: -1
|
||||
|
||||
const dqScores = compareItems.map(item => getProp(item)?.dataQuality.score ?? 1)
|
||||
const worstDQIdx = dqScores.length > 0 ? dqScores.indexOf(Math.min(...dqScores)) : -1
|
||||
|
||||
const missingCriticalCounts = compareItems.map(
|
||||
item => item.match.missingData?.filter(m => m.importance === 'CRITICAL').length ?? 0
|
||||
)
|
||||
const maxMissingCritical = missingCriticalCounts.length > 0 ? Math.max(...missingCriticalCounts) : 0
|
||||
|
||||
return {
|
||||
aiSummary,
|
||||
aiLoading,
|
||||
activeNeed,
|
||||
relevantCriteria,
|
||||
weightedTotals,
|
||||
overallWinnerIdx,
|
||||
bestScoreIdx,
|
||||
worstConfIdx,
|
||||
dqScores,
|
||||
worstDQIdx,
|
||||
missingCriticalCounts,
|
||||
maxMissingCritical,
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user