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:
parent
a0ae70670d
commit
93b0e28e34
1 changed files with 82 additions and 12 deletions
|
|
@ -24,6 +24,7 @@ export interface NostrRelayConfig {
|
||||||
interface UnreadMessageData {
|
interface UnreadMessageData {
|
||||||
lastReadTimestamp: number
|
lastReadTimestamp: number
|
||||||
unreadCount: number
|
unreadCount: number
|
||||||
|
processedMessageIds: Set<string> // Track which messages we've already counted as unread
|
||||||
}
|
}
|
||||||
|
|
||||||
const UNREAD_MESSAGES_KEY = 'nostr-chat-unread-messages'
|
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 => {
|
const getUnreadData = (peerPubkey: string): UnreadMessageData => {
|
||||||
try {
|
try {
|
||||||
const stored = localStorage.getItem(`${UNREAD_MESSAGES_KEY}-${peerPubkey}`)
|
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) {
|
} catch (error) {
|
||||||
console.warn('Failed to load unread data for peer:', peerPubkey, 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
|
// Save unread message data for a peer
|
||||||
const saveUnreadData = (peerPubkey: string, data: UnreadMessageData): void => {
|
const saveUnreadData = (peerPubkey: string, data: UnreadMessageData): void => {
|
||||||
try {
|
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) {
|
} catch (error) {
|
||||||
console.warn('Failed to save unread data for peer:', peerPubkey, 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 currentTimestamp = Math.floor(Date.now() / 1000)
|
||||||
const unreadData = getUnreadData(peerPubkey)
|
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 = {
|
const updatedData: UnreadMessageData = {
|
||||||
lastReadTimestamp: currentTimestamp,
|
lastReadTimestamp: currentTimestamp,
|
||||||
unreadCount: 0
|
unreadCount: 0,
|
||||||
|
processedMessageIds: new Set() // Clear processed messages when marking as read
|
||||||
}
|
}
|
||||||
|
|
||||||
saveUnreadData(peerPubkey, updatedData)
|
saveUnreadData(peerPubkey, updatedData)
|
||||||
|
|
@ -116,9 +131,17 @@ export function useNostrChat() {
|
||||||
key.startsWith(`${UNREAD_MESSAGES_KEY}-`)
|
key.startsWith(`${UNREAD_MESSAGES_KEY}-`)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
console.log('Loading unread counts from localStorage. Found keys:', keys)
|
||||||
|
|
||||||
for (const key of keys) {
|
for (const key of keys) {
|
||||||
const peerPubkey = key.replace(`${UNREAD_MESSAGES_KEY}-`, '')
|
const peerPubkey = key.replace(`${UNREAD_MESSAGES_KEY}-`, '')
|
||||||
const unreadData = getUnreadData(peerPubkey)
|
const unreadData = getUnreadData(peerPubkey)
|
||||||
|
console.log(`Peer ${peerPubkey}:`, {
|
||||||
|
lastReadTimestamp: unreadData.lastReadTimestamp,
|
||||||
|
unreadCount: unreadData.unreadCount,
|
||||||
|
processedMessageIdsCount: unreadData.processedMessageIds.size
|
||||||
|
})
|
||||||
|
|
||||||
if (unreadData.unreadCount > 0) {
|
if (unreadData.unreadCount > 0) {
|
||||||
unreadCounts.value.set(peerPubkey, unreadData.unreadCount)
|
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
|
// Get relays from config - requires VITE_NOSTR_RELAYS to be set
|
||||||
const getRelays = (): NostrRelayConfig[] => {
|
const getRelays = (): NostrRelayConfig[] => {
|
||||||
const configuredRelays = config.nostr.relays
|
const configuredRelays = config.nostr.relays
|
||||||
|
|
@ -536,22 +589,37 @@ export function useNostrChat() {
|
||||||
if (!isSentByMe) {
|
if (!isSentByMe) {
|
||||||
const unreadData = getUnreadData(peerPubkey)
|
const unreadData = getUnreadData(peerPubkey)
|
||||||
|
|
||||||
// Check if this message is newer than the last read timestamp
|
console.log(`Processing unread message logic for ${peerPubkey}:`, {
|
||||||
if (message.created_at > unreadData.lastReadTimestamp) {
|
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 = {
|
const updatedUnreadData: UnreadMessageData = {
|
||||||
lastReadTimestamp: unreadData.lastReadTimestamp,
|
lastReadTimestamp: unreadData.lastReadTimestamp,
|
||||||
unreadCount: unreadData.unreadCount + 1
|
unreadCount: unreadData.unreadCount + 1,
|
||||||
|
processedMessageIds: unreadData.processedMessageIds
|
||||||
}
|
}
|
||||||
|
|
||||||
saveUnreadData(peerPubkey, updatedUnreadData)
|
saveUnreadData(peerPubkey, updatedUnreadData)
|
||||||
updateUnreadCount(peerPubkey, updatedUnreadData.unreadCount)
|
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 {
|
} 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 {
|
} 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
|
// Trigger callback if set
|
||||||
|
|
@ -723,6 +791,8 @@ export function useNostrChat() {
|
||||||
getUnreadCount,
|
getUnreadCount,
|
||||||
getAllUnreadCounts,
|
getAllUnreadCounts,
|
||||||
getTotalUnreadCount,
|
getTotalUnreadCount,
|
||||||
clearAllUnreadCounts
|
clearAllUnreadCounts,
|
||||||
|
clearProcessedMessageIds,
|
||||||
|
debugUnreadData
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue