import React, { useState, useEffect } from 'react'; import { useNavigate } from 'react-router-dom'; import { Bot, Layers, Tag, AlertCircle, ShieldCheck, Zap, ArrowRight, Activity, FileText, BrainCircuit, LayoutGrid, CheckCircle2, ImageIcon, ChevronDown, Lightbulb } from 'lucide-react'; import useTicketStore from "../../store/ticketStore"; import { Card, CardContent } from "../../components/ui/card"; // ─── Shimmer Skeleton ──────────────────────────────────────────────── const Shimmer = ({ className = "" }) => (
); const SkeletonLoader = () => (
{/* Header skeleton */}
{/* Pipeline skeleton */}
{[1, 2, 3, 4].map(i => (
{i < 4 && }
))}
{/* Summary skeleton */}
{/* Grid skeleton */}
); // ─── Main Component ────────────────────────────────────────────────── const AIUnderstanding = () => { const navigate = useNavigate(); const aiTicket = useTicketStore((state) => state.aiTicket); const setAITicket = useTicketStore((state) => state.setAITicket); const [isLoading, setIsLoading] = useState(true); const [editedIssue, setEditedIssue] = useState(""); const [explainerOpen, setExplainerOpen] = useState(false); // Simulate a brief load to allow store hydration useEffect(() => { const timer = setTimeout(() => setIsLoading(false), 600); return () => clearTimeout(timer); }, []); useEffect(() => { if (!isLoading && !aiTicket) { navigate('/create-ticket'); } }, [isLoading, aiTicket, navigate]); useEffect(() => { if (aiTicket?.originalIssue) { setEditedIssue(aiTicket.originalIssue); } }, [aiTicket]); if (isLoading) return ; if (!aiTicket) return null; // ── Dynamic fields from store ── const summary = aiTicket.summary || aiTicket.originalIssue || "No issue text provided."; const category = aiTicket.category || "Uncategorized"; const subcategory = aiTicket.subcategory || "None"; const priority = aiTicket.priority || "Medium"; const assignedTeam = aiTicket.assigned_team || "Triage"; const entities = aiTicket.entities || []; const rawConfidence = aiTicket.confidence; const confidence = rawConfidence != null ? Math.round(rawConfidence * 100) : 95; let confBarColor = "bg-red-500"; if (confidence >= 90) confBarColor = "bg-emerald-500"; else if (confidence >= 70) confBarColor = "bg-amber-500"; const priorityLower = (priority || 'medium').toLowerCase(); let priorityColor = "bg-slate-100 text-slate-700"; if (priorityLower === 'high' || priorityLower === 'critical') priorityColor = "bg-red-50 text-red-700"; else if (priorityLower === 'medium') priorityColor = "bg-amber-50 text-amber-700"; else if (priorityLower === 'low') priorityColor = "bg-emerald-50 text-emerald-700"; const handleUpdate = () => { setAITicket({ ...aiTicket, originalIssue: editedIssue }); }; const handleContinue = () => { setAITicket({ ...aiTicket, originalIssue: editedIssue, status: 'duplicate_check' }); navigate('/knowledge-check'); }; // ── Pipeline stages ── const pipelineStages = [ { label: 'Input', icon: FileText }, { label: 'AI Analysis', icon: BrainCircuit }, { label: 'Classification', icon: LayoutGrid }, { label: 'Decision', icon: CheckCircle2 }, ]; const currentStage = aiTicket?.status === 'duplicate_check' ? 2 : (aiTicket?.status === 'analyzing' ? 1 : 0); // ── Group entities by label ── const groupedEntities = entities.reduce((acc, entity) => { const label = entity.label || 'Other'; if (!acc[label]) acc[label] = []; acc[label].push(entity.text); return acc; }, {}); // ── Explainer data ── const signalTexts = entities.map(e => e.text); const patternMatch = `${category} > ${subcategory}`; const safeCategory = String(category || 'General').toLowerCase(); const safeSubcategory = String(subcategory || 'Support').toLowerCase(); const confidenceExplanation = confidence >= 90 ? `This issue strongly matches known ${safeCategory} ${safeSubcategory} failures.` : confidence >= 70 ? `This issue partially matches patterns in ${safeCategory} issues.` : `This issue has a weak match; further review may be needed.`; return (
{/* 1. Page Header */}

AI Analysis Complete

Our AI analyzed your request and identified the issue.

{/* Horizontal Analysis Pipeline */}
{pipelineStages.map((stage, idx) => { const Icon = stage.icon; const isCompleted = idx < currentStage; const isCurrent = idx === currentStage; return (
{stage.label}
{idx < pipelineStages.length - 1 && (
)} ); })}
{/* 2. Issue Summary Card */}

AI Summary

{summary}

{/* 3. AI Classification Card */}

Classification

Category & Subcategory

{category} / {subcategory}

Priority

{priority}

Assigned Team

{assignedTeam}
{/* 4. Entities & 5. Confidence */}
{/* Entities Extracted — Grouped by Type */}

Technical Signals Detected

{Object.keys(groupedEntities).length > 0 ? (
{Object.entries(groupedEntities).map(([label, texts]) => (

{label}

{texts.map((t, idx) => ( {t} ))}
))}
) : ( No specific signals detected. )} {/* Technical Environment — User visible diagnostic */} {aiTicket.env_metadata && (

Technical Environment

Interface IP {aiTicket.env_metadata.ip || '127.0.0.1'}
Device Signal {aiTicket.env_metadata.user_agent ? aiTicket.env_metadata.user_agent.split(' ').slice(0, 3).join(' ') + '...' : 'SECURE_NODE'}
)} {/* OCR Screenshot Entities */} {aiTicket.ocrText && (

Detected from Screenshot

{aiTicket.ocrText.split(/\n|,/).filter(Boolean).map((line, idx) => { const trimmed = line.trim(); if (!trimmed) return null; return ( {trimmed} ); })}
)}
{/* Confidence Meter */}

AI Confidence: {confidence}%

{/* Collapsible: How AI reached this conclusion */}
{/* Signals Detected */}

Signals Detected

{signalTexts.length > 0 ? signalTexts.map((s, idx) => ( {s} )) : ( No specific signals )}
{/* Pattern Matched */}

Pattern Matched

{patternMatch}
{/* Confidence Explanation */}

Confidence Explanation

"{confidenceExplanation}"

{/* 6. User Correction Section */}

Is something missing?