MIF_E31221222/sigap-website/app/_components/map/sidebar/tabs/statistics-tab.tsx

146 lines
7.1 KiB
TypeScript

import React from 'react'
import { Activity, Calendar, CheckCircle, AlertTriangle, LineChart, PieChart, FileText } from 'lucide-react'
import { Card, CardContent, CardHeader, CardTitle, CardDescription } from "@/app/_components/ui/card"
import { Separator } from "@/app/_components/ui/separator"
import { cn } from "@/app/_lib/utils"
import { getMonthName } from "@/app/_utils/common"
import { SidebarSection } from "../components/sidebar-section"
import { StatCard } from "../components/stat-card"
import { CrimeTypeCard } from "../components/crime-type-card"
interface SidebarStatisticsTabProps {
crimeStats: any
selectedMonth?: number | "all"
selectedYear: number
}
export function SidebarStatisticsTab({
crimeStats,
selectedMonth = "all",
selectedYear
}: SidebarStatisticsTabProps) {
const topCategories = crimeStats.categoryCounts ?
Object.entries(crimeStats.categoryCounts)
.sort((a: any, b: any) => (b[1] as number) - (a[1] as number))
.slice(0, 4)
.map(([type, count]: [string, unknown]) => {
const countAsNumber = count as number;
const percentage = Math.round(((countAsNumber) / crimeStats.totalIncidents) * 100) || 0
return { type, count: countAsNumber, percentage }
}) : []
return (
<>
<Card className="bg-gradient-to-r from-sidebar-primary/30 to-sidebar-primary/20 border border-sidebar-primary/20 overflow-hidden">
<CardHeader className="p-3 pb-0">
<CardTitle className="text-sm font-medium flex items-center gap-2">
<LineChart className="h-4 w-4 text-green-400" />
Monthly Incidents
</CardTitle>
<CardDescription className="text-xs text-white/60">{selectedYear}</CardDescription>
</CardHeader>
<CardContent className="p-3">
<div className="h-32 flex items-end gap-1 mt-2">
{crimeStats.incidentsByMonth.map((count: number, i: number) => {
const maxCount = Math.max(...crimeStats.incidentsByMonth)
const height = maxCount > 0 ? (count / maxCount) * 100 : 0
return (
<div
key={i}
className={cn(
"bg-gradient-to-t from-emerald-600 to-green-400 w-full rounded-t-md",
selectedMonth !== 'all' && i + 1 === Number(selectedMonth) ? "from-amber-500 to-amber-400" : ""
)}
style={{
height: `${Math.max(5, height)}%`,
opacity: 0.7 + (i / 24)
}}
title={`${getMonthName(i + 1)}: ${count} incidents`}
/>
)
})}
</div>
<div className="flex justify-between mt-2 text-[10px] text-white/60">
<span>Jan</span>
<span>Feb</span>
<span>Mar</span>
<span>Apr</span>
<span>May</span>
<span>Jun</span>
<span>Jul</span>
<span>Aug</span>
<span>Sep</span>
<span>Oct</span>
<span>Nov</span>
<span>Dec</span>
</div>
</CardContent>
</Card>
<SidebarSection title="Crime Overview" icon={<Activity className="h-4 w-4 text-blue-400" />}>
<div className="space-y-3">
<StatCard
title="Total Incidents"
value={crimeStats.totalIncidents.toString()}
change={`${Object.keys(crimeStats.districts).length} districts`}
icon={<AlertTriangle className="h-4 w-4 text-blue-400" />}
bgColor="bg-gradient-to-r from-blue-900/30 to-blue-800/20"
/>
<StatCard
title={selectedMonth !== 'all' ?
`${getMonthName(Number(selectedMonth))} Cases` :
"Monthly Average"}
value={selectedMonth !== 'all' ?
crimeStats.totalIncidents.toString() :
Math.round(crimeStats.totalIncidents /
(crimeStats.incidentsByMonth.filter((c: number) => c > 0).length || 1)
).toString()}
change={selectedMonth !== 'all' ?
`in ${getMonthName(Number(selectedMonth))}` :
"per active month"}
isPositive={false}
icon={<Calendar className="h-4 w-4 text-amber-400" />}
bgColor="bg-gradient-to-r from-amber-900/30 to-amber-800/20"
/>
<StatCard
title="Clearance Rate"
value={`${crimeStats.clearanceRate}%`}
change="of cases resolved"
isPositive={crimeStats.clearanceRate > 50}
icon={<CheckCircle className="h-4 w-4 text-green-400" />}
bgColor="bg-gradient-to-r from-green-900/30 to-green-800/20"
/>
</div>
</SidebarSection>
<Separator className="bg-white/20 my-4" />
<SidebarSection title="Most Common Crimes" icon={<PieChart className="h-4 w-4 text-amber-400" />}>
<div className="space-y-3">
{topCategories.length > 0 ? (
topCategories.map((category: any) => (
<CrimeTypeCard
key={category.type}
type={category.type}
count={category.count}
percentage={category.percentage}
/>
))
) : (
<Card className="bg-white/5 border-0 text-white shadow-none">
<CardContent className="p-4 text-center">
<div className="flex flex-col items-center gap-2">
<FileText className="h-6 w-6 text-white/40" />
<p className="text-sm text-white/70">No crime data available</p>
<p className="text-xs text-white/50">Try selecting a different time period</p>
</div>
</CardContent>
</Card>
)}
</div>
</SidebarSection>
</>
)
}