More dry run fixes (#18865)
This commit is contained in:
@@ -42,7 +42,9 @@ export default function DryRunSuccessful() {
|
|||||||
<div className="bg-success mx-auto mb-4 flex h-12 w-12 items-center justify-center rounded-full">
|
<div className="bg-success mx-auto mb-4 flex h-12 w-12 items-center justify-center rounded-full">
|
||||||
<Icon name="check" className="h-6 w-6 text-green-600 dark:text-green-400" />
|
<Icon name="check" className="h-6 w-6 text-green-600 dark:text-green-400" />
|
||||||
</div>
|
</div>
|
||||||
<h1 className="text-emphasis mb-4 text-2xl font-medium">{t("booking_dry_run_successful")}</h1>
|
<h1 className="text-emphasis mb-4 text-2xl font-medium" data-testid="dry-run-success-msg">
|
||||||
|
{t("booking_dry_run_successful")}
|
||||||
|
</h1>
|
||||||
<p className="text-default mb-8 max-w-2xl text-sm">{t("booking_dry_run_successful_description")}</p>
|
<p className="text-default mb-8 max-w-2xl text-sm">{t("booking_dry_run_successful_description")}</p>
|
||||||
|
|
||||||
{/* <div className="border-subtle text-default mt-8 grid grid-cols-3 border-t pt-8 text-left">
|
{/* <div className="border-subtle text-default mt-8 grid grid-cols-3 border-t pt-8 text-left">
|
||||||
|
|||||||
@@ -4,6 +4,8 @@ import Head from "next/head";
|
|||||||
|
|
||||||
import type { inferSSRProps } from "@calcom/types/inferSSRProps";
|
import type { inferSSRProps } from "@calcom/types/inferSSRProps";
|
||||||
|
|
||||||
|
import PageWrapper from "@components/PageWrapper";
|
||||||
|
|
||||||
import { getServerSideProps } from "../../server/lib/router/getServerSideProps";
|
import { getServerSideProps } from "../../server/lib/router/getServerSideProps";
|
||||||
|
|
||||||
export default function Router({ form, message }: inferSSRProps<typeof getServerSideProps>) {
|
export default function Router({ form, message }: inferSSRProps<typeof getServerSideProps>) {
|
||||||
@@ -23,4 +25,6 @@ export default function Router({ form, message }: inferSSRProps<typeof getServer
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Router.PageWrapper = PageWrapper;
|
||||||
|
|
||||||
export { getServerSideProps };
|
export { getServerSideProps };
|
||||||
|
|||||||
@@ -0,0 +1,16 @@
|
|||||||
|
1. Navigate to Headless Router - acme.cal.com/router?formId={FORM_ID}&field1=value1&field2=value2
|
||||||
|
1. Validate the fields types and ensure required fields are present
|
||||||
|
2. Based on the fields values, choose a route.
|
||||||
|
3. Records a response for the form.
|
||||||
|
4. If the route is an eventTypeRedirect,
|
||||||
|
- Identify the teamMembers matching that route's attribute routing rules.
|
||||||
|
- Redirect to the booking page of the eventType, along with the `routedTeamMemberIds` query param that has the matching teamMembers' ids.
|
||||||
|
5. Notify through emails if they are members to be notified and fire Routing form related webhooks.
|
||||||
|
2. User reaches the booking page.
|
||||||
|
3. Sees the available slots for the matching teamMembers only
|
||||||
|
4. Selects a slot.
|
||||||
|
- Selecting a slot temporarily blocks the slot for other bookers.
|
||||||
|
5. Confirm the booking
|
||||||
|
1. Ensures that the members are available for the slot depending on various rules like type of event(RR, Collective) and other configurations in the eventType and selected calendars
|
||||||
|
2. Send Emails and fire webhooks
|
||||||
|
|
||||||
@@ -94,6 +94,7 @@ export function getFieldResponse({
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Not called in preview mode or dry run mode
|
* Not called in preview mode or dry run mode
|
||||||
|
* It takes care of sending webhooks and emails for form submissions
|
||||||
*/
|
*/
|
||||||
export async function onFormSubmission(
|
export async function onFormSubmission(
|
||||||
form: Ensure<
|
form: Ensure<
|
||||||
|
|||||||
@@ -19,7 +19,9 @@ export const DryRunMessage = ({ isEmbed }: { isEmbed?: boolean }) => {
|
|||||||
<div className="relative">
|
<div className="relative">
|
||||||
<Icon name="info" className="h-5 w-5 text-orange-500" />
|
<Icon name="info" className="h-5 w-5 text-orange-500" />
|
||||||
</div>
|
</div>
|
||||||
<div className="text-emphasis font-medium">{t("dry_run_mode_active")}</div>
|
<div className="text-emphasis font-medium" data-testid="dry-run-msg">
|
||||||
|
{t("dry_run_mode_active")}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -4,14 +4,17 @@ import { shallow } from "zustand/shallow";
|
|||||||
import dayjs from "@calcom/dayjs";
|
import dayjs from "@calcom/dayjs";
|
||||||
import { useBookerStore } from "@calcom/features/bookings/Booker/store";
|
import { useBookerStore } from "@calcom/features/bookings/Booker/store";
|
||||||
import { useSlotReservationId } from "@calcom/features/bookings/Booker/useSlotReservationId";
|
import { useSlotReservationId } from "@calcom/features/bookings/Booker/useSlotReservationId";
|
||||||
|
import { isBookingDryRun } from "@calcom/features/bookings/Booker/utils/isBookingDryRun";
|
||||||
import type { BookerEvent } from "@calcom/features/bookings/types";
|
import type { BookerEvent } from "@calcom/features/bookings/types";
|
||||||
import { MINUTES_TO_BOOK } from "@calcom/lib/constants";
|
import { MINUTES_TO_BOOK } from "@calcom/lib/constants";
|
||||||
|
import { useCompatSearchParams } from "@calcom/lib/hooks/useCompatSearchParams";
|
||||||
import { trpc } from "@calcom/trpc";
|
import { trpc } from "@calcom/trpc";
|
||||||
|
|
||||||
export type UseSlotsReturnType = ReturnType<typeof useSlots>;
|
export type UseSlotsReturnType = ReturnType<typeof useSlots>;
|
||||||
|
|
||||||
export const useSlots = (event: { data?: Pick<BookerEvent, "id" | "length"> | null }) => {
|
export const useSlots = (event: { data?: Pick<BookerEvent, "id" | "length"> | null }) => {
|
||||||
const selectedDuration = useBookerStore((state) => state.selectedDuration);
|
const selectedDuration = useBookerStore((state) => state.selectedDuration);
|
||||||
|
const searchParams = useCompatSearchParams();
|
||||||
const [selectedTimeslot, setSelectedTimeslot] = useBookerStore(
|
const [selectedTimeslot, setSelectedTimeslot] = useBookerStore(
|
||||||
(state) => [state.selectedTimeslot, state.setSelectedTimeslot],
|
(state) => [state.selectedTimeslot, state.setSelectedTimeslot],
|
||||||
shallow
|
shallow
|
||||||
@@ -45,6 +48,7 @@ export const useSlots = (event: { data?: Pick<BookerEvent, "id" | "length"> | nu
|
|||||||
.utc()
|
.utc()
|
||||||
.add(selectedDuration || event.data.length, "minutes")
|
.add(selectedDuration || event.data.length, "minutes")
|
||||||
.format(),
|
.format(),
|
||||||
|
_isDryRun: isBookingDryRun(searchParams),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ interface ReserveSlotOptions {
|
|||||||
export const reserveSlotHandler = async ({ ctx, input }: ReserveSlotOptions) => {
|
export const reserveSlotHandler = async ({ ctx, input }: ReserveSlotOptions) => {
|
||||||
const { prisma, req, res } = ctx;
|
const { prisma, req, res } = ctx;
|
||||||
const uid = req?.cookies?.uid || uuid();
|
const uid = req?.cookies?.uid || uuid();
|
||||||
const { slotUtcStartDate, slotUtcEndDate, eventTypeId, bookingUid } = input;
|
const { slotUtcStartDate, slotUtcEndDate, eventTypeId, bookingUid, _isDryRun } = input;
|
||||||
const releaseAt = dayjs.utc().add(parseInt(MINUTES_TO_BOOK), "minutes").format();
|
const releaseAt = dayjs.utc().add(parseInt(MINUTES_TO_BOOK), "minutes").format();
|
||||||
const eventType = await prisma.eventType.findUnique({
|
const eventType = await prisma.eventType.findUnique({
|
||||||
where: { id: eventTypeId },
|
where: { id: eventTypeId },
|
||||||
@@ -54,7 +54,7 @@ export const reserveSlotHandler = async ({ ctx, input }: ReserveSlotOptions) =>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (eventType && shouldReserveSlot) {
|
if (eventType && shouldReserveSlot && !_isDryRun) {
|
||||||
try {
|
try {
|
||||||
await Promise.all(
|
await Promise.all(
|
||||||
eventType.users.map((user) =>
|
eventType.users.map((user) =>
|
||||||
|
|||||||
@@ -56,6 +56,7 @@ export const reserveSlotSchema = z
|
|||||||
// endTime ISOString
|
// endTime ISOString
|
||||||
slotUtcEndDate: z.string(),
|
slotUtcEndDate: z.string(),
|
||||||
bookingUid: z.string().optional(),
|
bookingUid: z.string().optional(),
|
||||||
|
_isDryRun: z.boolean().optional(),
|
||||||
})
|
})
|
||||||
.refine(
|
.refine(
|
||||||
(data) => !!data.eventTypeId || !!data.slotUtcStartDate || !!data.slotUtcEndDate,
|
(data) => !!data.eventTypeId || !!data.slotUtcStartDate || !!data.slotUtcEndDate,
|
||||||
|
|||||||
Reference in New Issue
Block a user