Files
ocean-cleanup/server/src/controllers/notificationController.ts
Paul Bailey d61c21c54d 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
2025-11-17 00:31:23 +00:00

98 lines
2.6 KiB
TypeScript

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();