import * as React from "react"; import type { UpdateItem } from "../../lib/types"; import { haversineMiles, timeAgo } from "../../lib/geo"; export type NearbyAlertModalProps = { open: boolean; leaving?: boolean; onClose: () => void; onVerify: () => void; onClear: () => void; onSkip: () => void; current: UpdateItem | null; index: number; total: number; myLL: [number, number] | null; }; export default function NearbyAlertModal(props: NearbyAlertModalProps) { const { open, leaving, onClose, onVerify, onClear, onSkip, current, index, total, myLL, } = props; const cardRef = React.useRef(null); React.useEffect(() => { function onKey(e: KeyboardEvent) { if (e.key === "Escape") onClose(); } if (open) document.addEventListener("keydown", onKey); return () => document.removeEventListener("keydown", onKey); }, [open, onClose]); React.useEffect(() => { if (open && cardRef.current) { // focus first actionable element (Verify) for accessibility const btn = cardRef.current.querySelector( "button[data-primary]" ); btn?.focus(); } }, [open, current]); if (!open || !current) return null; const dist = myLL ? haversineMiles(myLL, [current.lat, current.lon]) : null; const when = timeAgo(current.time); const raw: any = (current as any).raw || {}; const thumb = raw.photo_url || raw.photoUrl || raw.image_url || raw.imageUrl || null; return (
{ if (e.target === e.currentTarget) onClose(); }} >
{current.emoji || "📍"}
{current.title || "Nearby alert"}
{thumb ? ( { (e.target as HTMLImageElement).style.display = "none"; }} /> ) : null}
Reported within 2 miles {typeof dist === "number" ? ( <> {" "} • approximately {dist.toFixed(1)} mi away ) : null}{" "} • {when}
{raw?.text ? (
{raw.text}
) : null}
{Array.from({ length: total }).map((_, i) => ( ))} {index + 1} of {total}
); }