"use client" import { Button } from "@/app/_components/ui/button" import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "@/app/_components/ui/tooltip" 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 ActionSearchBar from "@/app/_components/action-search-bar" import { Card } from "@/app/_components/ui/card" import { format } from 'date-fns' import { ITooltips } from "./tooltips" // 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" }, ]; // 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]; // Add more detailed properties for enhanced suggestions additionalData.push({ id, description: `${description} #${i}`, coordinates: `${-6 - (i % 5) * 0.01}, ${106 + (i % 7) * 0.01}`, address: `Jl. ${["Sudirman", "Thamrin", "Gatot Subroto", "Rasuna Said", "Asia Afrika"][i % 5]} No. ${i + 10}, Jakarta`, date: new Date(2022 + (i % 3), i % 12, i % 28 + 1), type: ["Theft", "Assault", "Vandalism", "Robbery", "Fraud"][i % 5], category: ["Property Crime", "Violent Crime", "Public Disturbance", "White Collar", "Misdemeanor"][i % 5] }); } return [...SAMPLE_CRIME_DATA, ...additionalData]; } const EXPANDED_SAMPLE_DATA = generateSampleData(); const ACTIONS = [ { 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", }, ] interface SearchTooltipProps { onControlChange?: (controlId: ITooltips) => void activeControl?: string } export default function SearchTooltip({ onControlChange, activeControl }: SearchTooltipProps) { const [showSearch, setShowSearch] = useState(false) 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) 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); // Immediately filter and show suggestions based on the selected search type let initialSuggestions: Array<{ id: string, description: string }> = []; if (actionId === 'crime_id') { initialSuggestions = EXPANDED_SAMPLE_DATA.filter(item => item.id.startsWith('CR-')); } else if (actionId === 'incident_id') { initialSuggestions = EXPANDED_SAMPLE_DATA.filter(item => item.id.startsWith('CI-')); } else if (actionId === 'description' || actionId === 'address') { initialSuggestions = EXPANDED_SAMPLE_DATA; } // Force a re-render by setting suggestions in the next tick setTimeout(() => { setSuggestions(initialSuggestions); }, 0); setTimeout(() => { if (searchInputRef.current) { searchInputRef.current.focus(); searchInputRef.current.selectionStart = prefix.length; searchInputRef.current.selectionEnd = prefix.length; } }, 50); } } // Create a helper function for filtering suggestions const filterSuggestions = (searchType: string, searchText: string): Array<{ id: string, description: string }> => { let filtered: Array<{ id: string, description: string }> = []; if (searchType === 'crime_id') { if (!searchText || searchText === 'CR-') { filtered = EXPANDED_SAMPLE_DATA.filter(item => item.id.startsWith('CR-')); } else { filtered = EXPANDED_SAMPLE_DATA.filter(item => item.id.startsWith('CR-') && (item.id.toLowerCase().includes(searchText.toLowerCase()) || item.description.toLowerCase().includes(searchText.toLowerCase())) ); } } else if (searchType === 'incident_id') { if (!searchText || searchText === 'CI-') { filtered = EXPANDED_SAMPLE_DATA.filter(item => item.id.startsWith('CI-')); } else { filtered = EXPANDED_SAMPLE_DATA.filter(item => item.id.startsWith('CI-') && (item.id.toLowerCase().includes(searchText.toLowerCase()) || item.description.toLowerCase().includes(searchText.toLowerCase())) ); } } else if (searchType === 'description') { if (!searchText) { filtered = EXPANDED_SAMPLE_DATA; } else { filtered = EXPANDED_SAMPLE_DATA.filter(item => item.description.toLowerCase().includes(searchText.toLowerCase()) ); } } else if (searchType === 'address') { if (!searchText) { filtered = EXPANDED_SAMPLE_DATA; } else { filtered = EXPANDED_SAMPLE_DATA.filter(item => item.description.toLowerCase().includes(searchText.toLowerCase()) ); } } return filtered; }; 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; } // Use the helper function to filter suggestions setSuggestions(filterSuggestions(selectedSearchType, value)); } 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); setShowInfoBox(false); setSelectedSuggestion(null); toggleSearch(); }; const handleCloseInfoBox = () => { setShowInfoBox(false); setSelectedSuggestion(null); // Restore original suggestions for the current search type if (selectedSearchType) { const initialSuggestions = filterSuggestions(selectedSearchType, searchValue); setSuggestions(initialSuggestions); } }; const toggleSearch = () => { setShowSearch(!showSearch) if (!showSearch && onControlChange) { onControlChange("search" as ITooltips) setSelectedSearchType(null); setSearchValue(""); setSuggestions([]); } } return ( <>

Search Incidents

{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 && selectedSearchType) && (

{suggestions.length} results found

    {suggestions.map((item, index) => (
  • handleSuggestionSelect(item)} > {item.id}
    {/* Show different information based on search type */} {selectedSearchType === 'crime_id' || selectedSearchType === 'incident_id' ? ( {item.description} ) : selectedSearchType === 'coordinates' && 'coordinates' in item ? ( {typeof item.coordinates === 'string' ? item.coordinates : 'N/A'} - {item.description} ) : selectedSearchType === 'address' && 'address' in item ? ( {'address' in item && typeof item.address === 'string' ? item.address : 'N/A'} ) : ( {item.description} )}
  • ))}
)} {selectedSearchType && searchValue.length > (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'}

)}
)}
)}
) }