diff --git a/sigap-website/app/_components/map/controls/map-sidebar.tsx b/sigap-website/app/_components/map/controls/map-sidebar.tsx
new file mode 100644
index 0000000..14c95e1
--- /dev/null
+++ b/sigap-website/app/_components/map/controls/map-sidebar.tsx
@@ -0,0 +1,310 @@
+"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 (
+
+
+
+
Crime Map Explorer
+
+
+ Close sidebar
+
+
+
+
+
+
+
+ Overview
+
+
+
+ Filters
+
+
+
+ Stats
+
+
+
+ Info
+
+
+
+
+
+
+
+ Crime Summary
+
+ {selectedYear}
+ {selectedMonth !== "all" ? ` - Month ${selectedMonth}` : ""}
+
+
+
+
+
+ Total Incidents
+ {totalIncidents}
+
+
+ High Risk Areas
+ {highRiskDistricts}
+
+
+ Districts
+ {districtCount}
+
+
+ Data Points
+
+ {crimes.reduce((total, district) => total + district.incidents.length, 0)}
+
+
+
+
+
+
+
+
+ District Overview
+
+
+
+
+
+
+ District
+ Incidents
+ Level
+
+
+
+ {crimes
+ .sort((a, b) => (b.number_of_crime || 0) - (a.number_of_crime || 0))
+ .map((district) => (
+
+ {district.district_name}
+ {district.number_of_crime || 0}
+
+
+ {district.level || "N/A"}
+
+
+
+ ))}
+
+
+
+
+
+
+
+
+
+
+ Filter Options
+ Customize what you see on the map
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Crime Statistics
+ Analysis of crime data
+
+
+
+
+
Crime by Type
+
+ Chart Placeholder
+
+
+
+
+
+
+
Crime by Time of Day
+
+ Chart Placeholder
+
+
+
+
+
+
+
Monthly Trend
+
+ Chart Placeholder
+
+
+
+
+
+
+
+
+
+
+ About This Map
+
+
+
+ This interactive crime map visualizes crime data across different districts. Use the controls to
+ explore different aspects of the data.
+
+
+ Legend
+
+
+
+
+
+
+
Critical Crime Rate
+
+
+
+ Data Sources
+
+ Crime data is collected from official police reports and updated monthly. District boundaries are
+ based on administrative regions.
+
+
+ Help & Support
+
+ For questions or support regarding this map, please contact the system administrator.
+
+
+
+
+
+
+
+
+ )
+}
diff --git a/sigap-website/app/_components/map/controls/map-toggle.tsx b/sigap-website/app/_components/map/controls/map-toggle.tsx
new file mode 100644
index 0000000..145e63a
--- /dev/null
+++ b/sigap-website/app/_components/map/controls/map-toggle.tsx
@@ -0,0 +1,25 @@
+"use client"
+
+import { Button } from "@/app/_components/ui/button"
+import { Menu } from "lucide-react"
+
+interface SidebarToggleProps {
+ isOpen: boolean
+ onToggle: () => void
+}
+
+export default function SidebarToggle({ isOpen, onToggle }: SidebarToggleProps) {
+ if (isOpen) return null
+
+ return (
+
+
+ Open sidebar
+
+ )
+}
diff --git a/sigap-website/app/_components/map/controls/severity-indicator.tsx b/sigap-website/app/_components/map/controls/severity-indicator.tsx
new file mode 100644
index 0000000..e31253e
--- /dev/null
+++ b/sigap-website/app/_components/map/controls/severity-indicator.tsx
@@ -0,0 +1,15 @@
+"use client"
+
+export default function SeverityIndicator() {
+ return (
+
+
+
+ Low
+ Medium
+ High
+
+
+
+ )
+}
diff --git a/sigap-website/app/_components/map/controls/time-control.tsx b/sigap-website/app/_components/map/controls/time-control.tsx
new file mode 100644
index 0000000..f36052a
--- /dev/null
+++ b/sigap-website/app/_components/map/controls/time-control.tsx
@@ -0,0 +1,31 @@
+"use client"
+import { Checkbox } from "@/app/_components/ui/checkbox"
+import { Label } from "@/app/_components/ui/label"
+
+interface TimeControlsProps {
+ onTimeChange: (time: string) => void
+ activeTime: string
+}
+
+export default function TimeControls({ onTimeChange, activeTime }: TimeControlsProps) {
+ const times = [
+ { id: "today", label: "Hari ini" },
+ { id: "yesterday", label: "Kemarin" },
+ { id: "week", label: "Minggu" },
+ { id: "month", label: "Bulan" },
+ ]
+
+ return (
+
+
Waktu
+ {times.map((time) => (
+
+ onTimeChange(time.id)} />
+
+ {time.label}
+
+
+ ))}
+
+ )
+}
diff --git a/sigap-website/app/_components/map/crime-map.tsx b/sigap-website/app/_components/map/crime-map.tsx
index c2a66ed..00ab63d 100644
--- a/sigap-website/app/_components/map/crime-map.tsx
+++ b/sigap-website/app/_components/map/crime-map.tsx
@@ -14,6 +14,7 @@ import { useState } from "react"
import { CrimePopup } from "./pop-up"
import CrimeMarker, { type CrimeIncident } from "./markers/crime-marker"
import { MapLegend } from "./controls/map-legend"
+import MapFilterControl from "./controls/map-filter-control"
const months = [
{ value: "1", label: "January" },
@@ -36,6 +37,7 @@ export default function CrimeMap() {
const [selectedMonth, setSelectedMonth] = useState
("all")
const [selectedDistrict, setSelectedDistrict] = useState(null)
const [selectedIncident, setSelectedIncident] = useState(null)
+ const [showLegend, setShowLegend] = useState(true)
const { availableYears, yearsLoading, yearsError, crimes, crimesLoading, crimesError, refetchCrimes } =
useCrimeMapHandler(selectedYear, selectedMonth)
@@ -83,26 +85,40 @@ export default function CrimeMap() {
let title = `${selectedYear}`
if (selectedMonth !== "all") {
title += ` - ${getMonthName(Number(selectedMonth))}`
- }
+ }
return title
}
+ // Create map filter controls - now MapView will only render these in fullscreen mode
+ const mapFilterControls = (
+
+ )
+
return (
Crime Map {getMapTitle()}
+ {/* Regular (non-fullscreen) controls */}
setSelectedYear(Number(value))}>
- {/* Removed "All Years" option */}
{!yearsLoading &&
availableYears
?.filter((year) => year !== null)
.map((year) => (
-
+
{year}
))}
@@ -133,6 +149,9 @@ export default function CrimeMap() {
Reset
+ setShowLegend(!showLegend)}>
+ {showLegend ? "Hide Legend" : "Show Legend"}
+
@@ -147,10 +166,17 @@ export default function CrimeMap() {
refetchCrimes()}>Retry
+ )}
- {/* District popup */}
- {selectedDistrict && selectedDistrict.longitude && selectedDistrict.latitude && (
-