Skip to content

Commit

Permalink
Merge branch 'main' into 13771-cal-3184-consoleurl-and-supportmail-no…
Browse files Browse the repository at this point in the history
…t-rendering-correctly-in-portugese-maybe-more-languages
  • Loading branch information
PeerRich committed Feb 22, 2024
2 parents 209cd39 + aa2db56 commit 8ff4dbb
Show file tree
Hide file tree
Showing 14 changed files with 394 additions and 54 deletions.
21 changes: 20 additions & 1 deletion apps/web/components/booking/CancelBooking.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { useRouter } from "next/navigation";
import { useCallback, useState } from "react";

import { sdkActionManager } from "@calcom/embed-core/embed-iframe";
import { useLocale } from "@calcom/lib/hooks/useLocale";
import { collectPageParameters, telemetryEventTypes, useTelemetry } from "@calcom/lib/telemetry";
import type { RecurringEvent } from "@calcom/types/Calendar";
Expand All @@ -23,13 +24,22 @@ type Props = {
theme: string | null;
allRemainingBookings: boolean;
seatReferenceUid?: string;
bookingCancelledEventProps: {
booking: unknown;
organizer: {
name: string;
email: string;
timeZone?: string;
};
eventType: unknown;
};
};

export default function CancelBooking(props: Props) {
const [cancellationReason, setCancellationReason] = useState<string>("");
const { t } = useLocale();
const router = useRouter();
const { booking, allRemainingBookings, seatReferenceUid } = props;
const { booking, allRemainingBookings, seatReferenceUid, bookingCancelledEventProps } = props;
const [loading, setLoading] = useState(false);
const telemetry = useTelemetry();
const [error, setError] = useState<string | null>(booking ? null : t("booking_already_cancelled"));
Expand Down Expand Up @@ -97,8 +107,17 @@ export default function CancelBooking(props: Props) {
method: "POST",
});

const bookingWithCancellationReason = {
...(bookingCancelledEventProps.booking as object),
cancellationReason,
} as unknown;

if (res.status >= 200 && res.status < 300) {
// tested by apps/web/playwright/booking-pages.e2e.ts
sdkActionManager?.fire("bookingCancelled", {
...bookingCancelledEventProps,
booking: bookingWithCancellationReason,
});
router.refresh();
} else {
setLoading(false);
Expand Down
10 changes: 6 additions & 4 deletions apps/web/components/getting-started/steps-views/UserProfile.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ const UserProfile = () => {
if (context.avatar) {
showToast(t("your_user_profile_updated_successfully"), "success");
await utils.viewer.me.refetch();
} else {
} else
try {
if (eventTypes?.length === 0) {
await Promise.all(
Expand All @@ -50,9 +50,11 @@ const UserProfile = () => {
console.error(error);
}

await utils.viewer.me.refetch();
router.push("/");
}
await utils.viewer.me.refetch();
const redirectUrl = localStorage.getItem("onBoardingRedirect");
localStorage.removeItem("onBoardingRedirect");

redirectUrl ? router.push(redirectUrl) : router.push("/");
},
onError: () => {
showToast(t("problem_saving_user_profile"), "error");
Expand Down
11 changes: 11 additions & 0 deletions apps/web/lib/signup/getServerSideProps.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,19 @@ export const getServerSideProps = async (ctx: GetServerSidePropsContext) => {
const signupDisabled = await getFeatureFlag(prisma, "disable-signup");
const ssr = await ssrInit(ctx);
const token = z.string().optional().parse(ctx.query.token);
const redirectUrlData = z
.string()
.refine((value) => value.startsWith(WEBAPP_URL), {
params: (value: string) => ({ value }),
message: "Redirect URL must start with 'cal.com'",
})
.optional()
.safeParse(ctx.query.redirect);

const redirectUrl = redirectUrlData.success && redirectUrlData.data ? redirectUrlData.data : null;

const props = {
redirectUrl,
isGoogleLoginEnabled: IS_GOOGLE_LOGIN_ENABLED,
isSAMLLoginEnabled,
trpcState: ssr.dehydrate(),
Expand Down
28 changes: 11 additions & 17 deletions apps/web/modules/bookings/views/bookings-single-view.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ import { getEventName } from "@calcom/core/event";
import type { ConfigType } from "@calcom/dayjs";
import dayjs from "@calcom/dayjs";
import {
sdkActionManager,
useEmbedNonStylesConfig,
useIsBackgroundTransparent,
useIsEmbed,
Expand Down Expand Up @@ -193,22 +192,6 @@ export default function Success(props: PageProps) {
}, [telemetry]); */

useEffect(() => {
const users = eventType.users;
if (!sdkActionManager) return;
// TODO: We should probably make it consistent with Webhook payload. Some data is not available here, as and when requirement comes we can add
sdkActionManager.fire("bookingSuccessful", {
booking: bookingInfo,
eventType,
date: date.toString(),
duration: calculatedDuration,
organizer: {
name: users[0].name || "Nameless",
email: bookingInfo?.userPrimaryEmail || users[0].email || "Email-less",
timeZone: users[0].timeZone,
},
confirmed: !needsConfirmation,
// TODO: Add payment details
});
setDate(
date.tz(localStorage.getItem("timeOption.preferredTimeZone") || dayjs.tz.guess() || "Europe/London")
);
Expand Down Expand Up @@ -294,6 +277,16 @@ export default function Success(props: PageProps) {
const providerName = guessEventLocationType(location)?.label;
const rescheduleProviderName = guessEventLocationType(rescheduleLocation)?.label;

const bookingCancelledEventProps = {
booking: bookingInfo,
organizer: {
name: bookingInfo?.user?.name || "Nameless",
email: bookingInfo?.userPrimaryEmail || bookingInfo?.user?.email || "Email-less",
timeZone: bookingInfo?.user?.timeZone,
},
eventType,
};

return (
<div className={isEmbed ? "" : "h-screen"} data-testid="success-page">
{!isEmbed && (
Expand Down Expand Up @@ -610,6 +603,7 @@ export default function Success(props: PageProps) {
theme={isSuccessBookingPage ? props.profile.theme : "light"}
allRemainingBookings={allRemainingBookings}
seatReferenceUid={seatReferenceUid}
bookingCancelledEventProps={bookingCancelledEventProps}
/>
</>
))}
Expand Down
7 changes: 7 additions & 0 deletions apps/web/pages/signup.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,7 @@ export default function Signup({
isGoogleLoginEnabled,
isSAMLLoginEnabled,
orgAutoAcceptEmail,
redirectUrl,
}: SignupProps) {
const [premiumUsername, setPremiumUsername] = useState(false);
const [usernameTaken, setUsernameTaken] = useState(false);
Expand All @@ -180,6 +181,12 @@ export default function Signup({
formState: { isSubmitting, errors, isSubmitSuccessful },
} = formMethods;

useEffect(() => {
if (redirectUrl) {
localStorage.setItem("onBoardingRedirect", redirectUrl);
}
}, [redirectUrl]);

const loadingSubmitState = isSubmitSuccessful || isSubmitting;

const handleErrorsAndStripe = async (resp: Response) => {
Expand Down
2 changes: 2 additions & 0 deletions apps/web/public/static/locales/zh-CN/common.json
Original file line number Diff line number Diff line change
Expand Up @@ -1446,6 +1446,8 @@
"copy_link_to_form": "将链接复制到表格",
"theme": "主题",
"theme_applies_note": "这仅适用于您的公开预约页面",
"app_theme": "仪表板主题",
"app_theme_applies_note": "这仅在您登录仪表板时适用",
"theme_system": "系统默认设置",
"add_a_team": "添加团队",
"add_webhook_description": "当 {{appName}} 上有活动时实时接收会议数据",
Expand Down
9 changes: 8 additions & 1 deletion packages/emails/templates/_base-email.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,14 @@ export default class BaseEmail {
}
}
)
).catch((e) => console.error("sendEmail", e));
).catch((e) =>
console.error(
"sendEmail",
`from: ${"from" in payloadWithUnEscapedSubject ? payloadWithUnEscapedSubject.from : ""}`,
`subject: ${"subject" in payloadWithUnEscapedSubject ? payloadWithUnEscapedSubject.subject : ""}`,
e
)
);
return new Promise((resolve) => resolve("send mail async"));
}
protected getMailerOptions() {
Expand Down
21 changes: 21 additions & 0 deletions packages/embeds/embed-core/src/sdk-action-manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,27 @@ export type EventDataMap = {
};
confirmed: boolean;
};
rescheduleBookingSuccessful: {
booking: unknown;
eventType: unknown;
date: string;
duration: number | undefined;
organizer: {
name: string;
email: string;
timeZone: string;
};
confirmed: boolean;
};
bookingCancelled: {
booking: unknown;
organizer: {
name: string;
email: string;
timeZone?: string | undefined;
};
eventType: unknown;
};
"*": Record<string, unknown>;
__routeChanged: Record<string, never>;
__windowLoadComplete: Record<string, never>;
Expand Down
41 changes: 41 additions & 0 deletions packages/features/bookings/Booker/components/hooks/useBookings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { useRef, useState, useEffect } from "react";

import { createPaymentLink } from "@calcom/app-store/stripepayment/lib/client";
import dayjs from "@calcom/dayjs";
import { sdkActionManager } from "@calcom/embed-core/embed-iframe";
import { useBookerStore } from "@calcom/features/bookings/Booker/store";
import type { useEventReturnType } from "@calcom/features/bookings/Booker/utils/event";
import { updateQueryParam, getQueryParam } from "@calcom/features/bookings/Booker/utils/query-param";
Expand All @@ -18,6 +19,7 @@ import {
import { getFullName } from "@calcom/features/form-builder/utils";
import { useBookingSuccessRedirect } from "@calcom/lib/bookingSuccessRedirect";
import { useLocale } from "@calcom/lib/hooks/useLocale";
import { BookingStatus } from "@calcom/prisma/enums";
import { bookingMetadataSchema } from "@calcom/prisma/zod-utils";
import { trpc } from "@calcom/trpc";
import { showToast } from "@calcom/ui";
Expand Down Expand Up @@ -103,6 +105,45 @@ export const useBookings = ({ event, hashedLink, bookingForm, metadata }: IUseBo
onSuccess: (responseData) => {
const { uid, paymentUid } = responseData;
const fullName = getFullName(bookingForm.getValues("responses.name"));

const users = !!event.data?.hosts?.length
? event.data?.hosts.map((host) => host.user)
: event.data?.users;

const validDuration = event.data?.isDynamic
? duration || event.data?.length
: duration && event.data?.metadata?.multipleDuration?.includes(duration)
? duration
: event.data?.length;

if (isRescheduling) {
sdkActionManager?.fire("rescheduleBookingSuccessful", {
booking: responseData,
eventType: event.data,
date: responseData?.startTime?.toString() || "",
duration: validDuration,
organizer: {
name: users?.[0].name || "Nameless",
email: responseData?.userPrimaryEmail || responseData.user?.email || "Email-less",
timeZone: responseData.user?.timeZone || "Europe/London",
},
confirmed: !(responseData.status === BookingStatus.PENDING && event.data?.requiresConfirmation),
});
} else {
sdkActionManager?.fire("bookingSuccessful", {
booking: responseData,
eventType: event.data,
date: responseData?.startTime?.toString() || "",
duration: validDuration,
organizer: {
name: users?.[0].name || "Nameless",
email: responseData?.userPrimaryEmail || responseData.user?.email || "Email-less",
timeZone: responseData.user?.timeZone || "Europe/London",
},
confirmed: !(responseData.status === BookingStatus.PENDING && event.data?.requiresConfirmation),
});
}

if (paymentUid) {
router.push(
createPaymentLink({
Expand Down
46 changes: 39 additions & 7 deletions packages/features/bookings/lib/handleNewBooking.ts
Original file line number Diff line number Diff line change
Expand Up @@ -379,7 +379,7 @@ export async function ensureAvailableUsers(
safeStringify({
startDateTimeUtc,
endDateTimeUtc,
timeZone: input.timeZone,
input,
})
);
continue;
Expand All @@ -406,7 +406,7 @@ export async function ensureAvailableUsers(
safeStringify({
startDateTimeUtc,
endDateTimeUtc,
timeZone: input.timeZone,
input,
})
);
continue;
Expand All @@ -428,7 +428,7 @@ export async function ensureAvailableUsers(
safeStringify({
startDateTimeUtc,
endDateTimeUtc,
timeZone: input.timeZone,
input,
})
);
throw new Error(ErrorCode.NoAvailableUsersFound);
Expand Down Expand Up @@ -1289,7 +1289,7 @@ async function handler(
}
// Pushing fixed user before the luckyUser guarantees the (first) fixed user as the organizer.
users = [...availableUsers.filter((user) => user.isFixed), ...luckyUsers];
luckyUserResponse = { luckyUsers };
luckyUserResponse = { luckyUsers: luckyUsers.map((u) => u.id) };
} else if (req.body.allRecurringDates && eventType.schedulingType === SchedulingType.ROUND_ROBIN) {
// all recurring slots except the first one
const luckyUsersFromFirstBooking = luckyUsers
Expand Down Expand Up @@ -1576,7 +1576,18 @@ async function handler(
});
if (newBooking) {
req.statusCode = 201;
return { ...newBooking, ...luckyUserResponse };
const bookingResponse = {
...newBooking,
user: {
...newBooking.user,
email: null,
},
};

return {
...bookingResponse,
...luckyUserResponse,
};
}
}
if (isTeamEventType) {
Expand Down Expand Up @@ -2170,8 +2181,18 @@ async function handler(
});

req.statusCode = 201;
return {
// TODO: Refactor better so this booking object is not passed
// all around and instead the individual fields are sent as args.
const bookingReponse = {
...booking,
user: {
...booking.user,
email: null,
},
};

return {
...bookingReponse,
...luckyUserResponse,
message: "Payment required",
paymentUid: payment?.uid,
Expand Down Expand Up @@ -2299,8 +2320,19 @@ async function handler(

// booking successful
req.statusCode = 201;
return {

// TODO: Refactor better so this booking object is not passed
// all around and instead the individual fields are sent as args.
const bookingResponse = {
...booking,
user: {
...booking.user,
email: null,
},
};

return {
...bookingResponse,
...luckyUserResponse,
references: referencesToCreate,
seatReferenceUid: evt.attendeeSeatId,
Expand Down
Loading

0 comments on commit 8ff4dbb

Please sign in to comment.