Files
Krow-workspace/frontend-web/src/components/reports/OperationalEfficiencyReport.jsx
2025-11-18 21:32:16 -05:00

238 lines
9.2 KiB
JavaScript

import React from "react";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
import { Button } from "@/components/ui/button";
import { Download, Zap, Clock, TrendingUp, CheckCircle } from "lucide-react";
import { BarChart, Bar, XAxis, YAxis, CartesianGrid, Tooltip, Legend, ResponsiveContainer, PieChart, Pie, Cell } from "recharts";
import { Badge } from "@/components/ui/badge";
import { useToast } from "@/components/ui/use-toast";
const COLORS = ['#10b981', '#3b82f6', '#f59e0b', '#ef4444'];
export default function OperationalEfficiencyReport({ events, staff }) {
const { toast } = useToast();
// Automation impact metrics
const totalEvents = events.length;
const autoAssignedEvents = events.filter(e =>
e.assigned_staff && e.assigned_staff.length > 0
).length;
const automationRate = totalEvents > 0 ? ((autoAssignedEvents / totalEvents) * 100).toFixed(1) : 0;
// Fill rate by status
const statusBreakdown = events.reduce((acc, event) => {
const status = event.status || 'Draft';
acc[status] = (acc[status] || 0) + 1;
return acc;
}, {});
const statusData = Object.entries(statusBreakdown).map(([name, value]) => ({
name,
value,
}));
// Time to fill metrics
const avgTimeToFill = 2.3; // Mock - would calculate from event creation to full assignment
const avgResponseTime = 1.5; // Mock - hours to respond to requests
// Efficiency over time
const efficiencyTrend = [
{ month: 'Jan', automation: 75, fillRate: 88, responseTime: 2.1 },
{ month: 'Feb', automation: 78, fillRate: 90, responseTime: 1.9 },
{ month: 'Mar', automation: 82, fillRate: 92, responseTime: 1.7 },
{ month: 'Apr', automation: 85, fillRate: 94, responseTime: 1.5 },
];
const handleExport = () => {
const csv = [
['Operational Efficiency Report'],
['Generated', new Date().toISOString()],
[''],
['Summary Metrics'],
['Total Events', totalEvents],
['Auto-Assigned Events', autoAssignedEvents],
['Automation Rate', `${automationRate}%`],
['Avg Time to Fill (hours)', avgTimeToFill],
['Avg Response Time (hours)', avgResponseTime],
[''],
['Status Breakdown'],
['Status', 'Count'],
...Object.entries(statusBreakdown).map(([status, count]) => [status, count]),
[''],
['Efficiency Trend'],
['Month', 'Automation %', 'Fill Rate %', 'Response Time (hrs)'],
...efficiencyTrend.map(t => [t.month, t.automation, t.fillRate, t.responseTime]),
].map(row => row.join(',')).join('\n');
const blob = new Blob([csv], { type: 'text/csv' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = `operational-efficiency-${new Date().toISOString().split('T')[0]}.csv`;
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
URL.revokeObjectURL(url);
toast({ title: "✅ Report Exported", description: "Efficiency report downloaded as CSV" });
};
return (
<div className="space-y-6">
<div className="flex justify-between items-center">
<div>
<h2 className="text-xl font-bold text-slate-900">Operational Efficiency & Automation Impact</h2>
<p className="text-sm text-slate-500">Track process improvements and automation effectiveness</p>
</div>
<Button onClick={handleExport} variant="outline">
<Download className="w-4 h-4 mr-2" />
Export CSV
</Button>
</div>
{/* Summary Cards */}
<div className="grid grid-cols-1 md:grid-cols-4 gap-4">
<Card>
<CardContent className="pt-6">
<div className="flex items-center justify-between">
<div>
<p className="text-sm text-slate-500">Automation Rate</p>
<p className="text-2xl font-bold text-slate-900">{automationRate}%</p>
</div>
<div className="w-12 h-12 bg-purple-100 rounded-full flex items-center justify-center">
<Zap className="w-6 h-6 text-purple-600" />
</div>
</div>
</CardContent>
</Card>
<Card>
<CardContent className="pt-6">
<div className="flex items-center justify-between">
<div>
<p className="text-sm text-slate-500">Avg Time to Fill</p>
<p className="text-2xl font-bold text-slate-900">{avgTimeToFill}h</p>
</div>
<div className="w-12 h-12 bg-blue-100 rounded-full flex items-center justify-center">
<Clock className="w-6 h-6 text-blue-600" />
</div>
</div>
</CardContent>
</Card>
<Card>
<CardContent className="pt-6">
<div className="flex items-center justify-between">
<div>
<p className="text-sm text-slate-500">Response Time</p>
<p className="text-2xl font-bold text-slate-900">{avgResponseTime}h</p>
</div>
<div className="w-12 h-12 bg-green-100 rounded-full flex items-center justify-center">
<TrendingUp className="w-6 h-6 text-green-600" />
</div>
</div>
</CardContent>
</Card>
<Card>
<CardContent className="pt-6">
<div className="flex items-center justify-between">
<div>
<p className="text-sm text-slate-500">Completed</p>
<p className="text-2xl font-bold text-slate-900">{events.filter(e => e.status === 'Completed').length}</p>
</div>
<div className="w-12 h-12 bg-emerald-100 rounded-full flex items-center justify-center">
<CheckCircle className="w-6 h-6 text-emerald-600" />
</div>
</div>
</CardContent>
</Card>
</div>
{/* Efficiency Trend */}
<Card>
<CardHeader>
<CardTitle>Efficiency Metrics Over Time</CardTitle>
</CardHeader>
<CardContent>
<ResponsiveContainer width="100%" height={300}>
<BarChart data={efficiencyTrend}>
<CartesianGrid strokeDasharray="3 3" />
<XAxis dataKey="month" />
<YAxis />
<Tooltip />
<Legend />
<Bar dataKey="automation" fill="#a855f7" name="Automation %" />
<Bar dataKey="fillRate" fill="#3b82f6" name="Fill Rate %" />
</BarChart>
</ResponsiveContainer>
</CardContent>
</Card>
{/* Status Breakdown */}
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
<Card>
<CardHeader>
<CardTitle>Event Status Distribution</CardTitle>
</CardHeader>
<CardContent>
<ResponsiveContainer width="100%" height={300}>
<PieChart>
<Pie
data={statusData}
cx="50%"
cy="50%"
labelLine={false}
label={({ name, percent }) => `${name}: ${(percent * 100).toFixed(0)}%`}
outerRadius={80}
fill="#8884d8"
dataKey="value"
>
{statusData.map((entry, index) => (
<Cell key={`cell-${index}`} fill={COLORS[index % COLORS.length]} />
))}
</Pie>
<Tooltip />
</PieChart>
</ResponsiveContainer>
</CardContent>
</Card>
<Card>
<CardHeader>
<CardTitle>Key Performance Indicators</CardTitle>
</CardHeader>
<CardContent className="space-y-4">
<div className="flex items-center justify-between p-3 bg-purple-50 rounded-lg">
<div>
<p className="text-sm font-medium text-slate-700">Manual Work Reduction</p>
<p className="text-2xl font-bold text-purple-700">85%</p>
</div>
<Badge className="bg-purple-600">Excellent</Badge>
</div>
<div className="flex items-center justify-between p-3 bg-blue-50 rounded-lg">
<div>
<p className="text-sm font-medium text-slate-700">First-Time Fill Rate</p>
<p className="text-2xl font-bold text-blue-700">92%</p>
</div>
<Badge className="bg-blue-600">Good</Badge>
</div>
<div className="flex items-center justify-between p-3 bg-green-50 rounded-lg">
<div>
<p className="text-sm font-medium text-slate-700">Staff Utilization</p>
<p className="text-2xl font-bold text-green-700">88%</p>
</div>
<Badge className="bg-green-600">Optimal</Badge>
</div>
<div className="flex items-center justify-between p-3 bg-amber-50 rounded-lg">
<div>
<p className="text-sm font-medium text-slate-700">Conflict Detection</p>
<p className="text-2xl font-bold text-amber-700">97%</p>
</div>
<Badge className="bg-amber-600">High</Badge>
</div>
</CardContent>
</Card>
</div>
</div>
);
}