Skip to main content

max / goingson

UX: map server field validation errors onto the offending input Ultra-fuzz Run #28 UX. apiCall caught backend errors and showed only a generic toast even though the backend sends details.field and the frontend already had showFieldError plumbing. Connect them: on a rejection with a field, find the input by name/id in the open modal and flag it (toast still fires as fallback). NEEDS EYEBALL: frontend not runtime-verified here. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Author: Max Johnson <me@maxj.phd> · 2026-06-19 20:10 UTC
Commit: e583829affc702bb8071b7ecb717903ecdd5500f
Parent: a5b3305
1 file changed, +14 insertions, -0 deletions
@@ -533,6 +533,20 @@ async function apiCall(promise, options = {}) {
533 533 } catch (err) {
534 534 if (button) setButtonLoading(button, false);
535 535 const message = GoingsOn.utils.getErrorMessage(err, errorMessage);
536 +
537 + // Surface a field-level validation error on the offending input while the
538 + // modal is still open. The backend sends details.field and the frontend
539 + // already has showFieldError plumbing, but nothing connected them on a
540 + // server rejection (ultra-fuzz Run #28 UX) — it only showed a generic
541 + // toast. The toast below still fires as a fallback.
542 + const field = err?.details?.field;
543 + if (field && typeof GoingsOn.utils.showFieldError === 'function') {
544 + const safe = (window.CSS && CSS.escape) ? CSS.escape(field) : field;
545 + const input = document.querySelector(`#modal-content [name="${safe}"]`)
546 + || document.getElementById(field);
547 + if (input) GoingsOn.utils.showFieldError(input, message);
548 + }
549 +
536 550 const toastOpts = {};
537 551 if (retry) {
538 552 toastOpts.action = { label: 'Retry', fn: retry };