Re_Figma_Code/src/components/dashboard/CriticalAlertCard/CriticalAlertCard.tsx

139 lines
4.2 KiB
TypeScript

import { Badge } from '@/components/ui/badge';
import { Progress } from '@/components/ui/progress';
import { Star } from 'lucide-react';
export interface CriticalAlertData {
requestId: string;
requestNumber: string;
title: string;
priority: string;
totalTATHours: number;
originalTATHours: number;
breachCount: number;
currentLevel: number;
totalLevels: number;
}
interface CriticalAlertCardProps {
alert: CriticalAlertData;
onNavigate?: (requestNumber: string) => void;
testId?: string;
}
// Utility functions
const calculateProgress = (alert: CriticalAlertData) => {
if (!alert.originalTATHours || alert.originalTATHours === 0) return 0;
const originalTAT = alert.originalTATHours;
const remainingTAT = alert.totalTATHours;
// If breached (negative remaining), show 100%
if (remainingTAT <= 0) return 100;
// Calculate elapsed time
const elapsedTAT = originalTAT - remainingTAT;
// Calculate percentage used
const percentageUsed = (elapsedTAT / originalTAT) * 100;
// Ensure it's between 0 and 100
return Math.min(100, Math.max(0, Math.round(percentageUsed)));
};
const formatRemainingTime = (alert: CriticalAlertData) => {
if (alert.totalTATHours === undefined || alert.totalTATHours === null) return 'N/A';
const hours = alert.totalTATHours;
// If TAT is breached (negative or zero)
if (hours <= 0) {
const overdue = Math.abs(hours);
if (overdue < 1) return `Breached`;
if (overdue < 24) return `${Math.round(overdue)}h overdue`;
return `${Math.round(overdue / 24)}d overdue`;
}
// If TAT is still remaining
if (hours < 1) return `${Math.round(hours * 60)}min left`;
if (hours < 24) return `${Math.round(hours)}h left`;
return `${Math.round(hours / 24)}d left`;
};
export function CriticalAlertCard({
alert,
onNavigate,
testId = 'critical-alert-card'
}: CriticalAlertCardProps) {
const progress = calculateProgress(alert);
return (
<div
className="p-3 sm:p-4 bg-red-50 rounded-lg sm:rounded-xl border border-red-100 hover:shadow-md transition-all duration-200 cursor-pointer"
onClick={() => onNavigate?.(alert.requestNumber)}
data-testid={`${testId}-${alert.requestId}`}
>
<div className="flex items-start justify-between gap-2 mb-2 sm:mb-3">
<div className="flex-1 min-w-0">
<div className="flex items-center gap-1 sm:gap-2 mb-1 flex-wrap">
<p
className="font-semibold text-xs sm:text-sm text-gray-900"
data-testid={`${testId}-request-number`}
>
{alert.requestNumber}
</p>
{alert.priority === 'express' && (
<Star
className="h-3 w-3 text-red-500 flex-shrink-0"
data-testid={`${testId}-priority-icon`}
/>
)}
{alert.breachCount > 0 && (
<Badge
variant="destructive"
className="text-xs"
data-testid={`${testId}-breach-count`}
>
{alert.breachCount}
</Badge>
)}
</div>
<p
className="text-xs sm:text-sm text-gray-700 line-clamp-2"
data-testid={`${testId}-title`}
>
{alert.title}
</p>
</div>
<Badge
variant="outline"
className="text-xs bg-white border-red-200 text-red-700 font-medium whitespace-nowrap"
data-testid={`${testId}-remaining-time`}
>
{formatRemainingTime(alert)}
</Badge>
</div>
<div className="space-y-1 sm:space-y-2">
<div className="flex justify-between text-xs text-gray-600">
<span>TAT Used</span>
<span
className="font-medium"
data-testid={`${testId}-progress-percentage`}
>
{progress}%
</span>
</div>
<Progress
value={progress}
className={`h-1.5 sm:h-2 ${
progress >= 80 ? '[&>div]:bg-red-600' :
progress >= 50 ? '[&>div]:bg-orange-500' :
'[&>div]:bg-green-600'
}`}
data-testid={`${testId}-progress-bar`}
/>
</div>
</div>
);
}