import { Layout } from "@/components/layout/Layout"; import type { ReactElement } from "react"; import { FileCheck, Briefcase, FileText, Users, Bell, } from "lucide-react"; import { QuickActions } from "@/features/dashboard/components/QuickActions"; import { RecentActivity } from "@/features/dashboard/components/RecentActivity"; import { cn } from "@/lib/utils"; import { useState, useEffect } from "react"; import { workflowService } from "@/services/workflow-service"; import { dashboardService, type TenantDashboardStats } from "@/services/dashboard-service"; import type { WorkflowTask } from "@/types/workflow"; import { useNavigate } from "react-router-dom"; interface StatCardProps { icon: React.ComponentType<{ className?: string; strokeWidth?: number }>; value: string | number; label: string; badge?: { text: string; variant: 'success' | 'warning' | 'info' | 'error'; }; } const StatCard = ({ icon: Icon, value, label, badge }: StatCardProps): ReactElement => { return (
{/* Interaction Gradient */}
{badge && (
{badge.text}
)}
{value}
{label}
); }; const TaskCard = ({ task }: { task: WorkflowTask }) => { const navigate = useNavigate(); const formatDeadline = (dueDate: string) => { const now = new Date(); const due = new Date(dueDate); const diffTime = due.getTime() - now.getTime(); const diffDays = Math.ceil(diffTime / (1000 * 60 * 60 * 24)); if (diffDays === 0) return 'Due today'; if (diffDays === 1) return 'Tomorrow'; if (diffDays < 0) return 'Overdue'; return `In ${diffDays} Days`; }; const handleView = () => { if (task.entity.type.toLowerCase() === 'document') { navigate(`/tenant/documents/${task.entity.id}`); } }; return (
{task.entity.type} {formatDeadline(task.due_at)}
{task.entity.name}
{task.step.name} • {task.assignment?.assigned_role || task.assignment?.assigned_to_name || 'Unassigned'}
); }; /* const CAPASummaryChart = () => { const data = [ { name: 'Jan', open: 35, inProgress: 48, closed: 25, trend: 15 }, { name: 'Feb', open: 28, inProgress: 35, closed: 20, trend: 12 }, { name: 'Mar', open: 45, inProgress: 75, closed: 38, trend: 32 }, { name: 'Apr', open: 40, inProgress: 65, closed: 42, trend: 28 }, { name: 'May', open: 55, inProgress: 95, closed: 78, trend: 52 }, { name: 'Jun', open: 42, inProgress: 82, closed: 72, trend: 45 }, { name: 'Jul', open: 38, inProgress: 70, closed: 65, trend: 38 }, { name: 'Aug', open: 48, inProgress: 94, closed: 82, trend: 48 }, { name: 'Sep', open: 32, inProgress: 65, closed: 58, trend: 35 }, { name: 'Oct', open: 44, inProgress: 88, closed: 85, trend: 58 }, { name: 'Nov', open: 52, inProgress: 92, closed: 98, trend: 62 }, { name: 'Dec', open: 60, inProgress: 105, closed: 115, trend: 58 }, ]; return (
); }; */ const Dashboard = (): ReactElement => { const navigate = useNavigate(); const [tasks, setTasks] = useState([]); const [stats, setStats] = useState(null); const [loading, setLoading] = useState(true); const [tasksLoading, setTasksLoading] = useState(true); useEffect(() => { fetchDashboardData(); }, []); const fetchDashboardData = async () => { setLoading(true); setTasksLoading(true); try { // Fetch tasks independently to avoid one failing the other workflowService.listTasks({ limit: 3 }) .then(response => { console.log("[Dashboard] Tasks response:", response); if (response.success && Array.isArray(response.data)) { setTasks(response.data); } }) .catch(error => { console.error("Error fetching tasks:", error); }) .finally(() => { setTasksLoading(false); }); // Fetch statistics independently dashboardService.getTenantStatistics() .then(response => { if (response.success) { setStats(response.data); } }) .catch(error => { console.error("Error fetching dashboard statistics:", error); }) .finally(() => { setLoading(false); }); } catch (error) { console.error("Critical error in fetchDashboardData:", error); setLoading(false); setTasksLoading(false); } }; const statCards: StatCardProps[] = [ stats?.documentsCount !== undefined && { icon: FileText, value: stats.documentsCount, label: "Total Documents", badge: { text: "Controlled", variant: "info" } }, stats?.pendingTasks !== undefined && { icon: FileCheck, value: stats.pendingTasks, label: "My Tasks", badge: { text: "Action Needed", variant: "warning" } }, stats?.usersCount !== undefined && { icon: Users, value: stats.usersCount, label: "Total Users", badge: { text: "Team Members", variant: "success" } }, stats?.unreadNotificationsCount !== undefined && { icon: Bell, value: stats.unreadNotificationsCount, label: "Notifications", badge: { text: "Unread", variant: "error" } }, stats?.activeModulesCount !== undefined && { icon: Briefcase, value: stats.activeModulesCount, label: "Running Modules", badge: { text: "Operational", variant: "success" } }, // Training Compliance is still static/placeholder for now // { // icon: GraduationCap, // value: "94%", // label: "Compliance", // badge: { text: "Target Met", variant: "success" } // }, ].filter(Boolean) as StatCardProps[]; return (
{/* Main Content Area (Left) */}
{/* Stats Grid */}
{loading ? (
Loading statistics...
) : statCards.length > 0 ? ( statCards.map((card, index) => ( )) ) : (
No statistics available
)}
{/* CAPA Summary Card (Commented out for now) */} {/*

CAPA Summary

Data Range
*/} {/* Recent Activity Card */}
{/* Sidebar area (Right) */}
{/* My Tasks Card */}

My Tasks

{tasksLoading ? (
Loading tasks...
) : tasks.length > 0 ? ( tasks.map((task) => ( )) ) : (
No pending tasks
)}
{/* Quick Actions Card */}
); }; export default Dashboard;