From b382a367beedb1f9976602d76bebafba893afb5a Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Fri, 26 Jun 2026 05:12:24 +0000 Subject: [PATCH] =?UTF-8?q?=F0=9F=8E=A8=20Palette:=20Add=20async=20loading?= =?UTF-8?q?=20states=20to=20auth=20buttons?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: singhaditya21 <53948039+singhaditya21@users.noreply.github.com> --- .Jules/palette.md | 1 + web-demo/js/app.js | 26 ++++++++++++++++++++++++++ 2 files changed, 27 insertions(+) create mode 100644 .Jules/palette.md diff --git a/.Jules/palette.md b/.Jules/palette.md new file mode 100644 index 0000000..46da24f --- /dev/null +++ b/.Jules/palette.md @@ -0,0 +1 @@ +## 2024-05-24 - Async Loading States for Form Submissions\n**Learning:** Implementing visual feedback (like disabling buttons and changing their text to 'Loading...') during async form submissions prevents double submissions and reduces user uncertainty. Wait states are essential UX elements for any async network request.\n**Action:** Add disabled styling or inline loading text to form submitters during async operations and ensure state restores in a `finally` block. diff --git a/web-demo/js/app.js b/web-demo/js/app.js index 11508de..7792b35 100644 --- a/web-demo/js/app.js +++ b/web-demo/js/app.js @@ -145,6 +145,14 @@ class ClimaAI { const email = document.getElementById('loginEmail').value; const password = document.getElementById('loginPassword').value; + const submitBtn = e.submitter; + let originalText = ''; + if (submitBtn) { + originalText = submitBtn.innerHTML; + submitBtn.disabled = true; + submitBtn.innerHTML = 'Signing In...'; + } + try { this.showToast('Logging in...', 'info'); const response = await api.login(email, password); @@ -155,6 +163,11 @@ class ClimaAI { this.checkSubscription(); } catch (error) { this.showToast(error.message || 'Login failed', 'error'); + } finally { + if (submitBtn) { + submitBtn.disabled = false; + submitBtn.innerHTML = originalText; + } } } @@ -164,6 +177,14 @@ class ClimaAI { const email = document.getElementById('registerEmail').value; const password = document.getElementById('registerPassword').value; + const submitBtn = e.submitter; + let originalText = ''; + if (submitBtn) { + originalText = submitBtn.innerHTML; + submitBtn.disabled = true; + submitBtn.innerHTML = 'Signing Up...'; + } + try { this.showToast('Creating account...', 'info'); const response = await api.register(email, password, name); @@ -174,6 +195,11 @@ class ClimaAI { this.checkSubscription(); } catch (error) { this.showToast(error.message || 'Registration failed', 'error'); + } finally { + if (submitBtn) { + submitBtn.disabled = false; + submitBtn.innerHTML = originalText; + } } }