import type { Event } from 'nostr-tools' import { SimplePool } from 'nostr-tools' import { nostrService } from './nostr' import { zapVerificationService } from './zapVerification' import type { Notification } from '@/types/notifications' const RELAY_URL = process.env.NEXT_PUBLIC_NOSTR_RELAY_URL || 'wss://relay.damus.io' /** * Service for monitoring and managing notifications */ export class NotificationService { private subscriptions: Map void> = new Map() /** * Subscribe to zap receipts (payments) for a user's articles */ subscribeToPayments( userPubkey: string, onNotification: (notification: Notification) => void ): () => void { const pool = nostrService.getPool() if (!pool) { return () => {} } // Subscribe to zap receipts targeting this user const filters = [ { kinds: [9735], // Zap receipt '#p': [userPubkey], // Receipts targeting this user }, ] const sub = (pool as any).sub([RELAY_URL], filters) sub.on('event', async (event: Event) => { try { // Extract payment info from zap receipt const paymentInfo = zapVerificationService.extractPaymentInfo(event) if (!paymentInfo || paymentInfo.recipient !== userPubkey) { return } // Get article info if available let articleTitle: string | undefined if (paymentInfo.articleId) { try { const article = await nostrService.getArticleById(paymentInfo.articleId) articleTitle = article?.title } catch (e) { console.error('Error loading article for notification:', e) } } // Create notification const notification: Notification = { id: event.id, type: 'payment', title: 'New Payment Received', message: articleTitle ? `You received ${paymentInfo.amount} sats for "${articleTitle}"` : `You received ${paymentInfo.amount} sats`, timestamp: event.created_at, read: false, articleId: paymentInfo.articleId || undefined, articleTitle, amount: paymentInfo.amount, fromPubkey: paymentInfo.payer, } onNotification(notification) } catch (error) { console.error('Error processing zap receipt notification:', error) } }) const unsubscribe = () => { sub.unsub() } return unsubscribe } /** * Stop all subscriptions */ stopAll(): void { this.subscriptions.forEach((unsubscribe) => unsubscribe()) this.subscriptions.clear() } } export const notificationService = new NotificationService() /** * Load stored notifications from localStorage */ export function loadStoredNotifications(userPubkey: string): Notification[] { try { const key = `notifications_${userPubkey}` const stored = localStorage.getItem(key) if (stored) { return JSON.parse(stored) as Notification[] } } catch (error) { console.error('Error loading stored notifications:', error) } return [] } /** * Save notifications to localStorage */ export function saveNotifications(userPubkey: string, notifications: Notification[]): void { try { const key = `notifications_${userPubkey}` localStorage.setItem(key, JSON.stringify(notifications)) } catch (error) { console.error('Error saving notifications:', error) } } /** * Mark notification as read */ export function markNotificationAsRead( userPubkey: string, notificationId: string, notifications: Notification[] ): Notification[] { const updated = notifications.map((n) => n.id === notificationId ? { ...n, read: true } : n ) saveNotifications(userPubkey, updated) return updated } /** * Mark all notifications as read */ export function markAllAsRead(userPubkey: string, notifications: Notification[]): Notification[] { const updated = notifications.map((n) => ({ ...n, read: true })) saveNotifications(userPubkey, updated) return updated } /** * Delete a notification */ export function deleteNotification( userPubkey: string, notificationId: string, notifications: Notification[] ): Notification[] { const updated = notifications.filter((n) => n.id !== notificationId) saveNotifications(userPubkey, updated) return updated }