From 3216fd2ee5752446711d23c19c3a96be1f60a0d3 Mon Sep 17 00:00:00 2001 From: "groombook-engineer[bot]" <3141748+groombook-engineer[bot]@users.noreply.github.com> Date: Thu, 2 Apr 2026 17:53:35 +0000 Subject: [PATCH 1/2] fix(web): replace services badge+button with toggle switch (GRO-404) - Replace colored "Active"/"Inactive" badge and separate Activate/Deactivate button with an inline toggle switch on the Services page - Toggle matches the existing pattern used on the Staff page - Shows loading indicator (dots) while the toggle API call is in flight - Removes the redundant status column header (now just the toggle in that cell) Co-Authored-By: Paperclip --- apps/web/src/pages/Services.tsx | 59 +++++++++++++++++++++++---------- 1 file changed, 41 insertions(+), 18 deletions(-) diff --git a/apps/web/src/pages/Services.tsx b/apps/web/src/pages/Services.tsx index 65cf380..7398c9d 100644 --- a/apps/web/src/pages/Services.tsx +++ b/apps/web/src/pages/Services.tsx @@ -26,6 +26,7 @@ export function ServicesPage() { const [form, setForm] = useState(EMPTY_FORM); const [saving, setSaving] = useState(false); const [formError, setFormError] = useState(null); + const [togglingId, setTogglingId] = useState(null); async function load() { const r = await fetch("/api/services?includeInactive=true"); @@ -102,12 +103,17 @@ export function ServicesPage() { } async function toggleActive(s: Service) { - await fetch(`/api/services/${s.id}`, { - method: "PATCH", - headers: { "Content-Type": "application/json" }, - body: JSON.stringify({ active: !s.active }), - }); - await load(); + setTogglingId(s.id); + try { + await fetch(`/api/services/${s.id}`, { + method: "PATCH", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ active: !s.active }), + }); + await load(); + } finally { + setTogglingId(null); + } } if (loading) return

Loading…

; @@ -147,26 +153,43 @@ export function ServicesPage() { ${(s.basePriceCents / 100).toFixed(2)} {s.durationMinutes} min - toggleActive(s)} + disabled={togglingId === s.id} + title={s.active ? "Deactivate" : "Activate"} style={{ - padding: "2px 8px", - borderRadius: 12, - fontSize: 11, - fontWeight: 600, - background: s.active ? "#d1fae5" : "#f3f4f6", - color: s.active ? "#065f46" : "#6b7280", + position: "relative", + width: 36, + height: 20, + borderRadius: 10, + border: "1px solid", + borderColor: s.active ? "#10b981" : "#d1d5db", + background: s.active ? "#d1fae5" : "#fff", + cursor: togglingId === s.id ? "not-allowed" : "pointer", + padding: 0, + display: "inline-flex", + alignItems: "center", + opacity: togglingId === s.id ? 0.6 : 1, }} > - {s.active ? "Active" : "Inactive"} - + + {togglingId === s.id && ( + + )} + - ))} -- 2.52.0 From 321bd902490fd70663fb1768e5b41c0c1c43d83d Mon Sep 17 00:00:00 2001 From: "groombook-engineer[bot]" <3141748+groombook-engineer[bot]@users.noreply.github.com> Date: Thu, 2 Apr 2026 18:02:02 +0000 Subject: [PATCH 2/2] fix(web): remove early-return guard from devFetch interceptor (GRO-406) The if (!getDevUser()) return at install time prevented the interceptor from installing on app startup before any dev user was selected. Since the per-call check already handles the no-dev-user case correctly, the early-return guard is unnecessary and breaks the interceptor install in deployed dev builds. Co-Authored-By: Paperclip --- apps/web/src/lib/devFetch.ts | 4 ---- 1 file changed, 4 deletions(-) diff --git a/apps/web/src/lib/devFetch.ts b/apps/web/src/lib/devFetch.ts index 76798a7..42078ce 100644 --- a/apps/web/src/lib/devFetch.ts +++ b/apps/web/src/lib/devFetch.ts @@ -9,10 +9,6 @@ const originalFetch = window.fetch; * Intentionally mutates window.fetch — this is dev-only (AUTH_DISABLED=true). */ export function installDevFetchInterceptor() { - // Only install if a dev user is selected (localStorage check, not build-time flag). - // This ensures the interceptor runs in deployed dev builds, not just `vite dev`. - if (!getDevUser()) return; - window.fetch = function (input: RequestInfo | URL, init?: RequestInit) { const user = getDevUser(); if (!user) return originalFetch(input, init); -- 2.52.0