"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 { 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 { Card } from "@/app/_components/ui/card" import { ICrimes } from "@/app/_utils/types/crimes" // Expanded sample crime data with more entries for testing const SAMPLE_CRIME_DATA = [ { id: "CR-12345-2023", description: "Robbery at Main Street" }, { id: "CR-23456-2023", description: "Assault in Central Park" }, { id: "CI-7890-2023", description: "Burglary report at Downtown" }, { id: "CI-4567-2024", description: "Vandalism at City Hall" }, { id: "CI-4167-2024", description: "Graffiti at Public Library" }, { id: "CI-4067-2024", description: "Property damage at School" }, { id: "CR-34567-2024", description: "Car theft on 5th Avenue" }, { 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 const generateSampleData = () => { const additionalData = []; for (let i = 1; i <= 90; i++) { // Mix of crime and incident IDs const prefix = i % 2 === 0 ? "CR-" : "CI-"; const id = `${prefix}${10000 + i}-${2022 + i % 3}`; const descriptions = [ "Theft at residence", "Traffic violation", "Noise complaint", "Suspicious activity", "Drug related incident", "Vandalism of public property", "Illegal parking", "Public disturbance", "Domestic dispute", "Assault case" ]; const description = descriptions[i % descriptions.length]; additionalData.push({ id, description: `${description} #${i}` }); } return [...SAMPLE_CRIME_DATA, ...additionalData]; } const EXPANDED_SAMPLE_DATA = generateSampleData(); const ACTIONS = [ { id: "crime_id", label: "Search by Crime ID", icon: , description: "e.g., CR-12345", category: "Search", prefix: "CR-", regex: /^CR-\d+(-\d{4})?$/, placeholder: "CR-12345-2023", }, { id: "incident_id", label: "Search by Incident ID", icon: , description: "e.g., CI-789", category: "Search", prefix: "CI-", regex: /^CI-\d+(-\d{4})?$/, placeholder: "CI-7890-2023", }, { id: "coordinates", label: "Search by Coordinates", icon: , description: "e.g., -6.2, 106.8", category: "Search", prefix: "", regex: /^-?\d+(\.\d+)?,\s*-?\d+(\.\d+)?$/, placeholder: "-6.2, 106.8", }, { id: "description", label: "Search by Description", icon: , description: "e.g., robbery", category: "Search", prefix: "", regex: /.+/, placeholder: "Enter crime description", }, { id: "address", label: "Search by Address", icon: , description: "e.g., Jalan Sudirman", category: "Search", prefix: "", regex: /.+/, placeholder: "Enter location or address", }, ] // 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 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) const [showSearch, setShowSearch] = useState(false) const containerRef = useRef(null) const searchInputRef = useRef(null) const [selectedSearchType, setSelectedSearchType] = useState(null) const [searchValue, setSearchValue] = useState("") const [suggestions, setSuggestions] = useState>([]) const [isInputValid, setIsInputValid] = useState(true) const [selectedSuggestion, setSelectedSuggestion] = useState<{ id: string; description: string; latitude?: number; longitude?: number; timestamp?: Date; category?: string; type?: string; address?: string; } | 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(() => { searchInputRef.current?.focus(); }, 100); } }, [showSearch]); const handleSearchTypeSelect = (actionId: string) => { const selectedAction = ACTIONS.find(action => action.id === actionId); if (selectedAction) { setSelectedSearchType(actionId); const prefix = selectedAction.prefix || ""; setSearchValue(prefix); setIsInputValid(true); const initialSuggestions = EXPANDED_SAMPLE_DATA.filter(item => { if (actionId === 'crime_id' && item.id.startsWith('CR-')) { return true; } else if (actionId === 'incident_id' && item.id.startsWith('CI-')) { return true; } else if (actionId === 'description' || actionId === 'address') { return true; } else if (actionId === 'coordinates') { return false; } return false; }); setSuggestions(initialSuggestions); setTimeout(() => { if (searchInputRef.current) { searchInputRef.current.focus(); searchInputRef.current.selectionStart = prefix.length; searchInputRef.current.selectionEnd = prefix.length; } }, 50); } }; const handleClearSearchType = () => { setSelectedSearchType(null); setSearchValue(""); setSuggestions([]); if (searchInputRef.current) { setTimeout(() => { searchInputRef.current?.focus(); }, 50); } }; const handleSuggestionSelect = (item: { id: string, description: string }) => { setSearchValue(item.id); setSuggestions([]); const fullIncidentData = { ...item, timestamp: new Date(), latitude: -6.2088, longitude: 106.8456, category: selectedSearchType === 'crime_id' ? "Theft" : "Vandalism", type: selectedSearchType === 'crime_id' ? "Property Crime" : "Public Disturbance", address: "Jl. Sudirman No. 123, Jakarta" }; setSelectedSuggestion(fullIncidentData); setShowInfoBox(true); }; const handleFlyToIncident = () => { if (!selectedSuggestion || !selectedSuggestion.latitude || !selectedSuggestion.longitude) return; const flyToEvent = new CustomEvent('fly_to_incident', { detail: { longitude: selectedSuggestion.longitude, latitude: selectedSuggestion.latitude, id: selectedSuggestion.id, zoom: 15 }, bubbles: true }); document.dispatchEvent(flyToEvent); toggleSearch(); }; const handleCloseInfoBox = () => { setShowInfoBox(false); setSelectedSuggestion(null); }; const handleSearchChange = (value: string) => { const currentSearchType = selectedSearchType ? ACTIONS.find(action => action.id === selectedSearchType) : null; if (currentSearchType?.prefix && currentSearchType.prefix.length > 0) { if (!value.startsWith(currentSearchType.prefix)) { value = currentSearchType.prefix; } } setSearchValue(value); if (currentSearchType?.regex) { if (!value || value === currentSearchType.prefix) { setIsInputValid(true); } else { setIsInputValid(currentSearchType.regex.test(value)); } } else { setIsInputValid(true); } if (!selectedSearchType) { setSuggestions([]); return; } let filteredSuggestions: Array<{ id: string, description: string }> = []; const searchText = value.toLowerCase(); if (currentSearchType?.id === 'crime_id') { filteredSuggestions = EXPANDED_SAMPLE_DATA.filter(item => item.id.startsWith('CR-') && (item.id.toLowerCase().includes(searchText) || item.description.toLowerCase().includes(searchText)) ); } else if (currentSearchType?.id === 'incident_id') { filteredSuggestions = EXPANDED_SAMPLE_DATA.filter(item => item.id.startsWith('CI-') && (item.id.toLowerCase().includes(searchText) || item.description.toLowerCase().includes(searchText)) ); } else if (currentSearchType?.id === 'description') { filteredSuggestions = EXPANDED_SAMPLE_DATA.filter(item => item.description.toLowerCase().includes(searchText) ); } else if (currentSearchType?.id === 'address') { filteredSuggestions = EXPANDED_SAMPLE_DATA.filter(item => item.description.toLowerCase().includes(searchText) ); } else if (currentSearchType?.id === 'coordinates') { filteredSuggestions = []; } if (!value || (currentSearchType?.prefix && value === currentSearchType.prefix)) { if (currentSearchType?.id === 'crime_id') { filteredSuggestions = EXPANDED_SAMPLE_DATA.filter(item => item.id.startsWith('CR-')); } else if (currentSearchType?.id === 'incident_id') { filteredSuggestions = EXPANDED_SAMPLE_DATA.filter(item => item.id.startsWith('CI-')); } else if (currentSearchType?.id === 'description' || currentSearchType?.id === 'address') { filteredSuggestions = EXPANDED_SAMPLE_DATA; } } setSuggestions(filteredSuggestions); }; const toggleSelectors = () => { setShowSelectors(!showSelectors) } const toggleSearch = () => { setShowSearch(!showSearch) if (!showSearch && onControlChange) { onControlChange("search" as ITopTooltipsMapId) } } return (
{crimeControls.map((control) => (

{control.label}

))}
{additionalControls.map((control) => (

{control.label}

))}
Year:
Month:
Category:

Search Incidents

{showSelectors && (
)} {showSearch && ( <>

Search Incidents

{!showInfoBox ? ( <> a.id === selectedSearchType)?.placeholder : "Select a search type..."} inputClassName={!isInputValid ? "border-destructive focus-visible:ring-destructive bg-destructive/50" : ""} /> {!isInputValid && selectedSearchType && (
Invalid format. {ACTIONS.find(a => a.id === selectedSearchType)?.description}
)} {suggestions.length > 0 && (

{suggestions.length} results found

    {suggestions.map((item, index) => (
  • handleSuggestionSelect(item)} > {item.id}
    {item.description}
  • ))}
)} {searchValue.length > (selectedSearchType && ACTIONS.find(a => a.id === selectedSearchType)?.prefix?.length || 0) && suggestions.length === 0 && (

No matching incidents found

)}

{selectedSearchType ? ( <> {ACTIONS.find(a => a.id === selectedSearchType)?.icon} {ACTIONS.find(a => a.id === selectedSearchType)?.description} ) : ( Select a search type and enter your search criteria )}

) : (

{selectedSuggestion?.id}

{/* */}
{selectedSuggestion && (

{selectedSuggestion.description}

{selectedSuggestion.timestamp && (

{format(selectedSuggestion.timestamp, 'PPP p')}

)} {selectedSuggestion.address && (

{selectedSuggestion.address}

)}

Category

{selectedSuggestion.category || 'N/A'}

Type

{selectedSuggestion.type || 'N/A'}

)}
)}
)}
) }