import * as React from 'react' import { cn } from '../../lib/utils' import { CalendarClock } from 'lucide-react' import { formatRelativeTime } from '../../utils' import { HealthCard, HealthDot } from './HealthCard' import { worstStatus, type HealthStatus } from './health-status' export type DeliveryState = 'on_time' | 'upcoming' | 'late' | 'missed' export interface DeliveryItem { label: string /** Explicit state; otherwise derived from due/delivered vs now. */ status?: DeliveryState dueAt?: string | Date | null deliveredAt?: string | Date | null } export interface DeliveryHealthProps { title?: string items: DeliveryItem[] /** Compare against this instant (injectable for tests); defaults to Date.now(). */ now?: number /** Cap the number of rows listed (summary counts still cover all). */ limit?: number emptyMessage?: string className?: string } const STATE_TONE: Record = { on_time: 'ok', upcoming: 'neutral', late: 'warn', missed: 'critical', } const STATE_LABEL: Record = { on_time: 'On time', upcoming: 'Upcoming', late: 'Late', missed: 'Missed', } function deriveState(item: DeliveryItem, now: number): DeliveryState { if (item.status) return item.status const due = item.dueAt ? new Date(item.dueAt).getTime() : null if (item.deliveredAt) { const delivered = new Date(item.deliveredAt).getTime() return due !== null && delivered > due ? 'late' : 'on_time' } if (due === null) return 'upcoming' return due < now ? 'missed' : 'upcoming' } /** * Delivery / schedule health: were scheduled deliverables (e.g. weekly briefs) * shipped on time? Missed/late deliveries drive the card critical/warn; upcoming * ones are informational. Presentational — a tenant widget derives states from a * type's scheduled_for / delivered_at fields. */ export function DeliveryHealth({ title = 'Delivery', items, now, limit, emptyMessage = 'Nothing scheduled.', className, }: DeliveryHealthProps) { const at = now ?? Date.now() const rows = items.map((it) => ({ ...it, state: deriveState(it, at) })) const counts = rows.reduce( (acc, r) => ((acc[r.state] += 1), acc), { on_time: 0, upcoming: 0, late: 0, missed: 0 } as Record, ) const status = worstStatus(rows.map((r) => STATE_TONE[r.state])) const problems = counts.late + counts.missed const statusLabel = items.length === 0 ? undefined : problems > 0 ? `${problems} off-track` : 'On track' const listed = limit ? rows.slice(0, limit) : rows return (
{(['on_time', 'late', 'missed', 'upcoming'] as DeliveryState[]) .filter((s) => counts[s] > 0) .map((s) => ( {counts[s]} {STATE_LABEL[s]} ))}
    {listed.map((row, i) => (
  • {row.label} {STATE_LABEL[row.state]} {row.deliveredAt ? ` · ${formatRelativeTime(row.deliveredAt)}` : row.dueAt ? ` · ${formatRelativeTime(row.dueAt)}` : ''}
  • ))}
) }