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] 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 && ( + … + )} + - ))}