feat: implement notification system with Mailgun email integration
- Add notifications table with migration - Create NotificationService with area-of-interest matching - Integrate Mailgun for email delivery - Add notification API endpoints (get, mark as read, unread count) - Create scheduled jobs for event reminders and cleanup - Build NotificationBell component for frontend - Add notification triggers for reports and events - Implement comprehensive test script - Update Header with notification bell - Add email templates with HTML formatting Requirements satisfied: - 10.1: Users can define areas of interest (1-50km radius) - 10.2: Notifications sent within 10 minutes - 10.3: Notifications for new reports/events in user area - 10.4: Configurable notification preferences (email/in-app) Task 33 completed
This commit is contained in:
97
server/src/controllers/notificationController.ts
Normal file
97
server/src/controllers/notificationController.ts
Normal file
@@ -0,0 +1,97 @@
|
||||
import { Request, Response } from 'express';
|
||||
import { notificationService } from '../services/notificationService';
|
||||
|
||||
export class NotificationController {
|
||||
/**
|
||||
* Get user's notifications
|
||||
* GET /api/notifications
|
||||
*/
|
||||
async getNotifications(req: Request, res: Response) {
|
||||
try {
|
||||
const userId = req.auth?.userId;
|
||||
if (!userId) {
|
||||
return res.status(401).json({ error: 'Unauthorized' });
|
||||
}
|
||||
|
||||
const unreadOnly = req.query.unreadOnly === 'true';
|
||||
|
||||
const notifications = await notificationService.getUserNotifications(
|
||||
userId,
|
||||
unreadOnly
|
||||
);
|
||||
|
||||
res.json(notifications);
|
||||
} catch (error) {
|
||||
console.error('Error fetching notifications:', error);
|
||||
res.status(500).json({ error: 'Failed to fetch notifications' });
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get unread notification count
|
||||
* GET /api/notifications/unread-count
|
||||
*/
|
||||
async getUnreadCount(req: Request, res: Response) {
|
||||
try {
|
||||
const userId = req.auth?.userId;
|
||||
if (!userId) {
|
||||
return res.status(401).json({ error: 'Unauthorized' });
|
||||
}
|
||||
|
||||
const count = await notificationService.getUnreadCount(userId);
|
||||
|
||||
res.json({ count });
|
||||
} catch (error) {
|
||||
console.error('Error fetching unread count:', error);
|
||||
res.status(500).json({ error: 'Failed to fetch unread count' });
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Mark notification as read
|
||||
* PATCH /api/notifications/:id/read
|
||||
*/
|
||||
async markAsRead(req: Request, res: Response) {
|
||||
try {
|
||||
const userId = req.auth?.userId;
|
||||
if (!userId) {
|
||||
return res.status(401).json({ error: 'Unauthorized' });
|
||||
}
|
||||
|
||||
const { id } = req.params;
|
||||
|
||||
const success = await notificationService.markAsRead(id, userId);
|
||||
|
||||
if (!success) {
|
||||
return res.status(404).json({ error: 'Notification not found' });
|
||||
}
|
||||
|
||||
res.json({ success: true });
|
||||
} catch (error) {
|
||||
console.error('Error marking notification as read:', error);
|
||||
res.status(500).json({ error: 'Failed to mark notification as read' });
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Mark all notifications as read
|
||||
* PATCH /api/notifications/read-all
|
||||
*/
|
||||
async markAllAsRead(req: Request, res: Response) {
|
||||
try {
|
||||
const userId = req.auth?.userId;
|
||||
if (!userId) {
|
||||
return res.status(401).json({ error: 'Unauthorized' });
|
||||
}
|
||||
|
||||
const count = await notificationService.markAllAsRead(userId);
|
||||
|
||||
res.json({ count });
|
||||
} catch (error) {
|
||||
console.error('Error marking all notifications as read:', error);
|
||||
res.status(500).json({ error: 'Failed to mark all notifications as read' });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const notificationController = new NotificationController();
|
||||
Reference in New Issue
Block a user