feat: implement complete web push notification system
- Add self-hosted push notifications using VAPID (no external services) - Create PushSubscription model in database - Implement server-side push logic with web-push library - Add notification helpers for list events (items, invitations, collaborators) - Create NotificationSettings UI component for profile page - Add usePushNotifications React hook for subscription management - Create API routes for subscription management and VAPID key - Update service worker with push event handlers - Integrate notifications into item actions (add, remove, complete) - Integrate notifications into sharing actions (invite, accept, remove) - Add VAPID key generation script - Add comprehensive documentation and setup guides Notifications are sent when: - Items are added/removed/completed in shared lists - Users are invited to lists - Invitations are accepted - Collaborators are removed from lists Works on iOS 16.4+ (when installed to home screen), Android, and desktop browsers.
This commit is contained in:
@@ -12,6 +12,11 @@ import {
|
||||
validateTags,
|
||||
sanitizeString,
|
||||
} from './validation'
|
||||
import {
|
||||
notifyItemAdded,
|
||||
notifyItemRemoved,
|
||||
notifyItemCompleted,
|
||||
} from './notification-helpers'
|
||||
|
||||
// Retry utility for database operations
|
||||
async function retryOperation<T>(
|
||||
@@ -370,6 +375,14 @@ export async function createItem(
|
||||
})
|
||||
)
|
||||
|
||||
// Send notification to collaborators
|
||||
try {
|
||||
await notifyItemAdded(listId, item.title, userId)
|
||||
} catch (error) {
|
||||
console.error('Failed to send notification:', error)
|
||||
// Don't fail the action if notification fails
|
||||
}
|
||||
|
||||
revalidatePath(`/list/${listId}`)
|
||||
return item
|
||||
} catch (error) {
|
||||
@@ -437,6 +450,15 @@ export async function toggleItem(itemId: string) {
|
||||
})
|
||||
)
|
||||
|
||||
// Send notification when item is completed (not uncompleted)
|
||||
if (updated.completed) {
|
||||
try {
|
||||
await notifyItemCompleted(item.listId, updated.title, userId)
|
||||
} catch (error) {
|
||||
console.error('Failed to send notification:', error)
|
||||
}
|
||||
}
|
||||
|
||||
revalidatePath(`/list/${item.listId}`)
|
||||
return updated
|
||||
} catch (error) {
|
||||
@@ -609,6 +631,13 @@ export async function deleteItem(itemId: string) {
|
||||
})
|
||||
)
|
||||
|
||||
// Send notification to collaborators
|
||||
try {
|
||||
await notifyItemRemoved(item.listId, item.title, userId)
|
||||
} catch (error) {
|
||||
console.error('Failed to send notification:', error)
|
||||
}
|
||||
|
||||
revalidatePath(`/list/${item.listId}`)
|
||||
return { success: true }
|
||||
} catch (error) {
|
||||
|
||||
Reference in New Issue
Block a user