import type { ReactNode } from "react"; import { Box, Button, Group, Paper, Stack, Text } from "@mantine/core"; import type { LucideIcon } from "lucide-react"; import { AlertTriangle, CheckCircle2, Clock, LayoutList, Plus, RefreshCw, } from "lucide-react"; import { MiniRing, MiniSparkline } from "@/components/common/MiniGraph"; import { ACCENT_CHIP_BG } from "@/components/overview/OverviewKpiCard"; import { overviewAccentGradients, type OverviewAccent, } from "@/components/overview/overview.styles"; import type { BookingListSummaryMetrics, BookingListSummaryTabs, } from "@/services/bookings.service"; /** Lifecycle stages for the pipeline distribution bar (in flow order). */ const PIPELINE_STAGES: Array<{ key: keyof BookingListSummaryTabs; label: string; color: string; }> = [ { key: "intake", label: "Intake", color: "#38bdf8" }, { key: "in_approval", label: "Approval", color: "#f59e0b" }, { key: "approved_contract", label: "Contract", color: "#8b5cf6" }, { key: "payment", label: "Payment", color: "#fb923c" }, { key: "operations", label: "Operations", color: "#14b8a6" }, { key: "completed", label: "Completed", color: "#22c55e" }, ]; const CARD_STYLE = { background: "var(--mantine-color-gray-0)", border: "1px solid var(--mantine-color-gray-2)", } as const; export interface BookingRequestsHeaderProps { metrics?: BookingListSummaryMetrics; tabs?: BookingListSummaryTabs; loading?: boolean; isFetching?: boolean; onCreate: () => void; onRefresh: () => void; } export function BookingRequestsHeader({ metrics, tabs, loading, isFetching, onCreate, onRefresh, }: BookingRequestsHeaderProps) { const val = (n?: number) => (loading ? "—" : (n ?? 0)); return ( {/* {tabs ? : null} */} ); } /** * KPI card matching the overview style: icon chip + value + label, with a mini * graph at the bottom. Ratio cards show a ring; the rest show an area/line trend. */ function HeroStat({ icon: Icon, label, value, hint, ratio, accent = "emerald", variant = "area", }: { icon: LucideIcon; label: string; value: ReactNode; hint?: string; ratio?: number; accent?: OverviewAccent; variant?: "area" | "line"; }) { const [, accentDeep] = overviewAccentGradients[accent] ?? overviewAccentGradients.default; const chipBg = ACCENT_CHIP_BG[accent] ?? ACCENT_CHIP_BG.default; const pct = ratio != null ? Math.round(Math.min(1, Math.max(0, ratio)) * 100) : null; return ( {value} {label} {hint ? ` · ${pct != null ? `${pct}% of queue` : hint}` : ""} {pct != null ? ( {pct}% ) : null} {pct == null ? ( ) : null} ); } function PipelineBar({ tabs }: { tabs: BookingListSummaryTabs }) { const segments = PIPELINE_STAGES.map((s) => ({ ...s, count: tabs[s.key] ?? 0 })); const total = segments.reduce((sum, s) => sum + s.count, 0); return ( Booking pipeline {total} active {total > 0 ? ( segments.map((s) => s.count > 0 ? ( ) : null, ) ) : ( )} {segments.map((s) => ( {s.label} {s.count} ))} ); }