Files
SkinbaseNova/resources/js/components/social/MessageInboxBadge.jsx

89 lines
2.4 KiB
JavaScript

import React, { useEffect, useMemo, useState } from 'react'
import { getEcho } from '../../bootstrap'
export default function MessageInboxBadge({ initialUnreadCount = 0, userId = null, href = '/messages' }) {
const [unreadCount, setUnreadCount] = useState(Math.max(0, Number(initialUnreadCount || 0)))
useEffect(() => {
let cancelled = false
const loadUnreadState = async () => {
try {
const response = await fetch('/api/messages/conversations', {
headers: { Accept: 'application/json' },
credentials: 'same-origin',
})
if (!response.ok) {
throw new Error('Failed to load unread conversations')
}
const payload = await response.json()
if (cancelled) {
return
}
if (cancelled) {
return
}
const nextUnreadTotal = Number(payload?.summary?.unread_total)
if (Number.isFinite(nextUnreadTotal)) {
setUnreadCount(Math.max(0, nextUnreadTotal))
}
} catch {
// Keep server-rendered count if bootstrap fetch fails.
}
}
loadUnreadState()
return () => {
cancelled = true
}
}, [])
useEffect(() => {
if (!userId) {
return undefined
}
const echo = getEcho()
if (!echo) {
return undefined
}
const channel = echo.private(`user.${userId}`)
const handleConversationUpdated = (payload) => {
const nextUnreadTotal = Number(payload?.summary?.unread_total)
if (Number.isFinite(nextUnreadTotal)) {
setUnreadCount(Math.max(0, nextUnreadTotal))
}
}
channel.listen('.conversation.updated', handleConversationUpdated)
return () => {
channel.stopListening('.conversation.updated', handleConversationUpdated)
echo.leaveChannel(`private-user.${userId}`)
}
}, [userId])
return (
<a
href={href}
className="relative w-10 h-10 inline-flex items-center justify-center rounded-lg hover:bg-white/5"
title="Messages"
>
<svg className="w-5 h-5" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2">
<path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z" />
</svg>
{unreadCount > 0 ? (
<span className="absolute -bottom-1 right-0 text-[11px] tabular-nums px-1.5 py-0.5 rounded bg-red-700/70 text-white border border-sb-line">
{unreadCount > 99 ? '99+' : unreadCount}
</span>
) : null}
</a>
)
}