import { Clock, Server, ArrowUp, ArrowDown } from "lucide-react"; import { Service, UptimeData } from "@/types/service.types"; import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; import { useMemo } from "react"; import { formatDistanceStrict } from "date-fns"; import {useLanguage} from "@/contexts/LanguageContext.tsx"; interface ServiceStatsCardsProps { service: Service; uptimeData: UptimeData[]; } export function ServiceStatsCards({ service, uptimeData }: ServiceStatsCardsProps) { const { t } = useLanguage(); // Calculate uptime percentage const calculateUptimePercentage = () => { if (uptimeData.length === 0) return 100; const totalChecks = uptimeData.length; const upChecks = uptimeData.filter(data => data.status === "up").length; return Math.round((upChecks / totalChecks) * 100); }; // Calculate total uptime/downtime const uptimeStats = useMemo(() => { if (uptimeData.length === 0) { return { totalUptimeFormatted: "N/A", totalDowntimeFormatted: "N/A", currentStatusDuration: "N/A" }; } // Sort data by timestamp for chronological analysis const sortedData = [...uptimeData].sort((a, b) => new Date(a.timestamp).getTime() - new Date(b.timestamp).getTime() ); // Get the status change events const statusChanges = sortedData.reduce((changes, check, index) => { if (index === 0 || (index > 0 && sortedData[index-1].status !== check.status)) { changes.push(check); } return changes; }, [] as UptimeData[]); let totalUptime = 0; let totalDowntime = 0; let currentStatus = service.status; let lastChangeTime = new Date(); // Calculate durations between status changes for (let i = 0; i < statusChanges.length; i++) { const currentChange = statusChanges[i]; const nextChange = statusChanges[i + 1]; if (nextChange) { const duration = new Date(nextChange.timestamp).getTime() - new Date(currentChange.timestamp).getTime(); if (currentChange.status === "up") { totalUptime += duration; } else { totalDowntime += duration; } } else { // For the last status, calculate time until now lastChangeTime = new Date(currentChange.timestamp); currentStatus = currentChange.status; } } // Add time from last change until now for current status const now = new Date(); const sinceLastChange = now.getTime() - lastChangeTime.getTime(); if (currentStatus === "up") { totalUptime += sinceLastChange; } else if (currentStatus === "down") { totalDowntime += sinceLastChange; } // Format durations const formatDuration = (ms: number): string => { if (ms < 1000) return "0s"; return formatDistanceStrict(0, ms, { addSuffix: false }); }; return { totalUptimeFormatted: formatDuration(totalUptime), totalDowntimeFormatted: formatDuration(totalDowntime), currentStatusDuration: formatDuration(sinceLastChange) }; }, [uptimeData, service.status]); // Calculate average response time from recent checks const calculateAverageResponseTime = () => { const upChecks = uptimeData.filter(data => data.status === "up" && data.responseTime > 0); if (upChecks.length === 0) return service.responseTime || 0; const sum = upChecks.reduce((total, check) => total + check.responseTime, 0); return Math.round((sum / upChecks.length) * 100) / 100; // Two decimal precision }; const uptimePercentage = calculateUptimePercentage(); const avgResponseTime = calculateAverageResponseTime(); // Define upChecks here so we can use it in both the calculation and the JSX const upChecks = uptimeData.filter(data => data.status === "up" && data.responseTime > 0); return (
{t('lastCheckedAt').replace('{datetime}', service.lastChecked)}
{avgResponseTime > 0 && avgResponseTime !== service.responseTime && ({t('avg')}: {avgResponseTime}ms ({t('lastUpChecksCount').replace('{count}', String(upChecks.length))})
)}{t('basedOnlastChecksCount').replace('{count}', String(uptimeData.length))}