Implements the five section components consumed by the HQ page: - HQWaitingForInputSection, HQNeedsReviewSection, HQNeedsApprovalSection, HQBlockedSection, HQEmptyState with typed props from RouterOutputs. - Shared types.ts defines the 5 item types from getHeadquartersDashboard. - Adds RouterOutputs export to trpc.ts via inferRouterOutputs<AppRouter>. - 22 unit tests verify rendering, navigation CTAs, truncation, and edge cases. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
66 lines
2.1 KiB
TypeScript
66 lines
2.1 KiB
TypeScript
import { useNavigate } from '@tanstack/react-router'
|
|
import { Card } from '@/components/ui/card'
|
|
import { Button } from '@/components/ui/button'
|
|
import {
|
|
Tooltip,
|
|
TooltipTrigger,
|
|
TooltipContent,
|
|
TooltipProvider,
|
|
} from '@/components/ui/tooltip'
|
|
import { formatRelativeTime } from '@/lib/utils'
|
|
import type { WaitingForInputItem } from './types'
|
|
|
|
interface Props {
|
|
items: WaitingForInputItem[]
|
|
}
|
|
|
|
export function HQWaitingForInputSection({ items }: Props) {
|
|
const navigate = useNavigate()
|
|
|
|
return (
|
|
<div className="space-y-3">
|
|
<h2 className="text-sm font-medium text-muted-foreground uppercase tracking-wide">
|
|
Waiting for Input
|
|
</h2>
|
|
<div className="space-y-2">
|
|
{items.map((item) => {
|
|
const truncated =
|
|
item.questionText.slice(0, 120) +
|
|
(item.questionText.length > 120 ? '…' : '')
|
|
|
|
return (
|
|
<Card key={item.agentId} className="p-4 flex items-center justify-between gap-4">
|
|
<div className="min-w-0 flex-1">
|
|
<p className="font-bold text-sm">
|
|
{item.agentName}
|
|
{item.initiativeName && (
|
|
<span className="font-normal text-muted-foreground"> · {item.initiativeName}</span>
|
|
)}
|
|
</p>
|
|
<TooltipProvider>
|
|
<Tooltip>
|
|
<TooltipTrigger asChild>
|
|
<p className="text-sm text-muted-foreground truncate">{truncated}</p>
|
|
</TooltipTrigger>
|
|
<TooltipContent forceMount>{item.questionText}</TooltipContent>
|
|
</Tooltip>
|
|
</TooltipProvider>
|
|
<p className="text-xs text-muted-foreground">
|
|
waiting {formatRelativeTime(item.waitingSince)}
|
|
</p>
|
|
</div>
|
|
<Button
|
|
variant="outline"
|
|
size="sm"
|
|
onClick={() => navigate({ to: '/inbox' })}
|
|
>
|
|
Answer
|
|
</Button>
|
|
</Card>
|
|
)
|
|
})}
|
|
</div>
|
|
</div>
|
|
)
|
|
}
|