diff --git a/sigap-website/app/_components/map/controls/time-control.tsx b/sigap-website/app/_components/map/controls/bottom-left/time-control.tsx
similarity index 97%
rename from sigap-website/app/_components/map/controls/time-control.tsx
rename to sigap-website/app/_components/map/controls/bottom-left/time-control.tsx
index 5dd0d11..69f317f 100644
--- a/sigap-website/app/_components/map/controls/time-control.tsx
+++ b/sigap-website/app/_components/map/controls/bottom-left/time-control.tsx
@@ -1,7 +1,7 @@
"use client"
import { Checkbox } from "@/app/_components/ui/checkbox"
import { Label } from "@/app/_components/ui/label"
-import { Overlay } from "../overlay"
+import { Overlay } from "../../overlay"
import { ControlPosition } from "mapbox-gl"
diff --git a/sigap-website/app/_components/map/controls/crime-timelapse.tsx b/sigap-website/app/_components/map/controls/bottom/crime-timelapse.tsx
similarity index 100%
rename from sigap-website/app/_components/map/controls/crime-timelapse.tsx
rename to sigap-website/app/_components/map/controls/bottom/crime-timelapse.tsx
diff --git a/sigap-website/app/_components/map/controls/time-slider.tsx b/sigap-website/app/_components/map/controls/bottom/time-slider.tsx
similarity index 100%
rename from sigap-website/app/_components/map/controls/time-slider.tsx
rename to sigap-website/app/_components/map/controls/bottom/time-slider.tsx
diff --git a/sigap-website/app/_components/map/controls/example.tsx b/sigap-website/app/_components/map/controls/example.tsx
deleted file mode 100644
index e8a268f..0000000
--- a/sigap-website/app/_components/map/controls/example.tsx
+++ /dev/null
@@ -1,66 +0,0 @@
-import { Map } from "mapbox-gl";
-
-/* Idea from Stack Overflow https://stackoverflow.com/a/51683226 */
-export class CustomControl {
- private _className: string;
- private _title: string;
- private _eventHandler: (event: MouseEvent) => void;
- private _btn!: HTMLButtonElement;
- private _container!: HTMLDivElement;
- private _map?: Map;
- private _root: any; // React root for rendering our component
-
- constructor({
- className = "",
- title = "",
- eventHandler = () => { }
- }: {
- className?: string;
- title?: string;
- eventHandler?: (event: MouseEvent) => void;
- }) {
- this._className = className;
- this._title = title;
- this._eventHandler = eventHandler;
- }
-
- onAdd(map: Map) {
- this._map = map;
- this._btn = document.createElement("button");
- this._btn.className = "mapboxgl-ctrl-icon" + " " + this._className;
- this._btn.type = "button";
- this._btn.title = this._title;
- this._btn.onclick = this._eventHandler;
-
- // Apply pointer-events: auto; style dynamically
- this._btn.style.pointerEvents = "auto";
-
- // Dynamically append the style to the auto-generated className
- const styleSheet = document.styleSheets[0];
- styleSheet.insertRule(
- `.${this._className} { pointer-events: auto; }`,
- styleSheet.cssRules.length
- );
-
- this._container = document.createElement("div");
- this._container.className = "mapboxgl-ctrl-group mapboxgl-ctrl";
- this._container.appendChild(this._btn);
-
- return this._container;
- }
-
- onRemove() {
- if (this._container && this._container.parentNode) {
- this._container.parentNode.removeChild(this._container);
- }
-
- // Defer unmounting React component to prevent race conditions
- if (this._root) {
- setTimeout(() => {
- this._root.unmount();
- });
- }
-
- this._map = undefined;
- }
-}
\ No newline at end of file
diff --git a/sigap-website/app/_components/map/sidebar/components/crime-type-card.tsx b/sigap-website/app/_components/map/controls/left/sidebar/components/crime-type-card.tsx
similarity index 100%
rename from sigap-website/app/_components/map/sidebar/components/crime-type-card.tsx
rename to sigap-website/app/_components/map/controls/left/sidebar/components/crime-type-card.tsx
diff --git a/sigap-website/app/_components/map/sidebar/components/incident-card.tsx b/sigap-website/app/_components/map/controls/left/sidebar/components/incident-card.tsx
similarity index 100%
rename from sigap-website/app/_components/map/sidebar/components/incident-card.tsx
rename to sigap-website/app/_components/map/controls/left/sidebar/components/incident-card.tsx
diff --git a/sigap-website/app/_components/map/sidebar/components/sidebar-section.tsx b/sigap-website/app/_components/map/controls/left/sidebar/components/sidebar-section.tsx
similarity index 100%
rename from sigap-website/app/_components/map/sidebar/components/sidebar-section.tsx
rename to sigap-website/app/_components/map/controls/left/sidebar/components/sidebar-section.tsx
diff --git a/sigap-website/app/_components/map/sidebar/components/stat-card.tsx b/sigap-website/app/_components/map/controls/left/sidebar/components/stat-card.tsx
similarity index 100%
rename from sigap-website/app/_components/map/sidebar/components/stat-card.tsx
rename to sigap-website/app/_components/map/controls/left/sidebar/components/stat-card.tsx
diff --git a/sigap-website/app/_components/map/sidebar/components/system-status-card.tsx b/sigap-website/app/_components/map/controls/left/sidebar/components/system-status-card.tsx
similarity index 100%
rename from sigap-website/app/_components/map/sidebar/components/system-status-card.tsx
rename to sigap-website/app/_components/map/controls/left/sidebar/components/system-status-card.tsx
diff --git a/sigap-website/app/_components/map/sidebar/map-sidebar.tsx b/sigap-website/app/_components/map/controls/left/sidebar/map-sidebar.tsx
similarity index 81%
rename from sigap-website/app/_components/map/sidebar/map-sidebar.tsx
rename to sigap-website/app/_components/map/controls/left/sidebar/map-sidebar.tsx
index 3c99293..d1981cb 100644
--- a/sigap-website/app/_components/map/sidebar/map-sidebar.tsx
+++ b/sigap-website/app/_components/map/controls/left/sidebar/map-sidebar.tsx
@@ -13,11 +13,11 @@ import { ICrimes } from "@/app/_utils/types/crimes"
// Import sidebar components
import { SidebarIncidentsTab } from "./tabs/incidents-tab"
-import { useCrimeAnalytics } from "../../../(pages)/(admin)/dashboard/crime-management/crime-overview/_hooks/use-crime-analytics"
-import { usePagination } from "../../../_hooks/use-pagination"
import { getMonthName } from "@/app/_utils/common"
import { SidebarInfoTab } from "./tabs/info-tab"
import { SidebarStatisticsTab } from "./tabs/statistics-tab"
+import { useCrimeAnalytics } from "@/app/(pages)/(admin)/dashboard/crime-management/crime-overview/_hooks/use-crime-analytics"
+import { usePagination } from "@/app/_hooks/use-pagination"
interface CrimeSidebarProps {
className?: string
@@ -211,35 +211,35 @@ export default function CrimeSidebar({
) : (
<>
-
-
-
+
+
+
-
-
-
+
+
+
-
-
-
+
+
+
>
)}
diff --git a/sigap-website/app/_components/map/sidebar/sidebar-toggle.tsx b/sigap-website/app/_components/map/controls/left/sidebar/sidebar-toggle.tsx
similarity index 95%
rename from sigap-website/app/_components/map/sidebar/sidebar-toggle.tsx
rename to sigap-website/app/_components/map/controls/left/sidebar/sidebar-toggle.tsx
index 297124b..e9216bc 100644
--- a/sigap-website/app/_components/map/sidebar/sidebar-toggle.tsx
+++ b/sigap-website/app/_components/map/controls/left/sidebar/sidebar-toggle.tsx
@@ -4,8 +4,9 @@ import React from "react"
import { Button } from "@/app/_components/ui/button"
import { cn } from "@/app/_lib/utils"
import { ChevronLeft, ChevronRight } from "lucide-react"
-import { Overlay } from "../overlay"
+
import type { ControlPosition } from "mapbox-gl"
+import { Overlay } from "../../../overlay"
interface SidebarToggleProps {
isCollapsed: boolean
diff --git a/sigap-website/app/_components/map/sidebar/tabs/incidents-tab.tsx b/sigap-website/app/_components/map/controls/left/sidebar/tabs/incidents-tab.tsx
similarity index 100%
rename from sigap-website/app/_components/map/sidebar/tabs/incidents-tab.tsx
rename to sigap-website/app/_components/map/controls/left/sidebar/tabs/incidents-tab.tsx
diff --git a/sigap-website/app/_components/map/sidebar/tabs/info-tab.tsx b/sigap-website/app/_components/map/controls/left/sidebar/tabs/info-tab.tsx
similarity index 100%
rename from sigap-website/app/_components/map/sidebar/tabs/info-tab.tsx
rename to sigap-website/app/_components/map/controls/left/sidebar/tabs/info-tab.tsx
diff --git a/sigap-website/app/_components/map/sidebar/tabs/statistics-tab.tsx b/sigap-website/app/_components/map/controls/left/sidebar/tabs/statistics-tab.tsx
similarity index 100%
rename from sigap-website/app/_components/map/sidebar/tabs/statistics-tab.tsx
rename to sigap-website/app/_components/map/controls/left/sidebar/tabs/statistics-tab.tsx
diff --git a/sigap-website/app/_components/map/controls/map-control.tsx b/sigap-website/app/_components/map/controls/map-control.tsx
deleted file mode 100644
index e69de29..0000000
diff --git a/sigap-website/app/_components/map/controls/map-filter-control.tsx b/sigap-website/app/_components/map/controls/map-filter-control.tsx
index b52904e..1ab9e49 100644
--- a/sigap-website/app/_components/map/controls/map-filter-control.tsx
+++ b/sigap-website/app/_components/map/controls/map-filter-control.tsx
@@ -1,107 +1,107 @@
-"use client"
+// "use client"
-import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/app/_components/ui/select"
-import { Button } from "@/app/_components/ui/button"
-import { FilterX } from "lucide-react"
-import { useCallback } from "react"
+// import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/app/_components/ui/select"
+// import { Button } from "@/app/_components/ui/button"
+// import { FilterX } from "lucide-react"
+// import { useCallback } from "react"
-interface MapFilterControlProps {
- selectedYear: number
- selectedMonth: number | "all"
- availableYears: (number | null)[]
- yearsLoading: boolean
- onYearChange: (year: number) => void
- onMonthChange: (month: number | "all") => void
- onApplyFilters: () => void
- onResetFilters: () => void
-}
+// interface MapFilterControlProps {
+// selectedYear: number
+// selectedMonth: number | "all"
+// availableYears: (number | null)[]
+// yearsLoading: boolean
+// onYearChange: (year: number) => void
+// onMonthChange: (month: number | "all") => void
+// onApplyFilters: () => void
+// onResetFilters: () => void
+// }
-const months = [
- { value: "1", label: "January" },
- { value: "2", label: "February" },
- { value: "3", label: "March" },
- { value: "4", label: "April" },
- { value: "5", label: "May" },
- { value: "6", label: "June" },
- { value: "7", label: "July" },
- { value: "8", label: "August" },
- { value: "9", label: "September" },
- { value: "10", label: "October" },
- { value: "11", label: "November" },
- { value: "12", label: "December" },
-]
+// const months = [
+// { value: "1", label: "January" },
+// { value: "2", label: "February" },
+// { value: "3", label: "March" },
+// { value: "4", label: "April" },
+// { value: "5", label: "May" },
+// { value: "6", label: "June" },
+// { value: "7", label: "July" },
+// { value: "8", label: "August" },
+// { value: "9", label: "September" },
+// { value: "10", label: "October" },
+// { value: "11", label: "November" },
+// { value: "12", label: "December" },
+// ]
-export default function MapFilterControl({
- selectedYear,
- selectedMonth,
- availableYears,
- yearsLoading,
- onYearChange,
- onMonthChange,
- onApplyFilters,
- onResetFilters,
-}: MapFilterControlProps) {
- const handleYearChange = useCallback(
- (value: string) => {
- onYearChange(Number(value))
- },
- [onYearChange],
- )
+// export default function MapFilterControl({
+// selectedYear,
+// selectedMonth,
+// availableYears,
+// yearsLoading,
+// onYearChange,
+// onMonthChange,
+// onApplyFilters,
+// onResetFilters,
+// }: MapFilterControlProps) {
+// const handleYearChange = useCallback(
+// (value: string) => {
+// onYearChange(Number(value))
+// },
+// [onYearChange],
+// )
- const handleMonthChange = useCallback(
- (value: string) => {
- onMonthChange(value === "all" ? "all" : Number(value))
- },
- [onMonthChange],
- )
+// const handleMonthChange = useCallback(
+// (value: string) => {
+// onMonthChange(value === "all" ? "all" : Number(value))
+// },
+// [onMonthChange],
+// )
- const isDefaultFilter = selectedYear === 2024 && selectedMonth === "all"
+// const isDefaultFilter = selectedYear === 2024 && selectedMonth === "all"
- return (
-
-
Map Filters
+// return (
+//
+//
Map Filters
-
-
+//
+//
-
+//
-
-
-
-
-
-
- )
-}
+//
+//
+//
+//
+//
+//
+// )
+// }
diff --git a/sigap-website/app/_components/map/controls/map-sidebar.tsx b/sigap-website/app/_components/map/controls/map-sidebar.tsx
deleted file mode 100644
index 053e1da..0000000
--- a/sigap-website/app/_components/map/controls/map-sidebar.tsx
+++ /dev/null
@@ -1,184 +0,0 @@
-"use client"
-import { ChevronLeft, ChevronRight, Cloud, Droplets, Wind } from "lucide-react"
-
-import { Button } from "@/app/_components/ui/button"
-import { Card, CardContent, CardHeader, CardTitle } from "@/app/_components/ui/card"
-import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/app/_components/ui/tabs"
-import { Collapsible, CollapsibleContent, CollapsibleTrigger } from "@/app/_components/ui/collapsible"
-import { cn } from "@/app/_lib/utils"
-
-interface MapSidebarProps {
- isOpen: boolean
- onToggle: () => void
- crimes?: Array<{
- id: string
- district_name: string
- district_id?: string
- number_of_crime?: number
- level?: "low" | "medium" | "high" | "critical"
- incidents: any[]
- }>
- selectedYear?: number | string
- selectedMonth?: number | string
- weatherData?: {
- temperature: number
- condition: string
- humidity: number
- windSpeed: number
- forecast: Array<{
- time: string
- temperature: number
- condition: string
- }>
- }
-}
-
-export default function MapSidebar({
- isOpen,
- onToggle,
- crimes = [],
- selectedYear,
- selectedMonth,
- weatherData = {
- temperature: 78,
- condition: "Mostly cloudy",
- humidity: 65,
- windSpeed: 8,
- forecast: [
- { time: "Now", temperature: 78, condition: "Cloudy" },
- { time: "9:00 PM", temperature: 75, condition: "Cloudy" },
- { time: "10:00 PM", temperature: 73, condition: "Cloudy" },
- { time: "11:00 PM", temperature: 72, condition: "Cloudy" },
- { time: "12:00 AM", temperature: 70, condition: "Cloudy" },
- ],
- },
-}: MapSidebarProps) {
- return (
-
-
-
Weather Information
-
-
-
-
-
-
- Current
- Forecast
-
-
-
-
-
-
- {weatherData.temperature}°F
- {weatherData.condition}
-
-
-
-
-
-
- Humidity: {weatherData.humidity}%
-
-
-
- Wind: {weatherData.windSpeed} mph
-
-
-
-
-
-
-
Today's Recommendations
-
-
-
-
-
-
🌂
-
Umbrella
-
No need
-
-
-
-
-
-
-
-
🏞️
-
Outdoors
-
Very poor
-
-
-
-
-
-
-
-
-
-
-
- {crimes.length > 0 ? (
- crimes.map((crime) => (
-
-
-
- {crime.district_name}
-
- {crime.number_of_crime}
-
-
-
-
- ))
- ) : (
- No crime data available
- )}
-
-
-
-
-
-
- {weatherData.forecast.map((item, index) => (
-
-
-
-
- {item.time}
-
-
- {item.condition}
- {item.temperature}°
-
-
-
- ))}
-
-
-
-
-
- )
-}
diff --git a/sigap-website/app/_components/map/controls/map-toggle.tsx b/sigap-website/app/_components/map/controls/map-toggle.tsx
deleted file mode 100644
index f1da82c..0000000
--- a/sigap-website/app/_components/map/controls/map-toggle.tsx
+++ /dev/null
@@ -1,40 +0,0 @@
-"use client"
-import { ChevronLeft, ChevronRight } from "lucide-react"
-import { Button } from "../../ui/button"
-import { cn } from "@/app/_lib/utils"
-import { Overlay } from "../overlay"
-
-interface SidebarToggleProps {
- isOpen: boolean
- onToggle: () => void
- position?: "left" | "right"
- className?: string
-}
-
-export default function SidebarToggle({ isOpen, onToggle, position = "left", className }: SidebarToggleProps) {
- return (
-
-
-
- )
-}
diff --git a/sigap-website/app/_components/map/controls/map-tooltips.tsx b/sigap-website/app/_components/map/controls/map-tooltips.tsx
deleted file mode 100644
index dabe928..0000000
--- a/sigap-website/app/_components/map/controls/map-tooltips.tsx
+++ /dev/null
@@ -1,35 +0,0 @@
-"use client"
-
-import { ReactNode } from "react"
-
-// Define the possible control IDs for the crime map
-export type ITopTooltipsMapId =
- // Crime data views
- | "incidents"
- | "heatmap"
- | "trends"
- | "patrol"
- | "reports"
- | "clusters"
- | "timeline"
-
- // Tools and features
- | "refresh"
- | "search"
- | "alerts"
- | "layers"
- | "evidence"
- | "arrests";
-
-// Map tools type definition
-export interface IMapTool {
- id: ITopTooltipsMapId;
- label: string;
- icon: ReactNode;
- description?: string;
-}
-
-// Default export for future expansion
-export default function MapTools() {
- return null;
-}
diff --git a/sigap-website/app/_components/map/controls/severity-indicator.tsx b/sigap-website/app/_components/map/controls/severity-indicator.tsx
deleted file mode 100644
index e31253e..0000000
--- a/sigap-website/app/_components/map/controls/severity-indicator.tsx
+++ /dev/null
@@ -1,15 +0,0 @@
-"use client"
-
-export default function SeverityIndicator() {
- return (
-
-
-
- Low
- Medium
- High
-
-
-
- )
-}
diff --git a/sigap-website/app/_components/map/controls/top/additional-tooltips.tsx b/sigap-website/app/_components/map/controls/top/additional-tooltips.tsx
new file mode 100644
index 0000000..abdcc9a
--- /dev/null
+++ b/sigap-website/app/_components/map/controls/top/additional-tooltips.tsx
@@ -0,0 +1,151 @@
+"use client"
+
+import { Button } from "@/app/_components/ui/button"
+import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "@/app/_components/ui/tooltip"
+import { Popover, PopoverContent, PopoverTrigger } from "@/app/_components/ui/popover"
+import { ChevronDown, Layers, Siren } from "lucide-react"
+import { IconMessage } from "@tabler/icons-react"
+
+import { useRef, useState } from "react"
+import { ITooltips } from "./tooltips"
+import MonthSelector from "../month-selector"
+import YearSelector from "../year-selector"
+import CategorySelector from "../category-selector"
+
+// Define the additional tools and features
+const additionalTooltips = [
+ { id: "reports" as ITooltips, icon: , label: "Police Report" },
+ { id: "layers" as ITooltips, icon: , label: "Map Layers" },
+ { id: "alerts" as ITooltips, icon: , label: "Active Alerts" },
+]
+
+interface AdditionalTooltipsProps {
+ activeControl?: string
+ onControlChange?: (controlId: ITooltips) => void
+ selectedYear: number
+ setSelectedYear: (year: number) => void
+ selectedMonth: number | "all"
+ setSelectedMonth: (month: number | "all") => void
+ selectedCategory: string | "all"
+ setSelectedCategory: (category: string | "all") => void
+ availableYears?: (number | null)[]
+ categories?: string[]
+}
+
+export default function AdditionalTooltips({
+ activeControl,
+ onControlChange,
+ selectedYear,
+ setSelectedYear,
+ selectedMonth,
+ setSelectedMonth,
+ selectedCategory,
+ setSelectedCategory,
+ availableYears = [2022, 2023, 2024],
+ categories = [],
+}: AdditionalTooltipsProps) {
+ const [showSelectors, setShowSelectors] = useState(false)
+ const containerRef = useRef(null)
+ const [isClient, setIsClient] = useState(false)
+
+ const container = isClient ? document.getElementById("root") : null
+
+ return (
+ <>
+
+
+ {additionalTooltips.map((control) => (
+
+
+
+
+
+ {control.label}
+
+
+ ))}
+
+
+
+
+
+
+
+
+
+ Year:
+
+
+
+ Month:
+
+
+
+ Category:
+
+
+
+
+
+
+
+
+
+ {showSelectors && (
+
+
+
+
+
+ )}
+ >
+ )
+}
diff --git a/sigap-website/app/_components/map/controls/top/crime-tooltips.tsx b/sigap-website/app/_components/map/controls/top/crime-tooltips.tsx
new file mode 100644
index 0000000..6279a37
--- /dev/null
+++ b/sigap-website/app/_components/map/controls/top/crime-tooltips.tsx
@@ -0,0 +1,52 @@
+"use client"
+
+import { Button } from "@/app/_components/ui/button"
+import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "@/app/_components/ui/tooltip"
+import { AlertTriangle, BarChart2, Clock, Map, Shield, Users } from "lucide-react"
+import { ITooltips } from "./tooltips"
+
+
+// Define the primary crime data controls
+const crimeTooltips = [
+ { id: "incidents" as ITooltips, icon: , label: "All Incidents" },
+ { id: "heatmap" as ITooltips, icon: , label: "Crime Heatmap" },
+ { id: "trends" as ITooltips, icon: , label: "Crime Trends" },
+ { id: "patrol" as ITooltips, icon: , label: "Patrol Areas" },
+ { id: "clusters" as ITooltips, icon: , label: "Clusters" },
+ { id: "timeline" as ITooltips, icon: , label: "Time Analysis" },
+]
+
+interface CrimeTooltipsProps {
+ activeControl?: string
+ onControlChange?: (controlId: ITooltips) => void
+}
+
+export default function CrimeTooltips({ activeControl, onControlChange }: CrimeTooltipsProps) {
+ return (
+
+
+ {crimeTooltips.map((control) => (
+
+
+
+
+
+ {control.label}
+
+
+ ))}
+
+
+ )
+}
diff --git a/sigap-website/app/_components/map/controls/top-controls.tsx b/sigap-website/app/_components/map/controls/top/search-control.tsx
similarity index 69%
rename from sigap-website/app/_components/map/controls/top-controls.tsx
rename to sigap-website/app/_components/map/controls/top/search-control.tsx
index e67af28..b4580b0 100644
--- a/sigap-website/app/_components/map/controls/top-controls.tsx
+++ b/sigap-website/app/_components/map/controls/top/search-control.tsx
@@ -1,38 +1,15 @@
"use client"
-import { useEffect, useRef, useState } from "react"
import { Button } from "@/app/_components/ui/button"
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "@/app/_components/ui/tooltip"
-import { Popover, PopoverContent, PopoverTrigger } from "@/app/_components/ui/popover"
-import { ChevronDown, MessageSquare, MapPin, Calendar, Info, ExternalLink } from "lucide-react"
-import YearSelector from "./year-selector"
-import MonthSelector from "./month-selector"
-import CategorySelector from "./category-selector"
-import ActionSearchBar from "@/app/_components/action-search-bar"
+import { Search, XCircle, Info, ExternalLink, Calendar, MapPin, MessageSquare, FileText, Map, FolderOpen } from 'lucide-react'
+
+import { useEffect, useRef, useState } from "react"
import { AnimatePresence, motion } from "framer-motion"
-import {
- AlertTriangle,
- Shield,
- FileText,
- Users,
- Map,
- BarChart2,
- Clock,
- Filter,
- Search,
- RefreshCw,
- Layers,
- Siren,
- BadgeAlert,
- FolderOpen,
- XCircle,
-} from "lucide-react"
-import { ITopTooltipsMapId } from "./map-tooltips"
-import { IconAnalyze, IconMessage } from "@tabler/icons-react"
-import { FloatingActionSearchBar } from "../../floating-action-search-bar"
-import { format } from 'date-fns'
+import ActionSearchBar from "@/app/_components/action-search-bar"
import { Card } from "@/app/_components/ui/card"
-import { ICrimes } from "@/app/_utils/types/crimes"
+import { format } from 'date-fns'
+import { ITooltips } from "./tooltips"
// Expanded sample crime data with more entries for testing
const SAMPLE_CRIME_DATA = [
@@ -46,8 +23,6 @@ const SAMPLE_CRIME_DATA = [
{ id: "CR-34517-2024", description: "Mugging at Central Station" },
{ id: "CR-14517-2024", description: "Shoplifting at Mall" },
{ id: "CR-24517-2024", description: "Break-in at Office Building" },
- // Add more entries for testing (up to 100)
- // ...more sample entries...
];
// Generate additional sample data for testing scrolling
@@ -140,52 +115,13 @@ const ACTIONS = [
},
]
-// Define the primary crime data controls
-const crimeControls = [
- { id: "incidents" as ITopTooltipsMapId, icon: , label: "All Incidents" },
- { id: "heatmap" as ITopTooltipsMapId, icon: , label: "Crime Heatmap" },
- { id: "trends" as ITopTooltipsMapId, icon: , label: "Crime Trends" },
- { id: "patrol" as ITopTooltipsMapId, icon: , label: "Patrol Areas" },
- { id: "clusters" as ITopTooltipsMapId, icon: , label: "Clusters" },
- { id: "timeline" as ITopTooltipsMapId, icon: , label: "Time Analysis" },
-]
-
-// Define the additional tools and features
-const additionalControls = [
- { id: "reports" as ITopTooltipsMapId, icon: , label: "Police Report" },
- { id: "layers" as ITopTooltipsMapId, icon: , label: "Map Layers" },
- { id: "alerts" as ITopTooltipsMapId, icon: , label: "Active Alerts" },
-]
-
-interface TopControlProps {
- onControlChange?: (controlId: ITopTooltipsMapId) => void
+interface SearchTooltipProps {
+ onControlChange?: (controlId: ITooltips) => void
activeControl?: string
- selectedYear: number
- setSelectedYear: (year: number) => void
- selectedMonth: number | "all"
- setSelectedMonth: (month: number | "all") => void
- selectedCategory: string | "all"
- setSelectedCategory: (category: string | "all") => void
- availableYears?: (number | null)[]
- categories?: string[]
}
-export default function TopControl({
- onControlChange,
- activeControl,
- selectedYear,
- setSelectedYear,
- selectedMonth,
- setSelectedMonth,
- selectedCategory,
- setSelectedCategory,
- availableYears = [2022, 2023, 2024],
- categories = [],
-
-}: TopControlProps) {
- const [showSelectors, setShowSelectors] = useState(false)
+export default function SearchTooltip({ onControlChange, activeControl }: SearchTooltipProps) {
const [showSearch, setShowSearch] = useState(false)
- const containerRef = useRef(null)
const searchInputRef = useRef(null)
const [selectedSearchType, setSelectedSearchType] = useState(null)
const [searchValue, setSearchValue] = useState("")
@@ -203,14 +139,6 @@ export default function TopControl({
} | null>(null)
const [showInfoBox, setShowInfoBox] = useState(false)
- const [isClient, setIsClient] = useState(false)
-
- const container = isClient ? document.getElementById("root") : null
-
- useEffect(() => {
- setIsClient(true)
- }, [])
-
useEffect(() => {
if (showSearch && searchInputRef.current) {
setTimeout(() => {
@@ -239,8 +167,6 @@ export default function TopControl({
initialSuggestions = EXPANDED_SAMPLE_DATA;
}
- console.log("Initial suggestions count:", initialSuggestions.length);
-
// Force a re-render by setting suggestions in the next tick
setTimeout(() => {
setSuggestions(initialSuggestions);
@@ -383,23 +309,15 @@ export default function TopControl({
// Restore original suggestions for the current search type
if (selectedSearchType) {
- const currentPrefix = ACTIONS.find(action => action.id === selectedSearchType)?.prefix || "";
- const initialSuggestions = filterSuggestions(selectedSearchType, currentPrefix);
-
- setTimeout(() => {
- setSuggestions(initialSuggestions);
- }, 0);
+ const initialSuggestions = filterSuggestions(selectedSearchType, searchValue);
+ setSuggestions(initialSuggestions);
}
};
- const toggleSelectors = () => {
- setShowSelectors(!showSelectors)
- }
-
const toggleSearch = () => {
setShowSearch(!showSearch)
if (!showSearch && onControlChange) {
- onControlChange("search" as ITopTooltipsMapId)
+ onControlChange("search" as ITooltips)
setSelectedSearchType(null);
setSearchValue("");
setSuggestions([]);
@@ -407,153 +325,31 @@ export default function TopControl({
}
return (
-
-
-
-
- {crimeControls.map((control) => (
-
-
-
-
-
- {control.label}
-
-
- ))}
-
-
-
-
-
- {additionalControls.map((control) => (
-
-
-
-
-
- {control.label}
-
-
- ))}
-
-
-
-
-
-
-
-
-
- Year:
-
-
-
- Month:
-
-
-
- Category:
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Search Incidents
-
-
-
-
+ <>
+
+
+
+
+
+
+
+ Search Incidents
+
+
+
- {showSelectors && (
-
-
-
-
-
- )}
-
{showSearch && (
<>
@@ -689,7 +485,7 @@ export default function TopControl({
) : (
-
{selectedSuggestion?.id}
+ {selectedSuggestion?.id}
{selectedSuggestion && (
@@ -754,6 +550,6 @@ export default function TopControl({
>
)}
-
+ >
)
}
diff --git a/sigap-website/app/_components/map/controls/top/tooltips.tsx b/sigap-website/app/_components/map/controls/top/tooltips.tsx
new file mode 100644
index 0000000..cc1332e
--- /dev/null
+++ b/sigap-website/app/_components/map/controls/top/tooltips.tsx
@@ -0,0 +1,90 @@
+"use client"
+
+import { useRef, useState } from "react"
+
+import CrimeTooltips from "./crime-tooltips"
+import AdditionalTooltips from "./additional-tooltips"
+import SearchTooltip from "./search-control"
+import { ReactNode } from "react"
+
+// Define the possible control IDs for the crime map
+export type ITooltips =
+ // Crime data views
+ | "incidents"
+ | "heatmap"
+ | "trends"
+ | "patrol"
+ | "reports"
+ | "clusters"
+ | "timeline"
+
+ // Tools and features
+ | "refresh"
+ | "search"
+ | "alerts"
+ | "layers"
+ | "evidence"
+ | "arrests";
+
+// Map tools type definition
+export interface IMapTools {
+ id: ITooltips;
+ label: string;
+ icon: ReactNode;
+ description?: string;
+}
+
+interface TooltipProps {
+ onControlChange?: (controlId: ITooltips) => void
+ activeControl?: string
+ selectedYear: number
+ setSelectedYear: (year: number) => void
+ selectedMonth: number | "all"
+ setSelectedMonth: (month: number | "all") => void
+ selectedCategory: string | "all"
+ setSelectedCategory: (category: string | "all") => void
+ availableYears?: (number | null)[]
+ categories?: string[]
+}
+
+export default function Tooltips({
+ onControlChange,
+ activeControl,
+ selectedYear,
+ setSelectedYear,
+ selectedMonth,
+ setSelectedMonth,
+ selectedCategory,
+ setSelectedCategory,
+ availableYears = [2022, 2023, 2024],
+ categories = [],
+}: TooltipProps) {
+ const containerRef = useRef
(null)
+ const [isClient, setIsClient] = useState(false)
+
+ return (
+
+
+ {/* Crime Tooltips Component */}
+
+
+ {/* Additional Tooltips Component */}
+
+
+ {/* Search Control Component */}
+
+
+
+ )
+}
diff --git a/sigap-website/app/_components/map/crime-map.tsx b/sigap-website/app/_components/map/crime-map.tsx
index be25c50..2506dee 100644
--- a/sigap-website/app/_components/map/crime-map.tsx
+++ b/sigap-website/app/_components/map/crime-map.tsx
@@ -10,18 +10,17 @@ import { getMonthName } from "@/app/_utils/common"
import { useRef, useState, useCallback, useMemo, useEffect } from "react"
import { useFullscreen } from "@/app/_hooks/use-fullscreen"
import { Overlay } from "./overlay"
-import MapLegend from "./controls/map-legend"
+import MapLegend from "./legends/map-legend"
import { useGetAvailableYears, useGetCrimeCategories, useGetCrimes } from "@/app/(pages)/(admin)/dashboard/crime-management/crime-overview/_queries/queries"
-import { ITopTooltipsMapId } from "./controls/map-tooltips"
import MapSelectors from "./controls/map-selector"
-import CrimeSidebar from "./sidebar/map-sidebar"
-import SidebarToggle from "./sidebar/sidebar-toggle"
import { cn } from "@/app/_lib/utils"
import CrimePopup from "./pop-up/crime-popup"
import { $Enums, crime_categories, crime_incidents, crimes, demographics, districts, geographics, locations } from "@prisma/client"
-import { CrimeTimelapse } from "./controls/crime-timelapse"
-import TopControl from "./controls/top-controls"
+import { CrimeTimelapse } from "./controls/bottom/crime-timelapse"
+import { ITooltips } from "./controls/top/tooltips"
+import CrimeSidebar from "./controls/left/sidebar/map-sidebar"
+import Tooltips from "./controls/top/tooltips"
// Updated CrimeIncident type to match the structure in crime_incidents
interface CrimeIncident {
@@ -45,7 +44,7 @@ export default function CrimeMap() {
const [selectedCategory, setSelectedCategory] = useState("all")
const [selectedYear, setSelectedYear] = useState(2024)
const [selectedMonth, setSelectedMonth] = useState("all")
- const [activeControl, setActiveControl] = useState("incidents")
+ const [activeControl, setActiveControl] = useState("incidents")
const [yearProgress, setYearProgress] = useState(0)
const [isTimelapsePlaying, setisTimelapsePlaying] = useState(false)
const [isSearchActive, setIsSearchActive] = useState(false)
@@ -277,7 +276,7 @@ export default function CrimeMap() {
}, [sidebarCollapsed])
// Handle control changes from the top controls component
- const handleControlChange = (controlId: ITopTooltipsMapId) => {
+ const handleControlChange = (controlId: ITooltips) => {
setActiveControl(controlId)
// Toggle search state when search control is clicked
@@ -348,7 +347,7 @@ export default function CrimeMap() {
<>
-