- 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
98 lines
2.6 KiB
TypeScript
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();
|