93 lines
2.6 KiB
TypeScript
93 lines
2.6 KiB
TypeScript
import { ref, computed } from 'vue'
|
|
import { useRouter } from 'vue-router'
|
|
import { rpcClient } from '@/api/rpc-client'
|
|
|
|
export interface ReceivedMessage {
|
|
from_pubkey: string
|
|
message: string
|
|
timestamp: string
|
|
}
|
|
|
|
const MESSAGE_POLL_INTERVAL = 30000 // 30s
|
|
|
|
// Shared state (singleton) so toast works across route changes
|
|
const receivedMessages = ref<ReceivedMessage[]>([])
|
|
const lastMessageCount = ref(0)
|
|
const loadingMessages = ref(false)
|
|
const toastMessage = ref<{ show: boolean; text: string }>({ show: false, text: '' })
|
|
let pollTimer: ReturnType<typeof setInterval> | null = null
|
|
|
|
export function useMessageToast() {
|
|
const router = useRouter()
|
|
|
|
const unreadCount = computed(() =>
|
|
Math.max(0, receivedMessages.value.length - lastMessageCount.value)
|
|
)
|
|
|
|
async function loadReceivedMessages() {
|
|
loadingMessages.value = true
|
|
try {
|
|
const res = await rpcClient.getReceivedMessages()
|
|
const msgs = (res.messages || []) as ReceivedMessage[]
|
|
receivedMessages.value = msgs
|
|
// New messages since last check? (don't show toast on initial load)
|
|
if (msgs.length > lastMessageCount.value && lastMessageCount.value > 0) {
|
|
const newCount = msgs.length - lastMessageCount.value
|
|
const latest = msgs[msgs.length - 1]
|
|
toastMessage.value = {
|
|
show: true,
|
|
text: (newCount === 1 ? latest?.message : null) ?? `${newCount} new messages`,
|
|
}
|
|
lastMessageCount.value = msgs.length
|
|
} else {
|
|
lastMessageCount.value = msgs.length
|
|
}
|
|
} catch (e) {
|
|
// Stop polling on auth failure — session expired, no point retrying
|
|
if (e instanceof Error && /401|Unauthorized/i.test(e.message)) {
|
|
stopPolling()
|
|
return
|
|
}
|
|
if (import.meta.env.DEV) console.error('Failed to load messages:', e)
|
|
} finally {
|
|
loadingMessages.value = false
|
|
}
|
|
}
|
|
|
|
function startPolling() {
|
|
if (pollTimer) return
|
|
loadReceivedMessages()
|
|
pollTimer = setInterval(loadReceivedMessages, MESSAGE_POLL_INTERVAL)
|
|
}
|
|
|
|
function stopPolling() {
|
|
if (pollTimer) {
|
|
clearInterval(pollTimer)
|
|
pollTimer = null
|
|
}
|
|
}
|
|
|
|
function markAsRead() {
|
|
lastMessageCount.value = receivedMessages.value.length
|
|
}
|
|
|
|
function dismissToastAndOpenMessages() {
|
|
toastMessage.value = { show: false, text: '' }
|
|
markAsRead()
|
|
router.push({ path: '/dashboard/web5', query: { tab: 'messages' } })
|
|
}
|
|
|
|
return {
|
|
receivedMessages,
|
|
lastMessageCount,
|
|
loadingMessages,
|
|
toastMessage,
|
|
unreadCount,
|
|
loadReceivedMessages,
|
|
startPolling,
|
|
stopPolling,
|
|
markAsRead,
|
|
dismissToastAndOpenMessages,
|
|
}
|
|
}
|