"use client" import { useState } from "react" import { Popup } from "react-map-gl/mapbox" import { X, ChevronLeft, ChevronRight, Filter } from 'lucide-react' import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "../../ui/card" import { Button } from "../../ui/button" import { Badge } from "../../ui/badge" interface TimelinePopupProps { longitude: number latitude: number onClose: () => void district: { id: string name: string formattedTime: string timeDescription: string totalIncidents: number earliestTime: string latestTime: string mostFrequentHour: number categoryCounts: Record timeOfDay: string incidents?: Array<{ id: string title: string time: string category: string }> selectedFilters?: { year: string month: string category: string label: string } allTimeCount?: number useAllData?: boolean } } export default function TimelinePopup({ longitude, latitude, onClose, district, }: TimelinePopupProps) { // Pagination state const [currentPage, setCurrentPage] = useState(1) const itemsPerPage = 3 // Get top 5 categories const topCategories = Object.entries(district.categoryCounts) .sort(([, countA], [, countB]) => countB - countA) .slice(0, 5) // Get time of day color const getTimeOfDayColor = (timeOfDay: string) => { switch (timeOfDay) { case "morning": return "bg-yellow-400 text-black" case "afternoon": return "bg-orange-500 text-white" case "evening": return "bg-indigo-600 text-white" case "night": return "bg-slate-800 text-white" default: return "bg-green-500 text-white" } } // Get text color for time of day const getTextColorForTimeOfDay = (timeOfDay: string) => { switch (timeOfDay) { case "morning": return "text-yellow-400" case "afternoon": return "text-orange-500" case "evening": return "text-indigo-600" case "night": return "text-slate-800" default: return "text-green-500" } } // Get paginated incidents const getPaginatedIncidents = () => { if (!district.incidents) return [] const startIndex = (currentPage - 1) * itemsPerPage return district.incidents.slice(startIndex, startIndex + itemsPerPage) } // Calculate total pages const totalPages = district.incidents ? Math.ceil(district.incidents.length / itemsPerPage) : 0 // Handle page navigation const goToNextPage = () => { if (currentPage < totalPages) { setCurrentPage(prev => prev + 1) } } const goToPrevPage = () => { if (currentPage > 1) { setCurrentPage(prev => prev - 1) } } // Get current incidents for display const currentIncidents = getPaginatedIncidents() // Extract filter info const filterLabel = district.selectedFilters?.label || "All data"; const isFiltered = district.selectedFilters?.year !== "all" || district.selectedFilters?.month !== "all"; const categoryFilter = district.selectedFilters?.category !== "all" ? district.selectedFilters?.category : null; // Get percentage of incidents in the time window compared to all time const percentageOfAll = district.allTimeCount && district.allTimeCount > 0 && district.totalIncidents !== district.allTimeCount ? Math.round((district.totalIncidents / district.allTimeCount) * 100) : null; return (
{district.name}
Average incident time analysis {isFiltered && ( {filterLabel} )}
{district.formattedTime}
{district.timeDescription}
Based on {district.totalIncidents} incidents {percentageOfAll && ( ({percentageOfAll}% of all time) )} {categoryFilter && ( {categoryFilter} )}
Earliest incident: {district.earliestTime}
Latest incident: {district.latestTime}
Top incident types:
{topCategories.map(([category, count]) => (
{category} {count}
))}
{district.incidents && district.incidents.length > 0 && (
Incidents Timeline:
{currentPage} of {totalPages}
{currentIncidents.map((incident) => (
{incident.category}
{incident.title} {incident.time}
))}
{/* Pagination Controls */}
)}
) }