other modifications days ago
This commit is contained in:
@@ -1,14 +1,15 @@
|
||||
import React, { useState } from "react";
|
||||
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Download, Users, TrendingUp, Clock } from "lucide-react";
|
||||
import { Download, Users, TrendingUp, Clock, AlertTriangle, Award } from "lucide-react";
|
||||
import { BarChart, Bar, XAxis, YAxis, CartesianGrid, Tooltip, Legend, ResponsiveContainer } from "recharts";
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table";
|
||||
import { Avatar, AvatarFallback } from "@/components/ui/avatar";
|
||||
import { useToast } from "@/components/ui/use-toast";
|
||||
import ReportInsightsBanner from "./ReportInsightsBanner";
|
||||
|
||||
export default function StaffPerformanceReport({ staff, events }) {
|
||||
export default function StaffPerformanceReport({ staff, events, userRole = 'admin' }) {
|
||||
const { toast } = useToast();
|
||||
|
||||
// Calculate staff metrics
|
||||
@@ -90,60 +91,79 @@ export default function StaffPerformanceReport({ staff, events }) {
|
||||
toast({ title: "✅ Report Exported", description: "Performance report downloaded as CSV" });
|
||||
};
|
||||
|
||||
// At-risk workers
|
||||
const atRiskWorkers = staffMetrics.filter(s => s.reliability < 70 || s.noShows > 2);
|
||||
|
||||
return (
|
||||
<div className="space-y-6">
|
||||
{/* AI Insights Banner */}
|
||||
<ReportInsightsBanner userRole={userRole} reportType="performance" />
|
||||
|
||||
<div className="flex justify-between items-center">
|
||||
<div>
|
||||
<h2 className="text-xl font-bold text-slate-900">Staff Performance Metrics</h2>
|
||||
<p className="text-sm text-slate-500">Reliability, fill rates, and performance tracking</p>
|
||||
<h2 className="text-xl font-bold text-slate-900">Workforce Performance</h2>
|
||||
<p className="text-sm text-slate-500">Reliability, fill rates & actionable insights</p>
|
||||
</div>
|
||||
<Button onClick={handleExport} variant="outline">
|
||||
<Download className="w-4 h-4 mr-2" />
|
||||
Export CSV
|
||||
<Button onClick={handleExport} size="sm" className="bg-[#0A39DF]">
|
||||
<Download className="w-4 h-4 mr-1" />
|
||||
Export
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
{/* Summary Cards */}
|
||||
<div className="grid grid-cols-1 md:grid-cols-3 gap-4">
|
||||
<Card>
|
||||
<CardContent className="pt-6">
|
||||
<div className="flex items-center justify-between">
|
||||
<div>
|
||||
<p className="text-sm text-slate-500">Avg Reliability</p>
|
||||
<p className="text-2xl font-bold text-slate-900">{avgReliability.toFixed(1)}%</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>
|
||||
{/* Quick Actions */}
|
||||
{atRiskWorkers.length > 0 && (
|
||||
<div className="bg-amber-50 border border-amber-200 rounded-lg p-3 flex items-center justify-between">
|
||||
<div className="flex items-center gap-2">
|
||||
<AlertTriangle className="w-5 h-5 text-amber-600" />
|
||||
<span className="text-sm font-medium text-amber-800">
|
||||
{atRiskWorkers.length} workers need attention (reliability <70% or 2+ no-shows)
|
||||
</span>
|
||||
</div>
|
||||
<Button size="sm" variant="outline" className="border-amber-300 text-amber-700 hover:bg-amber-100">
|
||||
View At-Risk Workers
|
||||
</Button>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Decision Cards */}
|
||||
<div className="grid grid-cols-1 md:grid-cols-4 gap-4">
|
||||
<Card className={`border-l-4 ${avgReliability >= 85 ? 'border-l-green-500' : avgReliability >= 70 ? 'border-l-amber-500' : 'border-l-red-500'}`}>
|
||||
<CardContent className="pt-4 pb-3">
|
||||
<p className="text-xs text-slate-500 uppercase tracking-wider">Avg Reliability</p>
|
||||
<p className="text-2xl font-bold text-slate-900">{avgReliability.toFixed(1)}%</p>
|
||||
<p className={`text-xs mt-1 ${avgReliability >= 85 ? 'text-green-600' : 'text-amber-600'}`}>
|
||||
{avgReliability >= 85 ? '✓ Excellent' : avgReliability >= 70 ? '⚠ Needs attention' : '✗ Critical'}
|
||||
</p>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
<Card>
|
||||
<CardContent className="pt-6">
|
||||
<div className="flex items-center justify-between">
|
||||
<div>
|
||||
<p className="text-sm text-slate-500">Avg Fill Rate</p>
|
||||
<p className="text-2xl font-bold text-slate-900">{avgFillRate.toFixed(1)}%</p>
|
||||
</div>
|
||||
<div className="w-12 h-12 bg-blue-100 rounded-full flex items-center justify-center">
|
||||
<Users className="w-6 h-6 text-blue-600" />
|
||||
</div>
|
||||
</div>
|
||||
<Card className={`border-l-4 ${avgFillRate >= 90 ? 'border-l-green-500' : avgFillRate >= 75 ? 'border-l-amber-500' : 'border-l-red-500'}`}>
|
||||
<CardContent className="pt-4 pb-3">
|
||||
<p className="text-xs text-slate-500 uppercase tracking-wider">Avg Fill Rate</p>
|
||||
<p className="text-2xl font-bold text-slate-900">{avgFillRate.toFixed(1)}%</p>
|
||||
<p className="text-xs text-slate-500 mt-1">{avgFillRate >= 90 ? 'Above target' : `${(90 - avgFillRate).toFixed(1)}% below target`}</p>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
<Card>
|
||||
<CardContent className="pt-6">
|
||||
<div className="flex items-center justify-between">
|
||||
<div>
|
||||
<p className="text-sm text-slate-500">Total Cancellations</p>
|
||||
<p className="text-2xl font-bold text-slate-900">{totalCancellations}</p>
|
||||
</div>
|
||||
<div className="w-12 h-12 bg-red-100 rounded-full flex items-center justify-center">
|
||||
<Clock className="w-6 h-6 text-red-600" />
|
||||
</div>
|
||||
</div>
|
||||
<Card className={`border-l-4 ${totalCancellations < 5 ? 'border-l-green-500' : totalCancellations < 15 ? 'border-l-amber-500' : 'border-l-red-500'}`}>
|
||||
<CardContent className="pt-4 pb-3">
|
||||
<p className="text-xs text-slate-500 uppercase tracking-wider">Cancellations</p>
|
||||
<p className="text-2xl font-bold text-slate-900">{totalCancellations}</p>
|
||||
<p className="text-xs text-red-600 mt-1">~${(totalCancellations * 150).toLocaleString()} impact</p>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
<Card className="border-l-4 border-l-purple-500 bg-purple-50">
|
||||
<CardContent className="pt-4 pb-3">
|
||||
<p className="text-xs text-purple-600 uppercase tracking-wider font-semibold">Quick Decision</p>
|
||||
<p className="text-sm font-medium text-purple-900 mt-1">
|
||||
{atRiskWorkers.length > 0
|
||||
? `Review ${atRiskWorkers.length} at-risk workers before next scheduling cycle`
|
||||
: avgFillRate < 90
|
||||
? 'Expand worker pool by 15% to improve fill rate'
|
||||
: 'Performance healthy — consider bonuses for top 10%'
|
||||
}
|
||||
</p>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user