other modifications days ago
This commit is contained in:
180
frontend-web/src/components/reports/ReportTemplateLibrary.jsx
Normal file
180
frontend-web/src/components/reports/ReportTemplateLibrary.jsx
Normal file
@@ -0,0 +1,180 @@
|
||||
import React, { useState } from "react";
|
||||
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import {
|
||||
Select,
|
||||
SelectContent,
|
||||
SelectItem,
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
} from "@/components/ui/select";
|
||||
import {
|
||||
FileText, DollarSign, Users, TrendingUp, Shield, Clock,
|
||||
Building2, Package, AlertTriangle, Star, Search, Filter,
|
||||
Download, Eye, Zap, BarChart3, PieChart, MapPin, Calendar
|
||||
} from "lucide-react";
|
||||
|
||||
const REPORT_TEMPLATES = [
|
||||
// Procurement Reports
|
||||
{ id: 'vendor-spend-analysis', name: 'Vendor Spend Analysis', category: 'Procurement', icon: DollarSign, color: 'blue', description: 'Detailed breakdown of spend by vendor, tier, and region', roles: ['procurement', 'admin'] },
|
||||
{ id: 'vendor-performance-scorecard', name: 'Vendor Performance Scorecard', category: 'Procurement', icon: Star, color: 'amber', description: 'Fill rates, reliability scores, and SLA compliance by vendor', roles: ['procurement', 'admin'] },
|
||||
{ id: 'rate-compliance', name: 'Rate Compliance Report', category: 'Procurement', icon: Shield, color: 'green', description: 'Contracted vs spot rate usage and savings opportunities', roles: ['procurement', 'admin'] },
|
||||
{ id: 'vendor-consolidation', name: 'Vendor Consolidation Analysis', category: 'Procurement', icon: Package, color: 'purple', description: 'Opportunities to consolidate vendors for better rates', roles: ['procurement', 'admin'] },
|
||||
|
||||
// Operator Reports
|
||||
{ id: 'enterprise-labor-summary', name: 'Enterprise Labor Summary', category: 'Operator', icon: Building2, color: 'indigo', description: 'Cross-sector labor costs, utilization, and trends', roles: ['operator', 'admin'] },
|
||||
{ id: 'sector-comparison', name: 'Sector Comparison Report', category: 'Operator', icon: BarChart3, color: 'blue', description: 'Performance benchmarks across all sectors', roles: ['operator', 'admin'] },
|
||||
{ id: 'overtime-exposure', name: 'Overtime Exposure Report', category: 'Operator', icon: Clock, color: 'red', description: 'OT hours by sector, site, and worker with cost impact', roles: ['operator', 'admin', 'sector'] },
|
||||
{ id: 'fill-rate-analysis', name: 'Fill Rate Analysis', category: 'Operator', icon: TrendingUp, color: 'emerald', description: 'Order fulfillment rates and gap analysis', roles: ['operator', 'admin', 'sector'] },
|
||||
|
||||
// Sector Reports
|
||||
{ id: 'site-labor-allocation', name: 'Site Labor Allocation', category: 'Sector', icon: MapPin, color: 'purple', description: 'Cost allocation by site, department, and cost center', roles: ['sector', 'operator', 'admin'] },
|
||||
{ id: 'attendance-patterns', name: 'Attendance Patterns Report', category: 'Sector', icon: Calendar, color: 'blue', description: 'No-shows, late arrivals, and attendance trends', roles: ['sector', 'operator', 'admin'] },
|
||||
{ id: 'worker-reliability', name: 'Worker Reliability Index', category: 'Sector', icon: Users, color: 'green', description: 'Individual worker performance and reliability scores', roles: ['sector', 'vendor', 'admin'] },
|
||||
{ id: 'compliance-risk', name: 'Compliance Risk Report', category: 'Sector', icon: AlertTriangle, color: 'amber', description: 'Certification expirations, background check status', roles: ['sector', 'admin'] },
|
||||
|
||||
// Vendor Reports
|
||||
{ id: 'client-revenue', name: 'Client Revenue Report', category: 'Vendor', icon: DollarSign, color: 'emerald', description: 'Revenue by client, event type, and time period', roles: ['vendor', 'admin'] },
|
||||
{ id: 'workforce-utilization', name: 'Workforce Utilization', category: 'Vendor', icon: Users, color: 'blue', description: 'Staff hours, availability, and utilization rates', roles: ['vendor', 'admin'] },
|
||||
{ id: 'margin-analysis', name: 'Margin Analysis Report', category: 'Vendor', icon: TrendingUp, color: 'purple', description: 'Profit margins by client, role, and event type', roles: ['vendor', 'admin'] },
|
||||
{ id: 'staff-performance', name: 'Staff Performance Report', category: 'Vendor', icon: Star, color: 'amber', description: 'Ratings, feedback, and performance trends', roles: ['vendor', 'admin'] },
|
||||
|
||||
// Finance & Compliance
|
||||
{ id: 'invoice-aging', name: 'Invoice Aging Report', category: 'Finance', icon: FileText, color: 'slate', description: 'Outstanding invoices by age and status', roles: ['admin', 'procurement', 'vendor'] },
|
||||
{ id: 'payroll-summary', name: 'Payroll Summary Report', category: 'Finance', icon: DollarSign, color: 'green', description: 'Total labor costs, taxes, and deductions', roles: ['admin', 'vendor'] },
|
||||
{ id: 'audit-trail', name: 'Audit Trail Report', category: 'Compliance', icon: Shield, color: 'indigo', description: 'All system changes and user activities', roles: ['admin'] },
|
||||
{ id: 'certification-status', name: 'Certification Status Report', category: 'Compliance', icon: AlertTriangle, color: 'red', description: 'Expiring and missing certifications', roles: ['admin', 'sector', 'vendor'] },
|
||||
|
||||
// Client Reports
|
||||
{ id: 'event-cost-summary', name: 'Event Cost Summary', category: 'Client', icon: Calendar, color: 'blue', description: 'Detailed costs for all events with breakdown', roles: ['client', 'admin'] },
|
||||
{ id: 'savings-report', name: 'Savings Achieved Report', category: 'Client', icon: Zap, color: 'emerald', description: 'Cost savings from preferred vendor usage', roles: ['client', 'admin'] },
|
||||
{ id: 'staff-feedback', name: 'Staff Feedback Report', category: 'Client', icon: Star, color: 'amber', description: 'Ratings and feedback on assigned staff', roles: ['client', 'admin'] },
|
||||
];
|
||||
|
||||
const CATEGORY_COLORS = {
|
||||
'Procurement': 'bg-blue-100 text-blue-700 border-blue-200',
|
||||
'Operator': 'bg-indigo-100 text-indigo-700 border-indigo-200',
|
||||
'Sector': 'bg-purple-100 text-purple-700 border-purple-200',
|
||||
'Vendor': 'bg-amber-100 text-amber-700 border-amber-200',
|
||||
'Finance': 'bg-emerald-100 text-emerald-700 border-emerald-200',
|
||||
'Compliance': 'bg-red-100 text-red-700 border-red-200',
|
||||
'Client': 'bg-green-100 text-green-700 border-green-200',
|
||||
};
|
||||
|
||||
const ICON_COLORS = {
|
||||
blue: 'bg-blue-500',
|
||||
amber: 'bg-amber-500',
|
||||
green: 'bg-green-500',
|
||||
purple: 'bg-purple-500',
|
||||
indigo: 'bg-indigo-500',
|
||||
red: 'bg-red-500',
|
||||
emerald: 'bg-emerald-500',
|
||||
slate: 'bg-slate-500',
|
||||
};
|
||||
|
||||
export default function ReportTemplateLibrary({ userRole, onSelectTemplate, onPreview }) {
|
||||
const [searchTerm, setSearchTerm] = useState("");
|
||||
const [categoryFilter, setCategoryFilter] = useState("all");
|
||||
|
||||
const filteredTemplates = REPORT_TEMPLATES.filter(template => {
|
||||
const matchesRole = template.roles.includes(userRole) || userRole === 'admin';
|
||||
const matchesSearch = template.name.toLowerCase().includes(searchTerm.toLowerCase()) ||
|
||||
template.description.toLowerCase().includes(searchTerm.toLowerCase());
|
||||
const matchesCategory = categoryFilter === "all" || template.category === categoryFilter;
|
||||
return matchesRole && matchesSearch && matchesCategory;
|
||||
});
|
||||
|
||||
const categories = [...new Set(REPORT_TEMPLATES.map(t => t.category))];
|
||||
|
||||
return (
|
||||
<div className="space-y-5">
|
||||
{/* Search & Filters - Clean Row */}
|
||||
<div className="flex items-center gap-3 flex-wrap bg-white p-3 rounded-xl border">
|
||||
<div className="relative flex-1 min-w-[200px] max-w-xs">
|
||||
<Search className="absolute left-3 top-1/2 -translate-y-1/2 w-4 h-4 text-slate-400" />
|
||||
<Input
|
||||
placeholder="Search reports..."
|
||||
value={searchTerm}
|
||||
onChange={(e) => setSearchTerm(e.target.value)}
|
||||
className="pl-9 h-9 bg-slate-50 border-slate-200"
|
||||
/>
|
||||
</div>
|
||||
<div className="flex gap-1.5 flex-wrap">
|
||||
<Button
|
||||
size="sm"
|
||||
variant={categoryFilter === "all" ? "default" : "ghost"}
|
||||
onClick={() => setCategoryFilter("all")}
|
||||
className={`h-8 px-3 ${categoryFilter === "all" ? "bg-[#0A39DF]" : "text-slate-600"}`}
|
||||
>
|
||||
All
|
||||
</Button>
|
||||
{categories.map(cat => (
|
||||
<Button
|
||||
key={cat}
|
||||
size="sm"
|
||||
variant={categoryFilter === cat ? "default" : "ghost"}
|
||||
onClick={() => setCategoryFilter(cat)}
|
||||
className={`h-8 px-3 ${categoryFilter === cat ? "bg-[#0A39DF]" : "text-slate-600"}`}
|
||||
>
|
||||
{cat}
|
||||
</Button>
|
||||
))}
|
||||
</div>
|
||||
<Badge variant="outline" className="ml-auto text-slate-500 font-normal">
|
||||
{filteredTemplates.length} reports
|
||||
</Badge>
|
||||
</div>
|
||||
|
||||
{/* Template Grid - Improved Cards */}
|
||||
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-4">
|
||||
{filteredTemplates.map(template => {
|
||||
const Icon = template.icon;
|
||||
return (
|
||||
<div
|
||||
key={template.id}
|
||||
className="bg-white rounded-xl border border-slate-200 hover:border-blue-400 hover:shadow-lg transition-all cursor-pointer group overflow-hidden"
|
||||
onClick={() => onSelectTemplate?.(template)}
|
||||
>
|
||||
<div className="p-4">
|
||||
<div className="flex items-start gap-3 mb-3">
|
||||
<div className={`w-10 h-10 ${ICON_COLORS[template.color]} rounded-xl flex items-center justify-center flex-shrink-0 shadow-sm`}>
|
||||
<Icon className="w-5 h-5 text-white" />
|
||||
</div>
|
||||
<div className="flex-1 min-w-0">
|
||||
<h4 className="font-semibold text-sm text-slate-900 group-hover:text-blue-700 leading-tight">
|
||||
{template.name}
|
||||
</h4>
|
||||
<Badge className={`${CATEGORY_COLORS[template.category]} text-[10px] px-1.5 py-0 mt-1`}>
|
||||
{template.category}
|
||||
</Badge>
|
||||
</div>
|
||||
</div>
|
||||
<p className="text-xs text-slate-500 line-clamp-2 mb-3 min-h-[32px]">{template.description}</p>
|
||||
</div>
|
||||
<div className="px-4 pb-4">
|
||||
<Button
|
||||
size="sm"
|
||||
className="w-full h-9 bg-[#0A39DF] hover:bg-[#0831b8] font-medium"
|
||||
onClick={(e) => { e.stopPropagation(); onSelectTemplate?.(template); }}
|
||||
>
|
||||
<Download className="w-4 h-4 mr-1.5" />
|
||||
Generate Report
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
|
||||
{filteredTemplates.length === 0 && (
|
||||
<div className="text-center py-16 bg-white rounded-xl border">
|
||||
<FileText className="w-12 h-12 mx-auto mb-3 text-slate-300" />
|
||||
<p className="text-slate-500 font-medium">No reports match your search</p>
|
||||
<p className="text-sm text-slate-400 mt-1">Try adjusting your filters</p>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user