// ================================================================
// frontend/src/components/dashboard/OrchestrationSummaryCard.tsx
// ================================================================
/**
* Orchestration Summary Card - What the system did for you
*
* Builds trust by showing transparency into automation decisions.
* Narrative format makes it feel like a helpful assistant.
*/
import React, { useState } from 'react';
import {
Bot,
TrendingUp,
Package,
Clock,
CheckCircle,
FileText,
Users,
Brain,
ChevronDown,
ChevronUp,
Loader2,
} from 'lucide-react';
import { OrchestrationSummary } from '../../api/hooks/newDashboard';
import { runDailyWorkflow } from '../../api/services/orchestrator';
import { formatDistanceToNow } from 'date-fns';
import { useTranslation } from 'react-i18next';
import { useTenant } from '../../stores/tenant.store';
import toast from 'react-hot-toast';
interface OrchestrationSummaryCardProps {
summary: OrchestrationSummary;
loading?: boolean;
onWorkflowComplete?: () => void;
}
export function OrchestrationSummaryCard({ summary, loading, onWorkflowComplete }: OrchestrationSummaryCardProps) {
const [expanded, setExpanded] = useState(false);
const [isRunning, setIsRunning] = useState(false);
const { t } = useTranslation('reasoning');
const { currentTenant } = useTenant();
const handleRunPlanning = async () => {
if (!currentTenant?.id) {
toast.error(t('jtbd.orchestration_summary.no_tenant_error') || 'No tenant ID found');
return;
}
setIsRunning(true);
try {
const result = await runDailyWorkflow(currentTenant.id);
if (result.success) {
toast.success(t('jtbd.orchestration_summary.planning_started') || 'Planning started successfully');
// Call callback to refresh the orchestration summary
if (onWorkflowComplete) {
onWorkflowComplete();
}
} else {
toast.error(result.message || t('jtbd.orchestration_summary.planning_failed') || 'Failed to start planning');
}
} catch (error) {
console.error('Error running daily workflow:', error);
toast.error(t('jtbd.orchestration_summary.planning_error') || 'An error occurred while starting planning');
} finally {
setIsRunning(false);
}
};
if (loading || !summary) {
return (
);
}
// Handle case where no orchestration has run yet
if (summary.status === 'no_runs') {
return (
{t('jtbd.orchestration_summary.ready_to_plan')}
{summary.message || ''}
);
}
const runTime = summary.runTimestamp
? formatDistanceToNow(new Date(summary.runTimestamp), { addSuffix: true })
: 'recently';
return (
{/* Header */}
{t('jtbd.orchestration_summary.title')}
{t('jtbd.orchestration_summary.run_info', { runNumber: summary.runNumber || 0 })} • {runTime}
{summary.durationSeconds && (
• {t('jtbd.orchestration_summary.took', { seconds: summary.durationSeconds })}
)}
{/* Purchase Orders Created */}
{summary.purchaseOrdersCreated > 0 && (
{t('jtbd.orchestration_summary.created_pos', { count: summary.purchaseOrdersCreated })}
{summary.purchaseOrdersSummary && summary.purchaseOrdersSummary.length > 0 && (
{summary.purchaseOrdersSummary.map((po, index) => (
-
{po.supplierName || 'Unknown Supplier'}
{' • '}
{(po.itemCategories || []).slice(0, 2).join(', ') || 'Items'}
{(po.itemCategories || []).length > 2 && ` +${po.itemCategories.length - 2} more`}
{' • '}
€{(po.totalAmount || 0).toFixed(2)}
))}
)}
)}
{/* Production Batches Created */}
{summary.productionBatchesCreated > 0 && (
{t('jtbd.orchestration_summary.scheduled_batches', {
count: summary.productionBatchesCreated,
})}
{summary.productionBatchesSummary && summary.productionBatchesSummary.length > 0 && (
{summary.productionBatchesSummary.slice(0, expanded ? undefined : 3).map((batch, index) => (
-
{batch.quantity || 0} {batch.productName || 'Product'}
{' • '}
ready by {batch.readyByTime ? new Date(batch.readyByTime).toLocaleTimeString('en-US', {
hour: 'numeric',
minute: '2-digit',
hour12: true,
}) : 'TBD'}
))}
)}
{summary.productionBatchesSummary && summary.productionBatchesSummary.length > 3 && (
)}
)}
{/* No actions created */}
{summary.purchaseOrdersCreated === 0 && summary.productionBatchesCreated === 0 && (
{t('jtbd.orchestration_summary.no_actions')}
)}
{/* Reasoning Inputs (How decisions were made) */}
{t('jtbd.orchestration_summary.based_on')}
{summary.reasoningInputs.customerOrders > 0 && (
{t('jtbd.orchestration_summary.customer_orders', {
count: summary.reasoningInputs.customerOrders,
})}
)}
{summary.reasoningInputs.historicalDemand && (
{t('jtbd.orchestration_summary.historical_demand')}
)}
{summary.reasoningInputs.inventoryLevels && (
{t('jtbd.orchestration_summary.inventory_levels')}
)}
{summary.reasoningInputs.aiInsights && (
{t('jtbd.orchestration_summary.ai_optimization')}
)}
{/* Actions Required Footer */}
{summary.userActionsRequired > 0 && (
{t('jtbd.orchestration_summary.actions_required', {
count: summary.userActionsRequired,
})}
)}
);
}