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

235 lines
11 KiB
TypeScript

"use client"
import React, { useState } from "react"
import { AlertTriangle, BarChart, ChevronRight, MapPin, Skull, Shield, FileText } from "lucide-react"
import { Separator } from "@/app/_components/ui/separator"
import { Card, CardContent, CardHeader, CardTitle } from "@/app/_components/ui/card"
import { cn } from "@/app/_lib/utils"
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/app/_components/ui/tabs"
interface CrimeSidebarProps {
className?: string
defaultCollapsed?: boolean
}
export default function CrimeSidebar({ className, defaultCollapsed = true }: CrimeSidebarProps) {
const [isCollapsed, setIsCollapsed] = useState(defaultCollapsed)
const [activeTab, setActiveTab] = useState("incidents")
return (
<div className={cn(
"absolute top-0 left-0 h-full z-10 transition-all duration-300 ease-in-out bg-background backdrop-blur-sm border-r border-white/10 ",
isCollapsed ? "translate-x-[-100%]" : "translate-x-0",
className
)}>
<div className="relative h-full flex items-stretch">
{/* Main Sidebar Content */}
<div className="bg-background backdrop-blur-sm border-r border-white/10 h-full w-[320px]">
<div className="p-4 text-white h-full flex flex-col">
<CardHeader className="p-0 pb-2">
<CardTitle className="text-xl font-semibold flex items-center gap-2">
<AlertTriangle className="h-5 w-5" />
Crime Analysis
</CardTitle>
</CardHeader>
<Tabs defaultValue="incidents" className="w-full" value={activeTab} onValueChange={setActiveTab}>
<TabsList className="w-full mb-2 bg-black/30">
<TabsTrigger value="incidents" className="flex-1">Incidents</TabsTrigger>
<TabsTrigger value="statistics" className="flex-1">Statistics</TabsTrigger>
<TabsTrigger value="reports" className="flex-1">Reports</TabsTrigger>
</TabsList>
<div className="flex-1 overflow-y-auto overflow-x-hidden pr-1 max-h-[calc(100vh-10rem)]">
<TabsContent value="incidents" className="m-0 p-0">
<SidebarSection title="Recent Incidents" icon={<AlertTriangle className="h-4 w-4 text-red-400" />}>
<div className="space-y-2">
{[1, 2, 3, 4, 5, 6].map((i) => (
<IncidentCard key={i} />
))}
</div>
</SidebarSection>
</TabsContent>
<TabsContent value="statistics" className="m-0 p-0">
<SidebarSection title="Crime Overview" icon={<BarChart className="h-4 w-4 text-blue-400" />}>
<div className="space-y-2">
<StatCard title="Total Incidents" value="254" change="+12%" />
<StatCard title="Hot Zones" value="6" change="+2" />
<StatCard title="Case Clearance" value="68%" change="+5%" isPositive />
</div>
</SidebarSection>
<Separator className="bg-white/20 my-4" />
<SidebarSection title="Most Reported" icon={<Skull className="h-4 w-4 text-amber-400" />}>
<div className="space-y-2">
<CrimeTypeCard type="Theft" count={42} percentage={23} />
<CrimeTypeCard type="Assault" count={28} percentage={15} />
<CrimeTypeCard type="Vandalism" count={19} percentage={10} />
<CrimeTypeCard type="Burglary" count={15} percentage={8} />
</div>
</SidebarSection>
</TabsContent>
<TabsContent value="reports" className="m-0 p-0">
<SidebarSection title="Recent Reports" icon={<FileText className="h-4 w-4 text-indigo-400" />}>
<div className="space-y-2">
<ReportCard
title="Monthly Crime Summary"
date="June 15, 2024"
author="Dept. Analysis Team"
/>
<ReportCard
title="High Risk Areas Analysis"
date="June 12, 2024"
author="Regional Coordinator"
/>
<ReportCard
title="Case Resolution Statistics"
date="June 10, 2024"
author="Investigation Unit"
/>
<ReportCard
title="Quarterly Report Q2 2024"
date="June 1, 2024"
author="Crime Analysis Department"
/>
</div>
</SidebarSection>
</TabsContent>
</div>
</Tabs>
</div>
</div>
{/* Toggle Button - always visible and positioned correctly */}
<button
onClick={() => setIsCollapsed(!isCollapsed)}
className={cn(
"absolute h-12 w-8 bg-background backdrop-blur-sm border-t border-b border-r border-white/10 flex items-center justify-center",
"top-1/2 -translate-y-1/2 transition-all duration-300 ease-in-out",
isCollapsed ? "-right-8 rounded-r-md" : "left-[320px] rounded-r-md",
)}
aria-label={isCollapsed ? "Expand sidebar" : "Collapse sidebar"}
>
<ChevronRight
className={cn("h-5 w-5 text-white/80 transition-transform",
!isCollapsed && "rotate-180")}
/>
</button>
</div>
</div>
)
}
// Helper components for sidebar content
interface SidebarSectionProps {
title: string
children: React.ReactNode
icon?: React.ReactNode
}
function SidebarSection({ title, children, icon }: SidebarSectionProps) {
return (
<div>
<h3 className="text-sm font-medium text-white/80 mb-2 flex items-center gap-1.5">
{icon}
{title}
</h3>
{children}
</div>
)
}
function IncidentCard() {
return (
<Card className="bg-white/10 border-0 text-white shadow-none">
<CardContent className="p-3 text-xs">
<div className="flex items-start gap-2">
<AlertTriangle className="h-4 w-4 text-red-400 shrink-0 mt-0.5" />
<div>
<p className="font-medium">Theft reported at Jalan Srikandi</p>
<div className="flex items-center gap-2 mt-1 text-white/60">
<MapPin className="h-3 w-3" />
<span>Jombang District</span>
</div>
<div className="mt-1 text-white/60">3 hours ago</div>
</div>
</div>
</CardContent>
</Card>
)
}
interface StatCardProps {
title: string
value: string
change: string
isPositive?: boolean
}
function StatCard({ title, value, change, isPositive = false }: StatCardProps) {
return (
<Card className="bg-white/10 border-0 text-white shadow-none">
<CardContent className="p-3">
<div className="flex justify-between items-center">
<span className="text-xs text-white/70">{title}</span>
<span className={`text-xs ${isPositive ? "text-green-400" : "text-red-400"}`}>{change}</span>
</div>
<div className="text-xl font-bold mt-1">{value}</div>
</CardContent>
</Card>
)
}
interface CrimeTypeCardProps {
type: string
count: number
percentage: number
}
function CrimeTypeCard({ type, count, percentage }: CrimeTypeCardProps) {
return (
<Card className="bg-white/10 border-0 text-white shadow-none">
<CardContent className="p-3">
<div className="flex justify-between items-center">
<span className="font-medium">{type}</span>
<span className="text-sm text-white/70">{count} cases</span>
</div>
<div className="mt-2 h-1.5 bg-white/20 rounded-full overflow-hidden">
<div className="bg-blue-500 h-full rounded-full" style={{ width: `${percentage}%` }}></div>
</div>
<div className="mt-1 text-xs text-white/70 text-right">{percentage}%</div>
</CardContent>
</Card>
)
}
interface ReportCardProps {
title: string
date: string
author: string
}
function ReportCard({ title, date, author }: ReportCardProps) {
return (
<Card className="bg-white/10 border-0 text-white shadow-none">
<CardContent className="p-3 text-xs">
<div className="flex items-start gap-2">
<FileText className="h-4 w-4 text-indigo-400 shrink-0 mt-0.5" />
<div>
<p className="font-medium">{title}</p>
<div className="flex items-center gap-2 mt-1 text-white/60">
<Shield className="h-3 w-3" />
<span>{author}</span>
</div>
<div className="mt-1 text-white/60">{date}</div>
</div>
</div>
</CardContent>
</Card>
)
}