Commit Graph

7 Commits

Author SHA1 Message Date
Scrubs McBarkley afde6b7857 feat: unify site theming via CSS custom properties (GH #91)
Replace all hardcoded brand color hex values with CSS custom properties
so BrandingContext drives both the customer portal and staff site.

- index.css: add derived accent/primary vars using color-mix()
  (--color-accent-hover, --color-accent-dark, --color-accent-light,
  --color-accent-lighter, --color-primary-dark); fix focus ring styles
  to use var(--color-primary) instead of hardcoded hex
- BrandingContext.tsx: also update <meta name="theme-color"> in sync
  with primaryColor so PWA theme-color tracks branding at runtime
- portal/sections: replace bg-[#8b7355], text-[#6b5a42], bg-[#f0ebe4],
  bg-[#faf5ef], hover:bg-[#7a6549] etc. with Tailwind v4 CSS var
  utilities (bg-(--color-accent), text-(--color-accent-dark), etc.)
- pages: replace inline style "#4f8a6f"/"#3d7a5f" with
  var(--color-primary) / var(--color-primary-dark) across Appointments,
  Book, Clients, GroupBooking, Invoices, Reports, Services, Staff, and
  DevSessionIndicator

Closes #91

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-03-21 23:50:43 +00:00
groombook-paperclip[bot] 1cf1f19e1d Improve admin UI visual design — polish look and feel (#59)
* Improve admin UI visual design — polish look and feel

- Sticky nav bar with subtle shadow, branded GroomBook wordmark, green gradient Book button
- Consistent brand green (#4f8a6f) for primary buttons across all admin pages
- Tables wrapped in white cards with rounded corners and soft shadows
- Uppercase table headers with better spacing and hierarchy
- Input/button border-radius increased to 6px for softer feel
- Global CSS: button transitions, input focus states with brand green ring, subtle card shadows
- Background changed from plain white to light gray (#f0f2f5) for depth
- Reports: polished stat cards with shadows, refined section headers, card-wrapped tables
- Custom scrollbar styling for a cleaner look

Closes groombook/groombook#58

Co-Authored-By: Paperclip <noreply@paperclip.ing>

* Fix test selectors for branded nav text

- Use regex /Groom\s*Book/ to match split-element brand text
- Use getByRole("link") for Book CTA to avoid matching brand <strong>

Co-Authored-By: Paperclip <noreply@paperclip.ing>

* Fix brand text test to handle split-element rendering

The nav brand was changed to <span>Groom</span>Book for color styling,
but getByText with a regex can't match text split across child elements.
Use a custom text matcher that checks the STRONG element's textContent.

Co-Authored-By: Paperclip <noreply@paperclip.ing>

* Fix E2E tests for split-element brand name

The brand is now <span>Groom</span>Book (no space), so Playwright's
getByText needs "GroomBook" instead of "Groom Book".

Co-Authored-By: Paperclip <noreply@paperclip.ing>

---------

Co-authored-by: Groom Book CTO <cto@groombook.dev>
Co-authored-by: Paperclip <noreply@paperclip.ing>
Co-authored-by: Groom Book CTO <cto@groombook.app>
2026-03-19 03:33:34 +00:00
groombook-paperclip[bot] 4ab5597fd5 feat: tip and payment splitting between staff roles (#34)
* feat: multi-groomer calendar view with per-groomer filtering

Add groomer view mode to the appointments calendar:
- Toggle between "Status" (existing) and "Groomer" color coding
- Per-groomer visibility toggles with color-coded buttons
- Appointments colored by assigned groomer in groomer view
- Groomer name shown on appointment blocks in groomer view
- Unassigned appointments shown in neutral gray

Satisfies groombook/groombook#11 requirements for side-by-side/unified
groomer schedule visibility and per-groomer filter/toggle.

Co-Authored-By: Paperclip <noreply@paperclip.ing>

* feat: tip and payment splitting between staff roles

Implements groombook/groombook#12 — track which staff worked on each
pet and calculate tip distribution based on who was involved.

Changes:
- DB: Add bather_staff_id to appointments (optional secondary staff)
- DB: Add invoice_tip_splits table (per-staff tip share ledger)
- API: appointments POST/PATCH accept batherStaffId
- API: GET /invoices/:id now includes tipSplits[]
- API: POST /invoices/:id/tip-splits — saves tip distribution
- API: GET /reports/tip-splits — payroll summary of tip earnings
- Frontend: Bather/Assistant select on New Appointment form
- Frontend: Tip Distribution section in Invoice Detail modal
  - Auto-populates 70%/30% split when bather is assigned
  - Editable percentages before payment; saved on Mark as Paid
  - Displays recorded splits on paid invoices

Co-Authored-By: Paperclip <noreply@paperclip.ing>

* fix: remove unused staff import from invoices route

Co-Authored-By: Paperclip <noreply@paperclip.ing>

---------

Co-authored-by: Groom Book CTO <cto@groombook.app>
Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-03-17 22:03:46 +00:00
groombook-paperclip[bot] 1b3a23bd52 feat: multi-groomer calendar view with per-groomer filtering (#33)
Add groomer view mode to the appointments calendar:
- Toggle between "Status" (existing) and "Groomer" color coding
- Per-groomer visibility toggles with color-coded buttons
- Appointments colored by assigned groomer in groomer view
- Groomer name shown on appointment blocks in groomer view
- Unassigned appointments shown in neutral gray

Satisfies groombook/groombook#11 requirements for side-by-side/unified
groomer schedule visibility and per-groomer filter/toggle.

Co-authored-by: Groom Book CTO <cto@groombook.app>
Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-03-17 21:55:07 +00:00
groombook-paperclip[bot] e7cf185d8c feat: recurring appointments with cascading change propagation (#28)
* feat: recurring appointments with cascading change propagation

Implements GitHub issue #9 — recurring appointment scheduling with
configurable frequency and cascade edit/cancel options.

Changes:
- DB: add `recurring_series` table (frequency_weeks) and series_id /
  series_index columns on appointments (migration 0003)
- API POST /appointments: accepts optional `recurrence` object
  (frequencyWeeks + count) that creates a full series in one transaction
- API PATCH /appointments/🆔 new `cascadeMode` field
  (this_only | this_and_future | all) applies time-delta shifts and
  field updates across the series
- API DELETE /appointments/🆔 new `?cascade=` query param cancels
  this_only / this_and_future / all series members
- Frontend: booking form gains a "Recurring appointment" checkbox with
  frequency and count pickers; calendar chips show a ↻ recurring label;
  detail modal shows "Recurring series" badge and a cascade-delete radio
  picker for series appointments

Co-Authored-By: Paperclip <noreply@paperclip.ing>

* fix: resolve TypeScript errors in recurring appointments route

Guard against possibly-undefined results from Drizzle .returning()
destructuring — use indexed access + explicit null checks instead of
array destructuring for the recurring_series insert, and add an early
throw when the series or first appointment row is missing.

Co-Authored-By: Paperclip <noreply@paperclip.ing>

---------

Co-authored-by: Groom Book CTO <cto@groombook.app>
Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-03-17 20:37:33 +00:00
groombook-paperclip[bot] 4f92b8bffb feat: appointment scheduling, client/pet/service/staff CRUD UI
* feat: appointment scheduling, client/pet/service/staff CRUD UI

- Weekly calendar view with navigation, color-coded by status
- Booking form with client→pet→service→staff→date/time flow
- Double-booking conflict detection on POST/PATCH appointments
- DELETE /api/appointments endpoint
- Staff API route (/api/staff) with full CRUD
- Clients page: searchable list, create/edit clients, add/edit pets
- Services page: table with create/edit/toggle-active
- Staff page: table with create/edit/toggle-active
- Nav bar with active-link highlighting, Staff link added

Resolves GitHub groombook/groombook#1, #2, #8

Co-Authored-By: Paperclip <noreply@paperclip.ing>

* fix: remove unused import, fix useCallback deps

- Remove unused `or` import from drizzle-orm in appointments route
- Compute week end directly in loadAppointments callback to avoid
  exhaustive-deps lint warning (weekEnd derived from weekStart)

Co-Authored-By: Paperclip <noreply@paperclip.ing>

* chore: add pnpm lockfile

Required for CI --frozen-lockfile installs.

Co-Authored-By: Paperclip <noreply@paperclip.ing>

* fix: resolve all typecheck, lint, and test failures

- Add @types/node to packages/db devDependencies (typecheck was missing process)
- Re-export drizzle-orm helpers (eq, gte, etc.) from @groombook/db to avoid
  duplicate-instance type conflicts; remove drizzle-orm direct dep from API
- Add @hono/zod-validator and jose as direct API dependencies
- Merge duplicate @groombook/db imports in all route files
- Fix noUncheckedIndexedAccess errors: appointments PATCH, web calendar grid
- Fix weightKg/dateOfBirth type conversion in pets route (numeric→string, string→Date)
- Add eslint.config.js for API and web (ESLint 9 flat config format)
- Add vitest.config.ts with passWithNoTests for API and web

Co-Authored-By: Paperclip <noreply@paperclip.ing>

---------

Co-authored-by: Groom Book CTO <cto@groombook.app>
Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-03-17 18:45:28 +00:00
Groom Book CTO a36436d128 Bootstrap monorepo: Hono API, React PWA, Drizzle DB, CI/CD
Sets up the initial project structure for groombook/groombook:

- pnpm monorepo with apps/api (Hono + TypeScript), apps/web (React + Vite + PWA), packages/db (Drizzle ORM), packages/types (shared types)
- Core DB schema: clients, pets, services, appointments, staff with CNPG-compatible Postgres
- REST API routes for clients, pets, services, appointments with Zod validation
- OIDC auth middleware for Authentik integration
- React PWA with vite-plugin-pwa, service worker, offline caching, installable manifest
- GitHub Actions CI: lint, typecheck, test, build, Docker image build (groombook-runners)
- Dockerfiles for API (Node.js) and Web (nginx)
- docker-compose.yml for local development

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-03-17 16:11:04 +00:00