"use client"; import { useEffect, useState } from "react"; import { collection, onSnapshot, query, where, FirestoreError } from "firebase/firestore"; import { onAuthStateChanged } from "firebase/auth"; import { db, auth } from "@/lib/firebase"; import { useAuth } from "@/components/AuthProvider"; import type { VesselTrack } from "@/lib/types"; // Same shape as useAircraft — `vessels` is a live snapshot (one per mmsi, // overwritten on every sighting, node-26#9), nothing prunes a doc when a // vessel goes out of range, so staleness is filtered client-side. AIS // position reports are much less frequent than ADS-B (minutes, not // seconds), so this window is longer than useAircraft's. const STALE_AFTER_MS = 10 * 60 * 1000; export function useVessels() { const [vessels, setVessels] = useState([]); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); const { orgId } = useAuth(); useEffect(() => { let unsubFirestore: (() => void) | undefined; const unsubAuth = onAuthStateChanged(auth, (user) => { if (unsubFirestore) { unsubFirestore(); unsubFirestore = undefined; } if (!user || !orgId) { setVessels([]); setLoading(false); return; } const q = query(collection(db, "vessels"), where("org_id", "==", orgId)); unsubFirestore = onSnapshot(q, (snap) => { const now = Date.now(); const fresh = snap.docs .map((d) => d.data() as VesselTrack) .filter((v) => now - new Date(v.last_seen).getTime() < STALE_AFTER_MS); setVessels(fresh); setLoading(false); }, (err: FirestoreError) => { console.error("useVessels:", err); setError(err.message); setLoading(false); }); }); return () => { unsubAuth(); if (unsubFirestore) unsubFirestore(); }; }, [orgId]); return { vessels, loading, error }; }