Files
property-match/.claude/worktrees/agent-a82a3716/src/components/future-signals/FutureSignalCard.tsx
T
Benjamin Sutter d15a13e485 feat: remove Administration workspace — keep only Verwaltung + Suche
- Delete all ops page components (ReviewQueue, AIMonitoring, Governance,
  SourceMonitoring, ActivityTimeline, SignalPipeline)
- Remove OPERATIONS workspace from AppShell config, nav order, path detection
- Remove all /ops/* routes from App.tsx
- Remove WorkspaceType.OPERATIONS from allowedWorkspaces in authService,
  sessionStore, permissions
- Keep MarketIntelligence page (already moved to /supply/market-intelligence)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-19 20:32:41 +02:00

102 lines
3.6 KiB
TypeScript

import { Box, Chip, LinearProgress, Typography } from '@mui/material'
import { SignalTypeBadge } from './SignalTypeBadge'
import { SensitivityBadge } from './SensitivityBadge'
import { SignalReviewStatusBadge } from './SignalReviewStatusBadge'
import { FutureSignalDisclaimer } from './FutureSignalDisclaimer'
import type { FutureSignal } from '../../domain/futureSignal'
const SOURCE_LABELS: Record<string, string> = {
PRESS: 'Presse',
CONSTRUCTION_PERMIT: 'Baubewilligung',
JOB_POSTING: 'Stelleninserat',
COMPANY_REPORT: 'Geschäftsbericht',
MARKET_DATA: 'Marktdaten',
MANUAL: 'Manuell',
}
function probColor(p: number): string {
return p >= 0.7 ? '#1a7a4a' : p >= 0.5 ? '#d97706' : '#c0392b'
}
interface Props {
signal: FutureSignal
isSelected: boolean
onSelect: (signal: FutureSignal) => void
}
export function FutureSignalCard({ signal, isSelected, onSelect }: Props) {
const isConfidential = signal.sensitivityLevel === 'CONFIDENTIAL'
return (
<Box
onClick={() => onSelect(signal)}
sx={{
p: 2,
cursor: 'pointer',
borderBottom: '1px solid #f1f5f9',
borderLeft: isSelected
? '3px solid #1e3a5f'
: isConfidential
? '3px solid #d97706'
: '3px solid transparent',
bgcolor: isSelected ? '#eff6ff' : isConfidential ? '#fffbeb' : 'transparent',
'&:hover': { bgcolor: isSelected ? '#eff6ff' : '#f8fafc' },
}}
>
{/* Row 1: type + sensitivity + review status */}
<Box sx={{ display: 'flex', flexWrap: 'wrap', gap: 0.5, mb: 1 }}>
<SignalTypeBadge type={signal.signalType} />
<SensitivityBadge level={signal.sensitivityLevel} />
<SignalReviewStatusBadge status={signal.reviewStatus} />
</Box>
{/* Row 2: title / company / location */}
<Typography variant="body2" sx={{ fontWeight: 600, mb: 0.25 }}>
{signal.title ?? signal.companyName ?? signal.locationHint}
</Typography>
{(signal.title || signal.companyName) && (
<Typography variant="caption" color="text.secondary" sx={{ display: 'block', mb: 0.75 }}>
{signal.locationHint}
</Typography>
)}
{/* Row 3: probability */}
<Box sx={{ mb: 0.75 }}>
<Box sx={{ display: 'flex', justifyContent: 'space-between', mb: 0.25 }}>
<Typography variant="caption" color="text.secondary">Wahrscheinlichkeit</Typography>
<Typography variant="caption" sx={{ fontWeight: 700, color: probColor(signal.probability) }}>
{Math.round(signal.probability * 100)}%
</Typography>
</Box>
<LinearProgress
variant="determinate"
value={signal.probability * 100}
sx={{
height: 4,
borderRadius: 2,
bgcolor: '#f1f5f9',
'& .MuiLinearProgress-bar': { bgcolor: probColor(signal.probability) },
}}
/>
</Box>
{/* Row 4: meta chips */}
<Box sx={{ display: 'flex', flexWrap: 'wrap', gap: 0.5, mb: 1 }}>
<Chip label={`${signal.timeHorizonMonths}M`} size="small" sx={{ fontSize: 10, height: 18 }} />
{signal.areaSqmEstimate && (
<Chip label={`~${signal.areaSqmEstimate.toLocaleString('de-CH')}`} size="small" sx={{ fontSize: 10, height: 18 }} />
)}
<Chip
label={SOURCE_LABELS[signal.source.type] ?? signal.source.type}
size="small"
variant="outlined"
sx={{ fontSize: 10, height: 18 }}
/>
</Box>
{/* Footer: mini disclaimer */}
<FutureSignalDisclaimer mini />
</Box>
)
}