web-app/src/stores/nostr.ts
padreug c05f40f1ec feat: Implement push notification system for admin announcements
- Add a notification manager to handle push notifications and integrate with Nostr events.
- Create a push notification service to manage subscription and permission requests.
- Introduce components for notification settings and permission prompts in the UI.
- Update Nostr store to manage push notification state and enable/disable functionality.
- Enhance NostrFeed to send notifications for new admin announcements.
- Implement test notification functionality for development purposes.
2025-07-12 18:10:33 +02:00

179 lines
No EOL
4.8 KiB
TypeScript

import { defineStore } from 'pinia'
import { ref } from 'vue'
import { NostrClient } from '@/lib/nostr/client'
import { config } from '@/lib/config'
import { pushService, type PushSubscriptionData } from '@/lib/notifications/push'
// Define an interface for the account object
interface NostrAccount {
privkey: string
pubkey: string
}
export const useNostrStore = defineStore('nostr', () => {
// Connection state
const isConnected = ref(false)
const isConnecting = ref(false)
const error = ref<Error | null>(null)
// Configuration
const relayUrls = ref<string[]>(config.nostr.relays)
const account = ref<NostrAccount | null>(null)
// Push notifications
const pushSubscription = ref<PushSubscriptionData | null>(null)
const notificationsEnabled = ref(false)
// Singleton client instance
let client: NostrClient | null = null
// Get or create client instance
function getClient(): NostrClient {
if (!client) {
client = new NostrClient({ relays: relayUrls.value })
}
return client
}
// Connection management
async function connect(): Promise<void> {
try {
error.value = null
isConnecting.value = true
const nostrClient = getClient()
await nostrClient.connect()
isConnected.value = nostrClient.isConnected
} catch (err) {
error.value = err instanceof Error ? err : new Error('Failed to connect')
isConnected.value = false
throw err
} finally {
isConnecting.value = false
}
}
function disconnect(): void {
if (client) {
client.disconnect()
client = null
}
isConnected.value = false
isConnecting.value = false
error.value = null
}
// Configuration setters
function setConnected(value: boolean) {
isConnected.value = value
}
function setRelayUrls(urls: string[]) {
relayUrls.value = urls
// Recreate client with new relays
if (client) {
client.disconnect()
client = null
}
}
function setAccount(nostrAccount: NostrAccount | null) {
account.value = nostrAccount
}
// Push notification management
async function enablePushNotifications(): Promise<PushSubscriptionData> {
try {
const subscription = await pushService.subscribe()
pushSubscription.value = subscription
notificationsEnabled.value = true
// Store subscription in localStorage for persistence
localStorage.setItem('push-subscription', JSON.stringify(subscription))
localStorage.setItem('notifications-enabled', 'true')
return subscription
} catch (error) {
console.error('Failed to enable push notifications:', error)
throw error
}
}
async function disablePushNotifications(): Promise<void> {
try {
await pushService.unsubscribe()
pushSubscription.value = null
notificationsEnabled.value = false
// Remove from localStorage
localStorage.removeItem('push-subscription')
localStorage.removeItem('notifications-enabled')
} catch (error) {
console.error('Failed to disable push notifications:', error)
throw error
}
}
async function checkPushNotificationStatus(): Promise<void> {
try {
// Check localStorage first
const storedEnabled = localStorage.getItem('notifications-enabled') === 'true'
const storedSubscription = localStorage.getItem('push-subscription')
if (storedEnabled && storedSubscription) {
pushSubscription.value = JSON.parse(storedSubscription)
notificationsEnabled.value = true
}
// Verify with push service
const currentSubscription = await pushService.getSubscription()
if (currentSubscription) {
pushSubscription.value = currentSubscription
notificationsEnabled.value = true
} else if (storedEnabled) {
// Stored state says enabled but no actual subscription - clear stored state
await disablePushNotifications()
}
} catch (error) {
console.error('Failed to check push notification status:', error)
}
}
// Send test notification
async function sendTestNotification(): Promise<void> {
await pushService.showLocalNotification({
title: '🚨 Test Admin Announcement',
body: 'This is a test notification to verify push notifications are working correctly.',
icon: '/pwa-192x192.png',
tag: 'test-notification',
data: {
url: '/',
type: 'admin-announcement'
}
})
}
return {
// State
isConnected,
isConnecting,
error,
relayUrls,
account,
pushSubscription,
notificationsEnabled,
// Actions
connect,
disconnect,
getClient,
setConnected,
setRelayUrls,
setAccount,
enablePushNotifications,
disablePushNotifications,
checkPushNotificationStatus,
sendTestNotification,
}
})