'use client'; import Link from 'next/link'; import { useState, useMemo } from 'react'; import { useJobs } from '@/contexts/JobsContext'; import { JobStatus } from '@/components/ScraperTest'; // Mock data for initial development - will be replaced with API data const MOCK_CLIENTS = [ { client_id: 'client-001', job_count: 45, success_rate: 94.2 }, { client_id: 'client-002', job_count: 38, success_rate: 89.5 }, { client_id: 'client-003', job_count: 27, success_rate: 96.3 }, { client_id: 'client-004', job_count: 19, success_rate: 84.2 }, { client_id: 'client-005', job_count: 12, success_rate: 91.7 }, ]; function formatDuration(seconds: number): string { if (seconds < 60) return `${seconds.toFixed(1)}s`; const mins = Math.floor(seconds / 60); const secs = Math.round(seconds % 60); return `${mins}m ${secs}s`; } function extractBusinessName(job: JobStatus): string { if (job.business_name) return job.business_name; try { const urlObj = new URL(job.url); const query = urlObj.searchParams.get('query'); return query ? decodeURIComponent(query) : 'Unknown Business'; } catch { return 'Unknown Business'; } } function formatDate(date: Date): string { return date.toLocaleDateString('en-US', { weekday: 'long', year: 'numeric', month: 'long', day: 'numeric', }); } function getErrorType(errorMessage: string | null): string { if (!errorMessage) return 'Unknown Error'; const msg = errorMessage.toLowerCase(); if (msg.includes('timeout')) return 'Timeout'; if (msg.includes('network') || msg.includes('connection')) return 'Network Error'; if (msg.includes('captcha') || msg.includes('bot')) return 'Bot Detection'; if (msg.includes('element') || msg.includes('selector')) return 'Element Not Found'; if (msg.includes('memory')) return 'Memory Error'; return 'Scrape Error'; } export default function DashboardPage() { const { jobs, isLoading } = useJobs(); const [currentDate] = useState(new Date()); // Calculate stats from jobs data const stats = useMemo(() => { const now = new Date(); const oneDayAgo = new Date(now.getTime() - 24 * 60 * 60 * 1000); // Jobs from last 24 hours const recentJobs = jobs.filter( (j) => new Date(j.created_at) >= oneDayAgo ); // Currently running jobs const activeJobs = jobs.filter((j) => j.status === 'running'); // Completed jobs from last 24h const completedRecent = recentJobs.filter( (j) => j.status === 'completed' ); // Failed jobs from last 24h const failedRecent = recentJobs.filter( (j) => j.status === 'failed' ); // Calculate success rate const totalWithOutcome = completedRecent.length + failedRecent.length; const successRate = totalWithOutcome > 0 ? (completedRecent.length / totalWithOutcome) * 100 : 0; // Calculate average duration for completed jobs const completedWithTime = jobs.filter( (j) => j.status === 'completed' && j.scrape_time !== null ); const avgDuration = completedWithTime.length > 0 ? completedWithTime.reduce((sum, j) => sum + (j.scrape_time || 0), 0) / completedWithTime.length : 0; // Previous 24h for trend comparison const twoDaysAgo = new Date(now.getTime() - 48 * 60 * 60 * 1000); const previousDayJobs = jobs.filter( (j) => new Date(j.created_at) >= twoDaysAgo && new Date(j.created_at) < oneDayAgo ); const jobsTrend = recentJobs.length - previousDayJobs.length; return { totalJobs24h: recentJobs.length, jobsTrend, successRate: successRate.toFixed(1), activeJobs: activeJobs.length, avgDuration, }; }, [jobs]); // Jobs by status counts const statusCounts = useMemo(() => { return { pending: jobs.filter((j) => j.status === 'pending').length, running: jobs.filter((j) => j.status === 'running').length, completed: jobs.filter((j) => j.status === 'completed').length, failed: jobs.filter((j) => j.status === 'failed').length, partial: jobs.filter((j) => j.status === 'partial').length, }; }, [jobs]); // Recent failed jobs const recentFailedJobs = useMemo(() => { return jobs .filter((j) => j.status === 'failed' || j.status === 'partial') .sort( (a, b) => new Date(b.created_at).getTime() - new Date(a.created_at).getTime() ) .slice(0, 5); }, [jobs]); if (isLoading) { return (
{formatDate(currentDate)}
No recent failures
All systems running smoothly
{extractBusinessName(job)}
{job.url}
))}{client.client_id}
{client.job_count} jobs
= 90 ? 'text-green-600' : client.success_rate >= 80 ? 'text-yellow-600' : 'text-red-600' }`} > {client.success_rate}%
success