From 854a888306fad7280208489a956e13337e8a378c Mon Sep 17 00:00:00 2001 From: John O'Keefe Date: Wed, 27 May 2026 11:22:13 -0400 Subject: [PATCH] fix(toast): show success toast for HTMX JSON responses Previously, when HTMX form submissions (profile update, password change) returned a successful JSON response like {"message": "profile updated successfully"}, the raw JSON was swapped into the target div as plain text. The htmx:afterSwap listener in toast.ts only handled error responses. Extend it to also intercept successful 2xx JSON responses that contain a "message" field, showing a green success toast and clearing the raw JSON from the target element. Only JSON responses are intercepted (checked via Content-Type header), so legitimate HTML swaps are unaffected. --- web/src/toast.ts | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/web/src/toast.ts b/web/src/toast.ts index 284713d..ab7c80c 100644 --- a/web/src/toast.ts +++ b/web/src/toast.ts @@ -138,14 +138,31 @@ const setupHTMXListeners = (): void => { const customEvent = evt as CustomEvent; - // Check if request failed - if (customEvent.detail.succeeded === false && customEvent.detail.xhr) { + if (customEvent.detail.xhr) { const xhr = customEvent.detail.xhr; - // Show toast for HTTP errors - if (xhr.status >= 400 && xhr.status < 600) { + if ( + customEvent.detail.succeeded === false && + xhr.status >= 400 && + xhr.status < 600 + ) { const errorMessage = parseXHRError(xhr); showToast(errorMessage, "error"); + } else if (xhr.status >= 200 && xhr.status < 300) { + const contentType = xhr.getResponseHeader("content-type"); + if (contentType && contentType.includes("application/json")) { + try { + const response = JSON.parse(xhr.responseText); + if (response.message) { + showToast(response.message, "success"); + if (customEvent.detail.target) { + customEvent.detail.target.innerHTML = ""; + } + } + } catch (e) { + // Not valid JSON — ignore + } + } } } });