'use client' import { useEffect, useMemo, useState } from 'react' import { Card, CardHeader, CardTitle, CardContent } from '@/components/ui/card' import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs' import { fetchPublishedManualsDashboard } from '@/lib/manuals-live-catalog' import { BarChart3, FileText, Search, AlertCircle, CheckCircle2, Download, Database, Code, MessageSquare, TrendingUp } from 'lucide-react' interface DashboardData { missingManuals: any qaData: any[] metadata: any[] structuredData: any[] semanticIndex: any acquisitionList: any nameMapping: any[] } interface ManualsDashboardClientProps { data: DashboardData } export function ManualsDashboardClient({ data }: ManualsDashboardClientProps) { const [searchTerm, setSearchTerm] = useState('') const [liveData, setLiveData] = useState(data) useEffect(() => { let cancelled = false void (async () => { const refreshed = await fetchPublishedManualsDashboard() if (cancelled || !refreshed) { return } setLiveData((current) => { const currentCount = Array.isArray(current?.metadata) ? current.metadata.length : 0 const refreshedCount = Array.isArray(refreshed?.metadata) ? refreshed.metadata.length : 0 return refreshedCount > currentCount ? refreshed : current }) })() return () => { cancelled = true } }, []) // Calculate statistics const stats = useMemo(() => { const missing = liveData.missingManuals?.summary || {} const qaCategories = liveData.qaData.reduce((acc: any, item: any) => { const cat = item.category || 'unknown' acc[cat] = (acc[cat] || 0) + 1 return acc }, {}) const metadataWithSpecs = liveData.metadata.filter((m: any) => m.specifications?.dimensions && Object.keys(m.specifications.dimensions).length > 0 ).length const metadataWithParts = liveData.metadata.filter((m: any) => m.parts_list && m.parts_list.length > 0 ).length const metadataWithTroubleshooting = liveData.metadata.filter((m: any) => m.troubleshooting && m.troubleshooting.length > 0 ).length const schemaTypes = liveData.structuredData.reduce((acc: any, item: any) => { item.schemas?.forEach((schema: any) => { const type = schema['@type'] || 'unknown' acc[type] = (acc[type] || 0) + 1 }) return acc }, {}) return { totalModels: missing.total_expected_models || 0, missingAll: missing.models_missing_all || 0, partial: missing.models_partial || 0, totalQAPairs: liveData.qaData.length, qaCategories, totalManuals: liveData.metadata.length, metadataWithSpecs, metadataWithParts, metadataWithTroubleshooting, totalChunks: liveData.semanticIndex?.total_chunks || 0, schemaTypes, highPriority: liveData.acquisitionList?.high_priority || 0, mediumPriority: liveData.acquisitionList?.medium_priority || 0, lowPriority: liveData.acquisitionList?.low_priority || 0, } }, [liveData]) // Filter Q&A data const filteredQA = useMemo(() => { if (!searchTerm) return liveData.qaData.slice(0, 50) const term = searchTerm.toLowerCase() return liveData.qaData.filter((item: any) => item.question?.toLowerCase().includes(term) || item.answer?.toLowerCase().includes(term) ).slice(0, 50) }, [liveData.qaData, searchTerm]) // Get high priority missing manuals const highPriorityMissing = useMemo(() => { return (liveData.acquisitionList?.acquisition_list || []) .filter((item: any) => item.priority === 'high') .slice(0, 20) }, [liveData.acquisitionList]) return (
{/* Statistics Cards */}
Total Models
{stats.totalModels}

In database

Processed Manuals
{stats.totalManuals}

With metadata

Q&A Pairs
{stats.totalQAPairs.toLocaleString()}

Generated

Missing Manuals
{stats.missingAll}

No manuals found

{/* Main Content Tabs */} Overview Missing Manuals Q&A Dataset Metadata Optimization {/* Overview Tab */}
Processing Statistics
Models Analyzed {stats.totalModels}
Manuals Processed {stats.totalManuals}
Q&A Pairs Generated {stats.totalQAPairs.toLocaleString()}
Semantic Chunks {stats.totalChunks}
Gap Analysis
Missing All Manuals {stats.missingAll}
Partial Manuals {stats.partial}
High Priority {stats.highPriority}
Medium Priority {stats.mediumPriority}
Q&A Categories
{Object.entries(stats.qaCategories) .sort(([, a]: any, [, b]: any) => b - a) .map(([category, count]: [string, any]) => (
{category} {count}
))}
Metadata Extraction
With Specifications {stats.metadataWithSpecs}
With Parts Lists {stats.metadataWithParts}
With Troubleshooting {stats.metadataWithTroubleshooting}
{/* Missing Manuals Tab */} High Priority Missing Manuals
{highPriorityMissing.map((item: any, index: number) => (

{item.manufacturer} {item.model_number}

{item.model_name}

High Priority

Missing: {item.missing_types?.join(', ')}

Sources: {item.source_urls?.length || 0} URLs found

))}
{/* Q&A Dataset Tab */} Q&A Dataset ({stats.totalQAPairs.toLocaleString()} pairs)
setSearchTerm(e.target.value)} className="w-full px-4 py-2 border rounded-lg" />
{filteredQA.map((item: any, index: number) => (

{item.question}

{item.category && ( {item.category} )}

{item.answer}

))}
{/* Metadata Tab */}
Metadata Statistics
Total Manuals {stats.totalManuals}
With Specifications {stats.metadataWithSpecs}
With Parts Lists {stats.metadataWithParts}
With Troubleshooting {stats.metadataWithTroubleshooting}
Sample Manual Metadata {liveData.metadata.length > 0 && (

Manufacturer: {liveData.metadata[0].manufacturer}

Model: {liveData.metadata[0].model_number || 'N/A'}

Type: {liveData.metadata[0].manual_type}

{liveData.metadata[0].specifications?.interfaces && (

Interfaces: {liveData.metadata[0].specifications.interfaces.join(', ')}

)}
)}
{/* Optimization Tab */}
Structured Data (JSON-LD)

Total Schemas: {liveData.structuredData.length}

Schema Types:

{Object.entries(stats.schemaTypes).map(([type, count]: [string, any]) => (
{type} {count}
))}
Semantic Index
Total Chunks {stats.totalChunks}
Manuals Indexed {liveData.semanticIndex?.total_manuals || 0}

Note: Using placeholder embeddings. Ready for production integration.

) }