Enhance market module with new chat and events features

- Introduce chat module with components, services, and composables for real-time messaging.
- Implement events module with API service, components, and ticket purchasing functionality.
- Update app configuration to include new modules and their respective settings.
- Refactor existing components to integrate with the new chat and events features.
- Enhance market store and services to support new functionalities and improve order management.
- Update routing to accommodate new views for chat and events, ensuring seamless navigation.
This commit is contained in:
padreug 2025-09-05 00:01:40 +02:00
parent 519a9003d4
commit e40ac91417
46 changed files with 6305 additions and 3264 deletions

View file

@ -0,0 +1,240 @@
import { ref, computed } from 'vue'
import { eventBus } from '@/core/event-bus'
import { injectService, SERVICE_TOKENS } from '@/core/di-container'
import type { ChatMessage, ChatPeer, UnreadMessageData, ChatConfig } from '../types'
const UNREAD_MESSAGES_KEY = 'nostr-chat-unread-messages'
const PEERS_KEY = 'nostr-chat-peers'
export class ChatService {
private messages = ref<Map<string, ChatMessage[]>>(new Map())
private peers = ref<Map<string, ChatPeer>>(new Map())
private config: ChatConfig
constructor(config: ChatConfig) {
this.config = config
this.loadPeersFromStorage()
}
// Computed properties
get allPeers() {
return computed(() => Array.from(this.peers.value.values()))
}
get totalUnreadCount() {
return computed(() => {
return Array.from(this.peers.value.values())
.reduce((total, peer) => total + peer.unreadCount, 0)
})
}
// Get messages for a specific peer
getMessages(peerPubkey: string): ChatMessage[] {
return this.messages.value.get(peerPubkey) || []
}
// Get peer by pubkey
getPeer(pubkey: string): ChatPeer | undefined {
return this.peers.value.get(pubkey)
}
// Add or update a peer
addPeer(pubkey: string, name?: string): ChatPeer {
let peer = this.peers.value.get(pubkey)
if (!peer) {
peer = {
pubkey,
name: name || `User ${pubkey.slice(0, 8)}`,
unreadCount: 0,
lastSeen: Date.now()
}
this.peers.value.set(pubkey, peer)
this.savePeersToStorage()
eventBus.emit('chat:peer-added', { peer }, 'chat-service')
} else if (name && name !== peer.name) {
peer.name = name
this.savePeersToStorage()
}
return peer
}
// Add a message
addMessage(peerPubkey: string, message: ChatMessage): void {
if (!this.messages.value.has(peerPubkey)) {
this.messages.value.set(peerPubkey, [])
}
const peerMessages = this.messages.value.get(peerPubkey)!
// Avoid duplicates
if (!peerMessages.some(m => m.id === message.id)) {
peerMessages.push(message)
// Sort by timestamp
peerMessages.sort((a, b) => a.created_at - b.created_at)
// Limit message count
if (peerMessages.length > this.config.maxMessages) {
peerMessages.splice(0, peerMessages.length - this.config.maxMessages)
}
// Update peer info
const peer = this.addPeer(peerPubkey)
peer.lastMessage = message
peer.lastSeen = Date.now()
// Update unread count if message is not sent by us
if (!message.sent) {
this.updateUnreadCount(peerPubkey, message)
}
// Emit events
const eventType = message.sent ? 'chat:message-sent' : 'chat:message-received'
eventBus.emit(eventType, { message, peerPubkey }, 'chat-service')
}
}
// Mark messages as read for a peer
markAsRead(peerPubkey: string): void {
const peer = this.peers.value.get(peerPubkey)
if (peer && peer.unreadCount > 0) {
peer.unreadCount = 0
// Save unread state
const unreadData: UnreadMessageData = {
lastReadTimestamp: Date.now(),
unreadCount: 0,
processedMessageIds: new Set()
}
this.saveUnreadData(peerPubkey, unreadData)
eventBus.emit('chat:unread-count-changed', {
peerPubkey,
count: 0,
totalUnread: this.totalUnreadCount.value
}, 'chat-service')
}
}
// Send a message
async sendMessage(peerPubkey: string, content: string): Promise<void> {
try {
const relayHub = injectService(SERVICE_TOKENS.RELAY_HUB)
const authService = injectService(SERVICE_TOKENS.AUTH_SERVICE) as any
if (!relayHub || !authService?.user?.value?.privkey) {
throw new Error('Required services not available')
}
// Create message
const message: ChatMessage = {
id: crypto.randomUUID(),
content,
created_at: Math.floor(Date.now() / 1000),
sent: true,
pubkey: authService.user.value.pubkey
}
// Add to local messages immediately
this.addMessage(peerPubkey, message)
// TODO: Implement actual Nostr message sending
// This would involve encrypting the message and publishing to relays
console.log('Sending message:', { peerPubkey, content })
} catch (error) {
console.error('Failed to send message:', error)
throw error
}
}
// Private methods
private updateUnreadCount(peerPubkey: string, message: ChatMessage): void {
const unreadData = this.getUnreadData(peerPubkey)
if (!unreadData.processedMessageIds.has(message.id)) {
unreadData.processedMessageIds.add(message.id)
unreadData.unreadCount++
const peer = this.peers.value.get(peerPubkey)
if (peer) {
peer.unreadCount = unreadData.unreadCount
this.savePeersToStorage()
}
this.saveUnreadData(peerPubkey, unreadData)
eventBus.emit('chat:unread-count-changed', {
peerPubkey,
count: unreadData.unreadCount,
totalUnread: this.totalUnreadCount.value
}, 'chat-service')
}
}
private getUnreadData(peerPubkey: string): UnreadMessageData {
try {
const stored = localStorage.getItem(`${UNREAD_MESSAGES_KEY}-${peerPubkey}`)
if (stored) {
const data = JSON.parse(stored)
return {
...data,
processedMessageIds: new Set(data.processedMessageIds || [])
}
}
} catch (error) {
console.warn('Failed to load unread data for peer:', peerPubkey, error)
}
return {
lastReadTimestamp: 0,
unreadCount: 0,
processedMessageIds: new Set()
}
}
private saveUnreadData(peerPubkey: string, data: UnreadMessageData): void {
try {
const serializable = {
...data,
processedMessageIds: Array.from(data.processedMessageIds)
}
localStorage.setItem(`${UNREAD_MESSAGES_KEY}-${peerPubkey}`, JSON.stringify(serializable))
} catch (error) {
console.warn('Failed to save unread data for peer:', peerPubkey, error)
}
}
private loadPeersFromStorage(): void {
try {
const stored = localStorage.getItem(PEERS_KEY)
if (stored) {
const peersArray = JSON.parse(stored) as ChatPeer[]
peersArray.forEach(peer => {
this.peers.value.set(peer.pubkey, peer)
})
}
} catch (error) {
console.warn('Failed to load peers from storage:', error)
}
}
private savePeersToStorage(): void {
try {
const peersArray = Array.from(this.peers.value.values())
localStorage.setItem(PEERS_KEY, JSON.stringify(peersArray))
} catch (error) {
console.warn('Failed to save peers to storage:', error)
}
}
// Cleanup
destroy(): void {
this.messages.value.clear()
this.peers.value.clear()
}
}