@@ -203,7 +202,7 @@ export function ActionQueueCard({
);
}
- if (actionQueue.actions.length === 0) {
+ if (!actionQueue.actions || actionQueue.actions.length === 0) {
return (
@@ -215,29 +214,31 @@ export function ActionQueueCard({
);
}
+ const displayedActions = showAll ? actionQueue.actions : actionQueue.actions.slice(0, 3);
+
return (
{/* Header */}
{t('jtbd.action_queue.title')}
- {actionQueue.totalActions > 3 && (
+ {(actionQueue.totalActions || 0) > 3 && (
- {actionQueue.totalActions} {t('jtbd.action_queue.total')}
+ {actionQueue.totalActions || 0} {t('jtbd.action_queue.total')}
)}
{/* Summary Badges */}
- {(actionQueue.criticalCount > 0 || actionQueue.importantCount > 0) && (
+ {((actionQueue.criticalCount || 0) > 0 || (actionQueue.importantCount || 0) > 0) && (
- {actionQueue.criticalCount > 0 && (
+ {(actionQueue.criticalCount || 0) > 0 && (
- {actionQueue.criticalCount} {t('jtbd.action_queue.critical')}
+ {actionQueue.criticalCount || 0} {t('jtbd.action_queue.critical')}
)}
- {actionQueue.importantCount > 0 && (
+ {(actionQueue.importantCount || 0) > 0 && (
- {actionQueue.importantCount} {t('jtbd.action_queue.important')}
+ {actionQueue.importantCount || 0} {t('jtbd.action_queue.important')}
)}
@@ -257,14 +258,14 @@ export function ActionQueueCard({
{/* Show More/Less */}
- {actionQueue.totalActions > 3 && (
+ {(actionQueue.totalActions || 0) > 3 && (
setShowAll(!showAll)}
className="w-full mt-4 py-3 bg-gray-100 hover:bg-gray-200 rounded-lg font-semibold text-gray-700 transition-colors duration-200"
>
{showAll
? t('jtbd.action_queue.show_less')
- : t('jtbd.action_queue.show_more', { count: actionQueue.totalActions - 3 })}
+ : t('jtbd.action_queue.show_more', { count: (actionQueue.totalActions || 3) - 3 })}
)}
diff --git a/frontend/src/components/dashboard/HealthStatusCard.tsx b/frontend/src/components/dashboard/HealthStatusCard.tsx
index 97a5dfcb..ebe709c8 100644
--- a/frontend/src/components/dashboard/HealthStatusCard.tsx
+++ b/frontend/src/components/dashboard/HealthStatusCard.tsx
@@ -50,11 +50,9 @@ const iconMap = {
};
export function HealthStatusCard({ healthStatus, loading }: HealthStatusCardProps) {
- const config = statusConfig[healthStatus.status];
- const StatusIcon = config.icon;
const { t } = useTranslation('reasoning');
- if (loading) {
+ if (loading || !healthStatus) {
return (
@@ -63,6 +61,10 @@ export function HealthStatusCard({ healthStatus, loading }: HealthStatusCardProp
);
}
+ const status = healthStatus.status || 'green';
+ const config = statusConfig[status];
+ const StatusIcon = config.icon;
+
return (
- {healthStatus.headline}
+ {healthStatus.headline || t(`jtbd.health_status.${status}`)}
{/* Last Update */}
@@ -91,19 +93,22 @@ export function HealthStatusCard({ healthStatus, loading }: HealthStatusCardProp
{/* Next Check */}
-
-
-
- {t('jtbd.health_status.next_check')}:{' '}
- {formatDistanceToNow(new Date(healthStatus.nextScheduledRun), { addSuffix: true })}
-
-
+ {healthStatus.nextScheduledRun && (
+
+
+
+ {t('jtbd.health_status.next_check')}:{' '}
+ {formatDistanceToNow(new Date(healthStatus.nextScheduledRun), { addSuffix: true })}
+
+
+ )}
{/* Status Checklist */}
-
- {healthStatus.checklistItems.map((item, index) => {
+ {healthStatus.checklistItems && healthStatus.checklistItems.length > 0 && (
+
+ {healthStatus.checklistItems.map((item, index) => {
const ItemIcon = iconMap[item.icon];
const iconColorClass = item.actionRequired ? 'text-amber-600' : 'text-green-600';
@@ -116,12 +121,13 @@ export function HealthStatusCard({ healthStatus, loading }: HealthStatusCardProp
>
- {item.text}
+ {item.text || ''}
);
})}
+ )}
{/* Summary Footer */}
{(healthStatus.criticalIssues > 0 || healthStatus.pendingActions > 0) && (
diff --git a/frontend/src/components/dashboard/InsightsGrid.tsx b/frontend/src/components/dashboard/InsightsGrid.tsx
index c606d4ce..9483ff8c 100644
--- a/frontend/src/components/dashboard/InsightsGrid.tsx
+++ b/frontend/src/components/dashboard/InsightsGrid.tsx
@@ -81,31 +81,36 @@ export function InsightsGrid({ insights, loading }: InsightsGridProps) {
);
}
+ // Guard against undefined values
+ if (!insights || !insights.savings || !insights.inventory || !insights.waste || !insights.deliveries) {
+ return null;
+ }
+
return (
);
diff --git a/frontend/src/components/dashboard/OrchestrationSummaryCard.tsx b/frontend/src/components/dashboard/OrchestrationSummaryCard.tsx
index b2d2682b..3b89e847 100644
--- a/frontend/src/components/dashboard/OrchestrationSummaryCard.tsx
+++ b/frontend/src/components/dashboard/OrchestrationSummaryCard.tsx
@@ -35,7 +35,7 @@ export function OrchestrationSummaryCard({ summary, loading }: OrchestrationSumm
const [expanded, setExpanded] = useState(false);
const { t } = useTranslation('reasoning');
- if (loading) {
+ if (loading || !summary) {
return (
@@ -62,7 +62,7 @@ export function OrchestrationSummaryCard({ summary, loading }: OrchestrationSumm
{t('jtbd.orchestration_summary.ready_to_plan')}
-
{summary.message}
+
{summary.message || ''}
{t('jtbd.orchestration_summary.run_planning')}
@@ -90,7 +90,7 @@ export function OrchestrationSummaryCard({ summary, loading }: OrchestrationSumm
- {t('jtbd.orchestration_summary.run_info', { runNumber: summary.runNumber })} • {runTime}
+ {t('jtbd.orchestration_summary.run_info', { runNumber: summary.runNumber || 0 })} • {runTime}
{summary.durationSeconds && (
@@ -111,16 +111,16 @@ export function OrchestrationSummaryCard({ summary, loading }: OrchestrationSumm
- {summary.purchaseOrdersSummary.length > 0 && (
+ {summary.purchaseOrdersSummary && summary.purchaseOrdersSummary.length > 0 && (
{summary.purchaseOrdersSummary.map((po, index) => (
- {po.supplierName}
+ {po.supplierName || 'Unknown Supplier'}
{' • '}
- {po.itemCategories.slice(0, 2).join(', ')}
- {po.itemCategories.length > 2 && ` +${po.itemCategories.length - 2} more`}
+ {(po.itemCategories || []).slice(0, 2).join(', ') || 'Items'}
+ {(po.itemCategories || []).length > 2 && ` +${po.itemCategories.length - 2} more`}
{' • '}
- €{po.totalAmount.toFixed(2)}
+ €{(po.totalAmount || 0).toFixed(2)}
))}
@@ -140,25 +140,25 @@ export function OrchestrationSummaryCard({ summary, loading }: OrchestrationSumm
- {summary.productionBatchesSummary.length > 0 && (
+ {summary.productionBatchesSummary && summary.productionBatchesSummary.length > 0 && (
{summary.productionBatchesSummary.slice(0, expanded ? undefined : 3).map((batch, index) => (
- {batch.quantity} {batch.productName}
+ {batch.quantity || 0} {batch.productName || 'Product'}
{' • '}
- ready by {new Date(batch.readyByTime).toLocaleTimeString('en-US', {
+ ready by {batch.readyByTime ? new Date(batch.readyByTime).toLocaleTimeString('en-US', {
hour: 'numeric',
minute: '2-digit',
hour12: true,
- })}
+ }) : 'TBD'}
))}
)}
- {summary.productionBatchesSummary.length > 3 && (
+ {summary.productionBatchesSummary && summary.productionBatchesSummary.length > 3 && (
setExpanded(!expanded)}
className="ml-8 mt-2 flex items-center gap-1 text-sm text-purple-600 hover:text-purple-800 font-medium"
diff --git a/frontend/src/components/dashboard/ProductionTimelineCard.tsx b/frontend/src/components/dashboard/ProductionTimelineCard.tsx
index 7fa47e27..afe999f4 100644
--- a/frontend/src/components/dashboard/ProductionTimelineCard.tsx
+++ b/frontend/src/components/dashboard/ProductionTimelineCard.tsx
@@ -65,7 +65,7 @@ function TimelineItemCard({
{/* Timeline icon and connector */}
-
{item.statusIcon}
+
{item.statusIcon || '🔵'}
{startTime}
@@ -74,22 +74,22 @@ function TimelineItemCard({
{/* Header */}
-
{item.productName}
+
{item.productName || 'Product'}
- {item.quantity} {item.unit} • Batch #{item.batchNumber}
+ {item.quantity || 0} {item.unit || 'units'} • Batch #{item.batchNumber || 'N/A'}
- {item.priority}
+ {item.priority || 'NORMAL'}
{/* Status and Progress */}
- {item.statusText}
+ {item.statusText || 'Status'}
{item.status === 'IN_PROGRESS' && (
- {item.progress}%
+ {item.progress || 0}%
)}
@@ -98,7 +98,7 @@ function TimelineItemCard({
)}
@@ -159,7 +159,7 @@ export function ProductionTimelineCard({
}: ProductionTimelineCardProps) {
const { t } = useTranslation('reasoning');
- if (loading) {
+ if (loading || !timeline) {
return (
@@ -173,7 +173,7 @@ export function ProductionTimelineCard({
);
}
- if (timeline.timeline.length === 0) {
+ if (!timeline.timeline || timeline.timeline.length === 0) {
return (
diff --git a/frontend/src/hooks/useReasoningTranslation.ts b/frontend/src/hooks/useReasoningTranslation.ts
index 119b2840..d1652643 100644
--- a/frontend/src/hooks/useReasoningTranslation.ts
+++ b/frontend/src/hooks/useReasoningTranslation.ts
@@ -138,30 +138,37 @@ export function useReasoningFormatter() {
const formatPOAction = (reasoningData?: ReasoningData) => {
if (!reasoningData) {
return {
- reasoning: translation.translatePOReasonng({} as ReasoningData),
+ reasoning: translation.translatePOReasonng({} as ReasoningData) || 'Purchase order required',
consequence: '',
severity: ''
};
}
+ const reasoning = translation.translatePOReasonng(reasoningData) || 'Purchase order required';
+ const consequence = translation.translateConsequence(reasoningData.consequence) || '';
+ const severity = translation.translateSeverity(reasoningData.consequence?.severity) || '';
+
return {
- reasoning: translation.translatePOReasonng(reasoningData),
- consequence: translation.translateConsequence(reasoningData.consequence),
- severity: translation.translateSeverity(reasoningData.consequence?.severity)
+ reasoning,
+ consequence,
+ severity
};
};
const formatBatchAction = (reasoningData?: ReasoningData) => {
if (!reasoningData) {
return {
- reasoning: translation.translateBatchReasoning({} as ReasoningData),
- urgency: ''
+ reasoning: translation.translateBatchReasoning({} as ReasoningData) || 'Production batch scheduled',
+ urgency: 'normal'
};
}
+ const reasoning = translation.translateBatchReasoning(reasoningData) || 'Production batch scheduled';
+ const urgency = reasoningData.urgency?.level || 'normal';
+
return {
- reasoning: translation.translateBatchReasoning(reasoningData),
- urgency: reasoningData.urgency?.level || 'normal'
+ reasoning,
+ urgency
};
};
diff --git a/frontend/src/pages/app/DashboardPage.tsx b/frontend/src/pages/app/DashboardPage.tsx
index c078c885..66b99936 100644
--- a/frontend/src/pages/app/DashboardPage.tsx
+++ b/frontend/src/pages/app/DashboardPage.tsx
@@ -147,43 +147,35 @@ export function NewDashboardPage() {
{/* Main Dashboard Layout */}
{/* SECTION 1: Bakery Health Status */}
- {healthStatus && (
-
- )}
+
{/* SECTION 2: What Needs Your Attention (Action Queue) */}
- {actionQueue && (
-
- )}
+
{/* SECTION 3: What the System Did for You (Orchestration Summary) */}
- {orchestrationSummary && (
-
- )}
+
{/* SECTION 4: Today's Production Timeline */}
- {productionTimeline && (
-
- )}
+
{/* SECTION 5: Quick Insights Grid */}
Key Metrics
- {insights && }
+
{/* SECTION 6: Quick Action Links */}