refactor: remove realtime visitors detail page
Remove the individual session journey page and make the live visitor count a static indicator. Prepares for the new aggregated User Journeys feature (v0.17).
This commit is contained in:
@@ -1,42 +0,0 @@
|
||||
import apiRequest from './client'
|
||||
|
||||
export interface Visitor {
|
||||
session_id: string
|
||||
first_seen: string
|
||||
last_seen: string
|
||||
pageviews: number
|
||||
current_path: string
|
||||
browser: string
|
||||
os: string
|
||||
device_type: string
|
||||
country: string
|
||||
city: string
|
||||
}
|
||||
|
||||
export interface SessionEvent {
|
||||
id: string
|
||||
site_id: string
|
||||
session_id: string
|
||||
path: string
|
||||
referrer: string | null
|
||||
user_agent: string
|
||||
country: string | null
|
||||
city: string | null
|
||||
region: string | null
|
||||
device_type: string
|
||||
screen_resolution: string | null
|
||||
browser: string | null
|
||||
os: string | null
|
||||
timestamp: string
|
||||
created_at: string
|
||||
}
|
||||
|
||||
export async function getRealtimeVisitors(siteId: string): Promise<Visitor[]> {
|
||||
const data = await apiRequest<{ visitors: Visitor[] }>(`/sites/${siteId}/realtime/visitors`)
|
||||
return data.visitors
|
||||
}
|
||||
|
||||
export async function getSessionDetails(siteId: string, sessionId: string): Promise<SessionEvent[]> {
|
||||
const data = await apiRequest<{ events: SessionEvent[] }>(`/sites/${siteId}/sessions/${sessionId}`)
|
||||
return data.events
|
||||
}
|
||||
@@ -1,53 +0,0 @@
|
||||
// * SSE hook for real-time visitor streaming.
|
||||
// * Replaces 5-second polling with a persistent EventSource connection.
|
||||
// * The backend broadcasts one DB query per site to all connected clients,
|
||||
// * so 1,000 users on the same site share a single query instead of each
|
||||
// * triggering their own.
|
||||
|
||||
import { useEffect, useRef, useState, useCallback } from 'react'
|
||||
import { API_URL } from '@/lib/api/client'
|
||||
import type { Visitor } from '@/lib/api/realtime'
|
||||
|
||||
interface UseRealtimeSSEReturn {
|
||||
visitors: Visitor[]
|
||||
connected: boolean
|
||||
}
|
||||
|
||||
export function useRealtimeSSE(siteId: string): UseRealtimeSSEReturn {
|
||||
const [visitors, setVisitors] = useState<Visitor[]>([])
|
||||
const [connected, setConnected] = useState(false)
|
||||
const esRef = useRef<EventSource | null>(null)
|
||||
|
||||
// Stable callback so we don't recreate EventSource on every render
|
||||
const handleMessage = useCallback((event: MessageEvent) => {
|
||||
try {
|
||||
const data = JSON.parse(event.data)
|
||||
setVisitors(data.visitors || [])
|
||||
} catch {
|
||||
// Ignore malformed messages
|
||||
}
|
||||
}, [])
|
||||
|
||||
useEffect(() => {
|
||||
if (!siteId) return
|
||||
|
||||
const url = `${API_URL}/api/v1/sites/${siteId}/realtime/stream`
|
||||
const es = new EventSource(url, { withCredentials: true })
|
||||
esRef.current = es
|
||||
|
||||
es.onopen = () => setConnected(true)
|
||||
es.onmessage = handleMessage
|
||||
es.onerror = () => {
|
||||
setConnected(false)
|
||||
// EventSource auto-reconnects with exponential backoff
|
||||
}
|
||||
|
||||
return () => {
|
||||
es.close()
|
||||
esRef.current = null
|
||||
setConnected(false)
|
||||
}
|
||||
}, [siteId, handleMessage])
|
||||
|
||||
return { visitors, connected }
|
||||
}
|
||||
Reference in New Issue
Block a user