// ================================================================
// 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';
import { useReasoningFormatter } from '../../hooks/useReasoningTranslation';
import { useTranslation } from 'react-i18next';
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 as keyof typeof urgencyConfig] || urgencyConfig.normal;
const UrgencyIcon = config.icon;
const { formatPOAction } = useReasoningFormatter();
const { t } = useTranslation('reasoning');
// Translate reasoning_data (or fallback to deprecated text fields)
const { reasoning, consequence, severity } = action.reasoning_data
? formatPOAction(action.reasoning_data)
: { reasoning: action.reasoning || '', consequence: action.consequence || '', severity: '' };
return (
{/* Header */}
{action.title || 'Action Required'}
{action.urgency || 'normal'}
{action.subtitle || ''}
{/* Amount (for POs) */}
{action.amount && (
{action.amount.toFixed(2)} {action.currency}
)}
{/* Reasoning (always visible) */}
{t('jtbd.action_queue.why_needed')}
{reasoning}
{/* Consequence (expandable) */}
{consequence && (
<>
{expanded && (
{consequence}
{severity && (
{severity}
)}
)}
>
)}
{/* Time Estimate */}
{t('jtbd.action_queue.estimated_time')}: {action.estimatedTimeMinutes || 5} 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 { t } = useTranslation('reasoning');
if (loading || !actionQueue) {
return (
);
}
if (!actionQueue.actions || actionQueue.actions.length === 0) {
return (
{t('jtbd.action_queue.all_caught_up')}
{t('jtbd.action_queue.no_actions')}
);
}
const displayedActions = showAll ? actionQueue.actions : actionQueue.actions.slice(0, 3);
return (
{/* Header */}
{t('jtbd.action_queue.title')}
{(actionQueue.totalActions || 0) > 3 && (
{actionQueue.totalActions || 0} {t('jtbd.action_queue.total')}
)}
{/* Summary Badges */}
{((actionQueue.criticalCount || 0) > 0 || (actionQueue.importantCount || 0) > 0) && (
{(actionQueue.criticalCount || 0) > 0 && (
{actionQueue.criticalCount || 0} {t('jtbd.action_queue.critical')}
)}
{(actionQueue.importantCount || 0) > 0 && (
{actionQueue.importantCount || 0} {t('jtbd.action_queue.important')}
)}
)}
{/* Action Items */}
{displayedActions.map((action) => (
))}
{/* Show More/Less */}
{(actionQueue.totalActions || 0) > 3 && (
)}
);
}