import React, { useEffect, useRef, useState } from 'react'; import { Box, Container, Grid, Typography, Alert, Skeleton, Chip, Button, IconButton, Tooltip, Menu, MenuItem, Divider, Avatar, Accordion, AccordionSummary, AccordionDetails, CircularProgress, } from '@mui/material'; import { motion, AnimatePresence } from 'framer-motion'; import { useAuth, useUser, SignOutButton, useClerk } from '@clerk/clerk-react'; import { apiClient } from '../../api/client'; import { Refresh as RefreshIcon, Person as PersonIcon, ExitToApp as ExitIcon, ArrowBack as ArrowBackIcon, MoreVert as MoreVertIcon, CheckCircle as CheckCircleIcon, Schedule as ScheduleIcon, Info as InfoIcon, ExpandMore as ExpandMoreIcon, AutoAwesome as AIIcon, Tab as TabIcon, } from '@mui/icons-material'; import { Tabs, Tab as MuiTab } from '@mui/material'; // Shared components import { DashboardContainer, GlassCard } from '../shared/styled'; import SEOAnalyzerPanel from './components/SEOAnalyzerPanel'; import { SEOCopilotSuggestions } from './index'; import SEOCopilot from './SEOCopilot'; // Removed SEOCopilotTest import useSEOCopilotStore from '../../stores/seoCopilotStore'; // Zustand store import { useSEODashboardStore } from '../../stores/seoDashboardStore'; // API import { userDataAPI } from '../../api/userData'; import { OnboardingScheduledTaskHealthResponse, OnboardingTaskStatus } from '../../api/seoDashboard'; // Shared components import PlatformAnalytics from '../shared/PlatformAnalytics'; import { cachedAnalyticsAPI } from '../../api/cachedAnalytics'; // OAuth hooks import { useBingOAuth } from '../../hooks/useBingOAuth'; import { useGSCConnection } from '../OnboardingWizard/common/useGSCConnection'; // SEO Dashboard component import { SitemapBenchmarkResults } from '../OnboardingWizard/CompetitorAnalysisStep/SitemapBenchmarkResults'; import { StrategicInsightsResults } from '../OnboardingWizard/CompetitorAnalysisStep/StrategicInsightsResults'; import { AdvertoolsInsights } from './components/AdvertoolsInsights'; // Phase 2B: Semantic Dashboard components import SemanticHealthCard from './components/SemanticHealthCard'; import SemanticInsights from './components/SemanticInsights'; // Phase 2A: Enterprise SEO Analysis import SEOAnalysisController from './SEOAnalysisController'; const SEODashboard: React.FC = () => { // Clerk authentication hooks const { isSignedIn, isLoaded } = useAuth(); const { user } = useUser(); const { openSignIn } = useClerk(); // Zustand store hooks const { loading, error, data, analysisData, analysisLoading, analysisError, setData, setLoading, runSEOAnalysis, refreshSEOAnalysis, getAnalysisFreshness, } = useSEODashboardStore(); // OAuth hooks const { connect: connectBing } = useBingOAuth(); const { handleGSCConnect } = useGSCConnection(); // Platform status state const [platformStatus, setPlatformStatus] = useState({ gsc: { connected: false, sites: [], last_sync: null, status: 'disconnected' }, bing: { connected: false, sites: [], last_sync: null, status: 'disconnected', has_expired_tokens: false, last_token_date: undefined, total_tokens: 0 } }); // Menu state const [userMenuAnchor, setUserMenuAnchor] = useState(null); const [statusMenuAnchor, setStatusMenuAnchor] = useState(null); // Dashboard Tab State for Enterprise Analysis const [dashboardTab, setDashboardTab] = useState(0); // Competitor analysis data from onboarding step 3 const [competitorAnalysisData, setCompetitorAnalysisData] = useState(null); const [deepCompetitorAnalysisData, setDeepCompetitorAnalysisData] = useState(null); const [strategicInsightsHistory, setStrategicInsightsHistory] = useState([]); const [strategicInsightsLoading, setStrategicInsightsLoading] = useState(false); const [competitiveSitemapBenchmarkingReport, setCompetitiveSitemapBenchmarkingReport] = useState(null); const [competitiveSitemapBenchmarkingLoading, setCompetitiveSitemapBenchmarkingLoading] = useState(false); const [competitiveSitemapBenchmarkingError, setCompetitiveSitemapBenchmarkingError] = useState(null); const [onboardingTaskHealth, setOnboardingTaskHealth] = useState(null); // PlatformAnalytics refresh handle const platformRefreshRef = useRef<(() => Promise) | null>(null); // Sync dashboard analysis to Copilot store so readables have URL/context const setCopilotAnalysisData = useSEOCopilotStore(state => state.setAnalysisData); useEffect(() => { if (analysisData) { setCopilotAnalysisData(analysisData as any); if (process.env.NODE_ENV === 'development') { console.log('[CopilotSync] Pushed analysis to Copilot store', analysisData?.url); } } }, [analysisData, setCopilotAnalysisData]); // Load competitor analysis data on component mount useEffect(() => { loadCompetitorAnalysisData(); fetchStrategicInsightsHistory(); }, []); const fetchStrategicInsightsHistory = async () => { setStrategicInsightsLoading(true); try { const res = await apiClient.get('/api/seo-dashboard/strategic-insights/history'); if (res.data?.history?.length > 0) { setStrategicInsightsHistory(res.data.history); } } catch (e) { console.error("Failed to fetch strategic insights history", e); } finally { setStrategicInsightsLoading(false); } }; // Reconnect handlers using existing OAuth hooks const handleGSCReconnect = async () => { try { console.log('Initiating GSC reconnect...'); await handleGSCConnect(); } catch (error) { console.error('Error reconnecting GSC:', error); } }; const handleBingReconnect = async () => { try { console.log('Initiating Bing reconnect...'); // Purge expired tokens before reconnecting to avoid refresh loops try { await apiClient.post('/bing/purge-expired'); console.log('Purged expired Bing tokens before reconnect'); } catch (purgeError) { console.warn('Failed to purge expired tokens (non-critical):', purgeError); } await connectBing(); // After successful reconnect, refresh platform status and run analysis try { // Invalidate backend analytics cache for Bing try { await apiClient.post('/api/analytics/cache/clear', null, { params: { platform: 'bing' } }); console.log('Cleared backend analytics cache for Bing'); } catch (cacheErr) { console.warn('Failed to clear backend analytics cache (non-critical):', cacheErr); } // Invalidate frontend cached analytics try { cachedAnalyticsAPI.invalidatePlatformStatus(); // Optional: clear all analytics cache if available // @ts-ignore - method may not exist in older builds cachedAnalyticsAPI.clearCache?.(); console.log('Cleared frontend analytics cache'); } catch (feCacheErr) { console.warn('Failed to clear frontend analytics cache (non-critical):', feCacheErr); } await fetchPlatformStatus(); } catch (e) { console.warn('Post-reconnect platform status refresh failed:', e); } try { await useSEODashboardStore.getState().refreshSEOAnalysis(); } catch (e) { console.warn('Post-reconnect analysis refresh failed:', e); } // Force PlatformAnalytics to refresh (bypass cache) try { await platformRefreshRef.current?.(); } catch (e) { console.warn('Platform analytics forced refresh failed (non-critical):', e); } } catch (error) { console.error('Error reconnecting Bing:', error); } }; // One-run guard to avoid duplicate fetches under StrictMode const dataFetchedRef = useRef(false); // Consolidated data fetching effect useEffect(() => { if (dataFetchedRef.current || !isSignedIn) return; dataFetchedRef.current = true; const fetchAllData = async () => { let websiteUrl = 'https://alwrity.com'; // Default fallback try { setLoading(true); // Fetch platform status and user data in parallel const [platformResponse, userData, onboardingTaskHealthResponse] = await Promise.all([ apiClient.get('/api/seo-dashboard/platforms'), userDataAPI.getUserData(), apiClient.get('/api/seo-dashboard/onboarding-task-health') ]); console.log('Platform status response:', platformResponse.status, platformResponse.statusText); console.log('Platform status data:', platformResponse.data); setPlatformStatus(platformResponse.data); setOnboardingTaskHealth(onboardingTaskHealthResponse.data); websiteUrl = userData?.website_url || 'https://alwrity.com'; // Fetch real data from backend using authenticated API client console.log('Fetching SEO dashboard overview...'); const response = await apiClient.get('/api/seo-dashboard/overview', { params: { site_url: websiteUrl } }); console.log('SEO overview response:', response.status, response.statusText); console.log('Real SEO data received:', response.data); setData(response.data); try { const deepResponse = await apiClient.get('/api/seo-dashboard/deep-competitor-analysis', { params: { site_url: websiteUrl } }); setDeepCompetitorAnalysisData(deepResponse.data); } catch (e) { console.warn('Deep competitor analysis not available yet:', e); setDeepCompetitorAnalysisData(null); } try { const sitemapBenchResponse = await apiClient.get('/api/seo/competitive-sitemap-benchmarking'); const report = sitemapBenchResponse?.data?.data?.report ?? null; setCompetitiveSitemapBenchmarkingReport(report); } catch (e) { console.warn('Competitive sitemap benchmarking not available yet:', e); setCompetitiveSitemapBenchmarkingReport(null); } try { setStrategicInsightsLoading(true); const strategicHistoryRes = await apiClient.get('/api/seo-dashboard/strategic-insights/history'); setStrategicInsightsHistory(strategicHistoryRes.data?.history || []); } catch (e) { console.warn('Strategic insights history not available yet:', e); } finally { setStrategicInsightsLoading(false); } } catch (error) { console.error('Error fetching SEO dashboard data:', error); // Fallback to mock data on error const mockData = { health_score: { score: 84, change: 5, trend: 'up', label: 'EXCELLENT', color: '#4CAF50' }, key_insight: 'Your website has excellent technical SEO foundation with room for improvement', priority_alert: 'Mobile page speed could be optimized further', metrics: { traffic: { value: 12500, change: 15, trend: 'up', description: 'Organic traffic', color: '#4CAF50' }, rankings: { value: 8.5, change: 2.3, trend: 'up', description: 'Average ranking', color: '#2196F3' }, mobile: { value: 92, change: -3, trend: 'down', description: 'Mobile speed', color: '#FF9800' }, keywords: { value: 150, change: 12, trend: 'up', description: 'Keywords tracked', color: '#9C27B0' } }, platforms: { google: { status: 'connected', connected: true, last_sync: '2024-01-15T10:30:00Z', data_points: 1250 }, bing: { status: 'connected', connected: true, last_sync: '2024-01-15T09:45:00Z', data_points: 850 }, yandex: { status: 'disconnected', connected: false } }, ai_insights: [ { insight: 'Your website has excellent technical SEO foundation', priority: 'low', category: 'technical', action_required: false }, { insight: 'Consider adding more internal links to improve page authority', priority: 'medium', category: 'content', action_required: false }, { insight: 'Mobile page speed could be optimized further', priority: 'high', category: 'performance', action_required: true, tool_path: '/seo-dashboard' } ], last_updated: new Date().toISOString(), website_url: websiteUrl || undefined // Convert null to undefined for TypeScript }; setData(mockData); setDeepCompetitorAnalysisData(null); setCompetitiveSitemapBenchmarkingReport(null); } finally { setLoading(false); } }; fetchAllData(); }, [isSignedIn, setLoading, setData]); useEffect(() => { // Run initial SEO analysis if no data exists if (!loading && !error && data) { // Check if we have cached analysis data first const store = useSEODashboardStore.getState(); store.checkAndRunInitialAnalysis(); // If no cached analysis data and we have a website URL, run initial analysis if (!store.analysisData && data.website_url) { console.log('No cached analysis data found, running initial SEO analysis...'); store.runSEOAnalysis(); } } }, [loading, error, data]); // Menu handlers const handleUserMenuOpen = (event: React.MouseEvent) => { setUserMenuAnchor(event.currentTarget); }; const handleUserMenuClose = () => { setUserMenuAnchor(null); }; const handleStatusMenuOpen = (event: React.MouseEvent) => { setStatusMenuAnchor(event.currentTarget); }; const handleStatusMenuClose = () => { setStatusMenuAnchor(null); }; const handleBackToDashboard = () => { window.location.href = '/seo-dashboard'; }; const handleRefreshData = async () => { try { setLoading(true); await refreshSEOAnalysis(); await fetchPlatformStatus(); } catch (error) { console.error('Error refreshing data:', error); } finally { setLoading(false); } }; const runStrategicInsights = async () => { setStrategicInsightsLoading(true); try { const res = await apiClient.post('/api/seo-dashboard/strategic-insights/run'); if (res.data?.success) { setStrategicInsightsHistory(prev => [res.data.report, ...prev]); } } catch (e: any) { console.error('Failed to run strategic insights:', e); } finally { setStrategicInsightsLoading(false); } }; // Background jobs visibility (user-triggered) const [showBackgroundJobs, setShowBackgroundJobs] = useState(false); // Platform status fetching function const fetchPlatformStatus = async () => { try { console.log('Fetching platform status...'); const response = await apiClient.get('/api/seo-dashboard/platforms'); console.log('Platform status response:', response.status, response.statusText); console.log('Platform status data:', response.data); setPlatformStatus(response.data); } catch (error) { console.error('Error fetching platform status:', error); } }; // Load competitor analysis data from onboarding step 3 const loadCompetitorAnalysisData = () => { try { const cachedData = localStorage.getItem('competitor_analysis_data'); const cachedUrl = localStorage.getItem('competitor_analysis_url'); const cachedTimestamp = localStorage.getItem('competitor_analysis_timestamp'); if (cachedData && cachedUrl && cachedTimestamp) { const analysisData = JSON.parse(cachedData); const timestamp = parseInt(cachedTimestamp); const isRecent = (Date.now() - timestamp) < (7 * 24 * 60 * 60 * 1000); // 7 days if (isRecent) { console.log('Loading competitor analysis data from onboarding step 3:', analysisData); setCompetitorAnalysisData(analysisData); } else { console.log('Competitor analysis data is too old, not loading'); } } else { console.log('No competitor analysis data found in localStorage'); } } catch (error) { console.error('Error loading competitor analysis data:', error); } }; const runCompetitiveSitemapBenchmarking = async () => { setCompetitiveSitemapBenchmarkingError(null); setCompetitiveSitemapBenchmarkingLoading(true); try { await apiClient.post('/api/seo/competitive-sitemap-benchmarking/run', { max_competitors: null }); const sitemapBenchResponse = await apiClient.get('/api/seo/competitive-sitemap-benchmarking'); const report = sitemapBenchResponse?.data?.data?.report ?? null; setCompetitiveSitemapBenchmarkingReport(report); } catch (e: any) { setCompetitiveSitemapBenchmarkingError(e?.response?.data?.detail || e?.message || 'Failed to run benchmark'); } finally { setCompetitiveSitemapBenchmarkingLoading(false); } }; if (loading) { return ; } if (error || !data) { return Failed to load dashboard data; } // Show sign-in prompt if not authenticated const statusUiMap: Record = { active: { label: 'Active', color: '#22c55e', bg: 'rgba(34,197,94,0.12)', border: 'rgba(34,197,94,0.4)', action: 'No action needed. Monitor next execution to confirm regular runs.' }, failed: { label: 'Failed', color: '#ef4444', bg: 'rgba(239,68,68,0.12)', border: 'rgba(239,68,68,0.4)', action: 'Review the latest error and rerun after fixing data/source issues.' }, paused: { label: 'Paused', color: '#f59e0b', bg: 'rgba(245,158,11,0.12)', border: 'rgba(245,158,11,0.4)', action: 'Resume this task from scheduler controls when ready.' }, needs_intervention: { label: 'Needs intervention', color: '#f97316', bg: 'rgba(249,115,22,0.12)', border: 'rgba(249,115,22,0.4)', action: 'Immediate action required. Inspect failures and reconfigure before retrying.' }, not_scheduled: { label: 'Not scheduled', color: '#94a3b8', bg: 'rgba(148,163,184,0.12)', border: 'rgba(148,163,184,0.4)', action: 'Complete onboarding scheduling or create the task in scheduler.' } }; const orderedTaskKeys = [ 'OnboardingFullWebsiteAnalysisTask', 'DeepCompetitorAnalysisTask', 'SIFIndexingTask', 'MarketTrendsTask' ]; if (!isLoaded) { return ; } if (!isSignedIn) { return ( πŸ” SEO Dashboard Sign in to access your SEO analytics and Google Search Console data ); } return ( {/* Professional Compact Header */} {/* Left Section - Navigation & Title */} SEO Dashboard AI-powered insights and recommendations {/* Center Section - Status Overview */} } label={(() => { const freshness = getAnalysisFreshness(); return freshness.label; })()} size="small" sx={{ bgcolor: 'rgba(255, 255, 255, 0.1)', color: 'white', border: '1px solid rgba(255, 255, 255, 0.2)', fontSize: '0.75rem' }} /> {onboardingTaskHealth && ( task?.status === 'active').length} active`} size="small" sx={{ ml: 2, bgcolor: 'rgba(255, 255, 255, 0.1)', color: 'white', border: '1px solid rgba(255, 255, 255, 0.2)' }} /> )} {/* Right Section - User Menu */} {/* Status Menu */} Platform Status {/* GSC Status */} Google Search Console: {platformStatus.gsc.connected ? 'Connected' : 'Disconnected'} {!platformStatus.gsc.connected && ( )} {/* Bing Status */} Bing Webmaster: {platformStatus.bing.connected ? 'Connected' : platformStatus.bing.status === 'expired' ? 'Expired' : 'Disconnected'} {platformStatus.bing.status === 'expired' && platformStatus.bing.last_token_date && ( Last connected: {new Date(platformStatus.bing.last_token_date).toLocaleDateString()} )} {!platformStatus.bing.connected && ( )} {/* User Menu */} {user?.primaryEmailAddress?.emailAddress || 'User'} Refresh Data Sign Out {/* CopilotKit Test Panel removed */} {/* Dashboard Tabs */} {/* Tab Content: Overview */} {dashboardTab === 0 && ( <> {/* Search Performance Overview */} πŸ“Š Search Performance Overview { console.log('Real analytics data loaded:', analyticsData); }} onRefreshReady={(fn) => { platformRefreshRef.current = fn; }} onReconnect={(platform) => { if (platform === 'gsc') { handleGSCReconnect(); } else if (platform === 'bing') { handleBingReconnect(); } }} showBackgroundJobs={showBackgroundJobs} /> {/* Enhanced Metrics with Tooltips */} Connected Platforms {(platformStatus.gsc.connected ? 1 : 0) + (platformStatus.bing.connected ? 1 : 0)} of 2 platforms Total Clicks {data.metrics?.traffic?.value || data.summary?.clicks || 0} from search results Total Impressions {data.metrics?.impressions?.value || data.summary?.impressions || 0} search appearances Overall CTR {data.metrics?.ctr?.value || data.summary?.ctr || 0}% click-through rate {/* Full Site Technical SEO Audit (from onboarding background job) */} {data.technical_seo_audit && ( 🧩 Technical SEO Audit {data.technical_seo_audit.status === 'scheduled' && ( } label={`Scheduled${data.technical_seo_audit.next_execution ? ` β€’ ${new Date(data.technical_seo_audit.next_execution).toLocaleString()}` : ''}`} sx={{ bgcolor: 'rgba(255, 193, 7, 0.15)', color: '#FFC107' }} /> )} {data.technical_seo_audit.status === 'ready' && ( } label="Results Available" sx={{ bgcolor: 'rgba(76, 175, 80, 0.15)', color: '#4CAF50' }} /> )} {data.technical_seo_audit.status === 'error' && ( )} {data.technical_seo_audit.status === 'scheduled' && ( Full-site audit runs automatically after onboarding. This may take a few minutes depending on how many pages we discover. )} Pages Audited {data.technical_seo_audit.pages_audited} Average Score {data.technical_seo_audit.avg_score}/100 Fix Scheduled {data.technical_seo_audit.fix_scheduled_pages} {data.technical_seo_audit.worst_pages?.length > 0 && ( Lowest Scoring Pages {data.technical_seo_audit.worst_pages.slice(0, 5).map((p) => ( {p.page_url} ))} )} )} {/* Data-Driven Content Intelligence (Advertools) */} {data.advertools_insights && ( )} {/* Competitive Analysis from Onboarding Step 3 */} {competitorAnalysisData && ( 🎯 Competitive Analysis Competitors Found {competitorAnalysisData.competitors?.length || 0} in your market Social Media Accounts {Object.keys(competitorAnalysisData.social_media_accounts || {}).length} competitor accounts Social Citations {competitorAnalysisData.social_media_citations?.length || 0} mentions found {/* Competitor List */} {competitorAnalysisData.competitors && competitorAnalysisData.competitors.length > 0 && ( Top Competitors {competitorAnalysisData.competitors.slice(0, 6).map((competitor: any, index: number) => ( {competitor.name || competitor.domain || `Competitor ${index + 1}`} {competitor.domain || competitor.url || 'No domain available'} {competitor.description && ( {competitor.description.length > 100 ? `${competitor.description.substring(0, 100)}...` : competitor.description} )} ))} )} {/* Research Summary */} {competitorAnalysisData.research_summary && ( Research Summary {competitorAnalysisData.research_summary} )} )} {/* Strategic Insights (Winning Moves) */} {strategicInsightsHistory.length > 0 && ( πŸ† Strategic Insights (Winning Moves) )} {/* Phase 2B: Semantic Intelligence Dashboard */} 🧠 Semantic Intelligence {/* Semantic Health Overview */} {/* Placeholder for additional semantic metrics */} {/* Full Semantic Dashboard */} {/* Deep Competitor Analysis (auto-scheduled) */} {deepCompetitorAnalysisData && ( πŸ” Deep Competitor Analysis Status {deepCompetitorAnalysisData.last_status && ( Last run: {deepCompetitorAnalysisData.last_status} )} Competitors {deepCompetitorAnalysisData.competitors_count ?? (deepCompetitorAnalysisData.report?.competitors?.length || 0)} analyzed Schedule {deepCompetitorAnalysisData.next_execution ? deepCompetitorAnalysisData.next_execution : (deepCompetitorAnalysisData.last_run ? 'Completed' : 'Pending')} {deepCompetitorAnalysisData.last_run && ( Last run: {deepCompetitorAnalysisData.last_run} )} {!deepCompetitorAnalysisData.report && ( Deep competitor analysis is scheduled or running. Once complete, the full per-competitor extraction, AI analysis, and aggregated insights will appear here. )} {deepCompetitorAnalysisData.report?.aggregation && ( Aggregated Insights Common Themes {(deepCompetitorAnalysisData.report.aggregation.common_patterns?.common_themes || []).slice(0, 8).join(' β€’ ') || 'β€”'} Top Opportunities {(deepCompetitorAnalysisData.report.aggregation.content_gaps_and_opportunities || []) .slice(0, 5) .map((g: any) => g.gap) .filter(Boolean) .join(' β€’ ') || 'β€”'} Recommended Actions {(deepCompetitorAnalysisData.report.aggregation.strategic_recommendations || []) .slice(0, 5) .map((r: any) => r.action) .filter(Boolean) .join(' β€’ ') || 'β€”'} )} {deepCompetitorAnalysisData.report?.competitors?.length > 0 && ( Per-Competitor Details {deepCompetitorAnalysisData.report.competitors.slice(0, 25).map((c: any, idx: number) => { const input = c?.input || {}; const extraction = c?.extraction || {}; const ai = c?.ai_analysis || {}; const title = input.name || input.domain || `Competitor ${idx + 1}`; const domain = input.domain || input.url || ''; return ( }> {title} {domain} Extraction {extraction.page_meta?.title || 'β€”'} {(extraction.page_meta?.meta_description || '').slice(0, 220) || 'β€”'} CTA signals: {(extraction.signals?.cta_signals?.keyword_hits || []).slice(0, 8).join(', ') || 'β€”'} Proof signals: {(extraction.signals?.proof_signals?.keyword_hits || []).slice(0, 6).join(', ') || 'β€”'} AI Analysis Value prop: {ai.positioning?.value_prop || 'β€”'} Primary offer: {ai.positioning?.primary_offer || 'β€”'} Themes: {(ai.content_strategy?.themes || []).slice(0, 6).join(' β€’ ') || 'β€”'} Opportunities vs you: {(ai.comparison_to_user_baseline?.opportunities || []).slice(0, 4).join(' β€’ ') || 'β€”'} ); })} )} )} {/* Weekly Strategic Brief */} 🧠 Weekly Strategy Brief {strategicInsightsHistory.length > 0 ? ( ) : ( No strategic insights generated yet. Run your first analysis to see "The Big Move" and market opportunities. )} {(competitiveSitemapBenchmarkingReport || competitorAnalysisData) && ( πŸ—ΊοΈ Competitive Sitemap Benchmarking (No AI) {competitiveSitemapBenchmarkingError && ( {competitiveSitemapBenchmarkingError} )} {!competitiveSitemapBenchmarkingReport && ( No benchmarking report yet. Run it to compare your sitemap structure against competitors and discover missing sections. )} {competitiveSitemapBenchmarkingReport && competitiveSitemapBenchmarkingReport.benchmark && ( )} )} {/* Strategic Insights Section */} {strategicInsightsHistory.length > 0 && ( 🧠 AI-Powered Strategic Insights )} {onboardingTaskHealth && ( Onboarding Scheduled SEO Tasks Unified health view for onboarding automation jobs. {orderedTaskKeys.map((taskKey) => { const task = onboardingTaskHealth.tasks?.[taskKey]; if (!task) return null; const status = (task.status || 'not_scheduled') as OnboardingTaskStatus; const ui = statusUiMap[status] || statusUiMap.not_scheduled; return ( {task.label || taskKey} Next: {task.next_execution ? new Date(task.next_execution).toLocaleString() : 'Not scheduled'} Last success: {task.last_success ? new Date(task.last_success).toLocaleString() : 'No successful runs yet'} Last failure: {task.last_failure ? new Date(task.last_failure).toLocaleString() : 'No failure recorded'} Consecutive failures: {task.consecutive_failures ?? 0} {ui.action} {task.latest_execution?.error_message ? ` Latest error: ${task.latest_execution.error_message}` : ''} ); })} )} {/* SEO Analyzer Panel */} {/* Copilot Suggestions Panel */} {/* SEO Copilot Component for data loading and error handling */} )} {/* Tab Content: Enterprise Analysis */} {dashboardTab === 1 && ( )} ); }; export default SEODashboard;