Rename /success to /manage and fix link in calendar event (#5719)

* fix need to make changes link in calendar event

* change /success link to /manage

* delete success.tsx file and use next.js rewrites

* fix e2e tests

* remove not needed waitForNavigation

* fix e2e tests

* rename manage?uid to booking/uid

* fix rewrite

* remove not needed export

* fix rescheduling e2e tests

* Minor fixes/cleannup

* Update BookingPage.tsx

* Moves cancel page to rewrite

Co-authored-by: CarinaWolli <wollencarina@gmail.com>
Co-authored-by: Peer Richelsen <peeroke@gmail.com>
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
Co-authored-by: zomars <zomars@me.com>
This commit is contained in:
Carina Wollendorfer 2022-11-29 21:27:29 +01:00 committed by GitHub
parent 0c746ec10f
commit dff49ec28a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 46 additions and 62 deletions

View File

@ -118,7 +118,7 @@ function BookingListItem(booking: BookingItemProps) {
label: isTabRecurring && isRecurring ? t("cancel_all_remaining") : t("cancel"),
/* When cancelling we need to let the UI and the API know if the intention is to
cancel all remaining bookings or just that booking instance. */
href: `/success?uid=${booking.uid}&cancel=true${
href: `/booking/${booking.uid}?cancel=true${
isTabRecurring && isRecurring ? "&allRemainingBookings=true" : ""
}`,
icon: Icon.FiX,
@ -195,11 +195,9 @@ function BookingListItem(booking: BookingItemProps) {
const onClickTableData = () => {
router.push({
pathname: "/success",
pathname: `/booking/${booking.uid}`,
query: {
uid: booking.uid,
allRemainingBookings: isTabRecurring,
listingStatus: booking.listingStatus,
email: booking.attendees[0] ? booking.attendees[0].email : undefined,
},
});

View File

@ -136,9 +136,8 @@ const BookingPage = ({
}
return router.push({
pathname: "/success",
pathname: `/booking/${uid}`,
query: {
uid,
isSuccessBookingPage: true,
email: bookingForm.getValues("email"),
eventTypeSlug: eventType.slug,
@ -152,9 +151,8 @@ const BookingPage = ({
const { uid } = responseData[0] || {};
return router.push({
pathname: "/success",
pathname: `/booking/${uid}`,
query: {
uid,
allRemainingBookings: true,
email: bookingForm.getValues("email"),
eventTypeSlug: eventType.slug,

View File

@ -47,7 +47,7 @@ export const RescheduleDialog = (props: IRescheduleDialog) => {
</div>
<div className="pt-1">
<DialogHeader title={t("send_reschedule_request")} />
<p className="-mt-8 text-sm text-gray-500">{t("reschedule_modal_description")}</p>
<p className="text-sm text-gray-500">{t("reschedule_modal_description")}</p>
<p className="mt-6 mb-2 text-sm font-bold text-black">
{t("reason_for_reschedule_request")}
<span className="font-normal text-gray-500"> (Optional)</span>

View File

@ -2,7 +2,7 @@ import { useRouter } from "next/router";
export default function usePublicPage() {
const router = useRouter();
const isPublicPage = ["/[user]", "/success", "/cancel", "/reschedule"].find((route) =>
const isPublicPage = ["/[user]", "/booking", "/cancel", "/reschedule"].find((route) =>
router.pathname.startsWith(route)
);
return isPublicPage;

View File

@ -149,6 +149,21 @@ const nextConfig = {
source: "/router",
destination: "/apps/routing-forms/router",
},
{
source: "/success/:path*",
has: [
{
type: "query",
key: "uid",
value: "(?<uid>.*)",
},
],
destination: "/booking/:uid/:path*",
},
{
source: "/cancel/:path*",
destination: "/booking/:path*",
},
/* TODO: have these files being served from another deployment or CDN {
source: "/embed/embed.js",
destination: process.env.NEXT_PUBLIC_EMBED_LIB_URL?,

View File

@ -38,7 +38,7 @@ export default function Custom404() {
setUrl(`${WEBSITE_URL}/signup?username=${username.replace("/", "")}`);
}, [username]);
const isSuccessPage = router.asPath.startsWith("/success");
const isSuccessPage = router.asPath.startsWith("/booking");
const isSubpage = router.asPath.includes("/", 2) || isSuccessPage;
const isSignup = router.asPath.startsWith("/signup");
const isCalcom = process.env.NEXT_PUBLIC_WEBAPP_URL === "https://app.cal.com";

View File

@ -147,6 +147,7 @@ const querySchema = z.object({
uid: z.string(),
allRemainingBookings: stringToBoolean,
cancel: stringToBoolean,
changes: stringToBoolean,
reschedule: stringToBoolean,
isSuccessBookingPage: z.string().optional(),
});
@ -159,9 +160,10 @@ export default function Success(props: SuccessProps) {
allRemainingBookings,
isSuccessBookingPage,
cancel: isCancellationMode,
changes,
} = querySchema.parse(router.query);
if (isCancellationMode && typeof window !== "undefined") {
if ((isCancellationMode || changes) && typeof window !== "undefined") {
window.scrollTo(0, document.body.scrollHeight);
}
const location: ReturnType<typeof getEventLocationValue> = Array.isArray(props.bookingInfo.location)
@ -221,7 +223,7 @@ export default function Success(props: SuccessProps) {
useEffect(() => {
if (top !== window) {
//page_view will be collected automatically by _middleware.ts
telemetry.event(telemetryEventTypes.embedView, collectPageParameters("/success"));
telemetry.event(telemetryEventTypes.embedView, collectPageParameters("/booking"));
}
}, [telemetry]);

View File

@ -1,24 +0,0 @@
import { GetServerSidePropsContext } from "next";
import z from "zod";
const querySchema = z.object({
uid: z.string(),
allRemainingBookings: z
.string()
.optional()
.transform((val) => (val ? JSON.parse(val) : false)),
});
export default function Type() {
return <></>;
}
export const getServerSideProps = async (context: GetServerSidePropsContext) => {
const { allRemainingBookings, uid } = querySchema.parse(context.query);
return {
redirect: {
permanent: false,
destination: `/success?uid=${uid}&allRemainingBookings=${allRemainingBookings}&cancel=true`,
},
};
};

View File

@ -93,7 +93,7 @@ test.describe("pro user", () => {
await page.locator('[data-testid="confirm-reschedule-button"]').click();
await page.waitForNavigation({
url(url) {
return url.pathname === "/success";
return url.pathname.startsWith("/booking");
},
});
});
@ -108,10 +108,9 @@ test.describe("pro user", () => {
await page.locator('[data-testid="cancel"]').first().click();
await page.waitForNavigation({
url: (url) => {
return url.pathname.startsWith("/success");
return url.pathname.startsWith("/booking");
},
});
// --- fill form
await page.locator('[data-testid="cancel"]').click();
const cancelledHeadline = await page.locator('[data-testid="cancelled-headline"]').innerText();

View File

@ -37,7 +37,7 @@ test("dynamic booking", async ({ page, users }) => {
await page.locator('[data-testid="confirm-reschedule-button"]').click();
await page.waitForNavigation({
url(url) {
return url.pathname === "/success";
return url.pathname.startsWith("/booking");
},
});
await expect(page.locator("[data-testid=success-page]")).toBeVisible();
@ -48,10 +48,9 @@ test("dynamic booking", async ({ page, users }) => {
await page.locator('[data-testid="cancel"]').first().click();
await page.waitForNavigation({
url: (url) => {
return url.pathname.startsWith("/success");
return url.pathname.startsWith("/booking");
},
});
// --- fill form
await page.locator('[data-testid="cancel"]').click();
const cancelledHeadline = await page.locator('[data-testid="cancelled-headline"]').innerText();

View File

@ -112,7 +112,7 @@ async function bookEventOnThisPage(page: Page) {
// Make sure we're navigated to the success page
await page.waitForNavigation({
url(url) {
return url.pathname.endsWith("/success");
return url.pathname.startsWith("/booking");
},
});
await expect(page.locator("[data-testid=success-page]")).toBeVisible();

View File

@ -150,7 +150,7 @@ test.describe("Reschedule Tests", async () => {
await page.locator('[data-testid="confirm-reschedule-button"]').click();
await expect(page).toHaveURL(/.*success/);
await expect(page).toHaveURL(/.*booking/);
await payment.delete();
});
@ -168,7 +168,7 @@ test.describe("Reschedule Tests", async () => {
await page.locator('[data-testid="confirm-reschedule-button"]').click();
await expect(page).toHaveURL(/.*success/);
await expect(page).toHaveURL(/.*booking/);
const newBooking = await prisma.booking.findFirst({ where: { fromReschedule: booking?.uid } });
expect(newBooking).not.toBeNull();
@ -189,7 +189,7 @@ test.describe("Reschedule Tests", async () => {
await page.locator('[data-testid="confirm-reschedule-button"]').click();
await expect(page).toHaveURL(/.*success/);
await expect(page).toHaveURL(/.*booking/);
const newBooking = await prisma.booking.findFirst({ where: { fromReschedule: booking?.uid } });
expect(newBooking).not.toBeNull();

View File

@ -1,7 +1,7 @@
import { createEvent, DateArray, Person } from "ics";
import dayjs from "@calcom/dayjs";
import { getCancelLink } from "@calcom/lib/CalEventParser";
import { getManageLink } from "@calcom/lib/CalEventParser";
import type { CalendarEvent } from "@calcom/types/Calendar";
import { renderEmail } from "..";
@ -89,7 +89,7 @@ ${this.t("request_reschedule_subtitle", {
})},
${this.getWhen()}
${this.t("need_to_reschedule_or_cancel")}
${getCancelLink(this.calEvent)}
${getManageLink(this.calEvent)}
`.replace(/(<([^>]+)>)/gi, "");
}
}

View File

@ -81,9 +81,7 @@ export default function PaymentComponent(props: Props) {
error: new Error(`Payment failed: ${payload.error.message}`),
});
} else {
const params: { [k: string]: any } = {
uid: props.bookingUid,
};
const params: { [k: string]: any } = {};
if (props.location) {
if (props.location.includes("integration")) {
@ -94,7 +92,7 @@ export default function PaymentComponent(props: Props) {
}
const query = stringify(params);
const successUrl = `/success?${query}`;
const successUrl = `/booking/${props.bookingUid}?${query}`;
await router.push(successUrl);
}

View File

@ -123,21 +123,20 @@ export const getProviderName = (calEvent: CalendarEvent): string => {
return "";
};
export const getManageLink = (calEvent: CalendarEvent) => {
return `
${calEvent.organizer.language.translate("need_to_reschedule_or_cancel")}
${getCancelLink(calEvent)}
`;
};
export const getUid = (calEvent: CalendarEvent): string => {
return calEvent.uid ?? translator.fromUUID(uuidv5(JSON.stringify(calEvent), uuidv5.URL));
};
export const getManageLink = (calEvent: CalendarEvent) => {
return `
${calEvent.organizer.language.translate("need_to_reschedule_or_cancel")}
${WEBAPP_URL + "/booking/" + getUid(calEvent) + "?changes=true"}
`;
};
export const getCancelLink = (calEvent: CalendarEvent): string => {
return (
WEBAPP_URL +
`/success?uid=${getUid(calEvent)}&cancel=true&allRemainingBookings=${!!calEvent.recurringEvent}`
WEBAPP_URL + `/booking/${getUid(calEvent)}?cancel=true&allRemainingBookings=${!!calEvent.recurringEvent}`
);
};