MIF_E31221222/sigap-website/app/_components/map/pop-up/timeline-popup.tsx

124 lines
4.7 KiB
TypeScript

"use client"
import { Popup } from "react-map-gl/mapbox"
import { X } 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<string, number>
timeOfDay: string
}
}
export default function TimelinePopup({
longitude,
latitude,
onClose,
district,
}: TimelinePopupProps) {
// 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"
}
}
return (
<Popup
longitude={longitude}
latitude={latitude}
anchor="bottom"
closeOnClick={false}
onClose={onClose}
className="timeline-popup z-10"
maxWidth="300px"
>
<div className="relative">
<Card className="border-0 shadow-none">
<CardHeader className="p-3 pb-2">
<div className="flex items-center justify-between">
<CardTitle className="text-base">{district.name}</CardTitle>
<Button
variant="ghost"
size="icon"
className="h-6 w-6"
onClick={onClose}
>
<X className="h-4 w-4" />
</Button>
</div>
<CardDescription className="text-xs">
Average incident time analysis
</CardDescription>
</CardHeader>
<CardContent className="p-3 pt-0">
<div className="mb-3">
<div className="flex items-center gap-2 mb-1">
<div className="text-xl font-bold font-mono">{district.formattedTime}</div>
<Badge variant="outline" className={`${getTimeOfDayColor(district.timeOfDay)}`}>
{district.timeDescription}
</Badge>
</div>
<div className="text-xs text-muted-foreground">
Based on {district.totalIncidents} incidents
</div>
</div>
<div className="text-sm space-y-1 mb-3">
<div className="flex justify-between">
<span>Earliest incident:</span>
<span className="font-medium">{district.earliestTime}</span>
</div>
<div className="flex justify-between">
<span>Latest incident:</span>
<span className="font-medium">{district.latestTime}</span>
</div>
</div>
<div className="border-t border-border pt-2">
<div className="text-xs font-medium mb-1">Top incident types:</div>
<div className="space-y-1">
{topCategories.map(([category, count]) => (
<div key={category} className="flex justify-between">
<span className="text-xs truncate mr-2">{category}</span>
<span className="text-xs font-semibold">{count}</span>
</div>
))}
</div>
</div>
</CardContent>
</Card>
</div>
</Popup>
)
}