feat: add resend notification action with push

This commit is contained in:
2026-06-14 10:05:19 -04:00
parent aea0a4d189
commit a25ebdcb75
4 changed files with 65 additions and 5 deletions

View File

@@ -58,3 +58,20 @@ function confirmDelete(id, title) {
})
.catch(() => showToast('error', 'Failed to delete notification'));
}
function confirmResend(id) {
const csrf = document.querySelector('meta[name="csrf-token"]')?.content || '';
fetch('/admin/notifications/' + id + '/resend', {
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);
})
.catch(() => showToast('error', 'Failed to resend notification'));
}

View File

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

View File

@@ -315,6 +315,41 @@ class AdminController
$this->view->json(['success' => true, 'message' => 'Notification deleted.']);
}
public function resendNotification(int $id): void
{
$this->requireSuperAdmin();
$notificationModel = new Notification();
$note = $notificationModel->findById($id);
if (!$note) {
$this->view->json(['success' => false, 'message' => 'Notification not found.'], 404);
}
$title = $note['title'];
$message = $note['message'];
$type = $note['type'] ?? 'info';
$userId = $note['user_id'] ? (int) $note['user_id'] : null;
$fcm = new FCMService();
$pushResult = '';
if ($userId) {
$sent = $fcm->sendToUser($userId, $title, $message, $type, $id);
$pushResult = $sent ? ' (push sent)' : ($fcm->isConfigured() ? ' (push failed)' : '');
} else {
$count = $fcm->sendToAll($title, $message, $type, $id);
$pushResult = $fcm->isConfigured() ? " (push sent to {$count} devices)" : '';
}
$this->auditService->log('notification_resent', 'notification', $id, [
'title' => $title,
'target' => $userId ? "user #{$userId}" : 'all users',
'push' => $fcm->isConfigured() ? 'sent' : 'not_configured',
]);
$this->view->json(['success' => true, 'message' => 'Notification resent successfully.' . $pushResult]);
}
public function sendNotification(): void
{
$this->requireSuperAdmin();

View File

@@ -67,11 +67,18 @@ $data = $notifications['data'] ?? [];
<?php endif; ?>
</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>
<div style="display:flex;gap:0.25rem">
<button class="btn btn-icon btn-xs" title="Resend"
onclick="confirmResend(<?= $note['id'] ?>)"
style="color:var(--info)">
<i class="fas fa-redo"></i>
</button>
<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>
</div>
</td>
</tr>
<?php endforeach; ?>