9f391d17cb
- 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>
96 lines
2.4 KiB
TypeScript
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>
|
|
)
|
|
}
|