Compare commits

...
4 Commits
Author SHA1 Message Date
GitHub Actions 0b2f09ab7d chore: release v4.8.5
Post release / release (push) Canceled after 0s
2024-12-19 15:10:13 +00:00
Benny Joo 355aaa7010 fix: include app directory in rewrites generation logic + migrate /reschedule pages to App Router (#18261)
* chore: app router - /reschedule pages (#18150)

* app router - /reschedule pages

* add to config.matcher

* generateMetdata is not needed

* include app directory in rewrites generation logic

* make it more readable

* make code more elegant

* fix

* fix

* fix

* fix

* test and refactor
2024-12-19 06:22:19 -07:00
Rajiv Sahal c27b73aa9a fix: event type atom availability (#18263) 2024-12-19 16:38:05 +05:30
Somay Chauhan a622c7b624 fix: seats option not working for booker atom (#18265) 2024-12-19 08:07:40 +00:00
12 changed files with 161 additions and 32 deletions
View File
@@ -10,7 +10,7 @@ export class OutputSchedulesService_2024_06_11 {
async getResponseSchedule(databaseSchedule: Schedule & { availability: Availability[] }) {
if (!databaseSchedule.timeZone) {
throw new Error("Failed to create schedule because its timezone is not set.");
databaseSchedule.timeZone = "Europe/London";
}
const ownerDefaultScheduleId = await this.usersRepository.getUserScheduleDefaultId(
@@ -1,15 +1,17 @@
import { getServerSideProps as _getServerSideProps } from "@pages/reschedule/[uid]";
import { withAppDirSsr } from "app/WithAppDirSsr";
import withEmbedSsrAppDir from "app/WithEmbedSSR";
import type { PageProps } from "app/_types";
import { cookies, headers } from "next/headers";
import { buildLegacyCtx } from "@lib/buildLegacyCtx";
import withEmbedSsr from "@lib/withEmbedSsr";
import { getServerSideProps } from "@lib/reschedule/[uid]/getServerSideProps";
const getData = withEmbedSsr(_getServerSideProps);
const getData = withAppDirSsr(getServerSideProps);
const getEmbedData = withEmbedSsrAppDir(getData);
const Page = async ({ params, searchParams }: PageProps) => {
const legacyCtx = buildLegacyCtx(headers(), cookies(), params, searchParams);
await getData(legacyCtx);
await getEmbedData(legacyCtx);
return null;
};
@@ -1,17 +1,10 @@
import { withAppDirSsr } from "app/WithAppDirSsr";
import type { PageProps } from "app/_types";
import { _generateMetadata } from "app/_utils";
import { headers, cookies } from "next/headers";
import { buildLegacyCtx } from "@lib/buildLegacyCtx";
import { getServerSideProps } from "@lib/reschedule/[uid]/getServerSideProps";
export const generateMetadata = async () =>
await _generateMetadata(
() => "",
() => ""
);
const getData = withAppDirSsr(getServerSideProps);
const Page = async ({ params, searchParams }: PageProps) => {
+1
View File
@@ -192,6 +192,7 @@ export const config = {
"/teams",
"/future/teams/",
"/settings/:path*",
"/reschedule/:path*",
"/availability/:path*",
"/booking/:path*",
],
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@calcom/web",
"version": "4.8.4",
"version": "4.8.5",
"private": true,
"scripts": {
"analyze": "ANALYZE=true next build",
-6
View File
@@ -1,6 +0,0 @@
export default function Type() {
// Just redirect to the schedule page to reschedule it.
return null;
}
export { getServerSideProps } from "@lib/reschedule/[uid]/getServerSideProps";
@@ -1,7 +0,0 @@
import withEmbedSsr from "@lib/withEmbedSsr";
import { getServerSideProps as _getServerSideProps } from "../[uid]";
export { default } from "../[uid]";
export const getServerSideProps = withEmbedSsr(_getServerSideProps);
+19 -3
View File
@@ -1,15 +1,31 @@
const glob = require("glob");
const { getSubdomainRegExp } = require("./getSubdomainRegExp");
/** Needed to rewrite public booking page, gets all static pages but [user] */
// Pages found here are excluded from redirects in beforeFiles in next.config.js
let pages = (exports.pages = glob
.sync("pages/**/[^_]*.{tsx,js,ts}", { cwd: __dirname })
.sync("{pages,app}/**/[^_]*.{tsx,js,ts}", { cwd: __dirname })
.map((filename) =>
filename
.substr(6)
.replace(/^(pages|app)\//, "")
.replace(/(\.tsx|\.js|\.ts)/, "")
.replace(/\/.*/, "")
)
.filter((v, i, self) => self.indexOf(v) === i && !v.startsWith("[user]")));
// "/future" is a temporary directory for incremental migration to App Router
.filter(
(v, i, self) =>
self.indexOf(v) === i &&
![
"[user]",
"future",
"_trpc",
"layout",
"layoutHOC",
"WithAppDirSsg",
"global-error",
"WithAppDirSsr",
"WithEmbedSSR",
].some((prefix) => v.startsWith(prefix))
));
// .* matches / as well(Note: *(i.e wildcard) doesn't match / but .*(i.e. RegExp) does)
// It would match /free/30min but not /bookings/upcoming because 'bookings' is an item in pages
@@ -0,0 +1,45 @@
import { it, expect, describe } from "vitest";
import { pages } from "../../pagesAndRewritePaths.js";
describe("pagesAndRewritePaths", () => {
describe("beforeFiles must exclude routes in pages/app router", () => {
const BEFORE_REWRITE_EXCLUDE_PAGES = [
"apps",
"availability",
"booking",
"connect-and-join",
"enterprise",
"error",
"getting-started",
"insights",
"maintenance",
"more",
"not-found",
"reschedule",
"settings",
"teams",
"upgrade",
"video",
"workflows",
"403",
"404",
"500",
"bookings",
"event-types",
"icons",
"org",
"payment",
"routing-forms",
"signup",
"team",
"d",
];
it("should include all required routes", () => {
BEFORE_REWRITE_EXCLUDE_PAGES.forEach((route) => {
expect(pages).toContain(route);
});
});
});
});
@@ -8,6 +8,11 @@ import {
systemBeforeFieldLocation,
systemAfterFieldRescheduleReason,
transformRecurrenceApiToInternal,
transformIntervalLimitsApiToInternal,
transformSeatsApiToInternal,
transformEventColorsApiToInternal,
transformConfirmationPolicyApiToInternal,
transformFutureBookingLimitsApiToInternal,
} from "@calcom/lib/event-types/transformers";
import { getBookerBaseUrlSync } from "@calcom/lib/getBookerUrl/client";
import type {
@@ -33,11 +38,28 @@ export function transformApiEventTypeForAtom(
entity: BookerPlatformWrapperAtomProps["entity"] | undefined,
defaultFormValues: BookerPlatformWrapperAtomProps["defaultFormValues"] | undefined
) {
const { lengthInMinutes, locations, bookingFields, users, recurrence, ...rest } = eventType;
const {
lengthInMinutes,
lengthInMinutesOptions,
locations,
bookingFields,
users,
recurrence,
bookingLimitsCount,
bookingLimitsDuration,
seats,
color,
confirmationPolicy,
customName,
useDestinationCalendarEmail,
bookingWindow,
...rest
} = eventType;
const isDefault = isDefaultEvent(rest.title);
const user = users[0];
const confirmationPolicyTransformed = transformConfirmationPolicyApiToInternal(confirmationPolicy);
const defaultEventBookerLayouts = {
enabledLayouts: [...bookerLayoutOptions],
defaultLayout: BookerLayouts.MONTH_VIEW,
@@ -101,7 +123,27 @@ export function transformApiEventTypeForAtom(
upId: `usr-${user.id}`,
},
})),
bookingLimits: bookingLimitsCount ? transformIntervalLimitsApiToInternal(bookingLimitsCount) : undefined,
durationLimits: bookingLimitsDuration
? transformIntervalLimitsApiToInternal(bookingLimitsDuration)
: undefined,
metadata: {
requiresConfirmationThreshold:
confirmationPolicyTransformed?.requiresConfirmationThreshold ?? undefined,
multipleDuration: lengthInMinutesOptions,
},
requiresConfirmation: confirmationPolicyTransformed?.requiresConfirmation ?? undefined,
requiresConfirmationWillBlockSlot:
confirmationPolicyTransformed?.requiresConfirmationWillBlockSlot ?? undefined,
eventTypeColor: transformEventColorsApiToInternal(color),
recurringEvent: recurrence ? transformRecurrenceApiToInternal(recurrence) : null,
...transformSeatsApiToInternal(seats),
eventName: customName,
useEventTypeDestinationCalendarEmail: useDestinationCalendarEmail,
...getBookingWindow(bookingWindow),
};
}
@@ -110,10 +152,28 @@ export function transformApiTeamEventTypeForAtom(
entity: BookerPlatformWrapperAtomProps["entity"] | undefined,
defaultFormValues: BookerPlatformWrapperAtomProps["defaultFormValues"] | undefined
) {
const { lengthInMinutes, locations, hosts, bookingFields, recurrence, team, ...rest } = eventType;
const {
lengthInMinutes,
lengthInMinutesOptions,
locations,
hosts,
bookingFields,
recurrence,
team,
bookingLimitsCount,
bookingLimitsDuration,
seats,
color,
confirmationPolicy,
customName,
useDestinationCalendarEmail,
bookingWindow,
...rest
} = eventType;
const isDefault = isDefaultEvent(rest.title);
const confirmationPolicyTransformed = transformConfirmationPolicyApiToInternal(confirmationPolicy);
const defaultEventBookerLayouts = {
enabledLayouts: [...bookerLayoutOptions],
defaultLayout: BookerLayouts.MONTH_VIEW,
@@ -191,6 +251,26 @@ export function transformApiTeamEventTypeForAtom(
},
})),
recurringEvent: recurrence ? transformRecurrenceApiToInternal(recurrence) : null,
bookingLimits: bookingLimitsCount ? transformIntervalLimitsApiToInternal(bookingLimitsCount) : undefined,
durationLimits: bookingLimitsDuration
? transformIntervalLimitsApiToInternal(bookingLimitsDuration)
: undefined,
metadata: {
requiresConfirmationThreshold:
confirmationPolicyTransformed?.requiresConfirmationThreshold ?? undefined,
multipleDuration: lengthInMinutesOptions,
},
requiresConfirmation: confirmationPolicyTransformed?.requiresConfirmation ?? undefined,
requiresConfirmationWillBlockSlot:
confirmationPolicyTransformed?.requiresConfirmationWillBlockSlot ?? undefined,
eventTypeColor: transformEventColorsApiToInternal(color),
...transformSeatsApiToInternal(seats),
eventName: customName,
useEventTypeDestinationCalendarEmail: useDestinationCalendarEmail,
...getBookingWindow(bookingWindow),
};
}
@@ -298,6 +378,11 @@ function isCustomField(
return field.type !== "unknown" && !field.isDefault;
}
function getBookingWindow(inputBookingWindow: EventTypeOutput_2024_06_14["bookingWindow"]) {
const res = transformFutureBookingLimitsApiToInternal(inputBookingWindow);
return !!res ? res : {};
}
function isDefaultEditableField(
field: EventTypeOutput_2024_06_14["bookingFields"][number]
): field is NameDefaultFieldOutput_2024_06_14 | EmailDefaultFieldOutput_2024_06_14 {
@@ -29,7 +29,7 @@ const EventAvailabilityTabPlatformWrapper = ({
const scheduleId = formMethods.watch("schedule");
const { isLoading: isSchedulePending, data: scheduleQueryData } = useSchedule(
scheduleId || (!props.isTeamEvent ? user?.defaultScheduleId : undefined) || undefined
scheduleId || user?.defaultScheduleId || undefined
);
const { data: schedulesQueryData, isLoading: isSchedulesPending } = useSchedules();