99 lines
2.3 KiB
JavaScript
99 lines
2.3 KiB
JavaScript
import { useEffect, useRef, useState, useCallback } from "react";
|
|
import { pollNewPosts } from "../../api/client";
|
|
|
|
/**
|
|
* Hook for real-time post streaming using polling (socket.io compatible)
|
|
*
|
|
* Usage:
|
|
* const { newPosts, clearNewPosts } = useRealtimeStream({
|
|
* enabled: true,
|
|
* lat: 40.7128,
|
|
* lon: -74.0060,
|
|
* radius_km: 500,
|
|
* category: "NEWS",
|
|
* pollInterval: 3000 // poll every 3 seconds
|
|
* });
|
|
*/
|
|
export function useRealtimeStream({
|
|
enabled = true,
|
|
lat,
|
|
lon,
|
|
radius_km = 500,
|
|
category = null,
|
|
pollInterval = 3000, // 3 seconds default
|
|
onNewPost = null, // callback when new posts arrive
|
|
}) {
|
|
const [newPosts, setNewPosts] = useState([]);
|
|
const [isStreaming, setIsStreaming] = useState(false);
|
|
const maxSeenIdRef = useRef(0);
|
|
const intervalRef = useRef(null);
|
|
|
|
const poll = useCallback(async () => {
|
|
if (!lat || !lon) return;
|
|
|
|
try {
|
|
const result = await pollNewPosts({
|
|
since_id: maxSeenIdRef.current,
|
|
lat,
|
|
lon,
|
|
radius_km,
|
|
category,
|
|
limit: 20,
|
|
});
|
|
|
|
if (result.posts && result.posts.length > 0) {
|
|
setNewPosts((prev) => [...prev, ...result.posts]);
|
|
|
|
// Update max seen ID
|
|
if (result.max_id > maxSeenIdRef.current) {
|
|
maxSeenIdRef.current = result.max_id;
|
|
}
|
|
|
|
// Call callback if provided
|
|
if (onNewPost) {
|
|
result.posts.forEach(onNewPost);
|
|
}
|
|
}
|
|
} catch (err) {
|
|
console.warn("Realtime stream poll error:", err);
|
|
}
|
|
}, [lat, lon, radius_km, category, onNewPost]);
|
|
|
|
useEffect(() => {
|
|
if (!enabled || !lat || !lon) {
|
|
setIsStreaming(false);
|
|
if (intervalRef.current) {
|
|
clearInterval(intervalRef.current);
|
|
intervalRef.current = null;
|
|
}
|
|
return;
|
|
}
|
|
|
|
setIsStreaming(true);
|
|
|
|
// Start polling
|
|
intervalRef.current = setInterval(poll, pollInterval);
|
|
|
|
// Initial poll
|
|
poll();
|
|
|
|
return () => {
|
|
if (intervalRef.current) {
|
|
clearInterval(intervalRef.current);
|
|
intervalRef.current = null;
|
|
}
|
|
setIsStreaming(false);
|
|
};
|
|
}, [enabled, lat, lon, radius_km, category, pollInterval, poll]);
|
|
|
|
const clearNewPosts = useCallback(() => {
|
|
setNewPosts([]);
|
|
}, []);
|
|
|
|
return {
|
|
newPosts,
|
|
clearNewPosts,
|
|
isStreaming,
|
|
};
|
|
}
|