feat: Implement sorting of peers by latest message timestamp and unread status in Nostr chat

- Introduce a computed property to sort peers based on the latest message timestamp and unread message count, enhancing the user experience by prioritizing relevant conversations.
- Add methods to track and retrieve the latest message timestamp for each peer, ensuring accurate sorting.
- Update the ChatComponent to utilize the new sorting logic, improving the display of peers in the chat interface.

refactor: Reorganize fuzzy search and mobile detection logic in ChatComponent

- Move fuzzy search implementation and mobile detection methods to improve code clarity and maintainability.
- Ensure consistent functionality for searching peers by username or pubkey with typo tolerance.
- Maintain mobile navigation logic for better user experience on smaller devices.
This commit is contained in:
padreug 2025-08-08 23:19:35 +02:00
parent 91e9756bf0
commit b0101915c7
2 changed files with 91 additions and 23 deletions

View file

@ -401,6 +401,62 @@ const scrollTarget = ref<HTMLElement | null>(null)
// Mobile detection // Mobile detection
const isMobile = ref(false) const isMobile = ref(false)
// Nostr chat composable
const {
isConnected,
messages,
connect,
disconnect,
subscribeToPeer,
subscribeToPeerForNotifications,
sendMessage: sendNostrMessage,
onMessageAdded,
markMessagesAsRead,
getUnreadCount,
getTotalUnreadCount,
getLatestMessageTimestamp
} = useNostrChat()
// Computed
const currentMessages = computed(() => {
if (!selectedPeer.value) return []
return messages.value.get(selectedPeer.value.pubkey) || []
})
// Sort peers by latest message timestamp (newest first) and unread status
const sortedPeers = computed(() => {
const sorted = [...peers.value].sort((a, b) => {
const aTimestamp = getLatestMessageTimestamp(a.pubkey)
const bTimestamp = getLatestMessageTimestamp(b.pubkey)
const aUnreadCount = getUnreadCount(a.pubkey)
const bUnreadCount = getUnreadCount(b.pubkey)
// First, sort by unread count (peers with unread messages appear first)
if (aUnreadCount > 0 && bUnreadCount === 0) return -1
if (aUnreadCount === 0 && bUnreadCount > 0) return 1
// Then, sort by latest message timestamp (newest first)
if (aTimestamp !== bTimestamp) {
return bTimestamp - aTimestamp
}
// Finally, sort alphabetically by username for peers with same timestamp
return (a.username || '').localeCompare(b.username || '')
})
// Debug logging (only in development)
if (process.env.NODE_ENV === 'development' && sorted.length > 0) {
console.log('Sorted peers:', sorted.map(p => ({
username: p.username,
pubkey: p.pubkey.slice(0, 8) + '...',
latestTimestamp: getLatestMessageTimestamp(p.pubkey),
unreadCount: getUnreadCount(p.pubkey)
})))
}
return sorted
})
// Fuzzy search for peers // Fuzzy search for peers
// This integrates the useFuzzySearch composable to provide intelligent search functionality // This integrates the useFuzzySearch composable to provide intelligent search functionality
// for finding peers by username or pubkey with typo tolerance and scoring // for finding peers by username or pubkey with typo tolerance and scoring
@ -410,7 +466,7 @@ const {
isSearching, isSearching,
resultCount, resultCount,
clearSearch clearSearch
} = useFuzzySearch(peers, { } = useFuzzySearch(sortedPeers, {
fuseOptions: { fuseOptions: {
keys: [ keys: [
{ name: 'username', weight: 0.7 }, // Username has higher weight for better UX { name: 'username', weight: 0.7 }, // Username has higher weight for better UX
@ -442,27 +498,6 @@ const goBackToPeers = () => {
selectedPeer.value = null selectedPeer.value = null
} }
// Nostr chat composable
const {
isConnected,
messages,
connect,
disconnect,
subscribeToPeer,
subscribeToPeerForNotifications,
sendMessage: sendNostrMessage,
onMessageAdded,
markMessagesAsRead,
getUnreadCount,
getTotalUnreadCount
} = useNostrChat()
// Computed
const currentMessages = computed(() => {
if (!selectedPeer.value) return []
return messages.value.get(selectedPeer.value.pubkey) || []
})
// Methods // Methods
const loadPeers = async () => { const loadPeers = async () => {
try { try {

View file

@ -75,6 +75,9 @@ export function useNostrChat() {
// Reactive unread counts // Reactive unread counts
const unreadCounts = ref<Map<string, number>>(new Map()) const unreadCounts = ref<Map<string, number>>(new Map())
// Track latest message timestamp for each peer (for sorting)
const latestMessageTimestamps = ref<Map<string, number>>(new Map())
// Computed // Computed
const isLoggedIn = computed(() => !!currentUser.value) const isLoggedIn = computed(() => !!currentUser.value)
@ -97,6 +100,26 @@ export function useNostrChat() {
return total return total
} }
// Get latest message timestamp for a peer
const getLatestMessageTimestamp = (peerPubkey: string): number => {
return latestMessageTimestamps.value.get(peerPubkey) || 0
}
// Get all latest message timestamps
const getAllLatestMessageTimestamps = (): Map<string, number> => {
return new Map(latestMessageTimestamps.value)
}
// Update latest message timestamp for a peer
const updateLatestMessageTimestamp = (peerPubkey: string, timestamp: number): void => {
const currentLatest = latestMessageTimestamps.value.get(peerPubkey) || 0
if (timestamp > currentLatest) {
latestMessageTimestamps.value.set(peerPubkey, timestamp)
// Force reactivity
latestMessageTimestamps.value = new Map(latestMessageTimestamps.value)
}
}
// 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 => {
if (count > 0) { if (count > 0) {
@ -584,6 +607,9 @@ export function useNostrChat() {
// Force reactivity by triggering a change // Force reactivity by triggering a change
messages.value = new Map(messages.value) messages.value = new Map(messages.value)
// Update latest message timestamp for this peer (for sorting)
updateLatestMessageTimestamp(peerPubkey, message.created_at)
// Track unread messages (only for received messages, not sent ones) // Track unread messages (only for received messages, not sent ones)
if (!isSentByMe) { if (!isSentByMe) {
const unreadData = getUnreadData(peerPubkey) const unreadData = getUnreadData(peerPubkey)
@ -748,6 +774,9 @@ export function useNostrChat() {
// Force reactivity by triggering a change // Force reactivity by triggering a change
messages.value = new Map(messages.value) messages.value = new Map(messages.value)
// Update latest message timestamp for this peer (for sorting)
updateLatestMessageTimestamp(peerPubkey, message.created_at)
// Trigger callback if set // Trigger callback if set
if (onMessageAdded.value) { if (onMessageAdded.value) {
onMessageAdded.value(peerPubkey) onMessageAdded.value(peerPubkey)
@ -792,6 +821,10 @@ export function useNostrChat() {
getTotalUnreadCount, getTotalUnreadCount,
clearAllUnreadCounts, clearAllUnreadCounts,
clearProcessedMessageIds, clearProcessedMessageIds,
debugUnreadData debugUnreadData,
// Timestamp methods (for sorting)
getLatestMessageTimestamp,
getAllLatestMessageTimestamps
} }
} }