metricsa dn backedn fixes

This commit is contained in:
IGNY8 VPS (Salman)
2025-12-29 04:33:22 +00:00
parent 53fdebf733
commit 0ffd21b9bf
17 changed files with 929 additions and 266 deletions

View File

@@ -8,6 +8,7 @@ import { Link } from 'react-router-dom';
import TablePageTemplate from '../../templates/TablePageTemplate';
import {
fetchContentImages,
fetchImages,
ContentImagesGroup,
ContentImagesResponse,
fetchImageGenerationSettings,
@@ -34,7 +35,13 @@ export default function Images() {
// Data state
const [images, setImages] = useState<ContentImagesGroup[]>([]);
const [loading, setLoading] = useState(true);
// Total counts for footer widget and header metrics (not page-filtered)
const [totalComplete, setTotalComplete] = useState(0);
const [totalPartial, setTotalPartial] = useState(0);
const [totalPending, setTotalPending] = useState(0);
const [totalImagesCount, setTotalImagesCount] = useState(0); // Actual images count
// Filter state
const [searchTerm, setSearchTerm] = useState('');
const [statusFilter, setStatusFilter] = useState('');
@@ -69,6 +76,49 @@ export default function Images() {
const [isImageModalOpen, setIsImageModalOpen] = useState(false);
const [modalImageUrl, setModalImageUrl] = useState<string | null>(null);
// Load total metrics for footer widget and header metrics (not affected by pagination)
const loadTotalMetrics = useCallback(async () => {
try {
// Fetch content-grouped images for status counts
const data: ContentImagesResponse = await fetchContentImages({});
const allImages = data.results || [];
// Count by overall_status (content-level status)
let complete = 0;
let partial = 0;
let pending = 0;
allImages.forEach(img => {
switch (img.overall_status) {
case 'complete':
complete++;
break;
case 'partial':
partial++;
break;
case 'pending':
pending++;
break;
}
});
setTotalComplete(complete);
setTotalPartial(partial);
setTotalPending(pending);
// Fetch ACTUAL total images count from the images endpoint
const imagesData = await fetchImages({ page_size: 1 });
setTotalImagesCount(imagesData.count || 0);
} catch (error) {
console.error('Error loading total metrics:', error);
}
}, []);
// Load total metrics on mount
useEffect(() => {
loadTotalMetrics();
}, [loadTotalMetrics]);
// Load images - wrapped in useCallback
const loadImages = useCallback(async () => {
setLoading(true);
@@ -155,18 +205,17 @@ export default function Images() {
};
}, [loadImages]);
// Debounced search
// Debounced search - reset to page 1 when search term changes
// Only depend on searchTerm to avoid pagination reset on page navigation
useEffect(() => {
const timer = setTimeout(() => {
if (currentPage === 1) {
loadImages();
} else {
setCurrentPage(1);
}
// Always reset to page 1 when search changes
// The main useEffect will handle reloading when currentPage changes
setCurrentPage(1);
}, 500);
return () => clearTimeout(timer);
}, [searchTerm, currentPage, loadImages]);
}, [searchTerm]);
// Handle sorting
const handleSort = (field: string, direction: 'asc' | 'desc') => {
@@ -438,16 +487,54 @@ export default function Images() {
});
}, [searchTerm, statusFilter, maxInArticleImages, handleGenerateImages, handleImageClick]);
// Calculate header metrics
// Calculate header metrics - use totals from API calls (not page data)
// This ensures metrics show correct totals across all pages, not just current page
const headerMetrics = useMemo(() => {
if (!pageConfig?.headerMetrics) return [];
return pageConfig.headerMetrics.map((metric) => ({
label: metric.label,
value: metric.calculate({ images, totalCount }),
accentColor: metric.accentColor,
tooltip: (metric as any).tooltip,
}));
}, [pageConfig?.headerMetrics, images, totalCount]);
// Override the calculate function to use pre-loaded totals instead of filtering page data
// Also add a "Total Images" metric at the end
const baseMetrics = pageConfig.headerMetrics.map((metric) => {
let value: number;
switch (metric.label) {
case 'Content':
value = totalCount || 0;
break;
case 'Complete':
// Use totalComplete from loadTotalMetrics()
value = totalComplete;
break;
case 'Partial':
// Use totalPartial from loadTotalMetrics()
value = totalPartial;
break;
case 'Pending':
// Use totalPending from loadTotalMetrics()
value = totalPending;
break;
default:
value = metric.calculate({ images, totalCount });
}
return {
label: metric.label,
value,
accentColor: metric.accentColor,
tooltip: (metric as any).tooltip,
};
});
// Add total images count metric
baseMetrics.push({
label: 'Total Images',
value: totalImagesCount,
accentColor: 'purple' as const,
tooltip: 'Total number of images across all content',
});
return baseMetrics;
}, [pageConfig?.headerMetrics, images, totalCount, totalComplete, totalPartial, totalPending, totalImagesCount]);
return (
<>
@@ -617,7 +704,7 @@ export default function Images() {
fromHref: '/writer/content',
actionLabel: 'Generate Images',
toLabel: 'Images',
toValue: totalCount,
toValue: totalImagesCount,
toHref: '/writer/images',
progress: 100,
color: 'purple',
@@ -650,7 +737,7 @@ export default function Images() {
],
writerItems: [
{ label: 'Content Generated', value: 0, color: 'blue' },
{ label: 'Images Created', value: totalCount, color: 'purple' },
{ label: 'Images Created', value: totalImagesCount, color: 'purple' },
{ label: 'Articles Published', value: 0, color: 'green' },
],
analyticsHref: '/account/usage',