"use client" import { useState, useEffect } from "react" import { AreaChart, Area, XAxis, YAxis, CartesianGrid, Tooltip, ResponsiveContainer, Legend } from "recharts" import { Loader2 } from "lucide-react" interface NetworkMetricsData { time: string timestamp: number netIn: number netOut: number } interface NetworkTrafficChartProps { timeframe: string interfaceName?: string onTotalsCalculated?: (totals: { received: number; sent: number }) => void refreshInterval?: number // En milisegundos, por defecto 60000 (60 segundos) isActive?: boolean } const CustomNetworkTooltip = ({ active, payload, label }: any) => { if (active && payload && payload.length) { return (

{label}

{payload.map((entry: any, index: number) => (
{entry.name}: {entry.value.toFixed(3)} GB
))}
) } return null } export function NetworkTrafficChart({ timeframe, interfaceName, onTotalsCalculated, refreshInterval = 60000, isActive = true, }: NetworkTrafficChartProps) { const [data, setData] = useState([]) const [loading, setLoading] = useState(true) const [error, setError] = useState(null) const [isInitialLoad, setIsInitialLoad] = useState(true) const [visibleLines, setVisibleLines] = useState({ netIn: true, netOut: true, }) useEffect(() => { setIsInitialLoad(true) fetchMetrics() }, [timeframe, interfaceName]) useEffect(() => { if (refreshInterval > 0 && isActive) { const interval = setInterval(() => { fetchMetrics() }, refreshInterval) return () => clearInterval(interval) } }, [timeframe, interfaceName, refreshInterval, isActive]) const fetchMetrics = async () => { if (!isActive) { return } if (isInitialLoad) { setLoading(true) } setError(null) try { const { protocol, hostname, port } = window.location const isStandardPort = port === "" || port === "80" || port === "443" const baseUrl = isStandardPort ? "" : `${protocol}//${hostname}:8008` const apiUrl = interfaceName ? `${baseUrl}/api/network/${interfaceName}/metrics?timeframe=${timeframe}` : `${baseUrl}/api/node/metrics?timeframe=${timeframe}` console.log("[v0] Fetching network metrics from:", apiUrl) const response = await fetch(apiUrl) if (!response.ok) { throw new Error(`Failed to fetch network metrics: ${response.status}`) } const result = await response.json() if (!result.data || !Array.isArray(result.data)) { throw new Error("Invalid data format received from server") } if (result.data.length === 0) { setData([]) setLoading(false) return } const transformedData = result.data.map((item: any, index: number) => { const date = new Date(item.time * 1000) let timeLabel = "" if (timeframe === "hour") { timeLabel = date.toLocaleString("en-US", { hour: "2-digit", minute: "2-digit", hour12: false, }) } else if (timeframe === "day") { timeLabel = date.toLocaleString("en-US", { hour: "2-digit", minute: "2-digit", hour12: false, }) } else if (timeframe === "week") { timeLabel = date.toLocaleString("en-US", { month: "short", day: "numeric", hour: "2-digit", hour12: false, }) } else if (timeframe === "year") { timeLabel = date.toLocaleString("en-US", { month: "short", day: "numeric", year: "numeric", }) } else { timeLabel = date.toLocaleString("en-US", { month: "short", day: "numeric", }) } let intervalSeconds = 60 if (index > 0) { intervalSeconds = item.time - result.data[index - 1].time } const netInBytes = (item.netin || 0) * intervalSeconds const netOutBytes = (item.netout || 0) * intervalSeconds return { time: timeLabel, timestamp: item.time, netIn: Number((netInBytes / 1024 / 1024 / 1024).toFixed(4)), netOut: Number((netOutBytes / 1024 / 1024 / 1024).toFixed(4)), } }) setData(transformedData) const totalReceived = transformedData.reduce((sum: number, item: NetworkMetricsData) => sum + item.netIn, 0) const totalSent = transformedData.reduce((sum: number, item: NetworkMetricsData) => sum + item.netOut, 0) if (onTotalsCalculated) { onTotalsCalculated({ received: totalReceived, sent: totalSent }) } if (isInitialLoad) { setIsInitialLoad(false) } } catch (err: any) { console.error("[v0] Error fetching network metrics:", err) setError(err.message || "Error loading metrics") } finally { setLoading(false) } } const tickInterval = Math.ceil(data.length / 8) const handleLegendClick = (dataKey: string) => { setVisibleLines((prev) => ({ ...prev, [dataKey as keyof typeof prev]: !prev[dataKey as keyof typeof prev], })) } const renderLegend = (props: any) => { const { payload } = props return (
{payload.map((entry: any, index: number) => { const isVisible = visibleLines[entry.dataKey as keyof typeof visibleLines] return (
handleLegendClick(entry.dataKey)} style={{ opacity: isVisible ? 1 : 0.4 }} >
{entry.value}
) })}
) } if (loading && isInitialLoad) { return (
) } if (error) { return (

Network metrics not available yet

{error}

) } if (data.length === 0) { return (

No network metrics available

) } return ( } /> ) }