feat: add delete notification button with confirmation in admin notifications

This commit is contained in:
2026-06-14 10:03:59 -04:00
parent 6b2300de07
commit aea0a4d189
5 changed files with 56 additions and 1 deletions

View File

@@ -38,3 +38,23 @@ function sendNotification() {
btn.innerHTML = '<i class="fas fa-paper-plane"></i> Send'; btn.innerHTML = '<i class="fas fa-paper-plane"></i> Send';
}); });
} }
function confirmDelete(id, title) {
if (!confirm('Delete notification "' + title + '"? This action cannot be undone.')) return;
const csrf = document.querySelector('meta[name="csrf-token"]')?.content || '';
fetch('/admin/notifications/' + id + '/delete', {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'X-CSRF-Token': csrf,
},
body: '_csrf_token=' + encodeURIComponent(csrf),
})
.then(r => r.json())
.then(data => {
showToast(data.success ? 'success' : 'error', data.message);
if (data.success) location.reload();
})
.catch(() => showToast('error', 'Failed to delete notification'));
}

View File

@@ -115,6 +115,7 @@ $router->group(['prefix' => 'admin', 'middleware' => [AuthMiddleware::class, Rol
$router->post('/app-version', [AdminController::class, 'appVersion'], [CSRFMiddleware::class]); $router->post('/app-version', [AdminController::class, 'appVersion'], [CSRFMiddleware::class]);
$router->get('/notifications', [AdminController::class, 'notifications']); $router->get('/notifications', [AdminController::class, 'notifications']);
$router->post('/notifications/send', [AdminController::class, 'sendNotification'], [CSRFMiddleware::class]); $router->post('/notifications/send', [AdminController::class, 'sendNotification'], [CSRFMiddleware::class]);
$router->post('/notifications/:id/delete', [AdminController::class, 'deleteNotification'], [CSRFMiddleware::class]);
$router->get('/policies', [AdminController::class, 'policies']); $router->get('/policies', [AdminController::class, 'policies']);
$router->post('/policies', [AdminController::class, 'savePolicies'], [CSRFMiddleware::class]); $router->post('/policies', [AdminController::class, 'savePolicies'], [CSRFMiddleware::class]);

View File

@@ -295,6 +295,26 @@ class AdminController
]); ]);
} }
public function deleteNotification(int $id): void
{
$this->requireSuperAdmin();
$notificationModel = new Notification();
$note = $notificationModel->findById($id);
if (!$note) {
$this->view->json(['success' => false, 'message' => 'Notification not found.'], 404);
}
$notificationModel->delete($id);
$this->auditService->log('notification_deleted', 'notification', $id, [
'title' => $note['title'],
]);
$this->view->json(['success' => true, 'message' => 'Notification deleted.']);
}
public function sendNotification(): void public function sendNotification(): void
{ {
$this->requireSuperAdmin(); $this->requireSuperAdmin();

View File

@@ -143,4 +143,10 @@ class Notification
$result = $this->db->fetch("SELECT COUNT(*) as total FROM users WHERE status = 'active'"); $result = $this->db->fetch("SELECT COUNT(*) as total FROM users WHERE status = 'active'");
return (int) ($result['total'] ?? 0); return (int) ($result['total'] ?? 0);
} }
public function delete(int $id): void
{
$this->db->delete('notifications', 'id = ?', [$id]);
$this->db->delete('notification_reads', 'notification_id = ?', [$id]);
}
} }

View File

@@ -29,12 +29,13 @@ $data = $notifications['data'] ?? [];
<th>Message</th> <th>Message</th>
<th>Target</th> <th>Target</th>
<th>Read by</th> <th>Read by</th>
<th style="width:60px">Actions</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
<?php if (empty($data)): ?> <?php if (empty($data)): ?>
<tr> <tr>
<td colspan="6" class="text-center text-muted">No notifications sent yet.</td> <td colspan="7" class="text-center text-muted">No notifications sent yet.</td>
</tr> </tr>
<?php else: ?> <?php else: ?>
<?php foreach ($data as $note): ?> <?php foreach ($data as $note): ?>
@@ -65,6 +66,13 @@ $data = $notifications['data'] ?? [];
</span> </span>
<?php endif; ?> <?php endif; ?>
</td> </td>
<td>
<button class="btn btn-icon btn-xs" title="Delete"
onclick="confirmDelete(<?= $note['id'] ?>, '<?= htmlspecialchars(addslashes($note['title'] ?? '')) ?>')"
style="color:var(--danger)">
<i class="fas fa-trash"></i>
</button>
</td>
</tr> </tr>
<?php endforeach; ?> <?php endforeach; ?>
<?php endif; ?> <?php endif; ?>