/** * Site Progress Widget - Stage 3 * Displays cluster-level completion bars for hub/supporting/attribute pages */ import React, { useState, useEffect } from 'react'; import { useNavigate } from 'react-router-dom'; import { Card } from '../ui/card'; import Badge from '../ui/badge/Badge'; // import { fetchSiteProgress, SiteProgress } from '../../services/api'; import { CheckCircleIcon, XCircleIcon, AlertCircleIcon, ArrowRightIcon } from 'lucide-react'; interface SiteProgressWidgetProps { blueprintId: number; siteId?: number; } export default function SiteProgressWidget({ blueprintId, siteId }: SiteProgressWidgetProps) { const navigate = useNavigate(); const [progress, setProgress] = useState(null); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); const [retryCount, setRetryCount] = useState(0); useEffect(() => { loadProgress(); }, [blueprintId]); const loadProgress = async () => { try { setLoading(true); setError(null); const data = await fetchSiteProgress(blueprintId); setProgress(data); setRetryCount(0); // Reset retry count on success } catch (error: any) { console.error('Failed to load site progress:', error); setError(error.message || 'Failed to load site progress. Please try again.'); setProgress(null); } finally { setLoading(false); } }; const handleRetry = () => { setRetryCount(prev => prev + 1); loadProgress(); }; if (loading) { return (
Loading progress...
); } if (error && !progress) { return (
{error}
); } if (!progress) { return (

No progress data available

); } const clusterCoverage: NonNullable = progress.cluster_coverage ?? { total_clusters: 0, covered_clusters: 0, details: [] as NonNullable['details'], }; const taxonomyCoverage: NonNullable = progress.taxonomy_coverage ?? { total_taxonomies: 0, defined_taxonomies: 0, details: [] as NonNullable['details'], }; const validationFlags: NonNullable = progress.validation_flags ?? { clusters_attached: false, taxonomies_defined: false, sitemap_generated: false, all_pages_generated: false, }; const getStatusColor = (status: string) => { switch (status) { case 'complete': return 'success'; case 'blocked': return 'error'; default: return 'warning'; } }; const getRoleColor = (role: string) => { switch (role) { case 'hub': return 'primary'; case 'supporting': return 'success'; case 'attribute': return 'warning'; default: return 'info'; } }; return (

Site Progress: {progress.blueprint_name}

{progress.overall_status ? progress.overall_status.replace('_', ' ').replace(/\b\w/g, l => l.toUpperCase()) : 'Unknown'}
{/* Overall Stats */}
{clusterCoverage.covered_clusters}/{clusterCoverage.total_clusters}
Clusters Covered
{taxonomyCoverage.defined_taxonomies}/{taxonomyCoverage.total_taxonomies}
Taxonomies Defined
{validationFlags.all_pages_generated ? '✓' : '✗'}
All Pages Generated
{/* Cluster Progress */}

Cluster Coverage

{clusterCoverage.details && clusterCoverage.details.length > 0 ? ( clusterCoverage.details.map((cluster) => { const hubPages = cluster.hub_pages ?? 0; const supportingPages = cluster.supporting_pages ?? 0; const attributePages = cluster.attribute_pages ?? 0; const contentCount = cluster.content_count ?? 0; const totalPages = hubPages + supportingPages + attributePages; const completionPercent = totalPages > 0 ? Math.min(100, (contentCount / totalPages) * 100) : 0; return (
{cluster.cluster_name}
{cluster.role} {cluster.is_complete ? ( ) : ( )}
{contentCount} content / {totalPages} pages
{/* Progress Bar */}
Completion {completionPercent.toFixed(0)}%
{/* Page Type Breakdown */}
{hubPages}
Hub
{supportingPages}
Supporting
{attributePages}
Attribute
{/* Validation Messages */} {cluster.validation_messages && cluster.validation_messages.length > 0 && (
Issues:
    {cluster.validation_messages.map((msg, idx) => (
  • {msg}
  • ))}
)}
); }) ) : (

No clusters found. Attach clusters to get started.

)}
{/* Validation Flags Summary */}

Validation Status

{validationFlags.clusters_attached ? ( ) : ( )} Clusters Attached
{validationFlags.taxonomies_defined ? ( ) : ( )} Taxonomies Defined
{validationFlags.sitemap_generated ? ( ) : ( )} Sitemap Generated
{validationFlags.all_pages_generated ? ( ) : ( )} All Pages Generated
{/* Error banner if data loaded but has errors */} {error && progress && (
Some data may be outdated.
)} ); }