/** * Single duty row: event type label, name, time range. * Used inside timeline cards and day detail. Ported from webapp/js/dutyList.js dutyItemHtml. */ "use client"; import { useTranslation } from "@/i18n/use-translation"; import { formatHHMM, formatDateKey } from "@/lib/date-utils"; import { cn } from "@/lib/utils"; import type { DutyWithUser } from "@/types"; export interface DutyItemProps { duty: DutyWithUser; /** Override type label (e.g. "On duty now"). */ typeLabelOverride?: string; /** Show "until HH:MM" instead of full range (for current duty). */ showUntilEnd?: boolean; /** Extra class, e.g. for current duty highlight. */ isCurrent?: boolean; className?: string; } const borderByType = { duty: "border-l-duty", unavailable: "border-l-unavailable", vacation: "border-l-vacation", } as const; /** * Renders type badge, name, and time. Timeline cards use event_type for border color. */ export function DutyItem({ duty, typeLabelOverride, showUntilEnd = false, isCurrent = false, className, }: DutyItemProps) { const { t } = useTranslation(); const typeLabel = typeLabelOverride ?? t(`event_type.${duty.event_type || "duty"}`); const eventType = (duty.event_type || "duty") as keyof typeof borderByType; const borderClass = isCurrent ? "border-l-today" : borderByType[eventType] ?? "border-l-duty"; let timeOrRange: string; if (showUntilEnd && duty.event_type === "duty") { timeOrRange = t("duty.until", { time: formatHHMM(duty.end_at) }); } else if (duty.event_type === "vacation" || duty.event_type === "unavailable") { const startStr = formatDateKey(duty.start_at); const endStr = formatDateKey(duty.end_at); timeOrRange = startStr === endStr ? startStr : `${startStr} – ${endStr}`; } else { timeOrRange = `${formatHHMM(duty.start_at)} – ${formatHHMM(duty.end_at)}`; } return (
{typeLabel} {duty.full_name} {timeOrRange}
); }