/*********************************************************************************************************************************************************************** * File Name : notification.controller.js * Type : Controller (Admin) * Description : Admin notification management. * GET /admin/notifications — paginated list, newest first * GET /admin/notifications/unseen — unseen count only * GET /admin/notifications/sticky — current sticky announcement, if any * PATCH /admin/notifications/:id/seen — mark one as seen * PATCH /admin/notifications/seen-all — mark all as seen * * Author: Kenneth Obsequio (@lash0000) * Date Created: Jun. 19, 2026 ***********************************************************************************************************************************************************************/ const AdminNotification = require('../../models/notifications/admin_notification.mdl'); const R = require('../../utils/response.util'); // ─── GET /admin/notifications ───────────────────────────────────────────────── async function list(req, res) { try { const page = Math.max(1, parseInt(req.query.page) || 1); const limit = Math.min(50, parseInt(req.query.limit) || 20); const offset = (page - 1) * limit; const { count, rows } = await AdminNotification.findAndCountAll({ order: [['createdAt', 'DESC']], limit, offset, where: { show_in_notifications: true }, }); return R.success(res, 'Notifications fetched.', { notifications: rows, pagination: { page, limit, total: count, pages: Math.ceil(count / limit) }, }); } catch (err) { console.error('[NOTIFICATION] list error:', err); return R.error(res, 'Failed to fetch notifications.'); } } // ─── GET /admin/notifications/unseen ───────────────────────────────────────── async function unseenCount(req, res) { try { const count = await AdminNotification.count({ where: { seen: false, show_in_notifications: true } }); return R.success(res, 'Unseen count fetched.', { count }); } catch (err) { console.error('[NOTIFICATION] unseenCount error:', err); return R.error(res, 'Failed to fetch unseen count.'); } } // ─── GET /admin/notifications/sticky ────────────────────────────────────────── // Not user-scoped, same as list()/unseenCount() above — one shared sticky // banner for every admin. Whoever dismisses it first dismisses it for all. async function stickyAnnouncement(req, res) { try { const notification = await AdminNotification.findOne({ where: { seen: false, show_in_sticky: true, type: 'announcement', }, order: [['createdAt', 'DESC']], }); return R.success(res, 'Sticky announcement fetched.', { announcement: notification }); } catch (err) { console.error('[NOTIFICATION] stickyAnnouncement error:', err); return R.error(res, 'Failed to fetch sticky announcement.'); } } // ─── PATCH /admin/notifications/:id/seen ───────────────────────────────────── async function markSeen(req, res) { try { const notification = await AdminNotification.findByPk(req.params.id); if (!notification) return R.error(res, 'Notification not found.', 404); await notification.update({ seen: true, seen_at: new Date() }); return R.success(res, 'Notification marked as seen.', notification); } catch (err) { console.error('[NOTIFICATION] markSeen error:', err); return R.error(res, 'Failed to mark notification as seen.'); } } // ─── PATCH /admin/notifications/seen-all ───────────────────────────────────── async function markAllSeen(req, res) { try { const now = new Date(); const [count] = await AdminNotification.update( { seen: true, seen_at: now }, { where: { seen: false } } ); return R.success(res, `${count} notification(s) marked as seen.`, { count }); } catch (err) { console.error('[NOTIFICATION] markAllSeen error:', err); return R.error(res, 'Failed to mark all notifications as seen.'); } } module.exports = { list, unseenCount, stickyAnnouncement, markSeen, markAllSeen };