Improve admin UI visual design — polish look and feel #59

Merged
ghost merged 4 commits from feat/ui-visual-polish into main 2026-03-19 03:33:35 +00:00
ghost commented 2026-03-19 03:00:48 +00:00 (Migrated from github.com)

Summary

  • Polished admin UI with consistent brand green, subtle shadows, rounded corners, and better visual hierarchy
  • Sticky nav bar with branded GroomBook wordmark and gradient Book button
  • Tables wrapped in white cards with soft shadows and uppercase headers
  • Global CSS adds button transitions, input focus rings, card shadows, and custom scrollbar
  • All admin pages updated: Appointments, Clients, Services, Staff, Invoices, Reports, Group Bookings

Closes #58

Test plan

  • Verify admin nav bar is sticky with shadow and branded styling
  • Check all admin pages render with white card-wrapped tables
  • Confirm primary buttons use brand green (#4f8a6f) consistently
  • Verify input focus states show green ring
  • Check customer portal is unaffected (no changes to portal components)
  • Test responsive behavior on mobile widths
## Summary - Polished admin UI with consistent brand green, subtle shadows, rounded corners, and better visual hierarchy - Sticky nav bar with branded GroomBook wordmark and gradient Book button - Tables wrapped in white cards with soft shadows and uppercase headers - Global CSS adds button transitions, input focus rings, card shadows, and custom scrollbar - All admin pages updated: Appointments, Clients, Services, Staff, Invoices, Reports, Group Bookings Closes #58 ## Test plan - [ ] Verify admin nav bar is sticky with shadow and branded styling - [ ] Check all admin pages render with white card-wrapped tables - [ ] Confirm primary buttons use brand green (#4f8a6f) consistently - [ ] Verify input focus states show green ring - [ ] Check customer portal is unaffected (no changes to portal components) - [ ] Test responsive behavior on mobile widths
ghost commented 2026-03-19 03:13:42 +00:00 (Migrated from github.com)

Good visual polish overall — consistent color palette, border-radius bump, sticky nav, table wrappers with subtle shadows, and uppercase table headers all look solid.

Two test failures to fix before merge:

  1. renders the Groom Book brand — The brand is now <span style="color: #4f8a6f">Groom</span>Book which splits the text across elements. getByText("Groom Book") can't find it. Fix: use getByText(/Groom\s*Book/) or keep the brand as a single text node.

  2. renders the Book CTA buttonwithin(nav).getByText("Book") now matches both the brand <strong> (which contains bare "Book") and the <a> link. Fix: use getByRole("link", { name: "Book" }) in the test to target the CTA specifically.

Please push a fix for the tests so CI goes green.

Good visual polish overall — consistent color palette, border-radius bump, sticky nav, table wrappers with subtle shadows, and uppercase table headers all look solid. **Two test failures to fix before merge:** 1. **`renders the Groom Book brand`** — The brand is now `<span style="color: #4f8a6f">Groom</span>Book` which splits the text across elements. `getByText("Groom Book")` can't find it. Fix: use `getByText(/Groom\s*Book/)` or keep the brand as a single text node. 2. **`renders the Book CTA button`** — `within(nav).getByText("Book")` now matches both the brand `<strong>` (which contains bare "Book") and the `<a>` link. Fix: use `getByRole("link", { name: "Book" })` in the test to target the CTA specifically. Please push a fix for the tests so CI goes green.
ghost commented 2026-03-19 03:19:42 +00:00 (Migrated from github.com)

CI is failing — test renders the Groom Book brand in App.test.tsx:26 cannot find text matching /Groom\s*Book/ because the brand is now split across child elements (<span>Groom</span>Book inside <strong>).

Fix the test to use a function matcher:

expect(within(nav).getByText((content, element) =>
  element?.tagName === "STRONG" && /Groom\s*Book/.test(element.textContent || "")
)).toBeInTheDocument();

Please fix and push — CI must be green before merge.

CI is failing — test `renders the Groom Book brand` in `App.test.tsx:26` cannot find text matching `/Groom\s*Book/` because the brand is now split across child elements (`<span>Groom</span>Book` inside `<strong>`). **Fix the test** to use a function matcher: ```tsx expect(within(nav).getByText((content, element) => element?.tagName === "STRONG" && /Groom\s*Book/.test(element.textContent || "") )).toBeInTheDocument(); ``` Please fix and push — CI must be green before merge.
ghost commented 2026-03-19 03:20:55 +00:00 (Migrated from github.com)

Pushed a test fix — the brand text <span>Groom</span>Book is split across elements, so getByText with a regex can't match it. Switched to a custom text matcher that checks the <strong> element's textContent. All 5 tests pass locally.

Pushed a test fix — the brand text `<span>Groom</span>Book` is split across elements, so `getByText` with a regex can't match it. Switched to a custom text matcher that checks the `<strong>` element's `textContent`. All 5 tests pass locally.
ghost commented 2026-03-19 03:27:42 +00:00 (Migrated from github.com)

E2E Test Fix Needed

PR looks good overall — nice visual polish. However, the E2E tests in apps/e2e/tests/navigation.spec.ts are failing because the brand text changed from Groom Book (single text node) to <span>Groom</span>Book (split elements).

The unit tests in App.test.tsx were correctly updated to use a custom text matcher, but the E2E tests (lines 49-84) still use getByText('Groom Book') which no longer matches.

Fix: Update the 6 failing E2E tests in navigation.spec.ts to match the new brand markup — e.g., use page.locator('strong', { hasText: /Groom.*Book/ }) or similar Playwright locator.

All other checks (lint, typecheck, unit tests, build) pass.

## E2E Test Fix Needed PR looks good overall — nice visual polish. However, the E2E tests in `apps/e2e/tests/navigation.spec.ts` are failing because the brand text changed from `Groom Book` (single text node) to `<span>Groom</span>Book` (split elements). The unit tests in `App.test.tsx` were correctly updated to use a custom text matcher, but the E2E tests (lines 49-84) still use `getByText('Groom Book')` which no longer matches. **Fix:** Update the 6 failing E2E tests in `navigation.spec.ts` to match the new brand markup — e.g., use `page.locator('strong', { hasText: /Groom.*Book/ })` or similar Playwright locator. All other checks (lint, typecheck, unit tests, build) pass.
This repo is archived. You cannot comment on pull requests.