feat: add SseProvider — SSE to ReactQuery bridge with tests
This commit is contained in:
@@ -0,0 +1,83 @@
|
|||||||
|
import { useEffect, useRef } from 'react'
|
||||||
|
import { useQueryClient } from '@tanstack/react-query'
|
||||||
|
import { useUnit } from 'effector-react'
|
||||||
|
import { createEventStream } from '@/shared/lib/sse'
|
||||||
|
import { $token } from '@/shared/model/auth'
|
||||||
|
|
||||||
|
export function SseProvider() {
|
||||||
|
const token = useUnit($token)
|
||||||
|
const queryClient = useQueryClient()
|
||||||
|
const sourceRef = useRef<EventSource | null>(null)
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!token) {
|
||||||
|
if (sourceRef.current) {
|
||||||
|
sourceRef.current.close()
|
||||||
|
sourceRef.current = null
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const es = createEventStream(token)
|
||||||
|
sourceRef.current = es
|
||||||
|
|
||||||
|
function handleEvent(eventName: string) {
|
||||||
|
return function (event: MessageEvent) {
|
||||||
|
try {
|
||||||
|
const data = JSON.parse(event.data)
|
||||||
|
const orderId = data.orderId
|
||||||
|
|
||||||
|
switch (eventName) {
|
||||||
|
case 'message:new':
|
||||||
|
queryClient.invalidateQueries({ queryKey: ['me', 'messages', 'unread-count'] })
|
||||||
|
queryClient.invalidateQueries({ queryKey: ['me', 'conversations'] })
|
||||||
|
if (orderId) {
|
||||||
|
queryClient.invalidateQueries({ queryKey: ['me', 'orders', orderId] })
|
||||||
|
queryClient.invalidateQueries({ queryKey: ['admin', 'orders', orderId] })
|
||||||
|
}
|
||||||
|
break
|
||||||
|
case 'order:statusChanged':
|
||||||
|
if (orderId) {
|
||||||
|
queryClient.invalidateQueries({ queryKey: ['me', 'orders', orderId] })
|
||||||
|
queryClient.invalidateQueries({ queryKey: ['admin', 'orders', orderId] })
|
||||||
|
}
|
||||||
|
break
|
||||||
|
case 'order:updated':
|
||||||
|
if (orderId) {
|
||||||
|
queryClient.invalidateQueries({ queryKey: ['me', 'orders', orderId] })
|
||||||
|
queryClient.invalidateQueries({ queryKey: ['admin', 'orders', orderId] })
|
||||||
|
}
|
||||||
|
break
|
||||||
|
case 'order:new':
|
||||||
|
queryClient.invalidateQueries({ queryKey: ['admin', 'orders', 'summary'] })
|
||||||
|
queryClient.invalidateQueries({ queryKey: ['admin', 'orders'] })
|
||||||
|
break
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
// ignore parse errors (e.g. heartbit comments)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const messageNewHandler = handleEvent('message:new')
|
||||||
|
const orderStatusHandler = handleEvent('order:statusChanged')
|
||||||
|
const orderUpdatedHandler = handleEvent('order:updated')
|
||||||
|
const orderNewHandler = handleEvent('order:new')
|
||||||
|
|
||||||
|
es.addEventListener('message:new', messageNewHandler)
|
||||||
|
es.addEventListener('order:statusChanged', orderStatusHandler)
|
||||||
|
es.addEventListener('order:updated', orderUpdatedHandler)
|
||||||
|
es.addEventListener('order:new', orderNewHandler)
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
es.removeEventListener('message:new', messageNewHandler)
|
||||||
|
es.removeEventListener('order:statusChanged', orderStatusHandler)
|
||||||
|
es.removeEventListener('order:updated', orderUpdatedHandler)
|
||||||
|
es.removeEventListener('order:new', orderNewHandler)
|
||||||
|
es.close()
|
||||||
|
sourceRef.current = null
|
||||||
|
}
|
||||||
|
}, [token, queryClient])
|
||||||
|
|
||||||
|
return null
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user