Initial commit — Director app (API + UI)
This commit is contained in:
82
ui/src/components/DirectorQueue.tsx
Normal file
82
ui/src/components/DirectorQueue.tsx
Normal file
@@ -0,0 +1,82 @@
|
||||
import type { QueueItem } from '../lib/api'
|
||||
import { relativeTime, absoluteTime } from '../lib/time'
|
||||
|
||||
const statusColors: Record<string, string> = {
|
||||
pending_verification: 'text-yellow-600',
|
||||
ready_for_approval: 'text-blue-600 dark:text-blue-400',
|
||||
returned: 'text-red-600',
|
||||
approved: 'text-green-600',
|
||||
redirected: 'text-orange-600',
|
||||
}
|
||||
|
||||
function QueueItemCard({ item, onReview }: { item: QueueItem; onReview: () => void }) {
|
||||
return (
|
||||
<div className="group p-3 rounded-md border border-gray-200 dark:border-gray-700 bg-white dark:bg-gray-800 hover:border-gray-400 dark:hover:border-gray-500 transition-colors">
|
||||
<div className="flex items-start justify-between gap-3 mb-1">
|
||||
<span className="font-medium text-sm text-gray-900 dark:text-gray-100 leading-snug">
|
||||
{item.plan_title || `Plan #${item.plan_id}`}
|
||||
</span>
|
||||
<span className={`shrink-0 font-mono text-[10px] uppercase tracking-wider ${statusColors[item.status] ?? ''}`}>
|
||||
{item.status.replace(/_/g, ' ')}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
{item.task_title && (
|
||||
<div className="font-mono text-[10px] text-gray-500 dark:text-gray-400 mb-1">
|
||||
→ {item.task_title}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{item.verification_notes && (
|
||||
<div className="text-xs text-gray-600 dark:text-gray-400 mt-2 leading-relaxed line-clamp-2">
|
||||
{item.verification_notes}
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="flex items-center justify-between mt-3 pt-2 border-t border-gray-100 dark:border-gray-700/50">
|
||||
<span className="font-mono text-[10px] tabular text-gray-400 dark:text-gray-500" title={absoluteTime(item.submitted_at)}>
|
||||
submitted {relativeTime(item.submitted_at)}
|
||||
</span>
|
||||
{item.status === 'ready_for_approval' && (
|
||||
<button
|
||||
onClick={onReview}
|
||||
className="font-mono text-[10px] uppercase tracking-wider px-3 py-1 rounded bg-blue-600 hover:bg-blue-700 text-white cursor-pointer"
|
||||
>
|
||||
review →
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export function DirectorQueue({
|
||||
items,
|
||||
onReview,
|
||||
}: {
|
||||
items: QueueItem[]
|
||||
onReview: (item: QueueItem) => void
|
||||
}) {
|
||||
return (
|
||||
<div className="rounded-lg border border-gray-200 dark:border-gray-700 bg-white dark:bg-gray-800 p-5">
|
||||
<div className="flex items-baseline justify-between mb-4">
|
||||
<h2 className="font-display text-xl font-medium text-gray-900 dark:text-gray-100">
|
||||
Director Queue
|
||||
</h2>
|
||||
<span className="font-mono text-[10px] uppercase tracking-wider text-gray-400">
|
||||
{items.length} {items.length === 1 ? 'item' : 'items'}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
{items.length === 0 ? (
|
||||
<p className="font-mono text-xs text-gray-500 italic">No items awaiting review</p>
|
||||
) : (
|
||||
<div className="space-y-2">
|
||||
{items.map((item) => (
|
||||
<QueueItemCard key={item.id} item={item} onReview={() => onReview(item)} />
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user