'use client';
/**
* DeliveryTable — bordered card containing one `` per
* item. Visual rendering of each row lives in `delivery-row.tsx` so the
* exact same primitive can be composed elsewhere (notably the linked-
* delivery surface inside ``).
*
* Props:
* - `items` — flat list of `DeliveryItem`. Two buckets (completed +
* in-progress) are rendered as two separate `DeliveryTable`s by
* the parent `DeliveryLists`.
* - `isLoading` — skeleton rows.
* - `focusId` — `?focus=` URL param. Marks the matching row
* `id="delivery-"` and applies the highlight ring so the
* deep-link from a ticket's linked-card scrolls + flashes the
* right row.
*/
import { DeliveryRow } from './delivery-row';
import type { DeliveryItem } from '../../../types/delivery';
import { devSectionAnchorId } from '../../../utils/dev-sections/dev-section-param-keys';
interface DeliveryTableProps {
items: DeliveryItem[];
isLoading?: boolean;
}
/**
* Skeleton loader for rows - matching responsive structure
*/
function SkeletonRow() {
return (
{/* Left: Title, subtitle, and description skeleton */}
{/* Title skeleton - responsive */}
{/* Subtitle skeleton - 1 line */}
{/* Description skeleton - 3 lines */}
{/* Right: Badge skeleton - two stacked badges */}
);
}
/**
* DeliveryTable Component
* Displays bug fixes and enhancements with fixed-height rows
*/
export function DeliveryTable({ items, isLoading = false }: DeliveryTableProps) {
// Show skeletons while loading
if (isLoading) {
return (
{[1, 2, 3, 4, 5].map((i) => (
))}
);
}
// Empty state
if (items.length === 0) {
return (
No tasks available
);
}
return (
{items.map((item) => (
// DOM id lives on DeliveryRow's own outer element (no wrapper
// div). Anchor mirrors `buildDevSectionUrl('delivery', )`
// → `#delivery-`; `useScrollToHash` in
// `delivery-lists.tsx` finds the row by id and scrolls. The
// outer wrapper here ONLY exists for the row separators.