refactor: add animations

This commit is contained in:
2026-03-18 12:56:39 +05:30
parent c650da161e
commit f35389ab69
14 changed files with 480 additions and 206 deletions

View File

@@ -30,6 +30,7 @@ import { Button } from "@/components/ui/button";
import { DashboardSkeleton } from "@/components/dashboard/dashboard-skeleton"
import { PoweredBy } from "@/components/powered-by";
import { toast } from "sonner";
import { Reveal, StaggerContainer, StaggerItem } from "@/components/ui/reveal";
const API_URL = process.env.NEXT_PUBLIC_API_URL;
@@ -215,10 +216,10 @@ export default function DashboardPage() {
try {
setIsLoading(true);
const projectsData = await fetchProjects();
setProjects(projectsData);
setProjects(projectsData.items);
if (projectsData.length > 0) {
setSelectedProjectId(projectsData[0].id);
if (projectsData.items.length > 0) {
setSelectedProjectId(projectsData.items[0].id);
}
} catch (err) {
console.error("Failed to load projects:", err);
@@ -432,142 +433,161 @@ export default function DashboardPage() {
icon={BarChart3}
/>
<Popover>
<PopoverTrigger asChild>
<Button variant="outline" className="gap-2 font-semibold">
<Settings2 className="h-4 w-4" />
<span>Filters</span>
</Button>
</PopoverTrigger>
<PopoverContent className="w-[320px] p-0 overflow-hidden" align="end">
<div className="p-4 border-b bg-muted/30">
<h3 className="font-bold text-sm flex items-center gap-2 text-foreground">
<Settings2 className="h-4 w-4 text-primary" />
Filter Analysis
</h3>
<p className="text-xs mt-1 text-muted-foreground">Refine your view by project, package, or location</p>
</div>
<div>
<FilterSelector
projects={projects}
selectedProjectId={selectedProjectId}
selectedPackageId={selectedPackageId}
selectedLocationId={selectedLocationId}
onProjectChange={setSelectedProjectId}
onPackageChange={setSelectedPackageId}
onLocationChange={setSelectedLocationId}
packages={packages}
locations={locations}
isLoading={isLoading}
/>
</div>
</PopoverContent>
</Popover>
<Reveal direction="down" delay={0.2}>
<Popover>
<PopoverTrigger asChild>
<Button variant="outline" className="gap-2 font-semibold">
<Settings2 className="h-4 w-4" />
<span>Filters</span>
</Button>
</PopoverTrigger>
<PopoverContent className="w-[320px] p-0 overflow-hidden" align="end">
<div className="p-4 border-b bg-muted/30">
<h3 className="font-bold text-sm flex items-center gap-2 text-foreground">
<Settings2 className="h-4 w-4 text-primary" />
Filter Analysis
</h3>
<p className="text-xs mt-1 text-muted-foreground">Refine your view by project, package, or location</p>
</div>
<div>
<FilterSelector
projects={projects}
selectedProjectId={selectedProjectId}
selectedPackageId={selectedPackageId}
selectedLocationId={selectedLocationId}
onProjectChange={setSelectedProjectId}
onPackageChange={setSelectedPackageId}
onLocationChange={setSelectedLocationId}
packages={packages}
locations={locations}
isLoading={isLoading}
/>
</div>
</PopoverContent>
</Popover>
</Reveal>
</div>
{isLoading && !projectSummary ? (
<DashboardSkeleton />
) : (
<>
{/* Stats Cards - Top Row */}
<div className="grid grid-cols-1 md:grid-cols-3 gap-4 mb-6">
<StatsCard
title="Total Road Damage"
subtitle="Combined damage detections"
value={stats.totalRoadDamage}
icon={Activity}
/>
<StatsCard
title="Potholes"
subtitle="Surface depressions"
value={stats.totalPothole}
icon={AlertCircle}
/>
<StatsCard
title="Defected Signboards"
subtitle="Damaged traffic signs"
value={stats.totalDefectedSignboard}
icon={AlertTriangle}
/>
<StatsCard
title="Road Cracks"
subtitle="Surface fissures"
value={stats.totalRoadCrack}
icon={Zap}
/>
<StatsCard
title="Damaged Markings"
subtitle="Worn road lines"
value={stats.totalDamagedRoadMarking}
icon={PencilLine}
/>
<StatsCard
title="Good Signboards"
subtitle="Informational markers"
value={stats.totalGoodSignboard}
icon={CheckCircle2}
/>
</div>
<StaggerContainer className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4 mb-6">
<StaggerItem>
<StatsCard
title="Total Road Damage"
subtitle="Combined damage detections"
value={stats.totalRoadDamage}
icon={Activity}
/>
</StaggerItem>
<StaggerItem>
<StatsCard
title="Potholes"
subtitle="Surface depressions"
value={stats.totalPothole}
icon={AlertCircle}
/>
</StaggerItem>
<StaggerItem>
<StatsCard
title="Defected Signboards"
subtitle="Damaged traffic signs"
value={stats.totalDefectedSignboard}
icon={AlertTriangle}
/>
</StaggerItem>
<StaggerItem>
<StatsCard
title="Road Cracks"
subtitle="Surface fissures"
value={stats.totalRoadCrack}
icon={Zap}
/>
</StaggerItem>
<StaggerItem>
<StatsCard
title="Damaged Markings"
subtitle="Worn road lines"
value={stats.totalDamagedRoadMarking}
icon={PencilLine}
/>
</StaggerItem>
<StaggerItem>
<StatsCard
title="Good Signboards"
subtitle="Informational markers"
value={stats.totalGoodSignboard}
icon={CheckCircle2}
/>
</StaggerItem>
</StaggerContainer>
{/* Charts Row - Side by Side */}
<div className="grid grid-cols-1 lg:grid-cols-2 gap-4 mb-4">
{/* Left Chart - Detection Distribution */}
<Card className="flex flex-col">
<CardHeader className="items-center pb-0">
<CardTitle>Detection Distribution</CardTitle>
<CardDescription>Breakdown of all detected road conditions</CardDescription>
</CardHeader>
<CardContent className="flex-1 pb-0">
<DetectionDonutChart
defectedSignboard={stats.totalDefectedSignboard}
pothole={stats.totalPothole}
roadCrack={stats.totalRoadCrack}
damagedRoadMarking={stats.totalDamagedRoadMarking}
goodSignboard={stats.totalGoodSignboard}
/>
</CardContent>
<CardFooter className="flex-col gap-2 text-sm">
<div className="leading-none text-muted-foreground">
Total detections: {stats.totalRoadDamage + stats.totalGoodSignboard}
</div>
</CardFooter>
</Card>
<Reveal delay={0.2} direction="left" className="flex flex-col">
<Card className="flex-1 h-full">
<CardHeader className="items-center pb-0">
<CardTitle>Detection Distribution</CardTitle>
<CardDescription>Breakdown of all detected road conditions</CardDescription>
</CardHeader>
<CardContent className="flex-1 pb-0">
<DetectionDonutChart
defectedSignboard={stats.totalDefectedSignboard}
pothole={stats.totalPothole}
roadCrack={stats.totalRoadCrack}
damagedRoadMarking={stats.totalDamagedRoadMarking}
goodSignboard={stats.totalGoodSignboard}
/>
</CardContent>
<CardFooter className="flex-col gap-2 text-sm">
<div className="leading-none text-muted-foreground">
Total detections: {stats.totalRoadDamage + stats.totalGoodSignboard}
</div>
</CardFooter>
</Card>
</Reveal>
{/* Right Chart - Detections by Location */}
<Card className="flex flex-col">
<CardHeader className="items-center pb-0">
<CardTitle>Detections by Location</CardTitle>
<CardDescription>Frequency of road issues across different map segments</CardDescription>
</CardHeader>
<CardContent className="flex-1 pb-0">
<LocationBarChart
data={stats.locationData.map((loc) => ({
name: loc.name,
defected_sign_board: loc.defected_sign_board,
pothole: loc.pothole,
road_crack: loc.road_crack,
damaged_road_marking: loc.damaged_road_marking,
total: loc.total,
}))}
/>
</CardContent>
<CardFooter className="flex-col gap-2 text-sm">
<div className="leading-none text-muted-foreground">
Analysis based on latest processed sequence
</div>
</CardFooter>
</Card>
<Reveal delay={0.3} direction="right" className="flex flex-col">
<Card className="flex-1 h-full">
<CardHeader className="items-center pb-0">
<CardTitle>Detections by Location</CardTitle>
<CardDescription>Frequency of road issues across different map segments</CardDescription>
</CardHeader>
<CardContent className="flex-1 pb-0">
<LocationBarChart
data={stats.locationData.map((loc) => ({
name: loc.name,
defected_sign_board: loc.defected_sign_board,
pothole: loc.pothole,
road_crack: loc.road_crack,
damaged_road_marking: loc.damaged_road_marking,
total: loc.total,
}))}
/>
</CardContent>
<CardFooter className="flex-col gap-2 text-sm">
<div className="leading-none text-muted-foreground">
Analysis based on latest processed sequence
</div>
</CardFooter>
</Card>
</Reveal>
</div>
{/* Map - Full Width Below Charts */}
<div>
<DashboardMap
selectedProjectId={selectedProjectId}
selectedPackageId={selectedPackageId}
selectedLocationId={selectedLocationId}
projectSummary={projectSummary}
/>
</div>
<Reveal delay={0.4} direction="up">
<div>
<DashboardMap
selectedProjectId={selectedProjectId}
selectedPackageId={selectedPackageId}
selectedLocationId={selectedLocationId}
projectSummary={projectSummary}
/>
</div>
</Reveal>
</>
)}