Files
SkinbaseNova/resources/js/components/social/MessageInboxBadge.jsx
2026-03-28 19:15:39 +01:00

89 lines
2.5 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 inline-flex h-9 w-9 lg:h-10 lg:w-10 items-center justify-center rounded-lg hover:bg-white/5"
title="Messages"
>
<svg className="h-[18px] w-[18px] lg:h-5 lg:w-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 rounded border border-sb-line bg-red-700/70 px-1 py-0 text-[10px] tabular-nums text-white lg:px-1.5 lg:py-0.5 lg:text-[11px]">
{unreadCount > 99 ? '99+' : unreadCount}
</span>
) : null}
</a>
)
}