import { useState, useEffect, useCallback } from 'react'; import { useNavigate } from 'react-router'; import PageMeta from '../../components/common/PageMeta'; import PageHeader from '../../components/common/PageHeader'; import ModuleNavigationTabs from '../../components/navigation/ModuleNavigationTabs'; import ModuleMetricsFooter, { MetricItem, ProgressMetric } from '../../components/dashboard/ModuleMetricsFooter'; import { optimizerApi, EntryPoint } from '../../api/optimizer.api'; import { fetchContent, Content as ContentType } from '../../services/api'; import { useToast } from '../../components/ui/toast/ToastContainer'; import { SourceBadge, ContentSource } from '../../components/content/SourceBadge'; import { SyncStatusBadge, SyncStatus } from '../../components/content/SyncStatusBadge'; import { ContentFilter, FilterState } from '../../components/content/ContentFilter'; import { OptimizationScores } from '../../components/optimizer/OptimizationScores'; import { BoltIcon, CheckCircleIcon, FileIcon } from '../../icons'; import { useSectorStore } from '../../store/sectorStore'; import { usePageSizeStore } from '../../store/pageSizeStore'; export default function OptimizerContentSelector() { const navigate = useNavigate(); const toast = useToast(); const { activeSector } = useSectorStore(); const { pageSize } = usePageSizeStore(); const [content, setContent] = useState([]); const [filteredContent, setFilteredContent] = useState([]); const [loading, setLoading] = useState(true); const [processing, setProcessing] = useState([]); const [selectedIds, setSelectedIds] = useState([]); const [filters, setFilters] = useState({ source: 'all', syncStatus: 'all', search: '', }); const [entryPoint, setEntryPoint] = useState('auto'); const [currentPage, setCurrentPage] = useState(1); const [totalCount, setTotalCount] = useState(0); const loadContent = useCallback(async () => { setLoading(true); try { const data = await fetchContent({ page: currentPage, page_size: pageSize, sector_id: activeSector?.id, }); setContent(data.results || []); setTotalCount(data.count || 0); } catch (error: any) { console.error('Error loading content:', error); toast.error(`Failed to load content: ${error.message}`); } finally { setLoading(false); } }, [currentPage, pageSize, activeSector, toast]); useEffect(() => { loadContent(); }, [loadContent]); // Apply filters useEffect(() => { let filtered = [...content]; // Search filter if (filters.search) { const searchLower = filters.search.toLowerCase(); filtered = filtered.filter( item => item.title?.toLowerCase().includes(searchLower) || item.meta_title?.toLowerCase().includes(searchLower) || item.primary_keyword?.toLowerCase().includes(searchLower) ); } // Source filter if (filters.source !== 'all') { filtered = filtered.filter(item => item.source === filters.source); } // Sync status filter if (filters.syncStatus !== 'all') { filtered = filtered.filter(item => item.sync_status === filters.syncStatus); } setFilteredContent(filtered); }, [content, filters]); const handleOptimize = async (contentId: number) => { try { setProcessing(prev => [...prev, contentId]); const result = await optimizerApi.optimize(contentId, entryPoint); toast.success(`Content optimized! Score: ${result.scores_after.overall_score.toFixed(1)}`); // Refresh content list await loadContent(); } catch (error: any) { console.error('Error optimizing content:', error); toast.error(`Failed to optimize content: ${error.message}`); } finally { setProcessing(prev => prev.filter(id => id !== contentId)); } }; const handleBatchOptimize = async () => { if (selectedIds.length === 0) { toast.error('Please select at least one content item'); return; } try { setProcessing(selectedIds); const result = await optimizerApi.batchOptimize(selectedIds, entryPoint); toast.success( `Optimized ${result.succeeded} content item${result.succeeded !== 1 ? 's' : ''}. ` + `${result.failed > 0 ? `${result.failed} failed.` : ''}` ); setSelectedIds([]); await loadContent(); } catch (error: any) { console.error('Error batch optimizing content:', error); toast.error(`Failed to optimize content: ${error.message}`); } finally { setProcessing([]); } }; const toggleSelection = (contentId: number) => { setSelectedIds(prev => prev.includes(contentId) ? prev.filter(id => id !== contentId) : [...prev, contentId] ); }; const toggleSelectAll = () => { if (selectedIds.length === filteredContent.length) { setSelectedIds([]); } else { setSelectedIds(filteredContent.map(item => item.id)); } }; return ( <>
, color: 'orange', }} /> }, ]} />

Select content to optimize for SEO, readability, and engagement

{/* Filters */} {loading ? (

Loading content...

) : (
{filteredContent.map((item) => { const isSelected = selectedIds.includes(item.id); const isProcessing = processing.includes(item.id); const scores = item.optimization_scores; return ( ); })}
0} onChange={toggleSelectAll} className="rounded border-gray-300 text-blue-600 focus:ring-blue-500" /> Title Source Status Score Version Actions
toggleSelection(item.id)} className="rounded border-gray-300 text-blue-600 focus:ring-blue-500" />
{item.title || 'Untitled'}
{scores?.overall_score ? ( {scores.overall_score.toFixed(1)} ) : ( N/A )} {item.optimizer_version || 0}
{/* Pagination */} {totalCount > pageSize && (
Showing {((currentPage - 1) * pageSize) + 1} to {Math.min(currentPage * pageSize, totalCount)} of {totalCount} results
)}
)} {/* Module Metrics Footer */} , accentColor: 'blue', href: '/optimizer/content', }, { title: 'Optimized', value: content.filter(c => c.optimizer_version && c.optimizer_version > 0).length.toLocaleString(), subtitle: `${processing.length} processing`, icon: , accentColor: 'orange', }, { title: 'Avg Score', value: content.length > 0 && content.some(c => c.optimization_scores?.overall_score) ? (content .filter(c => c.optimization_scores?.overall_score) .reduce((sum, c) => sum + (c.optimization_scores?.overall_score || 0), 0) / content.filter(c => c.optimization_scores?.overall_score).length ).toFixed(1) : '-', subtitle: `${content.filter(c => c.optimization_scores?.overall_score && c.optimization_scores.overall_score >= 80).length} high score`, icon: , accentColor: 'green', }, ]} progress={{ label: 'Content Optimization Progress', value: totalCount > 0 ? Math.round((content.filter(c => c.optimizer_version && c.optimizer_version > 0).length / totalCount) * 100) : 0, color: 'warning', }} />
); }