'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';
}