MIF_E31221222/sigap-website/app/_components/map/controls/map-sidebar.tsx

311 lines
14 KiB
TypeScript

"use client"
import { Button } from "@/app/_components/ui/button"
import { ChevronLeft, Filter, Map, BarChart3, Info } from "lucide-react"
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/app/_components/ui/tabs"
import { ScrollArea } from "@/app/_components/ui/scroll-area"
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/app/_components/ui/card"
import { Separator } from "@/app/_components/ui/separator"
interface MapSidebarProps {
isOpen: boolean
onToggle: () => void
crimes?: Array<{
id: string
district_name: string
distrcit_id?: string
number_of_crime?: number
level?: "low" | "medium" | "high" | "critical"
incidents: any[]
}>
selectedYear?: number | string
selectedMonth?: number | string
}
export default function MapSidebar({ isOpen, onToggle, crimes = [], selectedYear, selectedMonth }: MapSidebarProps) {
// Calculate some statistics for the sidebar
const totalIncidents = crimes.reduce((total, district) => total + (district.number_of_crime || 0), 0)
const highRiskDistricts = crimes.filter(
(district) => district.level === "high" || district.level === "critical",
).length
const districtCount = crimes.length
return (
<div
className={`absolute top-0 left-0 h-full bg-white dark:bg-gray-900 shadow-lg z-20 transition-all duration-300 ease-in-out ${
isOpen ? "w-80" : "w-0"
} overflow-hidden`}
>
<div className="flex flex-col h-full">
<div className="flex items-center justify-between p-4 border-b">
<h2 className="font-semibold text-lg">Crime Map Explorer</h2>
<Button variant="ghost" size="icon" onClick={onToggle}>
<ChevronLeft className="h-5 w-5" />
<span className="sr-only">Close sidebar</span>
</Button>
</div>
<Tabs defaultValue="overview" className="flex-1 flex flex-col">
<TabsList className="grid grid-cols-4 mx-2 mt-2">
<TabsTrigger value="overview">
<Map className="h-4 w-4 mr-1" />
<span className="sr-only sm:not-sr-only sm:inline-block">Overview</span>
</TabsTrigger>
<TabsTrigger value="filters">
<Filter className="h-4 w-4 mr-1" />
<span className="sr-only sm:not-sr-only sm:inline-block">Filters</span>
</TabsTrigger>
<TabsTrigger value="stats">
<BarChart3 className="h-4 w-4 mr-1" />
<span className="sr-only sm:not-sr-only sm:inline-block">Stats</span>
</TabsTrigger>
<TabsTrigger value="info">
<Info className="h-4 w-4 mr-1" />
<span className="sr-only sm:not-sr-only sm:inline-block">Info</span>
</TabsTrigger>
</TabsList>
<ScrollArea className="flex-1 p-4">
<TabsContent value="overview" className="mt-0 space-y-4">
<Card>
<CardHeader className="pb-2">
<CardTitle>Crime Summary</CardTitle>
<CardDescription>
{selectedYear}
{selectedMonth !== "all" ? ` - Month ${selectedMonth}` : ""}
</CardDescription>
</CardHeader>
<CardContent>
<div className="grid grid-cols-2 gap-4">
<div className="flex flex-col">
<span className="text-sm text-muted-foreground">Total Incidents</span>
<span className="text-2xl font-bold">{totalIncidents}</span>
</div>
<div className="flex flex-col">
<span className="text-sm text-muted-foreground">High Risk Areas</span>
<span className="text-2xl font-bold">{highRiskDistricts}</span>
</div>
<div className="flex flex-col">
<span className="text-sm text-muted-foreground">Districts</span>
<span className="text-2xl font-bold">{districtCount}</span>
</div>
<div className="flex flex-col">
<span className="text-sm text-muted-foreground">Data Points</span>
<span className="text-2xl font-bold">
{crimes.reduce((total, district) => total + district.incidents.length, 0)}
</span>
</div>
</div>
</CardContent>
</Card>
<Card>
<CardHeader className="pb-2">
<CardTitle>District Overview</CardTitle>
</CardHeader>
<CardContent className="p-0">
<div className="max-h-64 overflow-y-auto">
<table className="w-full">
<thead className="sticky top-0 bg-white dark:bg-gray-900">
<tr className="border-b">
<th className="text-left p-2 text-sm">District</th>
<th className="text-right p-2 text-sm">Incidents</th>
<th className="text-right p-2 text-sm">Level</th>
</tr>
</thead>
<tbody>
{crimes
.sort((a, b) => (b.number_of_crime || 0) - (a.number_of_crime || 0))
.map((district) => (
<tr key={district.id} className="border-b hover:bg-muted/50">
<td className="p-2 text-sm">{district.district_name}</td>
<td className="text-right p-2 text-sm">{district.number_of_crime || 0}</td>
<td className="text-right p-2 text-sm">
<span
className={`inline-block px-2 py-0.5 rounded-full text-xs ${
district.level === "low"
? "bg-green-100 text-green-800"
: district.level === "medium"
? "bg-yellow-100 text-yellow-800"
: district.level === "high"
? "bg-orange-100 text-orange-800"
: district.level === "critical"
? "bg-red-100 text-red-800"
: "bg-gray-100 text-gray-800"
}`}
>
{district.level || "N/A"}
</span>
</td>
</tr>
))}
</tbody>
</table>
</div>
</CardContent>
</Card>
</TabsContent>
<TabsContent value="filters" className="mt-0 space-y-4">
<Card>
<CardHeader>
<CardTitle>Filter Options</CardTitle>
<CardDescription>Customize what you see on the map</CardDescription>
</CardHeader>
<CardContent className="space-y-4">
<div className="space-y-2">
<h3 className="text-sm font-medium">Crime Types</h3>
<div className="grid grid-cols-2 gap-2">
<Button variant="outline" size="sm" className="justify-start">
<input type="checkbox" className="mr-2" />
Theft
</Button>
<Button variant="outline" size="sm" className="justify-start">
<input type="checkbox" className="mr-2" />
Violence
</Button>
<Button variant="outline" size="sm" className="justify-start">
<input type="checkbox" className="mr-2" />
Vandalism
</Button>
<Button variant="outline" size="sm" className="justify-start">
<input type="checkbox" className="mr-2" />
Traffic
</Button>
</div>
</div>
<Separator />
<div className="space-y-2">
<h3 className="text-sm font-medium">Severity Levels</h3>
<div className="grid grid-cols-2 gap-2">
<Button variant="outline" size="sm" className="justify-start">
<input type="checkbox" className="mr-2" />
Low
</Button>
<Button variant="outline" size="sm" className="justify-start">
<input type="checkbox" className="mr-2" />
Medium
</Button>
<Button variant="outline" size="sm" className="justify-start">
<input type="checkbox" className="mr-2" />
High
</Button>
<Button variant="outline" size="sm" className="justify-start">
<input type="checkbox" className="mr-2" />
Critical
</Button>
</div>
</div>
<Separator />
<div className="space-y-2">
<h3 className="text-sm font-medium">Display Options</h3>
<div className="grid grid-cols-1 gap-2">
<Button variant="outline" size="sm" className="justify-start">
<input type="checkbox" className="mr-2" />
Show District Labels
</Button>
<Button variant="outline" size="sm" className="justify-start">
<input type="checkbox" className="mr-2" />
Show Incident Markers
</Button>
<Button variant="outline" size="sm" className="justify-start">
<input type="checkbox" className="mr-2" />
Show Heatmap
</Button>
</div>
</div>
</CardContent>
</Card>
</TabsContent>
<TabsContent value="stats" className="mt-0 space-y-4">
<Card>
<CardHeader>
<CardTitle>Crime Statistics</CardTitle>
<CardDescription>Analysis of crime data</CardDescription>
</CardHeader>
<CardContent>
<div className="space-y-4">
<div>
<h3 className="text-sm font-medium mb-2">Crime by Type</h3>
<div className="h-40 bg-muted rounded-md flex items-center justify-center">
<span className="text-sm text-muted-foreground">Chart Placeholder</span>
</div>
</div>
<Separator />
<div>
<h3 className="text-sm font-medium mb-2">Crime by Time of Day</h3>
<div className="h-40 bg-muted rounded-md flex items-center justify-center">
<span className="text-sm text-muted-foreground">Chart Placeholder</span>
</div>
</div>
<Separator />
<div>
<h3 className="text-sm font-medium mb-2">Monthly Trend</h3>
<div className="h-40 bg-muted rounded-md flex items-center justify-center">
<span className="text-sm text-muted-foreground">Chart Placeholder</span>
</div>
</div>
</div>
</CardContent>
</Card>
</TabsContent>
<TabsContent value="info" className="mt-0 space-y-4">
<Card>
<CardHeader>
<CardTitle>About This Map</CardTitle>
</CardHeader>
<CardContent>
<p className="text-sm text-muted-foreground mb-4">
This interactive crime map visualizes crime data across different districts. Use the controls to
explore different aspects of the data.
</p>
<h3 className="text-sm font-medium mb-2">Legend</h3>
<div className="space-y-2 mb-4">
<div className="flex items-center">
<div className="w-4 h-4 bg-green-500 rounded-sm mr-2"></div>
<span className="text-sm">Low Crime Rate</span>
</div>
<div className="flex items-center">
<div className="w-4 h-4 bg-yellow-500 rounded-sm mr-2"></div>
<span className="text-sm">Medium Crime Rate</span>
</div>
<div className="flex items-center">
<div className="w-4 h-4 bg-orange-500 rounded-sm mr-2"></div>
<span className="text-sm">High Crime Rate</span>
</div>
<div className="flex items-center">
<div className="w-4 h-4 bg-red-500 rounded-sm mr-2"></div>
<span className="text-sm">Critical Crime Rate</span>
</div>
</div>
<h3 className="text-sm font-medium mb-2">Data Sources</h3>
<p className="text-sm text-muted-foreground mb-4">
Crime data is collected from official police reports and updated monthly. District boundaries are
based on administrative regions.
</p>
<h3 className="text-sm font-medium mb-2">Help & Support</h3>
<p className="text-sm text-muted-foreground">
For questions or support regarding this map, please contact the system administrator.
</p>
</CardContent>
</Card>
</TabsContent>
</ScrollArea>
</Tabs>
</div>
</div>
)
}