feat(realtime): implement SSE realtime notifications; publish events from resolvers; remove polling in chat/sidebar/supplies/warehouse and wire realtime refetch
This commit is contained in:
60
src/hooks/useRealtime.ts
Normal file
60
src/hooks/useRealtime.ts
Normal file
@ -0,0 +1,60 @@
|
||||
"use client"
|
||||
|
||||
import { useEffect, useRef } from 'react'
|
||||
|
||||
import { getAuthToken } from '@/lib/apollo-client'
|
||||
|
||||
export type RealtimeEvent = {
|
||||
type: string
|
||||
payload?: any
|
||||
createdAt?: string
|
||||
}
|
||||
|
||||
type Options = {
|
||||
onEvent?: (evt: RealtimeEvent) => void
|
||||
orgId?: string
|
||||
}
|
||||
|
||||
export function useRealtime({ onEvent, orgId }: Options = {}) {
|
||||
const handlerRef = useRef(onEvent)
|
||||
handlerRef.current = onEvent
|
||||
|
||||
useEffect(() => {
|
||||
if (typeof window === 'undefined') return
|
||||
const token = getAuthToken() || localStorage.getItem('adminAuthToken')
|
||||
// Try to infer orgId from cached userData if not provided
|
||||
let resolvedOrgId = orgId
|
||||
if (!resolvedOrgId) {
|
||||
try {
|
||||
const userDataRaw = localStorage.getItem('userData')
|
||||
if (userDataRaw) {
|
||||
const user = JSON.parse(userDataRaw)
|
||||
resolvedOrgId = user?.organization?.id
|
||||
}
|
||||
} catch {}
|
||||
}
|
||||
|
||||
if (!token || !resolvedOrgId) return
|
||||
|
||||
const url = `/api/events?token=${encodeURIComponent(token)}&orgId=${encodeURIComponent(resolvedOrgId)}`
|
||||
const es = new EventSource(url)
|
||||
|
||||
es.onmessage = (event) => {
|
||||
try {
|
||||
const data = JSON.parse(event.data)
|
||||
handlerRef.current?.(data)
|
||||
} catch (e) {
|
||||
// ignore malformed events
|
||||
}
|
||||
}
|
||||
|
||||
es.onerror = () => {
|
||||
// Let the browser auto-reconnect
|
||||
}
|
||||
|
||||
return () => {
|
||||
es.close()
|
||||
}
|
||||
}, [orgId])
|
||||
}
|
||||
|
Reference in New Issue
Block a user