![]() Server : Apache/2 System : Linux server-15-235-50-60 5.15.0-164-generic #174-Ubuntu SMP Fri Nov 14 20:25:16 UTC 2025 x86_64 User : gositeme ( 1004) PHP Version : 8.2.29 Disable Function : exec,system,passthru,shell_exec,proc_close,proc_open,dl,popen,show_source,posix_kill,posix_mkfifo,posix_getpwuid,posix_setpgid,posix_setsid,posix_setuid,posix_setgid,posix_seteuid,posix_setegid,posix_uname Directory : /home/gositeme/domains/lavocat.ca/public_html/src/components/ |
import React, { useState, useEffect } from 'react';
import { format } from 'date-fns';
interface AnalyticsData {
workloadDistribution: {
userId: string;
name: string;
role: string;
activeCases: number;
estimatedHours: number;
utilizationRate: number;
}[];
caseComplexityBreakdown: {
complexity: string;
count: number;
averageTime: number;
}[];
performanceMetrics: {
userId: string;
name: string;
successRate: number;
averageCompletionTime: number;
clientSatisfaction: number;
}[];
facilityDistribution: {
facility: string;
count: number;
averageComplexity: number;
}[];
timelineAnalysis: {
month: string;
newCases: number;
completedCases: number;
pendingCases: number;
}[];
}
const AdvancedAnalyticsDashboard: React.FC = () => {
const [analytics, setAnalytics] = useState<AnalyticsData | null>(null);
const [loading, setLoading] = useState(true);
const [selectedPeriod, setSelectedPeriod] = useState('last30days');
const [selectedView, setSelectedView] = useState<'overview' | 'workload' | 'performance' | 'trends'>('overview');
useEffect(() => {
fetchAnalytics();
}, [selectedPeriod]);
const fetchAnalytics = async () => {
try {
const response = await fetch(`/api/admin/analytics?period=${selectedPeriod}`);
if (response.ok) {
const data = await response.json();
setAnalytics(data);
}
} catch (error) {
console.error('Error fetching analytics:', error);
} finally {
setLoading(false);
}
};
if (loading) {
return (
<div className="flex items-center justify-center h-64">
<div className="animate-spin rounded-full h-8 w-8 border-b-2 border-primary"></div>
</div>
);
}
if (!analytics) {
return <div className="text-center py-8">No analytics data available</div>;
}
return (
<div className="space-y-6">
{/* Header with Controls */}
<div className="bg-white shadow rounded-lg p-6">
<div className="flex items-center justify-between mb-4">
<h1 className="text-2xl font-bold text-gray-900 flex items-center gap-2">
📊 Advanced Analytics Dashboard
</h1>
<div className="flex gap-4">
<select
value={selectedPeriod}
onChange={(e) => setSelectedPeriod(e.target.value)}
className="px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-primary"
>
<option value="last7days">Last 7 Days</option>
<option value="last30days">Last 30 Days</option>
<option value="last90days">Last 90 Days</option>
<option value="lastyear">Last Year</option>
</select>
</div>
</div>
<nav className="flex space-x-1">
{[
{ id: 'overview', label: '📈 Overview' },
{ id: 'workload', label: '⚖️ Workload Analysis' },
{ id: 'performance', label: '🎯 Performance Metrics' },
{ id: 'trends', label: '📊 Trends & Predictions' }
].map((tab) => (
<button
key={tab.id}
onClick={() => setSelectedView(tab.id as any)}
className={`px-4 py-2 text-sm font-medium rounded-md transition-colors ${
selectedView === tab.id
? 'bg-primary text-white'
: 'text-gray-500 hover:text-gray-700 hover:bg-gray-100'
}`}
>
{tab.label}
</button>
))}
</nav>
</div>
{/* Overview Dashboard */}
{selectedView === 'overview' && (
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6">
<div className="bg-white p-6 rounded-lg shadow">
<div className="flex items-center justify-between">
<div>
<p className="text-sm text-gray-600">Total Active Cases</p>
<p className="text-3xl font-bold text-primary">
{analytics.workloadDistribution.reduce((sum, user) => sum + user.activeCases, 0)}
</p>
</div>
<div className="text-4xl">📋</div>
</div>
</div>
<div className="bg-white p-6 rounded-lg shadow">
<div className="flex items-center justify-between">
<div>
<p className="text-sm text-gray-600">Average Utilization</p>
<p className="text-3xl font-bold text-green-600">
{Math.round(
analytics.workloadDistribution.reduce((sum, user) => sum + user.utilizationRate, 0) /
analytics.workloadDistribution.length
)}%
</p>
</div>
<div className="text-4xl">⚡</div>
</div>
</div>
<div className="bg-white p-6 rounded-lg shadow">
<div className="flex items-center justify-between">
<div>
<p className="text-sm text-gray-600">Success Rate</p>
<p className="text-3xl font-bold text-blue-600">
{Math.round(
analytics.performanceMetrics.reduce((sum, user) => sum + user.successRate, 0) /
analytics.performanceMetrics.length
)}%
</p>
</div>
<div className="text-4xl">🎯</div>
</div>
</div>
<div className="bg-white p-6 rounded-lg shadow">
<div className="flex items-center justify-between">
<div>
<p className="text-sm text-gray-600">Critical Cases</p>
<p className="text-3xl font-bold text-red-600">
{analytics.caseComplexityBreakdown.find(c => c.complexity === 'critical')?.count || 0}
</p>
</div>
<div className="text-4xl">🚨</div>
</div>
</div>
</div>
)}
{/* Workload Analysis */}
{selectedView === 'workload' && (
<div className="bg-white shadow rounded-lg p-6">
<h2 className="text-lg font-semibold text-gray-900 mb-4">⚖️ Team Workload Distribution</h2>
<div className="space-y-4">
{analytics.workloadDistribution.map((user) => (
<div key={user.userId} className="border border-gray-200 rounded-lg p-4">
<div className="flex items-center justify-between mb-2">
<div className="flex items-center gap-3">
<div className="w-10 h-10 bg-gradient-to-r from-primary to-primary-dark rounded-full flex items-center justify-center text-white font-semibold">
{user.name.charAt(0).toUpperCase()}
</div>
<div>
<h3 className="font-medium text-gray-900">{user.name}</h3>
<p className="text-sm text-gray-600">{user.role}</p>
</div>
</div>
<div className="text-right">
<p className="text-lg font-semibold">{user.activeCases} cases</p>
<p className="text-sm text-gray-600">{user.estimatedHours}h estimated</p>
</div>
</div>
<div className="mt-3">
<div className="flex justify-between text-sm text-gray-600 mb-1">
<span>Utilization</span>
<span>{user.utilizationRate}%</span>
</div>
<div className="w-full bg-gray-200 rounded-full h-2">
<div
className={`h-2 rounded-full ${
user.utilizationRate > 90 ? 'bg-red-500' :
user.utilizationRate > 70 ? 'bg-yellow-500' : 'bg-green-500'
}`}
style={{ width: `${Math.min(user.utilizationRate, 100)}%` }}
></div>
</div>
<div className="text-xs text-gray-500 mt-1">
{user.utilizationRate > 90 ? '🔴 Overloaded' :
user.utilizationRate > 70 ? '🟡 Busy' : '🟢 Optimal'}
</div>
</div>
</div>
))}
</div>
</div>
)}
{/* Performance Metrics */}
{selectedView === 'performance' && (
<div className="grid grid-cols-1 lg:grid-cols-2 gap-6">
<div className="bg-white shadow rounded-lg p-6">
<h2 className="text-lg font-semibold text-gray-900 mb-4">🎯 Individual Performance</h2>
<div className="space-y-4">
{analytics.performanceMetrics.map((user) => (
<div key={user.userId} className="border border-gray-200 rounded-lg p-4">
<h3 className="font-medium text-gray-900 mb-3">{user.name}</h3>
<div className="grid grid-cols-3 gap-4 text-center">
<div>
<p className="text-2xl font-bold text-green-600">{user.successRate}%</p>
<p className="text-xs text-gray-600">Success Rate</p>
</div>
<div>
<p className="text-2xl font-bold text-blue-600">{user.averageCompletionTime}d</p>
<p className="text-xs text-gray-600">Avg. Completion</p>
</div>
<div>
<p className="text-2xl font-bold text-purple-600">{user.clientSatisfaction}/5</p>
<p className="text-xs text-gray-600">Client Rating</p>
</div>
</div>
</div>
))}
</div>
</div>
<div className="bg-white shadow rounded-lg p-6">
<h2 className="text-lg font-semibold text-gray-900 mb-4">🏢 Facility Complexity Analysis</h2>
<div className="space-y-3">
{analytics.facilityDistribution.map((facility) => (
<div key={facility.facility} className="flex items-center justify-between p-3 border border-gray-200 rounded-lg">
<div>
<h4 className="font-medium text-gray-900">{facility.facility}</h4>
<p className="text-sm text-gray-600">{facility.count} cases</p>
</div>
<div className="text-right">
<div className={`px-2 py-1 rounded text-xs font-medium ${
facility.averageComplexity > 70 ? 'bg-red-100 text-red-800' :
facility.averageComplexity > 50 ? 'bg-yellow-100 text-yellow-800' :
'bg-green-100 text-green-800'
}`}>
{facility.averageComplexity}% complexity
</div>
</div>
</div>
))}
</div>
</div>
</div>
)}
{/* Trends & Predictions */}
{selectedView === 'trends' && (
<div className="bg-white shadow rounded-lg p-6">
<h2 className="text-lg font-semibold text-gray-900 mb-4">📊 Case Volume Trends</h2>
<div className="space-y-4">
{analytics.timelineAnalysis.map((month) => (
<div key={month.month} className="border border-gray-200 rounded-lg p-4">
<div className="flex items-center justify-between mb-3">
<h3 className="font-medium text-gray-900">{month.month}</h3>
<div className="flex gap-4 text-sm">
<span className="text-green-600">+{month.newCases} new</span>
<span className="text-blue-600">{month.completedCases} completed</span>
<span className="text-orange-600">{month.pendingCases} pending</span>
</div>
</div>
{/* Visual trend bar */}
<div className="flex h-4 bg-gray-200 rounded overflow-hidden">
<div
className="bg-green-500"
style={{ width: `${(month.newCases / (month.newCases + month.completedCases + month.pendingCases)) * 100}%` }}
></div>
<div
className="bg-blue-500"
style={{ width: `${(month.completedCases / (month.newCases + month.completedCases + month.pendingCases)) * 100}%` }}
></div>
<div
className="bg-orange-500"
style={{ width: `${(month.pendingCases / (month.newCases + month.completedCases + month.pendingCases)) * 100}%` }}
></div>
</div>
</div>
))}
</div>
{/* Predictions */}
<div className="mt-6 p-4 bg-blue-50 border border-blue-200 rounded-lg">
<h3 className="font-semibold text-blue-900 mb-2">🔮 AI Predictions</h3>
<div className="text-sm text-blue-800 space-y-1">
<p>• Expected 15% increase in case volume next month</p>
<p>• Marie Dubois may reach capacity by week 3</p>
<p>• Recommend hiring additional clerk for document-heavy cases</p>
<p>• Bordeaux facility cases trending more complex (+12% avg.)</p>
</div>
</div>
</div>
)}
</div>
);
};
export default AdvancedAnalyticsDashboard;