"use client"; import type { TimelineDemandEntry } from "./TimelineContext.js"; import { formatCents, formatDateLong } from "~/lib/format.js"; import { useViewportPopover } from "~/hooks/useViewportPopover.js"; interface DemandPopoverProps { demand: TimelineDemandEntry; onClose: () => void; onOpenPanel: (projectId: string) => void; onFillDemand: (demand: TimelineDemandEntry) => void; anchorX: number; anchorY: number; } export function DemandPopover({ demand, onClose, onOpenPanel, onFillDemand, anchorX, anchorY, }: DemandPopoverProps) { const { ref, style } = useViewportPopover({ anchor: { kind: "point", x: anchorX, y: anchorY }, width: 300, estimatedHeight: 340, onClose, }); const roleName = demand.roleEntity?.name ?? demand.role ?? "Unspecified"; const roleColor = demand.roleEntity?.color ?? "#f59e0b"; const startDate = new Date(demand.startDate); const endDate = new Date(demand.endDate); const days = Math.max(1, Math.round((endDate.getTime() - startDate.getTime()) / 86_400_000) + 1); const totalHours = demand.hoursPerDay * days; const budgetCents = demand.dailyCostCents * days; return (
{/* Header */}
{roleName}
{/* Project */}
Project:{" "} {demand.project.name} {" "} ({demand.project.shortCode})
{/* Status badge */}
Open Demand {demand.status}
{/* Headcount */}
Requested
{demand.requestedHeadcount} {demand.requestedHeadcount === 1 ? "person" : "people"}
Unfilled
{demand.unfilledHeadcount} remaining
{/* Date range */}
Start
{formatDateLong(startDate)}
End
{formatDateLong(endDate)}
{/* Hours */}
Hours / day
{demand.hoursPerDay}h
Total hours
{totalHours}h ({days}d)
{/* Budget */} {budgetCents > 0 && ( <>
Daily cost
{formatCents(demand.dailyCostCents)} EUR
Total cost
{formatCents(budgetCents)} EUR
)} {/* Percentage */} {demand.percentage > 0 && (
Percentage
{demand.percentage}%
)}
{/* Actions */}
{demand.unfilledHeadcount > 0 && ( )}
); }