import React, { useState, useEffect } from 'react'; import { Card, CardContent, CardHeader, CardTitle, CardDescription } from '@/components/ui/card'; import { Button } from '@/components/ui/button'; import { Badge } from '@/components/ui/badge'; import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '@/components/ui/table'; import { getDirectusClient, readItems, aggregate } from '@/lib/directus/client'; import type { DirectusSchema, GenerationJobs as GenerationJob, CampaignMasters as CampaignMaster, WorkLog } from '@/lib/schemas'; export default function ContentFactoryDashboard() { const [stats, setStats] = useState({ total: 0, published: 0, processing: 0 }); const [jobs, setJobs] = useState([]); const [campaigns, setCampaigns] = useState([]); const [logs, setLogs] = useState([]); const [loading, setLoading] = useState(true); const DIRECTUS_ADMIN_URL = "https://spark.jumpstartscaling.com/admin"; useEffect(() => { loadData(); const interval = setInterval(loadData, 5000); // Poll every 5s for "Factory" feel return () => clearInterval(interval); }, []); const loadData = async () => { try { const client = getDirectusClient(); // 1. Fetch KPI Stats // Article Count const articleAgg = await client.request(aggregate('generated_articles', { aggregate: { count: '*' } })); const totalArticles = Number(articleAgg[0]?.count || 0); // Published Count const publishedAgg = await client.request(aggregate('generated_articles', { aggregate: { count: '*' }, filter: { is_published: { _eq: true } } })); const totalPublished = Number(publishedAgg[0]?.count || 0); // Active Jobs Count const processingAgg = await client.request(aggregate('generation_jobs', { aggregate: { count: '*' }, filter: { status: { _eq: 'Processing' } } })); const totalProcessing = Number(processingAgg[0]?.count || 0); setStats({ total: totalArticles, published: totalPublished, processing: totalProcessing }); // 2. Fetch Active Campaigns const activeCampaigns = await client.request(readItems('campaign_masters', { limit: 5, sort: ['-date_created'], filter: { status: { _in: ['active', 'paused'] } } // Show active/paused })); setCampaigns(activeCampaigns as unknown as CampaignMaster[]); // 3. Fetch Production Jobs (The real "Factory" work) const recentJobs = await client.request(readItems('generation_jobs', { limit: 5, sort: ['-date_created'] })); setJobs(recentJobs as unknown as GenerationJob[]); // 4. Fetch Work Log const recentLogs = await client.request(readItems('work_log', { limit: 20, sort: ['-date_created'] })); setLogs(recentLogs as unknown as WorkLog[]); setLoading(false); } catch (error) { console.error("Dashboard Load Error:", error); setLoading(false); } }; const StatusBadge = ({ status }: { status: string }) => { const colors: Record = { active: 'bg-green-600', paused: 'bg-yellow-600', completed: 'bg-blue-600', draft: 'bg-slate-600', Pending: 'bg-slate-600', Processing: 'bg-blue-600', Complete: 'bg-green-600', Failed: 'bg-red-600' }; return {status}; }; if (loading) return
Initializing Factory Command Center...
; return (
{/* Header Actions */}

Tactical Command Center

Shields (SEO Defense) & Weapons (Content Offense) Status

{/* KPI Grid */}
Total Units (Articles)
{stats.total}
Pending QA
{stats.total - stats.published}
Deployed (Live)
{stats.published}
Active Operations
{stats.processing}
{/* Active Campaigns */} Active Campaigns Recent campaign activity and status Campaign Name Mode Status Target {campaigns.length > 0 ? campaigns.map((campaign) => ( {campaign.name} {campaign.location_mode || 'Standard'} {campaign.batch_count || 0} )) : ( No active campaigns )}
{/* Production Queue */} Production Jobs Recent generation tasks
{jobs.length > 0 ? jobs.map((job) => (
Job #{String(job.id)}
{job.current_offset} / {job.target_quantity} articles
)) : (
Queue is empty
)}
{/* Work Log / Activity */} System Activity Log Real-time backend operations
{logs.length > 0 ? logs.map((log) => (
[{new Date(log.date_created || '').toLocaleTimeString()}]{' '} {(log.action || 'INFO').toUpperCase()}{' '} {log.entity_type} #{log.entity_id}{' '} - {typeof log.details === 'string' ? log.details.substring(0, 50) : JSON.stringify(log.details || '').substring(0, 50)}...
)) : (
No recent activity
)}
); }