fix(notifications): surface action failures as an error banner
All checks were successful
CI / Unit & Component Tests (pull_request) Successful in 3m25s
CI / OCR Service Tests (pull_request) Successful in 20s
CI / Backend Unit Tests (pull_request) Successful in 3m23s
CI / fail2ban Regex (pull_request) Successful in 39s
CI / Semgrep Security Scan (pull_request) Successful in 18s
CI / Compose Bucket Idempotency (pull_request) Successful in 58s

When dismiss-notification or mark-all-read returns a failure the dropdown
now shows a localised error message above the list. Added
notification_error_generic key (de/en/es) as the fallback when the
action response carries no explicit error string.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Marcel
2026-05-19 23:56:33 +02:00
parent f9340366d1
commit 7fe8842b57
4 changed files with 17 additions and 2 deletions

View File

@@ -522,6 +522,7 @@
"notification_filter_unread": "Ungelesen",
"notification_filter_mention": "Erwähnung",
"notification_filter_reply": "Antwort",
"notification_error_generic": "Aktion fehlgeschlagen. Bitte versuche es erneut.",
"notification_mark_all_read_aria": "Alle Benachrichtigungen als gelesen markieren",
"notification_load_more": "Ältere laden",
"notification_empty_history": "Keine Benachrichtigungen",

View File

@@ -522,6 +522,7 @@
"notification_filter_unread": "Unread",
"notification_filter_mention": "Mention",
"notification_filter_reply": "Reply",
"notification_error_generic": "Action failed. Please try again.",
"notification_mark_all_read_aria": "Mark all notifications as read",
"notification_load_more": "Load older",
"notification_empty_history": "No notifications",

View File

@@ -522,6 +522,7 @@
"notification_filter_unread": "No leídas",
"notification_filter_mention": "Mención",
"notification_filter_reply": "Respuesta",
"notification_error_generic": "La acción ha fallado. Por favor, inténtalo de nuevo.",
"notification_mark_all_read_aria": "Marcar todas las notificaciones como leídas",
"notification_load_more": "Cargar anteriores",
"notification_empty_history": "Sin notificaciones",

View File

@@ -15,6 +15,8 @@ type Props = {
let { notifications, optimisticMarkRead, optimisticMarkAllRead, onClose }: Props = $props();
let errorMessage = $state<string | null>(null);
function handleViewAll() {
onClose(); // close first — avoids stale dropdown during navigation transition
goto('/aktivitaeten');
@@ -38,7 +40,10 @@ function handleViewAll() {
method="POST"
use:enhance={() => {
optimisticMarkAllRead();
return async ({ update }) => {
return async ({ result, update }) => {
if (result.type === 'failure') {
errorMessage = (result.data as { error?: string } | undefined)?.error ?? m.notification_error_generic();
}
await update({ reset: false, invalidateAll: false });
};
}}
@@ -53,6 +58,11 @@ function handleViewAll() {
{/if}
</div>
<!-- Error banner (shown when a dismiss or mark-all action fails) -->
{#if errorMessage}
<p class="px-4 py-2 text-sm text-red-600">{errorMessage}</p>
{/if}
<!-- Notification list -->
{#if notifications.length === 0}
<!-- Empty state -->
@@ -85,7 +95,9 @@ function handleViewAll() {
use:enhance={() => {
optimisticMarkRead(notification.id);
return async ({ result, update }) => {
if (result.type !== 'failure') {
if (result.type === 'failure') {
errorMessage = (result.data as { error?: string } | undefined)?.error ?? m.notification_error_generic();
} else {
onClose();
goto(
buildCommentHref(