"use client" import { useState, useEffect } from "react" import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card" import { AlertCircle, TrendingUp, MapPin as MapPinIcon, BarChart3, AlertTriangle, RectangleHorizontal } from "lucide-react" import { SidebarNavigation } from "@/components/sidebar-navigation" import { GradientStatsCard } from "@/components/dashboard/gradient-stats-card" import { CompactProjectSelector } from "@/components/dashboard/compact-project-selector" import { FilterSelector } from "@/components/dashboard/filter-selector" import { DetectionDonutChart } from "@/components/dashboard/detection-donut-chart" import { LocationBarChart } from "@/components/dashboard/location-bar-chart" import { DashboardMap } from "@/components/dashboard/dashboard-map" import { fetchProjects, type Project } from "@/lib/api" const API_URL = "http://127.0.0.1:8000/api/v1" interface ProjectSummary { project: { id: string name: string corridor_name: string | null state: string | null } packages: { [key: string]: { package_id: string region: string | null locations: { [key: string]: { location_id: string chainage: string | null detection_count: number detections: Array<{ id: number type: string class: string confidence: number latitude: number longitude: number }> } } } } } interface DetectionStats { totalPotholes: number totalSignboards: number totalDetections: number locationData: Array<{ name: string potholes: number signboards: number total: number }> } function calculateStats(summary: ProjectSummary | null): DetectionStats { if (!summary) { return { totalPotholes: 0, totalSignboards: 0, totalDetections: 0, locationData: [] } } let totalPotholes = 0 let totalSignboards = 0 const locationData: DetectionStats["locationData"] = [] for (const pkg of Object.values(summary.packages || {})) { for (const [locName, loc] of Object.entries(pkg.locations || {})) { let locPotholes = 0 let locSignboards = 0 for (const detection of loc.detections || []) { if (detection.type.toLowerCase().includes("pothole")) { locPotholes++ totalPotholes++ } else { locSignboards++ totalSignboards++ } } if (locPotholes > 0 || locSignboards > 0) { const shortName = locName.length > 20 ? locName.substring(0, 20) + "..." : locName locationData.push({ name: shortName, potholes: locPotholes, signboards: locSignboards, total: locPotholes + locSignboards }) } } } return { totalPotholes, totalSignboards, totalDetections: totalPotholes + totalSignboards, locationData } } export default function DashboardPage() { const [isLoading, setIsLoading] = useState(true) const [projects, setProjects] = useState([]) const [selectedProjectId, setSelectedProjectId] = useState(null) const [projectSummary, setProjectSummary] = useState(null) const [stats, setStats] = useState({ totalPotholes: 0, totalSignboards: 0, totalDetections: 0, locationData: [] }) const [error, setError] = useState(null) // Load projects on mount useEffect(() => { const loadProjects = async () => { try { setIsLoading(true) setError(null) const projectsData = await fetchProjects() setProjects(projectsData) if (projectsData.length > 0) { setSelectedProjectId(projectsData[0].id) } } catch (err) { console.error("Failed to load projects:", err) setError("Failed to load projects. Please check if the backend is running.") } finally { setIsLoading(false) } } loadProjects() }, []) const selectedProject = projects.find(p => p.id === selectedProjectId) // Extract packages from project summary const packages = projectSummary ? Object.keys(projectSummary.packages || {}).map(pkgName => ({ id: pkgName, name: pkgName })) : [] // Extract locations from selected package const [selectedPackageId, setSelectedPackageId] = useState(null) const [selectedLocationId, setSelectedLocationId] = useState(null) const locations = projectSummary && selectedPackageId && selectedPackageId !== "all" ? Object.keys(projectSummary.packages[selectedPackageId]?.locations || {}).map(locName => ({ id: locName, name: locName })) : [] // Load project summary when project changes useEffect(() => { if (!selectedProjectId) { setProjectSummary(null) return } const loadProjectSummary = async () => { try { setIsLoading(true) setError(null) const response = await fetch(`${API_URL}/summary/projects/${selectedProjectId}`, { headers: { "Content-Type": "application/json", "ngrok-skip-browser-warning": "true" } }) if (!response.ok) { throw new Error(`API Error: ${response.status}`) } const summary: ProjectSummary = await response.json() setProjectSummary(summary) } catch (err) { console.error("Failed to load project summary:", err) setError("Failed to load project summary.") setProjectSummary(null) } finally { setIsLoading(false) } } loadProjectSummary() }, [selectedProjectId]) // Reset package and location when project changes useEffect(() => { setSelectedPackageId(null) setSelectedLocationId(null) }, [selectedProjectId]) // Reset location when package changes useEffect(() => { setSelectedLocationId(null) }, [selectedPackageId]) // Filter stats based on selections useEffect(() => { if (!projectSummary) { setStats({ totalPotholes: 0, totalSignboards: 0, totalDetections: 0, locationData: [] }) return } let totalPotholes = 0 let totalSignboards = 0 const locationData: DetectionStats["locationData"] = [] const packagesToProcess = selectedPackageId && selectedPackageId !== "all" ? { [selectedPackageId]: projectSummary.packages[selectedPackageId] } : projectSummary.packages || {} for (const [pkgName, pkg] of Object.entries(packagesToProcess)) { const locationsToProcess = selectedLocationId && selectedLocationId !== "all" ? { [selectedLocationId]: pkg.locations[selectedLocationId] } : pkg.locations || {} for (const [locName, loc] of Object.entries(locationsToProcess)) { if (!loc) continue let locPotholes = 0 let locSignboards = 0 for (const detection of loc.detections || []) { if (detection.type.toLowerCase().includes("pothole")) { locPotholes++ totalPotholes++ } else { locSignboards++ totalSignboards++ } } if (locPotholes > 0 || locSignboards > 0) { const shortName = locName.length > 20 ? locName.substring(0, 20) + "..." : locName locationData.push({ name: shortName, potholes: locPotholes, signboards: locSignboards, total: locPotholes + locSignboards }) } } } setStats({ totalPotholes, totalSignboards, totalDetections: totalPotholes + totalSignboards, locationData }) }, [projectSummary, selectedPackageId, selectedLocationId]) return (
{/* Sidebar Navigation */} {/* Main Content - offset by sidebar width */}
{/* Header */}
{/* Constant orbit animations removed */}

VisionRoad Analytics Dashboard

A Comprehensive Overview Of Your Road Infrastructure Analysis

{/* Error Display */} {error && (

{error}

)} {/* Stats Cards - Top Row */}
{/* Filter Selector - Above main content */}
{/* Charts Row - Side by Side */}
{/* Left Chart - Detection Distribution */}
Detection Distribution
{/* Right Chart - Location Bar Chart */}
Detections by Location
{/* Map - Full Width Below Charts */}
{/* Footer */}

Sentient Geeks Pvt. Ltd.

) }