Files
property-match/src/components/match-center/MatchBriefingPanel.tsx
T
Benjamin Sutter e36c5bc979 refactor(arch): eliminate direct service calls in components — route all through hooks
New hook files:
- useAuth.ts: useLogin, useSwitchDemoRole, useSwitchOrganization
- useAI.ts: useParseNeed, useGenerateOfferEmail, useGenerateDecisionBrief, useParseListingText
- useAssistant.ts: useAssistantSuggestions (useQuery), useAssistantAnswer (useMutation)
- useOfferReport.ts: useOfferReportByInquiry, useCreateOfferReport, useUpdateOfferReport, useGenerateOfferReportPdf
- useInquiryReport.ts: useInquiryReportByInquiry, useCreateInquiryReport, useUpdateInquiryReport, useFinalizeInquiryReport
- useMarketReport.ts: useMarketReport
- useWeighting.ts: useDefaultWeights (synchronous wrapper)
- useUnitMatches.ts: useUnitMatchesMap, useUnitBundle, useBundleMatches (useMemo wrappers)

Extended hooks: useProperties (add update/create/remove mutations),
useNeeds (add useCreateNeed), useMatches (add useNeedMatchesForProperty,
useAdditionalMatchesForInquiry), useReviewQueue (add useCreateReviewTask)

Updated 21 components/pages: all direct service imports replaced with hooks.
Deliberate exception: getRecommendedActions in DataQuality.tsx (pure sync utility, no provider access).

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

98 lines
3.5 KiB
TypeScript

import { Box, CircularProgress, Typography } from '@mui/material'
import { useNavigate } from 'react-router'
import { useMatchesByProperty, useApproveMatch } from '../../hooks/useMatches'
import { usePropertyById } from '../../hooks/useProperties'
import { useCreateReviewTask } from '../../hooks/useReviewQueue'
import { useMatchCenterStore } from '../../stores/matchCenterStore'
import { useCompareStore } from '../../stores/compareStore'
import { useToastStore } from '../../stores/toastStore'
import { MatchCardExpanded } from '../match-card/MatchCardExpanded'
import { buildMatchCardViewModel } from '../../features/matching/matchCardAdapter'
import { MatchCenterEmptyState } from './MatchCenterEmptyState'
import { MatchStatusBadge } from './MatchStatusBadge'
import type { MatchCardAction } from '../match-card/MatchCardViewModel'
import type { VerifiedPortfolioResult } from '../../domain/unifiedResult'
export function MatchBriefingPanel() {
const navigate = useNavigate()
const { selectedPropertyId, selectedNeedId } = useMatchCenterStore()
const { addToCompare } = useCompareStore()
const approveMatch = useApproveMatch()
const createReviewTask = useCreateReviewTask()
const showToast = useToastStore((s) => s.showToast)
const { data: matches = [], isLoading: matchesLoading } = useMatchesByProperty(selectedPropertyId ?? '')
const { data: property = null, isLoading: propLoading } = usePropertyById(selectedPropertyId)
if (!selectedPropertyId && !selectedNeedId) return <MatchCenterEmptyState context="select-both" />
if (selectedPropertyId && !selectedNeedId) return <MatchCenterEmptyState context="no-need" />
if (!selectedPropertyId && selectedNeedId) return <MatchCenterEmptyState context="no-property" />
if (matchesLoading || propLoading) {
return (
<Box sx={{ display: 'flex', justifyContent: 'center', py: 8 }}>
<CircularProgress />
</Box>
)
}
const match = matches.find(m => m.needId === selectedNeedId) ?? null
if (!match || !property) return <MatchCenterEmptyState context="no-match" />
const result: VerifiedPortfolioResult = {
resultType: 'VERIFIED_PORTFOLIO',
matchId: match.id,
needId: match.needId,
matchScore: match.matchScore,
match,
property,
}
const actions: MatchCardAction[] = [
{
id: 'approve',
label: 'Genehmigen',
actionType: 'APPROVE',
variant: 'primary',
onClick: () => approveMatch.mutate(match.id, {
onSuccess: () => showToast('Match genehmigt.'),
onError: () => showToast('Genehmigung fehlgeschlagen.', 'error'),
}),
},
{
id: 'review',
label: 'Zur Prüfung',
actionType: 'SEND_REVIEW',
variant: 'secondary',
onClick: () => { createReviewTask.mutate(match.id) },
},
{
id: 'compare',
label: 'Vergleichen',
actionType: 'ADD_COMPARE',
variant: 'secondary',
onClick: () => { addToCompare(result); navigate('/demand/compare') },
},
{
id: 'details',
label: 'Details',
actionType: 'OPEN_DETAIL',
variant: 'secondary',
onClick: () => navigate(`/demand/results/${match.id}`),
},
]
const vm = buildMatchCardViewModel(result, actions)
return (
<Box sx={{ overflowY: 'auto', flex: 1, p: 2.5 }}>
<Box sx={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', mb: 2 }}>
<Typography variant="h6" sx={{ fontWeight: 700 }}>Match-Briefing</Typography>
<MatchStatusBadge status={match.status} />
</Box>
<MatchCardExpanded vm={vm} />
</Box>
)
}