import { useCallback } from 'react'; import { useLocalStorage } from '@/hooks/useLocalStorage'; import { useCurrentUser } from '@/hooks/useCurrentUser'; /** * Per-conversation "last read" timestamps (unix seconds) for direct messages, * stored per-pubkey in localStorage. A conversation counts as unread when its * latest message (from the OTHER person) is newer than this timestamp. * * Local-only by design: this is a lightweight "have I seen it" convenience, not * a synced read-receipt broadcast to anyone. Nothing here leaves the device. * * NIP-17 note: gift-wrapped DMs are decrypted client-side, so we compare against * the message's own `created_at`. (Gift-wrap timestamps can be slightly fuzzed, * but the inner rumor's `created_at` — what we store on DirectMessage — is the * sender's real time, so this comparison is reliable for read state.) */ export function useDMRead() { const { user } = useCurrentUser(); const key = user ? `dm-last-read:${user.pubkey}` : 'dm-last-read:anon'; const [map, setMap] = useLocalStorage>(key, {}); /** Mark a conversation (keyed by the other party's pubkey) read as of `ts`. */ const markRead = useCallback( (conversationWith: string, ts?: number) => { const at = ts ?? Math.floor(Date.now() / 1000); setMap((prev) => { const key = conversationWith.toLowerCase(); if ((prev[key] ?? 0) >= at) return prev; // never move backwards return { ...prev, [key]: at }; }); }, [setMap], ); /** Last-read unix seconds for a conversation, or 0 if never opened. */ const getLastRead = useCallback( (conversationWith: string) => map[conversationWith.toLowerCase()] ?? 0, [map], ); return { lastReadMap: map, markRead, getLastRead }; }