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:
parent
519a9003d4
commit
e40ac91417
46 changed files with 6305 additions and 3264 deletions
240
src/modules/chat/services/chat-service.ts
Normal file
240
src/modules/chat/services/chat-service.ts
Normal 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()
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue