feat: Enhance unread message tracking in Nostr chat

- Introduce a Set to track processed message IDs, preventing duplicate counting of unread messages.
- Update localStorage handling to serialize and deserialize processed message IDs correctly.
- Add methods to clear processed message IDs and debug unread data for specific peers, improving visibility and control over unread message state.
- Enhance logging for unread message processing to aid in debugging and understanding message flow.
This commit is contained in:
padreug 2025-08-08 22:36:23 +02:00
parent a0ae70670d
commit 93b0e28e34

View file

@ -24,6 +24,7 @@ export interface NostrRelayConfig {
interface UnreadMessageData {
lastReadTimestamp: number
unreadCount: number
processedMessageIds: Set<string> // Track which messages we've already counted as unread
}
const UNREAD_MESSAGES_KEY = 'nostr-chat-unread-messages'
@ -32,17 +33,30 @@ const UNREAD_MESSAGES_KEY = 'nostr-chat-unread-messages'
const getUnreadData = (peerPubkey: string): UnreadMessageData => {
try {
const stored = localStorage.getItem(`${UNREAD_MESSAGES_KEY}-${peerPubkey}`)
return stored ? JSON.parse(stored) : { lastReadTimestamp: 0, unreadCount: 0 }
if (stored) {
const data = JSON.parse(stored)
// Convert the array back to a Set for processedMessageIds
return {
...data,
processedMessageIds: new Set(data.processedMessageIds || [])
}
}
return { lastReadTimestamp: 0, unreadCount: 0, processedMessageIds: new Set() }
} catch (error) {
console.warn('Failed to load unread data for peer:', peerPubkey, error)
return { lastReadTimestamp: 0, unreadCount: 0 }
return { lastReadTimestamp: 0, unreadCount: 0, processedMessageIds: new Set() }
}
}
// Save unread message data for a peer
const saveUnreadData = (peerPubkey: string, data: UnreadMessageData): void => {
try {
localStorage.setItem(`${UNREAD_MESSAGES_KEY}-${peerPubkey}`, JSON.stringify(data))
// Convert Set to array for localStorage serialization
const serializableData = {
...data,
processedMessageIds: Array.from(data.processedMessageIds)
}
localStorage.setItem(`${UNREAD_MESSAGES_KEY}-${peerPubkey}`, JSON.stringify(serializableData))
} catch (error) {
console.warn('Failed to save unread data for peer:', peerPubkey, error)
}
@ -99,10 +113,11 @@ export function useNostrChat() {
const currentTimestamp = Math.floor(Date.now() / 1000)
const unreadData = getUnreadData(peerPubkey)
// Update last read timestamp and reset unread count
// Update last read timestamp, reset unread count, and clear processed message IDs
const updatedData: UnreadMessageData = {
lastReadTimestamp: currentTimestamp,
unreadCount: 0
unreadCount: 0,
processedMessageIds: new Set() // Clear processed messages when marking as read
}
saveUnreadData(peerPubkey, updatedData)
@ -116,9 +131,17 @@ export function useNostrChat() {
key.startsWith(`${UNREAD_MESSAGES_KEY}-`)
)
console.log('Loading unread counts from localStorage. Found keys:', keys)
for (const key of keys) {
const peerPubkey = key.replace(`${UNREAD_MESSAGES_KEY}-`, '')
const unreadData = getUnreadData(peerPubkey)
console.log(`Peer ${peerPubkey}:`, {
lastReadTimestamp: unreadData.lastReadTimestamp,
unreadCount: unreadData.unreadCount,
processedMessageIdsCount: unreadData.processedMessageIds.size
})
if (unreadData.unreadCount > 0) {
unreadCounts.value.set(peerPubkey, unreadData.unreadCount)
}
@ -150,6 +173,36 @@ export function useNostrChat() {
}
}
// Clear processed message IDs for a specific peer (useful for debugging)
const clearProcessedMessageIds = (peerPubkey: string): void => {
try {
const unreadData = getUnreadData(peerPubkey)
const updatedData: UnreadMessageData = {
...unreadData,
processedMessageIds: new Set()
}
saveUnreadData(peerPubkey, updatedData)
console.log(`Cleared processed message IDs for peer: ${peerPubkey}`)
} catch (error) {
console.warn('Failed to clear processed message IDs for peer:', peerPubkey, error)
}
}
// Debug function to show current state of unread data for a peer
const debugUnreadData = (peerPubkey: string): void => {
try {
const unreadData = getUnreadData(peerPubkey)
console.log(`Debug unread data for ${peerPubkey}:`, {
lastReadTimestamp: unreadData.lastReadTimestamp,
unreadCount: unreadData.unreadCount,
processedMessageIds: Array.from(unreadData.processedMessageIds),
processedMessageIdsCount: unreadData.processedMessageIds.size
})
} catch (error) {
console.warn('Failed to debug unread data for peer:', peerPubkey, error)
}
}
// Get relays from config - requires VITE_NOSTR_RELAYS to be set
const getRelays = (): NostrRelayConfig[] => {
const configuredRelays = config.nostr.relays
@ -536,22 +589,37 @@ export function useNostrChat() {
if (!isSentByMe) {
const unreadData = getUnreadData(peerPubkey)
// Check if this message is newer than the last read timestamp
if (message.created_at > unreadData.lastReadTimestamp) {
console.log(`Processing unread message logic for ${peerPubkey}:`, {
messageId: event.id,
messageTimestamp: message.created_at,
lastReadTimestamp: unreadData.lastReadTimestamp,
currentUnreadCount: unreadData.unreadCount,
alreadyProcessed: unreadData.processedMessageIds.has(event.id),
processedMessageIdsCount: unreadData.processedMessageIds.size
})
// Check if this message is newer than the last read timestamp AND we haven't already counted it
if (message.created_at > unreadData.lastReadTimestamp && !unreadData.processedMessageIds.has(event.id)) {
// Add this message ID to the processed set
unreadData.processedMessageIds.add(event.id)
const updatedUnreadData: UnreadMessageData = {
lastReadTimestamp: unreadData.lastReadTimestamp,
unreadCount: unreadData.unreadCount + 1
unreadCount: unreadData.unreadCount + 1,
processedMessageIds: unreadData.processedMessageIds
}
saveUnreadData(peerPubkey, updatedUnreadData)
updateUnreadCount(peerPubkey, updatedUnreadData.unreadCount)
console.log(`New unread message from ${peerPubkey}. Total unread: ${updatedUnreadData.unreadCount}`)
console.log(`✅ New unread message from ${peerPubkey}. Total unread: ${updatedUnreadData.unreadCount}`)
} else if (unreadData.processedMessageIds.has(event.id)) {
console.log(`⏭️ Message ${event.id} from ${peerPubkey} already counted as unread. Skipping.`)
} else {
console.log(`Message from ${peerPubkey} is older than last read timestamp. Skipping unread count.`)
console.log(`Message from ${peerPubkey} is older than last read timestamp. Skipping unread count.`)
}
} else {
console.log(`Message from ${peerPubkey} was sent by current user. Skipping unread count.`)
console.log(`📤 Message from ${peerPubkey} was sent by current user. Skipping unread count.`)
}
// Trigger callback if set
@ -723,6 +791,8 @@ export function useNostrChat() {
getUnreadCount,
getAllUnreadCounts,
getTotalUnreadCount,
clearAllUnreadCounts
clearAllUnreadCounts,
clearProcessedMessageIds,
debugUnreadData
}
}