Skip to content

Commit

Permalink
Merge branch 'main' into lauris/cal-4371-platform-fix-booker-types
Browse files Browse the repository at this point in the history
  • Loading branch information
supalarry authored Oct 1, 2024
2 parents 5f298b5 + 706e8e4 commit fdcf15f
Show file tree
Hide file tree
Showing 13 changed files with 75 additions and 98 deletions.
4 changes: 2 additions & 2 deletions apps/api/v1/pages/api/bookings/[id]/_delete.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import type { NextApiRequest } from "next";

import handleCancelBooking from "@calcom/features/bookings/lib/handleCancelBooking";
import { defaultResponder } from "@calcom/lib/server";
import { schemaBookingCancelParams } from "@calcom/prisma/zod-utils";
import { bookingCancelSchema } from "@calcom/prisma/zod-utils";

import { schemaQueryIdParseInt } from "~/lib/validations/shared/queryIdTransformParseInt";

Expand Down Expand Up @@ -65,7 +65,7 @@ import { schemaQueryIdParseInt } from "~/lib/validations/shared/queryIdTransform
*/
async function handler(req: NextApiRequest) {
const { id, allRemainingBookings, cancellationReason } = schemaQueryIdParseInt
.merge(schemaBookingCancelParams.pick({ allRemainingBookings: true, cancellationReason: true }))
.merge(bookingCancelSchema.pick({ allRemainingBookings: true, cancellationReason: true }))
.parse({
...req.query,
allRemainingBookings: req.query.allRemainingBookings === "true",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import type z from "zod";

import type { schemaBookingCancelParams } from "@calcom/prisma/zod-utils";
import type { bookingCancelSchema } from "@calcom/prisma/zod-utils";

export function getMockRequestDataForCancelBooking(data: z.infer<typeof schemaBookingCancelParams>) {
export function getMockRequestDataForCancelBooking(data: z.infer<typeof bookingCancelSchema>) {
return data;
}
16 changes: 4 additions & 12 deletions packages/features/bookings/lib/handleCancelBooking.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,7 @@ import prisma, { bookingMinimalSelect } from "@calcom/prisma";
import type { WebhookTriggerEvents } from "@calcom/prisma/enums";
import { BookingStatus } from "@calcom/prisma/enums";
import { credentialForCalendarServiceSelect } from "@calcom/prisma/selects/credential";
import {
bookingMetadataSchema,
EventTypeMetaDataSchema,
schemaBookingCancelParams,
} from "@calcom/prisma/zod-utils";
import { bookingMetadataSchema, EventTypeMetaDataSchema, bookingCancelInput } from "@calcom/prisma/zod-utils";
import type { EventTypeMetadata } from "@calcom/prisma/zod-utils";
import { getAllWorkflowsFromEventType } from "@calcom/trpc/server/routers/viewer/workflows/util";
import type { CalendarEvent } from "@calcom/types/Calendar";
Expand All @@ -43,7 +39,7 @@ import cancelAttendeeSeat from "./handleSeats/cancel/cancelAttendeeSeat";
const log = logger.getSubLogger({ prefix: ["handleCancelBooking"] });

async function getBookingToDelete(id: number | undefined, uid: string | undefined) {
return await prisma.booking.findUnique({
return await prisma.booking.findUniqueOrThrow({
where: {
id,
uid,
Expand Down Expand Up @@ -160,7 +156,7 @@ export type HandleCancelBookingResponse = {

async function handler(req: CustomRequest) {
const { id, uid, allRemainingBookings, cancellationReason, seatReferenceUid, cancelledBy } =
schemaBookingCancelParams.parse(req.body);
bookingCancelInput.parse(req.body);
req.bookingToDelete = await getBookingToDelete(id, uid);
const {
bookingToDelete,
Expand All @@ -172,11 +168,7 @@ async function handler(req: CustomRequest) {
arePlatformEmailsEnabled,
} = req;

if (!bookingToDelete || !bookingToDelete.user) {
throw new HttpError({ statusCode: 400, message: "Booking not found" });
}

if (!bookingToDelete.userId) {
if (!bookingToDelete.userId || !bookingToDelete.user) {
throw new HttpError({ statusCode: 400, message: "User not found" });
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import { WorkflowRepository } from "@calcom/lib/server/repository/workflow";
import prisma from "@calcom/prisma";
import { WebhookTriggerEvents } from "@calcom/prisma/enums";
import { credentialForCalendarServiceSelect } from "@calcom/prisma/selects/credential";
import { schemaBookingCancelParams } from "@calcom/prisma/zod-utils";
import { bookingCancelAttendeeSeatSchema } from "@calcom/prisma/zod-utils";
import type { EventTypeMetadata } from "@calcom/prisma/zod-utils";
import type { CalendarEvent } from "@calcom/types/Calendar";

Expand All @@ -32,9 +32,10 @@ async function cancelAttendeeSeat(
},
eventTypeMetadata: EventTypeMetadata
) {
const { seatReferenceUid } = schemaBookingCancelParams.parse(req.body);
const input = bookingCancelAttendeeSeatSchema.safeParse(req.body);
const { webhooks, evt, eventTypeInfo } = dataForWebhooks;
if (!seatReferenceUid) return;
if (!input.success) return;
const { seatReferenceUid } = input.data;
const bookingToDelete = req.bookingToDelete;
if (!bookingToDelete?.attendees.length || bookingToDelete.attendees.length < 2) return;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2664,6 +2664,7 @@ describe("handleSeats", () => {

const mockBookingData = getMockRequestDataForBooking({
data: {
id: firstBookingId,
eventTypeId: 1,
responses: {
email: booker.email,
Expand Down
97 changes: 29 additions & 68 deletions packages/features/ee/workflows/components/WorkflowStepContainer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -161,14 +161,8 @@ export default function WorkflowStepContainer(props: WorkflowStepProps) {
? form.register(`steps.${step.stepNumber - 1}.emailSubject`)
: { ref: null, name: "" };

const { ref: reminderBodyFormRef, ...restReminderBodyForm } = step
? form.register(`steps.${step.stepNumber - 1}.reminderBody`)
: { ref: null, name: "" };

const refEmailSubject = useRef<HTMLTextAreaElement | null>(null);

const refReminderBody = useRef<HTMLTextAreaElement | null>(null);

const getNumberVerificationStatus = () =>
!!step &&
!!verifiedNumbers.find(
Expand All @@ -185,17 +179,6 @@ export default function WorkflowStepContainer(props: WorkflowStepProps) {
useEffect(() => setNumberVerified(getNumberVerificationStatus()), [verifiedNumbers.length]);
useEffect(() => setEmailVerified(getEmailVerificationStatus()), [verifiedEmails.length]);

const addVariableBody = (variable: string) => {
if (step) {
const currentMessageBody = refReminderBody?.current?.value || "";
const cursorPosition = refReminderBody?.current?.selectionStart || currentMessageBody.length;
const messageWithAddedVariable = `${currentMessageBody.substring(0, cursorPosition)}{${variable
.toUpperCase()
.replace(/ /g, "_")}}${currentMessageBody.substring(cursorPosition)}`;
form.setValue(`steps.${step.stepNumber - 1}.reminderBody`, messageWithAddedVariable);
}
};

const addVariableEmailSubject = (variable: string) => {
if (step) {
const currentEmailSubject = refEmailSubject?.current?.value || "";
Expand Down Expand Up @@ -920,57 +903,35 @@ export default function WorkflowStepContainer(props: WorkflowStepProps) {
</div>
)}

{step.action !== WorkflowActions.SMS_ATTENDEE &&
step.action !== WorkflowActions.SMS_NUMBER ? (
<>
<div className="mb-2 flex items-center pb-[1.5px]">
<Label className="mb-0 flex-none ">
{isEmailSubjectNeeded ? t("email_body") : t("text_message")}
</Label>
</div>
<Editor
getText={() => {
return props.form.getValues(`steps.${step.stepNumber - 1}.reminderBody`) || "";
}}
setText={(text: string) => {
props.form.setValue(`steps.${step.stepNumber - 1}.reminderBody`, text);
props.form.clearErrors();
}}
variables={DYNAMIC_TEXT_VARIABLES}
height="200px"
updateTemplate={updateTemplate}
firstRender={firstRender}
setFirstRender={setFirstRender}
editable={!props.readOnly && !isWhatsappAction(step.action)}
/>
</>
) : (
<>
<div className="flex items-center">
<Label className={classNames("flex-none", props.readOnly ? "mb-2" : "mb-0")}>
{isEmailSubjectNeeded ? t("email_body") : t("text_message")}
</Label>
{!props.readOnly && (
<div className="flex-grow text-right">
<AddVariablesDropdown
addVariable={addVariableBody}
variables={DYNAMIC_TEXT_VARIABLES}
/>
</div>
)}
</div>
<TextArea
ref={(e) => {
reminderBodyFormRef?.(e);
refReminderBody.current = e;
}}
className="my-0 h-24"
disabled={props.readOnly}
required
{...restReminderBodyForm}
/>
</>
)}
<div className="mb-2 flex items-center pb-1">
<Label className="mb-0 flex-none ">
{isEmailSubjectNeeded ? t("email_body") : t("text_message")}
</Label>
</div>
<Editor
getText={() => {
return props.form.getValues(`steps.${step.stepNumber - 1}.reminderBody`) || "";
}}
setText={(text: string) => {
props.form.setValue(`steps.${step.stepNumber - 1}.reminderBody`, text);
props.form.clearErrors();
}}
variables={DYNAMIC_TEXT_VARIABLES}
addVariableButtonTop={
step.action === WorkflowActions.SMS_ATTENDEE || step.action === WorkflowActions.SMS_NUMBER
}
height="200px"
updateTemplate={updateTemplate}
firstRender={firstRender}
setFirstRender={setFirstRender}
editable={!props.readOnly && !isWhatsappAction(step.action)}
excludedToolbarItems={
step.action !== WorkflowActions.SMS_ATTENDEE && step.action !== WorkflowActions.SMS_NUMBER
? []
: ["blockType", "bold", "italic", "link"]
}
/>

{form.formState.errors.steps &&
form.formState?.errors?.steps[step.stepNumber - 1]?.reminderBody && (
<p className="mt-1 text-sm text-red-500">
Expand Down
11 changes: 6 additions & 5 deletions packages/lib/server/defaultResponder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,13 @@ export function defaultResponder<T>(f: Handle<T>) {
return res.json(result);
}
} catch (err) {
console.error(err);
const error = getServerErrorFromUnknown(err);
// dynamic import of Sentry so it's only loaded when something goes wrong.
const captureException = (await import("@sentry/nextjs")).captureException;
captureException(err);
// return API route response
// we don't want to report Bad Request errors to Sentry / console
if (!(error.statusCode >= 400 && error.statusCode < 500)) {
console.error(err);
const captureException = (await import("@sentry/nextjs")).captureException;
captureException(err);
}
return res
.status(error.statusCode)
.json({ message: error.message, url: error.url, method: error.method });
Expand Down
1 change: 0 additions & 1 deletion packages/lib/server/getServerErrorFromUnknown.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@ function parseZodErrorIssues(issues: ZodIssue[]): string {

export function getServerErrorFromUnknown(cause: unknown): HttpError {
if (isZodError(cause)) {
console.log("cause", cause);
return new HttpError({
statusCode: 400,
message: parseZodErrorIssues(cause.issues),
Expand Down
4 changes: 2 additions & 2 deletions packages/platform/atoms/hooks/useCancelBooking.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import type { z } from "zod";

import { SUCCESS_STATUS } from "@calcom/platform-constants";
import type { ApiResponse, ApiErrorResponse } from "@calcom/platform-types";
import type { schemaBookingCancelParams } from "@calcom/prisma/zod-utils";
import type { bookingCancelSchema } from "@calcom/prisma/zod-utils";

import http from "../lib/http";

Expand All @@ -12,7 +12,7 @@ interface IUseCancelBooking {
onError?: (err: ApiErrorResponse | Error) => void;
}

type inputParams = z.infer<typeof schemaBookingCancelParams>;
type inputParams = z.infer<typeof bookingCancelSchema>;

export const useCancelBooking = (
{ onSuccess, onError }: IUseCancelBooking = {
Expand Down
11 changes: 10 additions & 1 deletion packages/prisma/zod-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -314,7 +314,7 @@ export const bookingCreateBodySchemaForApi = extendedBookingCreateBody.merge(
bookingCreateSchemaLegacyPropsForApi.partial()
);

export const schemaBookingCancelParams = z.object({
export const bookingCancelSchema = z.object({
id: z.number().optional(),
uid: z.string().optional(),
allRemainingBookings: z.boolean().optional(),
Expand All @@ -323,6 +323,15 @@ export const schemaBookingCancelParams = z.object({
cancelledBy: z.string().email({ message: "Invalid email" }).optional(),
});

export const bookingCancelAttendeeSeatSchema = z.object({
seatReferenceUid: z.string(),
});

export const bookingCancelInput = bookingCancelSchema.refine(
(data) => !!data.id || !!data.uid,
"At least one of the following required: 'id', 'uid'."
);

export const vitalSettingsUpdateSchema = z.object({
connected: z.boolean().optional(),
selectedParam: z.string().optional(),
Expand Down
2 changes: 2 additions & 0 deletions packages/ui/components/editor/Editor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ export type TextEditorProps = {
setText: (text: string) => void;
excludedToolbarItems?: string[];
variables?: string[];
addVariableButtonTop?: boolean;
height?: string;
maxHeight?: string;
placeholder?: string;
Expand Down Expand Up @@ -80,6 +81,7 @@ export const Editor = (props: TextEditorProps) => {
editable={editable}
excludedToolbarItems={props.excludedToolbarItems}
variables={props.variables}
addVariableButtonTop={props.addVariableButtonTop}
updateTemplate={props.updateTemplate}
firstRender={props.firstRender}
setFirstRender={props.setFirstRender}
Expand Down
12 changes: 11 additions & 1 deletion packages/ui/components/editor/plugins/AddVariablesDropdown.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ interface IAddVariablesDropdown {
addVariable: (variable: string) => void;
isTextEditor?: boolean;
variables: string[];
addVariableButtonTop?: boolean;
}

export const AddVariablesDropdown = (props: IAddVariablesDropdown) => {
Expand All @@ -22,7 +23,16 @@ export const AddVariablesDropdown = (props: IAddVariablesDropdown) => {
{t("add_variable")}
<Icon name="chevron-down" className="ml-1 mt-[2px] h-4 w-4" />
</div>
<div className="block sm:hidden">+</div>
<div className="block sm:hidden">
{props.addVariableButtonTop ? (
<div className="flex">
{t("add_variable")}
<Icon name="chevron-down" className="ml-1 mt-[2px] h-4 w-4" />
</div>
) : (
"+"
)}
</div>
</>
) : (
<div className="flex">
Expand Down
3 changes: 2 additions & 1 deletion packages/ui/components/editor/plugins/ToolbarPlugin.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -507,11 +507,12 @@ export default function ToolbarPlugin(props: TextEditorProps) {
)}
</>
{props.variables && (
<div className="ml-auto">
<div className={`${props.addVariableButtonTop ? "-mt-10" : ""} ml-auto`}>
<AddVariablesDropdown
addVariable={addVariable}
isTextEditor={true}
variables={props.variables || []}
addVariableButtonTop={props.addVariableButtonTop}
/>
</div>
)}
Expand Down

0 comments on commit fdcf15f

Please sign in to comment.