'use client'; import Link from "next/link"; import { useRouter } from "next/navigation"; import { useState } from "react"; import { ChevronLeft, MapPin, Droplets, Wind, Thermometer, Hexagon } from "lucide-react"; import { useSensor } from "@/hooks/use-sensors"; import { useReadings } from "@/hooks/use-readings"; import { LoadingScreen } from "@/components/LoadingScreen"; import { TelemetryChart } from "@/components/TelemetryChart"; import { KpiCard, getPhStatus, getTurbidityStatus, getTempStatus, getHardnessStatus } from "@/components/KpiCard"; import { CreateReadingDialog } from "@/components/CreateReadingDialog"; export default function SensorDetailClient({ sensorId }: { sensorId: string }) { const [timeRange, setTimeRange] = useState<"1h" | "1d" | "1w" | "1m">("1d"); const { data: sensor, isLoading: sensorLoading } = useSensor(sensorId || ""); const { data: readings, isLoading: readingsLoading } = useReadings(sensorId, timeRange); if (sensorLoading) return ; if (!sensor) { return (

UPLINK FAILED

Sensor Node {sensorId} could not be located in the grid database.

Return to Grid
); } // Ensure chronological order for Recharts const sortedReadings = [...(readings || [])].sort( (a, b) => new Date(a.timestamp).getTime() - new Date(b.timestamp).getTime() ); const latestReading = sortedReadings[sortedReadings.length - 1]; return (
{/* Header Section */}
Return to Global Grid

{sensor.locationName || "Unassigned Sector"}

ID: {sensor.sensorId} LAT: {sensor.latitude} LNG: {sensor.longitude}
{/* Real-time KPI Cards */}
{/* Potability Status Banner */} {latestReading && (
{getPotabilityIcon(latestReading.potability)}

{getPotabilityStatusText(latestReading.potability)}

ML INFERENCE {latestReading.potability !== null ? `— ${(latestReading.potability * 100).toFixed(2)}% CONFIDENCE` : '— AWAITING MODEL'}

)} {/* Time Range Selector & Charts */}

TELEMETRY HISTORY

{(["1h", "1d", "1w", "1m"] as const).map((tr) => ( ))}
{readingsLoading ? (
) : (
)}
); } function getPotabilityColor(potability: number | null | undefined): string { if (potability === null || potability === undefined) return 'text-gray-500'; const percentage = potability * 100; if (percentage > 80) return 'text-green-600'; if (percentage >= 30) return 'text-yellow-600'; return 'text-red-600'; } function getPotabilityIcon(potability: number | null | undefined): string { if (potability === null || potability === undefined) return '⏳'; const percentage = potability * 100; if (percentage > 80) return '✅'; if (percentage >= 30) return '⚠️'; return '⛔'; } function getPotabilityBannerStyle(potability: number | null | undefined): string { if (potability === null || potability === undefined) return 'bg-slate-900/50 border-slate-700'; const percentage = potability * 100; if (percentage > 80) return 'bg-green-950/30 border-green-500/50 shadow-[0_0_20px_rgba(74,222,128,0.1)]'; if (percentage >= 30) return 'bg-yellow-950/30 border-yellow-500/50 shadow-[0_0_20px_rgba(251,191,36,0.1)]'; return 'bg-red-950/30 border-red-500/50 shadow-[0_0_20px_rgba(248,113,113,0.1)]'; } function getPotabilityGlow(potability: number | null | undefined): string { if (potability === null || potability === undefined) return ''; const percentage = potability * 100; if (percentage > 80) return 'drop-shadow-[0_0_8px_rgba(74,222,128,0.8)]'; if (percentage >= 30) return 'drop-shadow-[0_0_8px_rgba(251,191,36,0.8)]'; return 'drop-shadow-[0_0_8px_rgba(248,113,113,0.8)]'; } function getPotabilityTextColor(potability: number | null | undefined): string { if (potability === null || potability === undefined) return 'text-slate-500'; const percentage = potability * 100; if (percentage > 80) return 'text-green-400'; if (percentage >= 30) return 'text-yellow-400'; return 'text-red-400'; } function getPotabilityStatusText(potability: number | null | undefined): string { if (potability === null || potability === undefined) return 'POTABILITY UNKNOWN'; const percentage = potability * 100; if (percentage > 80) return 'HIGH POTABILITY'; if (percentage >= 30) return 'MODERATE POTABILITY'; return 'LOW POTABILITY'; }