![]() 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/.cursor-server/data/User/History/-5eef8fc7/ |
'use client';
import React, { useState, useEffect } from 'react';
import { useSession } from 'next-auth/react';
import {
BarChart3,
TrendingUp,
Users,
Calendar,
DollarSign,
Clock,
CheckCircle,
XCircle,
AlertTriangle,
FileText,
Target,
Award,
Activity,
PieChart,
LineChart,
Building
} from 'lucide-react';
// UI components replaced with standard HTML elements and Tailwind CSS
interface CaseAnalytics {
totalCases: number;
activeCases: number;
completedCases: number;
pendingCases: number;
suspendedCases: number;
totalRevenue: number;
averageCaseDuration: number;
successRate: number;
casesByType: Array<{
type: string;
count: number;
percentage: number;
}>;
casesByStatus: Array<{
status: string;
count: number;
percentage: number;
}>;
monthlyTrends: Array<{
month: string;
newCases: number;
completedCases: number;
revenue: number;
}>;
performanceMetrics: {
averageResponseTime: number;
clientSatisfaction: number;
caseResolutionRate: number;
documentCompletionRate: number;
};
roleSpecificMetrics: {
[key: string]: {
casesAssigned: number;
casesCompleted: number;
averageRating: number;
totalEarnings: number;
};
};
}
interface CaseAnalyticsProps {
timeRange?: '7d' | '30d' | '90d' | '1y' | 'all';
className?: string;
}
const CaseAnalytics: React.FC<CaseAnalyticsProps> = ({
timeRange = '30d',
className = ''
}) => {
const { data: session } = useSession();
const [analytics, setAnalytics] = useState<CaseAnalytics | null>(null);
const [loading, setLoading] = useState(true);
const [selectedTimeRange, setSelectedTimeRange] = useState(timeRange);
const [selectedMetric, setSelectedMetric] = useState('overview');
useEffect(() => {
if (session?.user) {
fetchAnalytics();
}
}, [session, selectedTimeRange]);
const fetchAnalytics = async () => {
try {
setLoading(true);
const response = await fetch(`/api/analytics/cases?timeRange=${selectedTimeRange}`, {
credentials: 'same-origin',
});
if (response.ok) {
const data = await response.json();
setAnalytics(data);
} else {
}
} catch (error) {
} finally {
setLoading(false);
}
};
const getStatusColor = (status: string) => {
switch (status) {
case 'active': return 'text-green-600 bg-green-100';
case 'completed': return 'text-blue-600 bg-blue-100';
case 'pending': return 'text-yellow-600 bg-yellow-100';
case 'suspended': return 'text-red-600 bg-red-100';
default: return 'text-gray-600 bg-gray-100';
}
};
const getTypeIcon = (type: string) => {
switch (type.toLowerCase()) {
case 'criminal': return <AlertTriangle className="h-4 w-4" />;
case 'civil': return <FileText className="h-4 w-4" />;
case 'family': return <Users className="h-4 w-4" />;
case 'corporate': return <Building className="h-4 w-4" />;
case 'mediation': return <Target className="h-4 w-4" />;
case 'investigation': return <Activity className="h-4 w-4" />;
default: return <FileText className="h-4 w-4" />;
}
};
const formatCurrency = (amount: number) => {
return new Intl.NumberFormat('en-CA', {
style: 'currency',
currency: 'CAD',
}).format(amount);
};
const formatDuration = (days: number) => {
if (days < 30) return `${days} days`;
if (days < 365) return `${Math.round(days / 30)} months`;
return `${Math.round(days / 365)} years`;
};
if (loading) {
return (
<div className={`space-y-6 ${className}`}>
<div className="flex items-center justify-between">
<h2 className="text-2xl font-bold text-gray-900">Case Analytics</h2>
<div className="flex items-center gap-2">
<div className="h-10 w-32 bg-gray-200 rounded animate-pulse"></div>
<div className="h-10 w-24 bg-gray-200 rounded animate-pulse"></div>
</div>
</div>
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6">
{[...Array(4)].map((_, i) => (
<div key={i} className="bg-white rounded-lg shadow-sm border p-6">
<div className="pb-2">
<div className="h-4 w-24 bg-gray-200 rounded animate-pulse"></div>
</div>
<div>
<div className="h-8 w-16 bg-gray-200 rounded animate-pulse"></div>
</div>
</div>
))}
</div>
</div>
);
}
if (!analytics) {
return (
<div className={`text-center py-12 ${className}`}>
<BarChart3 className="h-12 w-12 text-gray-400 mx-auto mb-4" />
<h3 className="text-lg font-semibold text-gray-900 mb-2">No Analytics Available</h3>
<p className="text-gray-600">Analytics data will appear here once cases are created.</p>
</div>
);
}
return (
<div className={`space-y-6 ${className}`}>
{/* Header */}
<div className="flex items-center justify-between">
<div>
<h2 className="text-2xl font-bold text-gray-900">Case Analytics</h2>
<p className="text-gray-600">Comprehensive insights into case performance and trends</p>
</div>
<div className="flex items-center gap-2">
<select
value={selectedTimeRange}
onChange={(e) => setSelectedTimeRange(e.target.value as any)}
className="px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent w-32"
>
<option value="7d">Last 7 days</option>
<option value="30d">Last 30 days</option>
<option value="90d">Last 90 days</option>
<option value="1y">Last year</option>
<option value="all">All time</option>
</select>
<select
value={selectedMetric}
onChange={(e) => setSelectedMetric(e.target.value)}
className="px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent w-40"
>
<option value="overview">Overview</option>
<option value="performance">Performance</option>
<option value="financial">Financial</option>
<option value="trends">Trends</option>
</select>
</div>
</div>
{/* Key Metrics */}
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6">
<div className="bg-white rounded-lg shadow-sm border p-6">
<div className="flex flex-row items-center justify-between space-y-0 pb-2">
<h3 className="text-sm font-medium">Total Cases</h3>
<BarChart3 className="h-4 w-4 text-gray-400" />
</div>
<div>
<div className="text-2xl font-bold">{analytics.totalCases}</div>
<p className="text-xs text-gray-500">
{analytics.activeCases} active cases
</p>
</div>
</div>
<div className="bg-white rounded-lg shadow-sm border p-6">
<div className="flex flex-row items-center justify-between space-y-0 pb-2">
<h3 className="text-sm font-medium">Success Rate</h3>
<TrendingUp className="h-4 w-4 text-gray-400" />
</div>
<div>
<div className="text-2xl font-bold">{analytics.successRate}%</div>
<p className="text-xs text-gray-500">
{analytics.completedCases} completed cases
</p>
</div>
</div>
<div className="bg-white rounded-lg shadow-sm border p-6">
<div className="flex flex-row items-center justify-between space-y-0 pb-2">
<h3 className="text-sm font-medium">Total Revenue</h3>
<DollarSign className="h-4 w-4 text-gray-400" />
</div>
<div>
<div className="text-2xl font-bold">{formatCurrency(analytics.totalRevenue)}</div>
<p className="text-xs text-gray-500">
Average: {formatCurrency(analytics.totalRevenue / Math.max(analytics.totalCases, 1))}
</p>
</div>
</div>
<div className="bg-white rounded-lg shadow-sm border p-6">
<div className="flex flex-row items-center justify-between space-y-0 pb-2">
<h3 className="text-sm font-medium">Avg Duration</h3>
<Clock className="h-4 w-4 text-gray-400" />
</div>
<div>
<div className="text-2xl font-bold">{formatDuration(analytics.averageCaseDuration)}</div>
<p className="text-xs text-gray-500">
Per case average
</p>
</div>
</div>
</div>
{/* Performance Metrics */}
<div className="grid grid-cols-1 lg:grid-cols-2 gap-6">
<div className="bg-white rounded-lg shadow-sm border p-6">
<div className="pb-4">
<h3 className="text-lg font-semibold flex items-center gap-2">
<Target className="h-5 w-5" />
Performance Metrics
</h3>
</div>
<div className="space-y-4">
<div>
<div className="flex items-center justify-between mb-2">
<span className="text-sm font-medium">Response Time</span>
<span className="text-sm text-gray-600">{analytics.performanceMetrics.averageResponseTime}h</span>
</div>
<div className="w-full bg-gray-200 rounded-full h-2">
<div
className="bg-blue-600 h-2 rounded-full"
style={{ width: `${Math.min(analytics.performanceMetrics.averageResponseTime / 24 * 100, 100)}%` }}
></div>
</div>
</div>
<div>
<div className="flex items-center justify-between mb-2">
<span className="text-sm font-medium">Client Satisfaction</span>
<span className="text-sm text-gray-600">{analytics.performanceMetrics.clientSatisfaction}%</span>
</div>
<div className="w-full bg-gray-200 rounded-full h-2">
<div
className="bg-green-600 h-2 rounded-full"
style={{ width: `${analytics.performanceMetrics.clientSatisfaction}%` }}
></div>
</div>
</div>
<div>
<div className="flex items-center justify-between mb-2">
<span className="text-sm font-medium">Resolution Rate</span>
<span className="text-sm text-gray-600">{analytics.performanceMetrics.caseResolutionRate}%</span>
</div>
<div className="w-full bg-gray-200 rounded-full h-2">
<div
className="bg-purple-600 h-2 rounded-full"
style={{ width: `${analytics.performanceMetrics.caseResolutionRate}%` }}
></div>
</div>
</div>
<div>
<div className="flex items-center justify-between mb-2">
<span className="text-sm font-medium">Document Completion</span>
<span className="text-sm text-gray-600">{analytics.performanceMetrics.documentCompletionRate}%</span>
</div>
<div className="w-full bg-gray-200 rounded-full h-2">
<div
className="bg-orange-600 h-2 rounded-full"
style={{ width: `${analytics.performanceMetrics.documentCompletionRate}%` }}
></div>
</div>
</div>
</div>
</div>
<div className="bg-white rounded-lg shadow-sm border p-6">
<div className="pb-4">
<h3 className="text-lg font-semibold flex items-center gap-2">
<PieChart className="h-5 w-5" />
Cases by Status
</h3>
</div>
<div className="space-y-3">
{analytics.casesByStatus.map((status) => (
<div key={status.status} className="flex items-center justify-between">
<div className="flex items-center gap-2">
<span className={`inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium ${getStatusColor(status.status)}`}>
{status.status}
</span>
<span className="text-sm text-gray-600">{status.count} cases</span>
</div>
<span className="text-sm font-medium">{status.percentage}%</span>
</div>
))}
</div>
</div>
</div>
{/* Case Types Distribution */}
<div className="bg-white rounded-lg shadow-sm border p-6">
<div className="pb-4">
<h3 className="text-lg font-semibold flex items-center gap-2">
<BarChart3 className="h-5 w-5" />
Cases by Type
</h3>
</div>
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
{analytics.casesByType.map((type) => (
<div key={type.type} className="flex items-center justify-between p-3 border rounded-lg">
<div className="flex items-center gap-2">
{getTypeIcon(type.type)}
<span className="font-medium">{type.type}</span>
</div>
<div className="text-right">
<div className="font-semibold">{type.count}</div>
<div className="text-sm text-gray-500">{type.percentage}%</div>
</div>
</div>
))}
</div>
</div>
{/* Monthly Trends */}
<div className="bg-white rounded-lg shadow-sm border p-6">
<div className="pb-4">
<h3 className="text-lg font-semibold flex items-center gap-2">
<LineChart className="h-5 w-5" />
Monthly Trends
</h3>
</div>
<div className="space-y-4">
{analytics.monthlyTrends.map((trend) => (
<div key={trend.month} className="flex items-center justify-between p-3 border rounded-lg">
<div className="flex items-center gap-4">
<span className="font-medium">{trend.month}</span>
<div className="flex items-center gap-4 text-sm text-gray-600">
<span>{trend.newCases} new cases</span>
<span>{trend.completedCases} completed</span>
</div>
</div>
<div className="text-right">
<div className="font-semibold">{formatCurrency(trend.revenue)}</div>
<div className="text-sm text-gray-500">Revenue</div>
</div>
</div>
))}
</div>
</div>
</div>
);
};
export default CaseAnalytics;