feat: Integrate Nostr chat preloader for improved chat data handling

- Introduce a new composable, useNostrChatPreloader, to manage chat data preloading, including peer loading and subscription for notifications.
- Update ChatComponent to utilize the preloader, ensuring chat data is ready before connecting.
- Enhance Navbar to display unread message counts with notification badges for better user experience.
- Refactor App.vue to trigger both market and chat preloading upon successful login, streamlining the user experience.
This commit is contained in:
padreug 2025-08-09 14:58:35 +02:00
parent b0101915c7
commit 855a003962
4 changed files with 233 additions and 133 deletions

View file

@ -376,9 +376,8 @@ import { Badge } from '@/components/ui/badge'
import { ScrollArea } from '@/components/ui/scroll-area'
import { Avatar, AvatarImage, AvatarFallback } from '@/components/ui/avatar'
import { useNostrChat } from '@/composables/useNostrChat'
import { useNostrChatPreloader } from '@/composables/useNostrChatPreloader'
import { useFuzzySearch } from '@/composables/useFuzzySearch'
import { getAuthToken } from '@/lib/config/lnbits'
import { config } from '@/lib/config'
// Types
interface Peer {
@ -387,12 +386,15 @@ interface Peer {
pubkey: string
}
// Initialize preloader and chat
const chatPreloader = useNostrChatPreloader()
// State
const peers = ref<Peer[]>([])
const peers = computed(() => chatPreloader.peers.value)
const selectedPeer = ref<Peer | null>(null)
const messageInput = ref('')
const isLoading = ref(false)
const isLoading = computed(() => chatPreloader.isPreloading.value)
const showChat = ref(false)
const messagesScrollArea = ref<HTMLElement | null>(null)
const messagesContainer = ref<HTMLElement | null>(null)
@ -408,7 +410,6 @@ const {
connect,
disconnect,
subscribeToPeer,
subscribeToPeerForNotifications,
sendMessage: sendNostrMessage,
onMessageAdded,
markMessagesAsRead,
@ -499,106 +500,12 @@ const goBackToPeers = () => {
}
// Methods
const loadPeers = async () => {
try {
isLoading.value = true
const authToken = getAuthToken()
if (!authToken) {
console.warn('No authentication token found - cannot load peers')
return
}
const API_BASE_URL = config.api.baseUrl || 'http://localhost:5006'
const response = await fetch(`${API_BASE_URL}/api/v1/auth/nostr/pubkeys`, {
headers: {
'Authorization': `Bearer ${authToken}`,
'Content-Type': 'application/json'
}
})
console.log('Peers API Response status:', response.status)
if (!response.ok) {
const errorText = await response.text()
console.error('Peers API Error:', response.status, errorText)
throw new Error(`Failed to load peers: ${response.status}`)
}
const responseText = await response.text()
console.log('Peers API Response text:', responseText)
try {
const data = JSON.parse(responseText)
peers.value = data.map((peer: any) => ({
user_id: peer.user_id,
username: peer.username,
pubkey: peer.pubkey
}))
console.log(`Loaded ${peers.value.length} peers`)
// Note: Subscriptions will be handled by the isConnected watcher
} catch (parseError) {
console.error('JSON Parse Error for peers:', parseError)
console.error('Response was:', responseText)
throw new Error('Invalid JSON response from peers API')
}
} catch (error) {
console.error('Failed to load peers:', error)
} finally {
isLoading.value = false
}
}
// Subscribe to all peers for notifications (without loading full message history)
const subscribeToAllPeers = async () => {
if (!peers.value.length) {
console.log('No peers to subscribe to')
return
}
// Wait for connection to be established
if (!isConnected.value) {
console.log('Waiting for connection to be established before subscribing to peers')
// Wait a bit for connection to establish
await new Promise(resolve => setTimeout(resolve, 1000))
if (!isConnected.value) {
console.warn('Still not connected, skipping peer subscriptions')
return
}
}
console.log(`Subscribing to ${peers.value.length} peers for notifications`)
console.log('Peers to subscribe to:', peers.value.map(p => ({ pubkey: p.pubkey, username: p.username })))
let successCount = 0
let errorCount = 0
for (const peer of peers.value) {
try {
console.log(`Attempting to subscribe to peer: ${peer.pubkey} (${peer.username})`)
// Subscribe to peer for notifications only (don't load full history)
const subscription = await subscribeToPeerForNotifications(peer.pubkey)
if (subscription) {
console.log(`Successfully subscribed to notifications for peer: ${peer.pubkey}`)
successCount++
} else {
console.warn(`Failed to create subscription for peer: ${peer.pubkey}`)
errorCount++
}
} catch (error) {
console.warn(`Failed to subscribe to peer ${peer.pubkey}:`, error)
errorCount++
}
}
console.log(`Subscription summary: ${successCount} successful, ${errorCount} failed`)
}
const refreshPeers = () => {
loadPeers()
const refreshPeers = async () => {
console.log('Refreshing peers and chat data...')
await chatPreloader.preloadChat()
}
const selectPeer = async (peer: Peer) => {
@ -693,21 +600,22 @@ onMounted(async () => {
}
}
console.log('Starting connection and peer loading...')
await connect()
console.log('Connection established, loading peers...')
await loadPeers()
console.log('Peers loaded, checking if we should subscribe...')
console.log('Chat component mounted - checking if preloader has data...')
// If we're connected and have peers, subscribe to them
if (isConnected.value && peers.value.length > 0) {
console.log('Connection and peers ready, subscribing to all peers for notifications')
await subscribeToAllPeers()
// If chat is already preloaded, we're good to go
if (chatPreloader.isPreloaded.value) {
console.log('Chat data was preloaded, connecting to chat...')
await connect()
console.log('Chat connected successfully')
} else if (!chatPreloader.isPreloading.value) {
// If not preloaded and not currently preloading, trigger preload
console.log('Chat data not preloaded, triggering preload...')
await chatPreloader.preloadChat()
await connect()
} else {
console.log('Not ready to subscribe yet:', {
isConnected: isConnected.value,
peerCount: peers.value.length
})
// Currently preloading, just connect
console.log('Chat is currently preloading, just connecting...')
await connect()
}
})
@ -716,13 +624,10 @@ onUnmounted(() => {
disconnect()
})
// Watch for connection state changes and subscribe to peers when connected
// Watch for connection state changes
watch(isConnected, async (connected, prevConnected) => {
console.log('Connection state changed:', { connected, prevConnected, peerCount: peers.value.length })
if (connected && peers.value.length > 0 && !prevConnected) {
console.log('Connection established and peers available, subscribing to peers for notifications')
await subscribeToAllPeers()
}
// Note: Peer subscriptions are handled by the preloader
})
// Watch for new messages and scroll to bottom