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

@ -0,0 +1,166 @@
import { ref, readonly } from 'vue'
import { useNostrChat } from './useNostrChat'
import { getAuthToken } from '@/lib/config/lnbits'
import { config } from '@/lib/config'
export interface Peer {
user_id: string
username: string
pubkey: string
}
export function useNostrChatPreloader() {
const isPreloading = ref(false)
const isPreloaded = ref(false)
const preloadError = ref<string | null>(null)
const peers = ref<Peer[]>([])
const chat = useNostrChat()
const preloadChat = async () => {
// Don't preload if already done or currently preloading
if (isPreloaded.value || isPreloading.value) {
return
}
try {
isPreloading.value = true
preloadError.value = null
console.log('Preloading chat data...')
// Connect to chat
await chat.connect()
// Load peers
await loadPeers()
// Subscribe to all peers for notifications (without loading full history)
if (peers.value.length > 0) {
console.log(`Subscribing to ${peers.value.length} peers for notifications`)
await subscribeToAllPeersForNotifications()
}
isPreloaded.value = true
console.log('Chat data preloaded successfully')
} catch (error) {
console.error('Failed to preload chat:', error)
preloadError.value = error instanceof Error ? error.message : 'Failed to preload chat'
// Don't throw error, let the UI handle it gracefully
} finally {
isPreloading.value = false
}
}
const loadPeers = async () => {
try {
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'
}
})
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()
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 for chat preloader`)
} catch (parseError) {
console.error('JSON Parse Error for peers:', parseError)
throw new Error('Invalid JSON response from peers API')
}
} catch (error) {
console.error('Failed to load peers in preloader:', error)
throw error
}
}
// Subscribe to all peers for notifications (without loading full message history)
const subscribeToAllPeersForNotifications = async () => {
if (!peers.value.length) {
console.log('No peers to subscribe to')
return
}
// Wait for connection to be established
if (!chat.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 (!chat.isConnected.value) {
console.warn('Still not connected, skipping peer subscriptions')
return
}
}
console.log(`Subscribing to ${peers.value.length} peers for notifications`)
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 chat.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(`Chat preloader subscription summary: ${successCount} successful, ${errorCount} failed`)
}
const resetPreload = () => {
isPreloaded.value = false
preloadError.value = null
peers.value = []
}
return {
isPreloading: readonly(isPreloading),
isPreloaded: readonly(isPreloaded),
preloadError: readonly(preloadError),
peers: readonly(peers),
preloadChat,
resetPreload,
// Expose chat composable methods for global access
getTotalUnreadCount: chat.getTotalUnreadCount,
getUnreadCount: chat.getUnreadCount,
getAllUnreadCounts: chat.getAllUnreadCounts,
markMessagesAsRead: chat.markMessagesAsRead,
clearAllUnreadCounts: chat.clearAllUnreadCounts
}
}