feat: Enhance Nostr chat debugging and unread message management

- Introduce debug functions in ChatComponent for resetting unread counts and displaying unread message details for specific peers, improving troubleshooting capabilities.
- Update unread count management in useNostrChat to ensure accurate tracking and storage of unread messages, including recalculating counts based on message timestamps.
- Implement logic to prevent duplicate message processing and enhance overall message handling efficiency.
This commit is contained in:
padreug 2025-08-10 17:18:36 +02:00
parent 94c85e3a0e
commit de918419fa
2 changed files with 176 additions and 31 deletions

View file

@ -412,7 +412,10 @@ const {
markMessagesAsRead, markMessagesAsRead,
getUnreadCount, getUnreadCount,
totalUnreadCount, totalUnreadCount,
getLatestMessageTimestamp getLatestMessageTimestamp,
clearAllUnreadCounts,
debugUnreadData,
getUnreadData
} = nostrChat } = nostrChat
// Computed // Computed
@ -602,6 +605,61 @@ const getPeerInitials = (peer: Peer) => {
return peer.pubkey.slice(0, 2).toUpperCase() return peer.pubkey.slice(0, 2).toUpperCase()
} }
// Debug function to reset unread counts (can be called from browser console)
const debugResetUnreadCounts = () => {
console.log('🔧 Debug: Resetting all unread counts...')
clearAllUnreadCounts()
console.log('🔧 Debug: Unread counts reset. You may need to refresh the page to see the changes.')
}
// Debug function to show unread count details for a specific peer
const debugPeerUnreadCounts = (peerPubkey?: string) => {
if (peerPubkey) {
console.log(`🔧 Debug: Unread count details for peer ${peerPubkey}:`)
debugUnreadData(peerPubkey)
console.log(`Current unread count: ${getUnreadCount(peerPubkey)}`)
// Show timestamp details for debugging
const peerMessages = messages.value.get(peerPubkey) || []
const unreadData = getUnreadData(peerPubkey)
console.log(`Last read timestamp: ${unreadData.lastReadTimestamp} (${new Date(unreadData.lastReadTimestamp * 1000).toLocaleString()})`)
console.log(`Total messages: ${peerMessages.length}`)
// Show messages that would count as unread
const unreadMessages = peerMessages.filter(msg => !msg.sent && msg.created_at > unreadData.lastReadTimestamp)
console.log(`Messages that count as unread: ${unreadMessages.length}`)
unreadMessages.forEach(msg => {
console.log(` - ${msg.content.substring(0, 50)}... (${new Date(msg.created_at * 1000).toLocaleString()})`)
})
} else {
console.log('🔧 Debug: All unread counts:')
console.log('Total unread count:', totalUnreadCount.value)
// Simplified peer iteration to avoid TypeScript issues
const peerList = peers.value
if (peerList && peerList.length > 0) {
peerList.forEach((peer: any) => {
const count = getUnreadCount(peer.pubkey)
if (count > 0) {
const name = peer.username || peer.pubkey.slice(0, 8)
console.log(`${name}: ${count}`)
}
})
}
}
}
// Make debug functions available globally for browser console access
if (typeof window !== 'undefined') {
// Use type assertion to avoid TypeScript errors
const globalWindow = window as any
globalWindow.debugResetUnreadCounts = debugResetUnreadCounts
globalWindow.debugPeerUnreadCounts = debugPeerUnreadCounts
console.log('🔧 Debug functions available:')
console.log(' - debugResetUnreadCounts() - reset all unread counts')
console.log(' - debugPeerUnreadCounts(peerPubkey?) - show unread count details')
}
// Lifecycle // Lifecycle
onMounted(async () => { onMounted(async () => {
checkMobile() checkMobile()

View file

@ -189,43 +189,88 @@ export function useNostrChat() {
// Update unread count for a peer // Update unread count for a peer
const updateUnreadCount = (peerPubkey: string, count: number): void => { const updateUnreadCount = (peerPubkey: string, count: number): void => {
const current = unreadCounts.value.get(peerPubkey) || 0 if (count > 0) {
unreadCounts.value.set(peerPubkey, current + count) unreadCounts.value.set(peerPubkey, count)
} else {
unreadCounts.value.delete(peerPubkey)
}
// Force reactivity
unreadCounts.value = new Map(unreadCounts.value)
// Save to localStorage // Save to localStorage
const unreadData = getUnreadData(peerPubkey) const unreadData = getUnreadData(peerPubkey)
unreadData.unreadCount = current + count unreadData.unreadCount = count
saveUnreadData(peerPubkey, unreadData) saveUnreadData(peerPubkey, unreadData)
} }
// Mark messages as read for a peer // Mark messages as read for a peer
const markMessagesAsRead = (peerPubkey: string): void => { const markMessagesAsRead = (peerPubkey: string): void => {
const current = unreadCounts.value.get(peerPubkey) || 0 const currentTimestamp = Math.floor(Date.now() / 1000)
if (current > 0) {
unreadCounts.value.set(peerPubkey, 0)
// Save to localStorage // Update last read timestamp, reset unread count, and clear processed message IDs
const unreadData = getUnreadData(peerPubkey) const updatedData: UnreadMessageData = {
unreadData.unreadCount = 0 lastReadTimestamp: currentTimestamp,
unreadData.lastReadTimestamp = Date.now() unreadCount: 0,
saveUnreadData(peerPubkey, unreadData) processedMessageIds: new Set() // Clear processed messages when marking as read
} }
saveUnreadData(peerPubkey, updatedData)
updateUnreadCount(peerPubkey, 0)
// Also clear any processed message IDs from the global set that might be from this peer
// This helps prevent duplicate message issues
console.log(`Marked messages as read for peer: ${peerPubkey}`)
} }
// Load unread counts from localStorage // Load unread counts from localStorage
// const loadUnreadCounts = (): void => { const loadUnreadCounts = (): void => {
// try { try {
// // Load unread counts for all peers we have messages for const keys = Object.keys(localStorage).filter(key =>
// for (const [peerPubkey] of messages.value) { key.startsWith(`${UNREAD_MESSAGES_KEY}-`)
// const unreadData = getUnreadData(peerPubkey) )
// if (unreadData.unreadCount > 0) {
// unreadCounts.value.set(peerPubkey, unreadData.unreadCount) console.log('Loading unread counts from localStorage. Found keys:', keys)
// }
// } for (const key of keys) {
// } catch (error) { const peerPubkey = key.replace(`${UNREAD_MESSAGES_KEY}-`, '')
// console.warn('Failed to load unread counts:', error) const unreadData = getUnreadData(peerPubkey)
// }
// } // Recalculate unread count based on actual messages and lastReadTimestamp
const peerMessages = messages.value.get(peerPubkey) || []
let actualUnreadCount = 0
for (const message of peerMessages) {
// Only count messages not sent by us and created after last read timestamp
if (!message.sent && message.created_at > unreadData.lastReadTimestamp) {
actualUnreadCount++
}
}
// Update the stored count to match reality
if (actualUnreadCount !== unreadData.unreadCount) {
console.log(`Correcting unread count for peer ${peerPubkey}: stored=${unreadData.unreadCount}, actual=${actualUnreadCount}`)
unreadData.unreadCount = actualUnreadCount
saveUnreadData(peerPubkey, unreadData)
}
console.log(`Peer ${peerPubkey}:`, {
lastReadTimestamp: unreadData.lastReadTimestamp,
unreadCount: unreadData.unreadCount,
processedMessageIdsCount: unreadData.processedMessageIds.size,
messageCount: peerMessages.length
})
if (actualUnreadCount > 0) {
unreadCounts.value.set(peerPubkey, actualUnreadCount)
}
}
} catch (error) {
console.warn('Failed to load unread counts:', error)
}
}
// Initialize unread counts on startup
loadUnreadCounts()
// Clear unread count for a peer // Clear unread count for a peer
// const clearUnreadCount = (peerPubkey: string): void => { // const clearUnreadCount = (peerPubkey: string): void => {
@ -247,6 +292,22 @@ export function useNostrChat() {
unreadData.unreadCount = 0 unreadData.unreadCount = 0
saveUnreadData(peerPubkey, unreadData) saveUnreadData(peerPubkey, unreadData)
} }
// Also clear from localStorage for all stored keys
try {
const keys = Object.keys(localStorage).filter(key =>
key.startsWith(`${UNREAD_MESSAGES_KEY}-`)
)
for (const key of keys) {
const peerPubkey = key.replace(`${UNREAD_MESSAGES_KEY}-`, '')
const unreadData = getUnreadData(peerPubkey)
unreadData.unreadCount = 0
saveUnreadData(peerPubkey, unreadData)
}
} catch (error) {
console.warn('Failed to clear unread counts from localStorage:', error)
}
} }
// Clear processed message IDs for a peer // Clear processed message IDs for a peer
@ -509,6 +570,12 @@ export function useNostrChat() {
return return
} }
// Check if we've already processed this message to prevent duplicates
if (processedMessageIds.value.has(event.id)) {
console.log('Message already processed, skipping:', event.id)
return
}
try { try {
// For NIP-04 direct messages, always use peerPubkey as the second argument // For NIP-04 direct messages, always use peerPubkey as the second argument
// This is the public key of the other party in the conversation // This is the public key of the other party in the conversation
@ -550,17 +617,36 @@ export function useNostrChat() {
} }
messages.value.get(peerPubkey)!.push(message) messages.value.get(peerPubkey)!.push(message)
// Mark as unread if not sent by us // Mark as unread if not sent by us AND created after last read timestamp
if (!isSentByMe) { if (!isSentByMe) {
// For now, just update the unread count const unreadData = getUnreadData(peerPubkey)
// TODO: Implement proper unread message tracking
// Only count as unread if message was created after last read timestamp
if (event.created_at > unreadData.lastReadTimestamp) {
// Increment the unread count for this peer
const currentCount = unreadCounts.value.get(peerPubkey) || 0 const currentCount = unreadCounts.value.get(peerPubkey) || 0
updateUnreadCount(peerPubkey, currentCount + 1) const newCount = currentCount + 1
unreadCounts.value.set(peerPubkey, newCount)
// Force reactivity
unreadCounts.value = new Map(unreadCounts.value)
// Save to localStorage
unreadData.unreadCount = newCount
saveUnreadData(peerPubkey, unreadData)
console.log(`Message marked as unread for peer ${peerPubkey}. Count: ${newCount}`)
} else {
console.log(`Message not marked as unread (created before last read): ${event.created_at} <= ${unreadData.lastReadTimestamp}`)
}
} }
// Update latest message timestamp // Update latest message timestamp
updateLatestMessageTimestamp(peerPubkey, event.created_at) updateLatestMessageTimestamp(peerPubkey, event.created_at)
// Mark this message as processed to prevent duplicates
processedMessageIds.value.add(event.id)
// Trigger callback if set // Trigger callback if set
if (onMessageAdded.value) { if (onMessageAdded.value) {
onMessageAdded.value(peerPubkey) onMessageAdded.value(peerPubkey)
@ -813,6 +899,7 @@ export function useNostrChat() {
clearAllUnreadCounts, clearAllUnreadCounts,
clearProcessedMessageIds, clearProcessedMessageIds,
debugUnreadData, debugUnreadData,
getUnreadData,
// Timestamp methods (for sorting) // Timestamp methods (for sorting)
getLatestMessageTimestamp, getLatestMessageTimestamp,