import React, { useState, useEffect } from 'react'; import { Stack, Group, Text, Button, SegmentedControl, Loader, Alert, Card, } from '@mantine/core'; import { useTranslation } from 'react-i18next'; import usageAnalyticsService, { EndpointStatisticsResponse } from '@app/services/usageAnalyticsService'; import UsageAnalyticsChart from '@app/components/shared/config/configSections/usage/UsageAnalyticsChart'; import UsageAnalyticsTable from '@app/components/shared/config/configSections/usage/UsageAnalyticsTable'; import LocalIcon from '@app/components/shared/LocalIcon'; import { useLoginRequired } from '@app/hooks/useLoginRequired'; import LoginRequiredBanner from '@app/components/shared/config/LoginRequiredBanner'; const AdminUsageSection: React.FC = () => { const { t } = useTranslation(); const { loginEnabled, validateLoginEnabled } = useLoginRequired(); const [data, setData] = useState(null); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); const [displayMode, setDisplayMode] = useState<'top10' | 'top20' | 'all'>('top10'); const [dataType, setDataType] = useState<'all' | 'api' | 'ui'>('all'); const fetchData = async () => { if (!validateLoginEnabled()) { return; } try { setLoading(true); setError(null); const limit = displayMode === 'all' ? undefined : displayMode === 'top10' ? 10 : 20; const response = await usageAnalyticsService.getEndpointStatistics(limit, dataType); setData(response); } catch (err) { setError(err instanceof Error ? err.message : 'Failed to load usage statistics'); } finally { setLoading(false); } }; useEffect(() => { if (loginEnabled) { fetchData(); } else { // Provide example usage analytics data when login is disabled const totalVisits = 15847; const allEndpoints = [ { endpoint: 'merge-pdfs', visits: 3245, percentage: (3245 / totalVisits) * 100 }, { endpoint: 'compress-pdf', visits: 2891, percentage: (2891 / totalVisits) * 100 }, { endpoint: 'pdf-to-img', visits: 2156, percentage: (2156 / totalVisits) * 100 }, { endpoint: 'split-pdf', visits: 1834, percentage: (1834 / totalVisits) * 100 }, { endpoint: 'rotate-pdf', visits: 1523, percentage: (1523 / totalVisits) * 100 }, { endpoint: 'ocr-pdf', visits: 1287, percentage: (1287 / totalVisits) * 100 }, { endpoint: 'add-watermark', visits: 945, percentage: (945 / totalVisits) * 100 }, { endpoint: 'extract-images', visits: 782, percentage: (782 / totalVisits) * 100 }, { endpoint: 'add-password', visits: 621, percentage: (621 / totalVisits) * 100 }, { endpoint: 'html-to-pdf', visits: 563, percentage: (563 / totalVisits) * 100 }, { endpoint: 'remove-password', visits: 487, percentage: (487 / totalVisits) * 100 }, { endpoint: 'pdf-to-pdfa', visits: 423, percentage: (423 / totalVisits) * 100 }, { endpoint: 'extract-pdf-metadata', visits: 356, percentage: (356 / totalVisits) * 100 }, { endpoint: 'add-page-numbers', visits: 298, percentage: (298 / totalVisits) * 100 }, { endpoint: 'crop', visits: 245, percentage: (245 / totalVisits) * 100 }, { endpoint: 'flatten', visits: 187, percentage: (187 / totalVisits) * 100 }, { endpoint: 'sanitize-pdf', visits: 134, percentage: (134 / totalVisits) * 100 }, { endpoint: 'auto-split-pdf', visits: 98, percentage: (98 / totalVisits) * 100 }, { endpoint: 'scale-pages', visits: 76, percentage: (76 / totalVisits) * 100 }, { endpoint: 'compare-pdfs', visits: 42, percentage: (42 / totalVisits) * 100 }, ]; // Filter based on display mode let filteredEndpoints = allEndpoints; if (displayMode === 'top10') { filteredEndpoints = allEndpoints.slice(0, 10); } else if (displayMode === 'top20') { filteredEndpoints = allEndpoints.slice(0, 20); } setData({ totalVisits: totalVisits, totalEndpoints: filteredEndpoints.length, endpoints: filteredEndpoints, }); setLoading(false); } }, [displayMode, dataType, loginEnabled]); const handleRefresh = () => { if (!validateLoginEnabled()) { return; } fetchData(); }; const getDisplayModeLabel = () => { switch (displayMode) { case 'top10': return t('usage.showing.top10', 'Top 10'); case 'top20': return t('usage.showing.top20', 'Top 20'); case 'all': return t('usage.showing.all', 'All'); default: return ''; } }; // Override loading state when login is disabled const actualLoading = loginEnabled ? loading : false; // Early returns for loading/error states if (actualLoading) { return (
); } if (error) { return ( {error} ); } if (!data) { return ( {t('usage.noDataMessage', 'No usage statistics are currently available.')} ); } const chartData = data?.endpoints?.map((e) => ({ label: e.endpoint, value: e.visits })) || []; const displayedVisits = data?.endpoints?.reduce((sum, e) => sum + e.visits, 0) || 0; const displayedPercentage = (data?.totalVisits || 0) > 0 ? ((displayedVisits / (data?.totalVisits || 1)) * 100).toFixed(1) : '0'; return ( {/* Controls */} setDisplayMode(value as 'top10' | 'top20' | 'all')} disabled={!loginEnabled} data={[ { value: 'top10', label: t('usage.controls.top10', 'Top 10'), }, { value: 'top20', label: t('usage.controls.top20', 'Top 20'), }, { value: 'all', label: t('usage.controls.all', 'All'), }, ]} /> {t('usage.controls.dataTypeLabel', 'Data Type:')} setDataType(value as 'all' | 'api' | 'ui')} disabled={!loginEnabled} data={[ { value: 'all', label: t('usage.controls.dataType.all', 'All'), }, { value: 'api', label: t('usage.controls.dataType.api', 'API'), }, { value: 'ui', label: t('usage.controls.dataType.ui', 'UI'), }, ]} /> {/* Statistics Summary */}
{t('usage.stats.totalEndpoints', 'Total Endpoints')} {data.totalEndpoints}
{t('usage.stats.totalVisits', 'Total Visits')} {data.totalVisits.toLocaleString()}
{t('usage.stats.showing', 'Showing')} {getDisplayModeLabel()}
{t('usage.stats.selectedVisits', 'Selected Visits')} {displayedVisits.toLocaleString()} ({displayedPercentage}%)
{/* Chart and Table */}
); }; export default AdminUsageSection;