import React from "react"; import { AlertCircle, Bug, CheckCircle, Clock, Filter, FlameIcon, PieChart, RefreshCw, ShieldAlert, ThumbsUp } from "lucide-react"; import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; import { Avatar, AvatarFallback } from "@/components/ui/avatar"; import { Badge } from "@/components/ui/badge"; import ChartCard from "./chart-card"; import StatsCard from "./stats-card"; import { Task } from "@/services/tasksApi"; import { Employee } from "@/types"; import "@/styles/dashboard.css"; // Helper function to get severity value from a bug const getBugSeverity = (bug: Task): string => { // First check if we have a severity field if (bug.severity) { return bug.severity; } // Fall back to type field which may have been used for severity return bug.type || ''; }; interface DashboardBugsProps { bugs: Task[]; employees: Employee[]; } const DashboardBugs: React.FC = ({ bugs, employees }) => { // Calculate stats for the dashboard const totalBugs = bugs.length; const openBugs = bugs.filter(bug => ["New", "Open", "In Progress", "Reopened"].includes(bug.status) ).length; const resolvedBugs = bugs.filter(bug => ["Completed", "Resolved", "Closed"].includes(bug.status) ).length; const criticalBugs = bugs.filter(bug => ["Blocker", "Critical"].includes(getBugSeverity(bug)) ).length; // Get top assignees by bug count const assigneeCounts = bugs.reduce((acc, bug) => { if (bug.assignedTo) { acc[bug.assignedTo] = (acc[bug.assignedTo] || 0) + 1; } return acc; }, {} as Record); const topAssignees = Object.entries(assigneeCounts) .map(([id, count]) => ({ id: parseInt(id), count })) .sort((a, b) => b.count - a.count) .slice(0, 5) .map(item => { const employee = employees.find(emp => emp.id === item.id); return { id: item.id, name: employee ? `${employee.firstName} ${employee.lastName}` : `User ${item.id}`, initials: employee ? `${employee.firstName.charAt(0)}${employee.lastName.charAt(0)}`.toUpperCase() : "UN", count: item.count }; }); // Prepare data for charts const statusChartData = [{ name: "Open", value: bugs.filter(bug => bug.status === "Open").length, }, { name: "In Progress", value: bugs.filter(bug => bug.status === "In Progress").length, }, { name: "In Review", value: bugs.filter(bug => bug.status === "In Review").length, }, { name: "Completed", value: bugs.filter(bug => bug.status === "Completed").length, }, { name: "Closed", value: bugs.filter(bug => bug.status === "Closed").length, }]; const severityChartData = [{ name: "Blocker", value: bugs.filter(bug => getBugSeverity(bug) === "Blocker").length, }, { name: "Critical", value: bugs.filter(bug => getBugSeverity(bug) === "Critical").length, }, { name: "Major", value: bugs.filter(bug => getBugSeverity(bug) === "Major").length, }, { name: "Minor", value: bugs.filter(bug => getBugSeverity(bug) === "Minor").length, }, { name: "Trivial", value: bugs.filter(bug => getBugSeverity(bug) === "Trivial").length, }]; const trendData = Array(7).fill(0).map((_, i) => { const date = new Date(); date.setDate(date.getDate() - (6 - i)); // Count bugs created on this date const count = bugs.filter(bug => { if (!bug.createdAt) return false; const bugDate = new Date(bug.createdAt); return bugDate.toDateString() === date.toDateString(); }).length; return { name: date.toLocaleDateString('en-US', { weekday: 'short' }), value: count }; }); const getStatusBadge = (status: string) => { switch (status) { case "Completed": case "Closed": case "Resolved": return ( {status} ); case "In Progress": return ( {status} ); case "Reopened": case "Re-Open": return ( {status} ); case "In Review": case "Ready for QA": return ( {status} ); case "Open": case "New": return ( {status} ); default: return ( {status || "Unknown"} ); } }; const getSeverityBadge = (severity: string | Task) => { // Use our helper function if we're passed a bug object if (typeof severity === 'object') { severity = getBugSeverity(severity); } switch (severity) { case "Blocker": return ( {severity} ); case "Critical": return ( {severity} ); case "Major": return ( {severity} ); case "Minor": return ( {severity} ); case "Trivial": return ( {severity} ); default: return ( {severity || "Unknown"} ); } }; return (

Bug Tracking Dashboard

{/* Stats Overview */}
{/* Charts Row */}
{/* Additional Charts & Widgets */}
Top Bug Handlers
{topAssignees.length > 0 ? topAssignees.map((assignee, index) => (
{assignee.initials}

{assignee.name}

{assignee.count} {assignee.count === 1 ? "bug" : "bugs"}

a.count))) * 100)}%` }} >
)) : (

No assigned bugs yet

)}
{/* Recent Issues */} Recent Issues {bugs.length > 0 ? (
{bugs .sort((a, b) => { const dateA = a.createdAt ? new Date(a.createdAt).getTime() : 0; const dateB = b.createdAt ? new Date(b.createdAt).getTime() : 0; return dateB - dateA; }) .slice(0, 5) .map((bug, index) => (

{bug.title}

{bug.taskCode || `BUG-${bug.id}`}

{bug.description}

{getStatusBadge(bug.status)} {getSeverityBadge(bug)}
{bug.assignedTo ? (
{(() => { const employee = employees.find(emp => emp.id === bug.assignedTo); return employee ? `${employee.firstName.charAt(0)}${employee.lastName.charAt(0)}`.toUpperCase() : "UN"; })()} {(() => { const employee = employees.find(emp => emp.id === bug.assignedTo); return employee ? `${employee.firstName} ${employee.lastName}` : `User ${bug.assignedTo}`; })()}
) : ( Unassigned )}
{bug.createdAt ? new Date(bug.createdAt).toLocaleDateString() : "N/A"}
))}
) : (

No bugs available for your assigned projects

)}
); }; export default DashboardBugs;