Compare commits

...

2 Commits

Author SHA1 Message Date
Flea Flicker 82f1e3856f fix(e2e): respect PLAYWRIGHT_BASE_URL env var and add host.docker.internal resolution
CI / Test (pull_request) Successful in 28s
CI / Lint & Typecheck (pull_request) Successful in 31s
CI / E2E Tests (pull_request) Successful in 1m32s
CI / Build (pull_request) Successful in 2m32s
CI / Build & Push Docker Images (pull_request) Successful in 35s
CI / Update Infra Image Tags (pull_request) Has been skipped
CI / Web E2E (Dev) (pull_request) Has been cancelled
CI / Deploy PR to groombook-dev (pull_request) Has been cancelled
The Playwright config hardcoded localhost:8080 as baseURL, ignoring
the PLAYWRIGHT_BASE_URL env var set in CI. Docker Compose was also
missing extra_hosts to resolve host.docker.internal on Gitea Actions
runners (which use DIND).

Fixes GRO-1496.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-05-21 20:53:30 +00:00
Flea Flicker 526251b63a fix: resolve lint errors and xlarge mismatch for dev→uat promotion
CI / Test (push) Successful in 26s
CI / Lint & Typecheck (push) Successful in 27s
CI / E2E Tests (push) Failing after 3m27s
CI / Update Infra Image Tags (push) Has been skipped
CI / Build (push) Successful in 24s
CI / Build & Push Docker Images (push) Has been skipped
CI / Web E2E (Dev) (push) Has been cancelled
CI / Deploy PR to groombook-dev (push) Has been cancelled
- Remove unused gte/lt/ne imports from cascade.ts
- Prefix unused params originalEndTime, originalStartTime, newStartTime
  with underscore in cascade.ts and appointments.ts callers
- Remove unused petCoatType query param from book.ts availability route
- Align xlarge value: Book.tsx now uses "xlarge" (no hyphen) everywhere
  to match the Zod booking schema

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-05-21 20:28:43 +00:00
6 changed files with 14 additions and 13 deletions
+7 -7
View File
@@ -1,4 +1,4 @@
import { eq, and, gt, gte, lt, ne, or, asc } from "@groombook/db";
import { eq, and, gt, or, asc } from "@groombook/db";
import { appointments, clients, pets, services, staff, type Db } from "@groombook/db";
import { resolveBufferMinutes } from "./buffer.js";
import { sendEmail, buildRescheduleNotificationEmail } from "../services/email.js";
@@ -53,12 +53,12 @@ export async function detectAndCascadeOverrun({
db,
overrunningAppointmentId,
newEndTime,
originalEndTime,
_originalEndTime,
}: {
db: Db;
overrunningAppointmentId: string;
newEndTime: Date;
originalEndTime: Date;
_originalEndTime: Date;
}): Promise<CascadeResult> {
const result: CascadeResult = { shifted: [], flaggedForReview: [] };
@@ -178,16 +178,16 @@ export async function detectAndCascadeOverrun({
export function isOverrun({
originalEndTime,
newEndTime,
originalStartTime,
newStartTime,
_originalStartTime,
_newStartTime,
status,
currentTime,
bufferMinutes,
}: {
originalEndTime: Date;
newEndTime: Date;
originalStartTime: Date;
newStartTime?: Date;
_originalStartTime: Date;
_newStartTime?: Date;
status: string;
currentTime: Date;
bufferMinutes: number;
+2 -2
View File
@@ -700,7 +700,7 @@ appointmentsRouter.patch(
isOverrun({
originalEndTime,
newEndTime: new Date(updateFields.endTime),
originalStartTime: row.startTime,
_originalStartTime: row.startTime,
status: row.status,
currentTime: new Date(),
bufferMinutes: row.bufferMinutes ?? 0,
@@ -710,7 +710,7 @@ appointmentsRouter.patch(
db,
overrunningAppointmentId: id,
newEndTime: new Date(updateFields.endTime),
originalEndTime,
_originalEndTime: originalEndTime,
});
return c.json({ ...row, cascade: cascadeResult });
}
-1
View File
@@ -44,7 +44,6 @@ bookRouter.get("/availability", async (c) => {
const serviceId = c.req.query("serviceId");
const dateStr = c.req.query("date");
const petSizeCategory = c.req.query("petSizeCategory") ?? undefined;
const petCoatType = c.req.query("petCoatType") ?? undefined;
if (!serviceId || !dateStr) {
return c.json({ error: "serviceId and date are required" }, 400);
+1 -1
View File
@@ -19,7 +19,7 @@ export default defineConfig({
reporter: process.env.CI ? "github" : "list",
use: {
baseURL: "http://localhost:8080",
baseURL: process.env.PLAYWRIGHT_BASE_URL ?? "http://localhost:8080",
trace: "on-first-retry",
screenshot: "only-on-failure",
serviceWorkers: "block",
+2 -2
View File
@@ -515,7 +515,7 @@ export function BookPage() {
<option value="small">Small (under 15 lbs)</option>
<option value="medium">Medium (1540 lbs)</option>
<option value="large">Large (4080 lbs)</option>
<option value="x-large">X-Large (over 80 lbs)</option>
<option value="xlarge">X-Large (over 80 lbs)</option>
</select>
</div>
<div>
@@ -568,7 +568,7 @@ export function BookPage() {
<div>
<div style={{ color: "#9ca3af", fontSize: 12, fontWeight: 600, textTransform: "uppercase" }}>Service</div>
<div style={{ fontWeight: 600 }}>{selectedService.name}</div>
<div style={{ color: "#6b7280" }}>{fmtPrice(selectedService.basePriceCents)} · {fmtDuration(selectedService.durationMinutes + ((form.petSizeCategory === "large" || form.petSizeCategory === "x-large") ? (selectedService.defaultBufferMinutes ?? 0) : 0))}</div>
<div style={{ color: "#6b7280" }}>{fmtPrice(selectedService.basePriceCents)} · {fmtDuration(selectedService.durationMinutes + ((form.petSizeCategory === "large" || form.petSizeCategory === "xlarge") ? (selectedService.defaultBufferMinutes ?? 0) : 0))}</div>
</div>
<div>
<div style={{ color: "#9ca3af", fontSize: 12, fontWeight: 600, textTransform: "uppercase" }}>Date & Time</div>
+2
View File
@@ -50,6 +50,8 @@ services:
dockerfile: apps/web/Dockerfile
ports:
- "8080:80"
extra_hosts:
- "host.docker.internal:host-gateway"
depends_on:
- api