fix: maintain uid parameter in BookingDetailsSheet URL (#27872)

* fix: maintain uid parameter in BookingDetailsSheet URL

Move the isSyncedFromUrlToStoreRef guard from the effect level to inside
the Zustand subscription callback. This ensures the Store→URL subscription
is always created while still preventing premature URL overwrites during
URL→Store sync.

Also adds an E2E test verifying the uid parameter appears in the URL
after clicking a booking item in the v3 bookings view.

Co-Authored-By: eunjae@cal.com <hey@eunjae.dev>

* Update apps/web/playwright/bookings-list.e2e.ts

Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>

* fix: clean up bookings-v3 feature flag after E2E test

Co-Authored-By: eunjae@cal.com <hey@eunjae.dev>

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>
This commit is contained in:
Eunjae Lee
2026-02-12 10:39:08 +05:30
committed by GitHub
co-authored by cubic-dev-ai[bot] Devin AI
parent 0d55939d13
commit c7e66a3aa9
2 changed files with 51 additions and 4 deletions
@@ -185,11 +185,8 @@ function useBiDirectionalSyncBetweenStoreAndUrl({ store }: { store: BookingDetai
// Sync Store → URL
useEffect(() => {
// We can't sync from Store to URL if URL hasn't first been synced to Store
// This is to prevent override of any user configuration provided by URL query params. Think about page being refreshed
if (!isSyncedFromUrlToStoreRef.current) return;
const unsubscribe = store.subscribe((state) => {
if (!isSyncedFromUrlToStoreRef.current) return;
if (state.selectedBookingUid !== selectedBookingUidFromUrl) {
setSelectedBookingUidToUrl(state.selectedBookingUid);
}
+50
View File
@@ -763,6 +763,56 @@ test.describe("Bookings", () => {
.toBe(1);
});
});
test("clicking a booking item adds uid param to URL when bookings-v3 is enabled", async ({
page,
users,
bookings,
prisma,
}) => {
const existingFlag = await prisma.feature.findUnique({ where: { slug: "bookings-v3" } });
await prisma.feature.upsert({
where: { slug: "bookings-v3" },
update: { enabled: true },
create: { slug: "bookings-v3", enabled: true, type: "OPERATIONAL" },
});
try {
const user = await users.create();
const bookingFixture = await createBooking({
title: "Test booking for uid param",
bookingsFixture: bookings,
relativeDate: 3,
organizer: user,
organizerEventType: user.eventTypes[0],
attendees: [{ name: "Attendee", email: "attendee@example.com", timeZone: "Europe/Berlin" }],
});
await user.apiLogin();
const bookingsGetResponse = page.waitForResponse((response) =>
/\/api\/trpc\/bookings\/get.*/.test(response.url())
);
await page.goto("/bookings/upcoming", { waitUntil: "domcontentloaded" });
await bookingsGetResponse;
const bookingItem = page.locator(`[data-booking-uid="${bookingFixture.uid}"]`);
await expect(bookingItem).toBeVisible();
await bookingItem.locator('[role="button"]').first().click();
await expect(page).toHaveURL(new RegExp(`[?&]uid=${bookingFixture.uid}(&|$)`));
} finally {
if (existingFlag) {
await prisma.feature.update({
where: { slug: "bookings-v3" },
data: { enabled: existingFlag.enabled },
});
} else {
await prisma.feature.deleteMany({ where: { slug: "bookings-v3" } });
}
}
});
});
async function createBooking({