- presence.ts: tambah notifSubs (ADMIN+DEVELOPER) dan broadcastNotification - app.ts: broadcast new_bug event setelah bug dibuat, update WS handler - usePresence: terima callback onNewBug, expose NewBugPayload type - DashboardLayout: pasang usePresence, tampilkan Mantine notification saat bug baru masuk
55 lines
1.5 KiB
TypeScript
55 lines
1.5 KiB
TypeScript
import { useEffect, useRef, useState } from 'react'
|
|
import { useSession } from './useAuth'
|
|
|
|
export interface NewBugPayload {
|
|
id: string
|
|
description: string
|
|
appId: string | null
|
|
source: string
|
|
affectedVersion: string
|
|
createdAt: string
|
|
}
|
|
|
|
export function usePresence(onNewBug?: (bug: NewBugPayload) => void) {
|
|
const { data } = useSession()
|
|
const [onlineUserIds, setOnlineUserIds] = useState<string[]>([])
|
|
const wsRef = useRef<WebSocket | null>(null)
|
|
const reconnectTimer = useRef<ReturnType<typeof setTimeout> | undefined>(undefined)
|
|
const onNewBugRef = useRef(onNewBug)
|
|
onNewBugRef.current = onNewBug
|
|
|
|
useEffect(() => {
|
|
if (!data?.user) return
|
|
|
|
function connect() {
|
|
const proto = location.protocol === 'https:' ? 'wss' : 'ws'
|
|
const ws = new WebSocket(`${proto}://${location.host}/ws/presence`)
|
|
wsRef.current = ws
|
|
|
|
ws.onmessage = (e) => {
|
|
const msg = JSON.parse(e.data)
|
|
if (msg.type === 'presence') setOnlineUserIds(msg.online)
|
|
if (msg.type === 'new_bug') onNewBugRef.current?.(msg.bug)
|
|
}
|
|
ws.onclose = () => {
|
|
wsRef.current = null
|
|
reconnectTimer.current = setTimeout(connect, 3000)
|
|
}
|
|
ws.onerror = () => ws.close()
|
|
}
|
|
|
|
connect()
|
|
|
|
return () => {
|
|
clearTimeout(reconnectTimer.current)
|
|
if (wsRef.current) {
|
|
wsRef.current.onclose = null
|
|
wsRef.current.close()
|
|
wsRef.current = null
|
|
}
|
|
}
|
|
}, [data?.user?.id, data?.user])
|
|
|
|
return { onlineUserIds }
|
|
}
|