@adventurelabs/scout-core
Version:
Core utilities and helpers for Adventure Labs Scout applications
85 lines (84 loc) • 3.48 kB
JavaScript
"use client";
import { useSelector } from "react-redux";
import { useEffect, useRef, useCallback, useState, useMemo } from "react";
import { EnumRealtimeOperation } from "../types/realtime";
export function useScoutRealtimeConnectivity(scoutSupabase) {
const channels = useRef([]);
const [latestConnectivityUpdate, setLatestConnectivityUpdate] = useState(null);
const activeHerdId = useSelector((state) => state.scout.active_herd_id);
const herdModules = useSelector((state) => state.scout.herd_modules);
// Create stable reference for GPS device IDs to prevent unnecessary refetching
const gpsDeviceIds = useMemo(() => {
if (!activeHerdId)
return "";
const activeHerdModule = herdModules.find((hm) => hm.herd.id.toString() === activeHerdId);
if (!activeHerdModule)
return "";
const gpsDevices = activeHerdModule.devices.filter((device) => device.device_type &&
["gps_tracker", "gps_tracker_vehicle", "gps_tracker_person"].includes(device.device_type));
return gpsDevices
.map((d) => d.id)
.filter(Boolean)
.sort()
.join(",");
}, [activeHerdId, herdModules]);
// Handle connectivity broadcasts
const handleConnectivityBroadcast = useCallback((payload) => {
const { event, payload: data } = payload;
const connectivityData = data.record || data.old_record;
// Only process GPS tracker data (no session_id)
if (!connectivityData?.device_id || connectivityData.session_id) {
return;
}
let operation;
switch (data.operation) {
case "INSERT":
operation = EnumRealtimeOperation.INSERT;
break;
case "UPDATE":
operation = EnumRealtimeOperation.UPDATE;
break;
case "DELETE":
operation = EnumRealtimeOperation.DELETE;
break;
default:
return;
}
console.log(`[scout-core realtime] CONNECTIVITY ${data.operation} received for device ${connectivityData.device_id}:`, JSON.stringify(connectivityData));
const realtimeData = {
data: connectivityData,
operation,
};
setLatestConnectivityUpdate(realtimeData);
}, []);
// Clear latest update
const clearLatestUpdate = useCallback(() => {
setLatestConnectivityUpdate(null);
}, []);
useEffect(() => {
if (!scoutSupabase || gpsDeviceIds === "")
return;
// Clean up existing channels
channels.current.forEach((channel) => scoutSupabase.removeChannel(channel));
channels.current = [];
// Clear previous update when switching herds
clearLatestUpdate();
// Create connectivity channel
const channel = scoutSupabase
.channel(`${activeHerdId}-connectivity`, { config: { private: true } })
.on("broadcast", { event: "*" }, handleConnectivityBroadcast)
.subscribe();
channels.current.push(channel);
return () => {
channels.current.forEach((ch) => scoutSupabase.removeChannel(ch));
channels.current = [];
};
}, [
scoutSupabase,
gpsDeviceIds,
activeHerdId,
handleConnectivityBroadcast,
clearLatestUpdate,
]);
return [latestConnectivityUpdate, clearLatestUpdate];
}