Files
property-match/src/components/supply/ReminderKpiBar.tsx
T
Benjamin Sutter 9f391d17cb feat: Reminder Manager + Schattenmarkt-Freigabe + mock data overhaul
- Add Reminder Manager page (/supply/reminder-manager) with KPI bar,
  filter bar, list/card feed, and detail drawer (7 sections incl.
  activity log, snooze, complete, dismiss actions)
- Add Schattenmarkt-Freigabe toggle on PropertyDetailView: Verwaltung
  can opt-in properties for early market exposure before contract expiry
- Auto-generate FutureSignal cards via useSchattenmarktSignals hook
  when leaseEndDate - leadTimeMonths <= MOCK_TODAY
- Fix useUnifiedResults: use property.resultType as fallback (was
  defaulting everything to VERIFIED_PORTFOLIO)
- Fix demand Results: hide VERIFIED_PORTFOLIO from non-manager users
  even when showOwnProperties toggle was previously enabled
- Fix AppShell: redirect to allowed workspace on user role switch
- Fix 3 wrong match scores (match-002: 93→62, match-009: 86→55,
  match-017: 87→52)
- Add 7 new match records (match-050–056) for need-001, need-002,
  need-011
- Add need-011 (Retail Bern Innenstadt)
- Add prop-031–036 (EXTERNAL_MARKET / MAISON_WORK / FUTURE_AVAILABILITY)
- Fix duplicate image URLs across all properties
- Add signal-011 (Bern Altstadt, Mode Boutique) + propertyId to
  signal-001

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-20 11:52:24 +02:00

96 lines
2.4 KiB
TypeScript

import { Box, Paper, Typography, Skeleton } from '@mui/material'
import { AlertTriangle, Calendar, CalendarDays, Eye } from 'lucide-react'
import { useReminderInsights } from '../../hooks/useReminders'
interface KpiItemProps {
icon: React.ReactNode
label: string
value: number | string
color: string
}
function KpiItem({ icon, label, value, color }: KpiItemProps) {
return (
<Paper
variant="outlined"
sx={{
flex: 1,
p: 1.5,
display: 'flex',
alignItems: 'center',
gap: 1.5,
borderColor: '#e2e8f0',
minWidth: 0,
}}
>
<Box
sx={{
width: 36,
height: 36,
borderRadius: 1,
bgcolor: `${color}18`,
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
flexShrink: 0,
}}
>
{icon}
</Box>
<Box sx={{ minWidth: 0 }}>
<Typography variant="h6" sx={{ fontWeight: 700, color, lineHeight: 1.2, fontSize: '1.25rem' }}>
{value}
</Typography>
<Typography variant="caption" color="text.secondary" sx={{ whiteSpace: 'nowrap' }}>
{label}
</Typography>
</Box>
</Paper>
)
}
export function ReminderKpiBar() {
const { data, isLoading } = useReminderInsights()
if (isLoading) {
return (
<Box className="flex gap-3">
{[1, 2, 3, 4].map(i => (
<Skeleton key={i} variant="rounded" height={68} sx={{ flex: 1 }} />
))}
</Box>
)
}
const insights = data ?? { urgentCount: 0, dueThisWeek: 0, dueThisMonth: 0, schattenmarktReadyCount: 0 }
return (
<Box className="flex gap-3">
<KpiItem
icon={<AlertTriangle size={18} color="#dc2626" />}
label="Dringend"
value={insights.urgentCount}
color="#dc2626"
/>
<KpiItem
icon={<Calendar size={18} color="#ea580c" />}
label="Diese Woche"
value={insights.dueThisWeek}
color="#ea580c"
/>
<KpiItem
icon={<CalendarDays size={18} color="#0369a1" />}
label="Dieser Monat"
value={insights.dueThisMonth}
color="#0369a1"
/>
<KpiItem
icon={<Eye size={18} color="#be185d" />}
label="Schattenmarkt-Risiko"
value={insights.schattenmarktReadyCount}
color="#be185d"
/>
</Box>
)
}