130 lines
3.5 KiB
TypeScript
130 lines
3.5 KiB
TypeScript
import { Layout } from '@/components/layout/Layout';
|
|
import type { ReactElement } from 'react';
|
|
import { Info, FileCheck, Briefcase, FileText, GraduationCap } from 'lucide-react';
|
|
|
|
interface StatCardProps {
|
|
icon: React.ComponentType<{ className?: string }>;
|
|
value: string | number;
|
|
label: string;
|
|
status: 'success' | 'process' | 'warning' | 'disabled';
|
|
statusLabel: string;
|
|
}
|
|
|
|
const StatCard = ({ icon: Icon, value, label, status, statusLabel }: StatCardProps): ReactElement => {
|
|
const statusConfig = {
|
|
success: {
|
|
bg: 'bg-[#f1fffb]',
|
|
dot: 'bg-[#16c784]',
|
|
text: 'text-[#16c784]',
|
|
},
|
|
process: {
|
|
bg: 'bg-[#fff5e5]',
|
|
dot: 'bg-[#fca004]',
|
|
text: 'text-[#fca004]',
|
|
},
|
|
warning: {
|
|
bg: 'bg-[#fdf5f4]',
|
|
dot: 'bg-[#e0352a]',
|
|
text: 'text-[#e0352a]',
|
|
},
|
|
disabled: {
|
|
bg: 'bg-[#e5e7eb]',
|
|
dot: 'bg-[#9ca3af]',
|
|
text: 'text-[#9ca3af]',
|
|
},
|
|
};
|
|
|
|
const config = statusConfig[status];
|
|
const valueColor = status === 'warning' && label === 'Overdue Tasks' ? 'text-[#e0352a]' : 'text-[#0f1724]';
|
|
|
|
return (
|
|
<div className="relative p-[1px] rounded-lg" style={{ backgroundImage: 'linear-gradient(172.99deg, rgb(8, 76, 200) 1.15%, rgb(117, 192, 68) 44.3%, rgb(254, 211, 20) 89.74%)' }}>
|
|
<div className="bg-white border border-[#d1d5db] rounded-lg p-[17px] flex flex-col gap-3">
|
|
{/* Header with icon and status */}
|
|
<div className="flex items-start justify-between">
|
|
<Icon className="w-5 h-5 text-[#0f1724] shrink-0" />
|
|
<div className={`${config.bg} flex gap-1 items-center px-3 py-1 rounded-full`}>
|
|
<div className={`${config.dot} rounded-sm w-1.5 h-1.5`} />
|
|
<span className={`${config.text} text-xs font-medium capitalize`}>{statusLabel}</span>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Value and Label */}
|
|
<div className="flex flex-col gap-0">
|
|
<div className={`text-2xl font-bold tracking-[-0.48px] ${valueColor}`}>
|
|
{value}
|
|
</div>
|
|
<div className="text-xs font-medium text-[#6b7280]">
|
|
{label}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
);
|
|
};
|
|
|
|
const Dashboard = (): ReactElement => {
|
|
const statCards: StatCardProps[] = [
|
|
{
|
|
icon: Info,
|
|
value: '18',
|
|
label: 'Open CAPAs',
|
|
status: 'success',
|
|
statusLabel: 'Success',
|
|
},
|
|
{
|
|
icon: FileCheck,
|
|
value: '7',
|
|
label: 'Pending Approvals',
|
|
status: 'process',
|
|
statusLabel: 'Process',
|
|
},
|
|
{
|
|
icon: Briefcase,
|
|
value: '9',
|
|
label: 'Active Projects',
|
|
status: 'warning',
|
|
statusLabel: 'Warning',
|
|
},
|
|
{
|
|
icon: Info,
|
|
value: '3',
|
|
label: 'Overdue Tasks',
|
|
status: 'warning',
|
|
statusLabel: 'Warning',
|
|
},
|
|
{
|
|
icon: FileText,
|
|
value: '14',
|
|
label: 'Docs Pending Review',
|
|
status: 'disabled',
|
|
statusLabel: 'Disabled',
|
|
},
|
|
{
|
|
icon: GraduationCap,
|
|
value: '94%',
|
|
label: 'Training Compliance',
|
|
status: 'success',
|
|
statusLabel: 'Success',
|
|
},
|
|
];
|
|
|
|
return (
|
|
<Layout
|
|
currentPage="Dashboard Overview"
|
|
pageHeader={{
|
|
title: 'Tenant Overview',
|
|
description: 'Key quality metrics and performance indicators.',
|
|
}}
|
|
>
|
|
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
|
|
{statCards.map((card, index) => (
|
|
<StatCard key={index} {...card} />
|
|
))}
|
|
</div>
|
|
</Layout>
|
|
);
|
|
};
|
|
|
|
export default Dashboard;
|