7b7be0b436
- dataQualityService with getPortfolioQualitySummary() - Service methods: getDashboardPropertiesSummary, getStrongMatches, getSignalSummary, getDashboardTasks added to respective services - dashboardService uses Promise.allSettled for partial error resilience - KpiCard: onClick + Tooltip support - KpiGrid: navigate actions and tooltips per card - StrongMatchMiniCard: Match Center, Prüfung, Vergleichen action buttons - FutureSignalWidget: time horizon distribution (0–6, 6–12, 12–24 Mo.) - SupplyDashboard: DashboardHeader, empty state, error state, partial widget errors, permission-based rendering per UserRole Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
62 lines
1.5 KiB
TypeScript
62 lines
1.5 KiB
TypeScript
import { Card, CardContent, CardActionArea, Chip, Tooltip, Typography } from '@mui/material'
|
|
import type { KpiCardData } from '../../domain/dashboard'
|
|
|
|
interface KpiCardProps {
|
|
card: KpiCardData
|
|
}
|
|
|
|
export function KpiCard({ card }: KpiCardProps) {
|
|
const trendColor =
|
|
card.trend === 'up' ? 'success' : card.trend === 'down' ? 'error' : 'default'
|
|
|
|
const content = (
|
|
<CardContent sx={{ p: 2.5 }}>
|
|
<Typography
|
|
variant="overline"
|
|
sx={{ color: 'text.secondary', lineHeight: 1.4, display: 'block' }}
|
|
>
|
|
{card.label}
|
|
</Typography>
|
|
<Typography variant="h4" sx={{ fontWeight: 700, mt: 0.5, mb: 0.5 }}>
|
|
{card.value}
|
|
</Typography>
|
|
{card.trendLabel && (
|
|
<Chip
|
|
label={card.trendLabel}
|
|
size="small"
|
|
color={trendColor as 'success' | 'error' | 'default'}
|
|
sx={{ mt: 0.5 }}
|
|
/>
|
|
)}
|
|
</CardContent>
|
|
)
|
|
|
|
const card_ = (
|
|
<Card
|
|
sx={{
|
|
borderTop: card.accent ? `4px solid ${card.accent}` : '4px solid transparent',
|
|
height: '100%',
|
|
cursor: card.onClick ? 'pointer' : 'default',
|
|
}}
|
|
>
|
|
{card.onClick ? (
|
|
<CardActionArea onClick={card.onClick} sx={{ height: '100%', alignItems: 'flex-start' }}>
|
|
{content}
|
|
</CardActionArea>
|
|
) : (
|
|
content
|
|
)}
|
|
</Card>
|
|
)
|
|
|
|
if (card.tooltip) {
|
|
return (
|
|
<Tooltip title={card.tooltip} placement="top" arrow>
|
|
<span style={{ display: 'contents' }}>{card_}</span>
|
|
</Tooltip>
|
|
)
|
|
}
|
|
|
|
return card_
|
|
}
|