process-aware-ai / frontend /components /process-flow.tsx
borndeveloper's picture
Backedns erach functionality added
5533d3b
Raw
History Blame Contribute Delete
13.2 kB
"use client";
import { AlertTriangle, Zap, HelpCircle, CheckCircle } from "lucide-react";
import clsx from "clsx";
interface ProcessFlowProps {
data: any;
simulated?: any;
}
import { InfoTooltip } from "@/components/ui/tooltip";
export function ProcessFlow({ data, simulated }: ProcessFlowProps) {
if (!data || !data.intelligence) return <div className="text-neutral-500">Loading intelligence...</div>;
const {
waterfall, norm_adequacy, intervention_roi, yield_rate, break_even_tolerance,
blame_breakdown, elasticity, false_yield_warning, safety_recommendation,
po_imbalance, min_charge_distortion, risk_fingerprint
} = data.intelligence;
const hasShortfall = data.metrics['Shortfall'] > 0;
const maxValue = Math.max(...waterfall.map((w: any) => Math.abs(w.value))) * 1.2;
return (
<div className="w-full space-y-6">
{/* SUCCESS BANNER - Only show when fulfilled */}
{!hasShortfall && (
<div className="bg-emerald-900/30 border border-emerald-700 rounded-lg p-3 flex items-center gap-3">
<CheckCircle className="h-5 w-5 text-emerald-400 shrink-0" />
<div>
<span className="font-bold text-emerald-200">Order Fulfilled</span>
<span className="text-emerald-300 ml-2">
Surplus: +{Math.round(Math.abs(data.metrics['Shortfall']))}m
</span>
</div>
</div>
)}
{/* FALSE YIELD WARNING BANNER - Only when there's a shortfall */}
{hasShortfall && false_yield_warning && (
<div className="bg-amber-900/30 border border-amber-700 rounded-lg p-3 flex items-center gap-3">
<AlertTriangle className="h-5 w-5 text-amber-400 shrink-0" />
<div>
<span className="font-bold text-amber-200">False Yield Alert:</span>
<span className="text-amber-300 ml-2">High yield ({yield_rate}%) but insufficient delivery ({norm_adequacy}%)</span>
</div>
</div>
)}
{/* 1. Policy Intelligence Header */}
<div className={clsx("grid gap-3 grid-cols-1 sm:grid-cols-2", hasShortfall ? "lg:grid-cols-5" : "lg:grid-cols-4")}>
<div className="bg-neutral-900 border border-neutral-800 p-4 rounded-xl">
<div className="text-xs text-neutral-500 uppercase tracking-wider mb-1">
Norm Score
<InfoTooltip content="Output ÷ Order Quantity. Shows how well norms predict requirements." />
</div>
<div className={clsx("text-2xl font-bold", norm_adequacy < 95 ? "text-red-400" : "text-emerald-400")}>
{norm_adequacy}%
</div>
</div>
<div className="bg-neutral-900 border border-neutral-800 p-4 rounded-xl">
<div className="text-xs text-neutral-500 uppercase tracking-wider mb-1">
Production Efficiency
<InfoTooltip content="Total: Output ÷ Total Issued. Fresh: First-run efficiency (Output ÷ Fresh Issued)." />
</div>
<div className="flex items-baseline gap-2">
<span className="text-2xl font-bold text-blue-400">{yield_rate}%</span>
<span className="text-[10px] text-neutral-500">Total</span>
</div>
{data.metrics?.["Fresh Yield %"] !== undefined && (
<div className="flex items-baseline gap-2 mt-1 pt-1 border-t border-neutral-800">
<span className="text-lg font-bold text-emerald-400">{data.metrics["Fresh Yield %"]}%</span>
<span className="text-[10px] text-neutral-500">Fresh Yield</span>
</div>
)}
</div>
<div className="bg-neutral-900 border border-neutral-800 p-4 rounded-xl">
<div className="text-xs text-neutral-500 uppercase tracking-wider mb-1">
Elasticity
<InfoTooltip content="How responsive this article is to safety margin changes. LOW = changing policy won't help much." />
</div>
<div className={clsx("text-lg font-bold",
elasticity.classification === "HIGH" ? "text-emerald-400" :
elasticity.classification === "MEDIUM" ? "text-amber-400" : "text-red-400"
)}>
{elasticity.classification}
</div>
<div className="text-xs text-neutral-600">{elasticity.value}</div>
</div>
<div className="bg-neutral-900 border border-neutral-800 p-4 rounded-xl">
<div className="text-xs text-neutral-500 uppercase tracking-wider mb-1">
Intervention ROI
<InfoTooltip content="Did the planner's manual adjustment (over/under issue) help or hurt?" />
</div>
<div className={clsx("text-sm font-bold", intervention_roi.includes("High") ? "text-emerald-400" : "text-amber-400")}>
{intervention_roi}
</div>
</div>
{/* Only show Safety Needed when there's a shortfall */}
{hasShortfall && (
<div className="bg-purple-900/30 border border-purple-700 p-4 rounded-xl">
<div className="text-xs text-purple-300 uppercase tracking-wider mb-1">
Safety Needed
<InfoTooltip content="The exact safety margin % that would have fulfilled this order." />
</div>
<div className="text-2xl font-bold text-purple-400">+{safety_recommendation.value}%</div>
<div className="text-xs text-purple-500">{safety_recommendation.confidence_low}-{safety_recommendation.confidence_high}%</div>
</div>
)}
</div>
{/* 2. BLAME BREAKDOWN - Only show when there's a shortfall */}
{hasShortfall && (
<div className="bg-neutral-900 border border-neutral-800 rounded-xl p-5">
<h3 className="text-sm font-bold mb-4 text-neutral-300 uppercase tracking-wider">
Shortfall Responsibility Breakdown
<InfoTooltip content="Who caused the shortfall? Policy (norms too low), Execution (planner cut), or Process (manufacturing loss)." />
</h3>
<div className="flex gap-1 h-8 mb-3 overflow-hidden rounded-lg">
<div
className="bg-red-600 flex items-center justify-center text-xs font-bold text-white transition-all"
style={{ width: `${Math.max(1, blame_breakdown.policy_pct)}%` }}
title={`Norm: ${blame_breakdown.policy_impact}m`}
>
{blame_breakdown.policy_pct > 15 && `${blame_breakdown.policy_pct}%`}
</div>
<div
className="bg-amber-500 flex items-center justify-center text-xs font-bold text-black transition-all"
style={{ width: `${Math.max(1, blame_breakdown.execution_pct)}%` }}
title={`Execution: ${blame_breakdown.execution_impact}m`}
>
{blame_breakdown.execution_pct > 15 && `${blame_breakdown.execution_pct}%`}
</div>
<div
className="bg-blue-500 flex items-center justify-center text-xs font-bold text-white transition-all"
style={{ width: `${Math.max(1, blame_breakdown.process_pct)}%` }}
title={`Process: ${blame_breakdown.process_impact}m`}
>
{blame_breakdown.process_pct > 15 && `${blame_breakdown.process_pct}%`}
</div>
</div>
<div className="flex justify-between text-xs">
<span className="text-red-400">■ Policy {blame_breakdown.policy_pct}%</span>
<span className="text-amber-400">■ Execution {blame_breakdown.execution_pct}%</span>
<span className="text-blue-400">■ Process {blame_breakdown.process_pct}%</span>
</div>
{blame_breakdown.policy_pct > 70 && (
<div className="mt-3 text-xs text-red-300 bg-red-900/20 p-2 rounded">
⚠️ {Math.round(blame_breakdown.policy_pct)}% of shortfall is policy-driven. Operators did NOT cause this loss.
</div>
)}
</div>
)}
{/* 3. Loss Waterfall Visual */}
<div className="bg-neutral-900 border border-neutral-800 rounded-xl p-5">
<h3 className="text-sm font-bold mb-4 flex items-center text-neutral-300 uppercase tracking-wider">
<Zap className="mr-2 h-4 w-4 text-yellow-500" />
{hasShortfall ? "Loss Waterfall" : "Material Flow"}
<InfoTooltip content="Shows how material quantity changes through each stage: Order Quantity → Norm → Execution → Manufacturing → Output" />
</h3>
<div className="space-y-3">
{waterfall.map((step: any, i: number) => {
const isNegative = step.value < 0;
const maxValue = Math.max(...waterfall.map((w: any) => Math.abs(w.value)));
const width = Math.min(100, (Math.abs(step.value) / maxValue) * 100);
return (
<div key={i} className="flex items-center text-sm">
<div className="w-40 text-neutral-400 font-medium text-xs">{step.label}</div>
<div className="flex-1 h-6 flex items-center bg-neutral-950 rounded relative overflow-hidden">
<div
className={clsx(
"h-full rounded-sm transition-all duration-500 flex items-center px-2",
step.type === 'base' ? "bg-blue-900/50 text-blue-200" :
step.type === 'final' ? (step.value < waterfall[0].value ? "bg-red-900/50 text-red-200" : "bg-emerald-900/50 text-emerald-200") :
isNegative ? "bg-red-900/40 text-red-300" : "bg-emerald-900/40 text-emerald-300"
)}
style={{ width: `${width}%` }}
>
<span className="font-mono text-xs font-bold">
{step.value > 0 && step.type !== 'base' ? '+' : ''}{Math.round(step.value)}m
</span>
</div>
</div>
<div className="w-24 text-right text-[10px] text-neutral-500 ml-3">
{step.desc}
</div>
</div>
)
})}
</div>
</div>
{/* 5. PO IMBALANCE WARNING */}
{po_imbalance?.detected && (
<div className="bg-amber-900/20 border border-amber-800 rounded-lg p-3 flex items-start gap-3">
<AlertTriangle className="h-5 w-5 text-amber-400 shrink-0 mt-0.5" />
<div>
<div className="font-bold text-amber-200 text-sm">
Uneven PO Norm Allocation Detected
<InfoTooltip content="Different POs for the same article got different norm %s. This may indicate minimum charge distortion." />
</div>
<div className="text-xs text-amber-400 mt-1">
StdDev of Norm Gap: {po_imbalance.stddev}% across {po_imbalance.details?.length || 0} POs
</div>
{min_charge_distortion && (
<div className="text-xs text-red-400 mt-1">⚠️ Possible Minimum Charge Distortion</div>
)}
</div>
</div>
)}
</div>
);
}