// ================================================================ // frontend/src/components/dashboard/ActionQueueCard.tsx // ================================================================ /** * Action Queue Card - What needs your attention right now * * Prioritized list of actions the user needs to take, with context * about why each action is needed and what happens if they don't do it. */ import React, { useState } from 'react'; import { FileText, AlertCircle, CheckCircle2, Eye, Edit, Clock, Euro, ChevronDown, ChevronUp, } from 'lucide-react'; import { ActionItem, ActionQueue } from '../../api/hooks/newDashboard'; interface ActionQueueCardProps { actionQueue: ActionQueue; loading?: boolean; onApprove?: (actionId: string) => void; onViewDetails?: (actionId: string) => void; onModify?: (actionId: string) => void; } const urgencyConfig = { critical: { bg: 'bg-red-50', border: 'border-red-300', badge: 'bg-red-100 text-red-800', icon: AlertCircle, }, important: { bg: 'bg-amber-50', border: 'border-amber-300', badge: 'bg-amber-100 text-amber-800', icon: AlertCircle, }, normal: { bg: 'bg-blue-50', border: 'border-blue-300', badge: 'bg-blue-100 text-blue-800', icon: FileText, }, }; function ActionItemCard({ action, onApprove, onViewDetails, onModify, }: { action: ActionItem; onApprove?: (id: string) => void; onViewDetails?: (id: string) => void; onModify?: (id: string) => void; }) { const [expanded, setExpanded] = useState(false); const config = urgencyConfig[action.urgency]; const UrgencyIcon = config.icon; return (
{/* Header */}

{action.title}

{action.urgency}

{action.subtitle}

{/* Amount (for POs) */} {action.amount && (
{action.amount.toFixed(2)} {action.currency}
)} {/* Reasoning (always visible) */}

Why this is needed:

{action.reasoning}

{/* Consequence (expandable) */} {expanded && (

{action.consequence}

)} {/* Time Estimate */}
Estimated time: {action.estimatedTimeMinutes} min
{/* Action Buttons */}
{action.actions.map((button, index) => { const buttonStyles = { primary: 'bg-blue-600 hover:bg-blue-700 text-white', secondary: 'bg-gray-200 hover:bg-gray-300 text-gray-800', tertiary: 'bg-white hover:bg-gray-50 text-gray-700 border border-gray-300', }; const handleClick = () => { if (button.action === 'approve' && onApprove) { onApprove(action.id); } else if (button.action === 'view_details' && onViewDetails) { onViewDetails(action.id); } else if (button.action === 'modify' && onModify) { onModify(action.id); } }; return ( ); })}
); } export function ActionQueueCard({ actionQueue, loading, onApprove, onViewDetails, onModify, }: ActionQueueCardProps) { const [showAll, setShowAll] = useState(false); const displayedActions = showAll ? actionQueue.actions : actionQueue.actions.slice(0, 3); if (loading) { return (
); } if (actionQueue.actions.length === 0) { return (

All caught up!

No actions requiring your attention right now.

); } return (
{/* Header */}

What Needs Your Attention

{actionQueue.totalActions > 3 && ( {actionQueue.totalActions} total )}
{/* Summary Badges */} {(actionQueue.criticalCount > 0 || actionQueue.importantCount > 0) && (
{actionQueue.criticalCount > 0 && ( {actionQueue.criticalCount} critical )} {actionQueue.importantCount > 0 && ( {actionQueue.importantCount} important )}
)} {/* Action Items */}
{displayedActions.map((action) => ( ))}
{/* Show More/Less */} {actionQueue.totalActions > 3 && ( )}
); }