Skip to content

Commit efcbc3a

Browse files
authored
fix: avatar URL breaking for team/orgs in BookerEmbed atom (calcom#27424)
* fix: avatar URL breaking for team/orgs in booker embed * fix: api v2 breaking because of type mismatch * fix: atoms build * chore: implement PR feedback
1 parent 2ccff0a commit efcbc3a

3 files changed

Lines changed: 46 additions & 20 deletions

File tree

packages/lib/getAvatarUrl.ts

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,20 @@
1-
import { z } from "zod";
2-
31
import { AVATAR_FALLBACK, CAL_URL } from "@calcom/lib/constants";
42
import type { User } from "@calcom/prisma/client";
3+
import { z } from "zod";
4+
5+
export const getAbsoluteAvatarUrl = (url: string): string => {
6+
const isAbsolute = z.string().url().safeParse(url).success;
7+
return isAbsolute ? url : CAL_URL + url;
8+
};
59

610
/**
711
* Gives an organization aware avatar url for a user
812
* It ensures that the wrong avatar isn't fetched by ensuring that organizationId is always passed
913
* It should always return a fully formed url
1014
*/
11-
export const getUserAvatarUrl = (user: Pick<User, "avatarUrl"> | undefined) => {
15+
export const getUserAvatarUrl = (user: Pick<User, "avatarUrl"> | undefined): string => {
1216
if (user?.avatarUrl) {
13-
const isAbsoluteUrl = z.string().url().safeParse(user.avatarUrl).success;
14-
if (isAbsoluteUrl) {
15-
return user.avatarUrl;
16-
} else {
17-
return CAL_URL + user.avatarUrl;
18-
}
17+
return getAbsoluteAvatarUrl(user.avatarUrl);
1918
}
2019
return CAL_URL + AVATAR_FALLBACK;
2120
};

packages/platform/atoms/hooks/event-types/public/useAtomGetPublicEvent.tsx

Lines changed: 37 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,14 @@ import { useQuery } from "@tanstack/react-query";
22
import { useMemo } from "react";
33

44
import { getUsernameList } from "@calcom/features/eventtypes/lib/defaultEvents";
5+
import { getAbsoluteAvatarUrl } from "@calcom/lib/getAvatarUrl";
56
import { SUCCESS_STATUS, V2_ENDPOINTS } from "@calcom/platform-constants";
67
import type { PublicEventType } from "@calcom/features/eventtypes/lib/getPublicEvent";
78
import type { ApiResponse } from "@calcom/platform-types";
89

910
import http from "../../../lib/http";
1011
import { useAtomsContext } from "../../../hooks/useAtomsContext";
12+
import { useIsPlatformBookerEmbed } from "../../../hooks/useIsPlatformBookerEmbed";
1113

1214
export const QUERY_KEY = "get-public-event";
1315
export type UsePublicEventReturnType = ReturnType<typeof useAtomGetPublicEvent>;
@@ -20,9 +22,15 @@ type Props = {
2022
selectedDuration: number | null;
2123
};
2224

23-
export const useAtomGetPublicEvent = ({ username, eventSlug, isTeamEvent, teamId, selectedDuration }: Props) => {
24-
25+
export const useAtomGetPublicEvent = ({
26+
username,
27+
eventSlug,
28+
isTeamEvent,
29+
teamId,
30+
selectedDuration,
31+
}: Props) => {
2532
const { organizationId } = useAtomsContext();
33+
const isPlatformBookerEmbed = useIsPlatformBookerEmbed();
2634

2735
const isDynamic = useMemo(() => {
2836
return getUsernameList(username ?? "").length > 1;
@@ -31,29 +39,49 @@ export const useAtomGetPublicEvent = ({ username, eventSlug, isTeamEvent, teamId
3139
const pathname = `/atoms/${V2_ENDPOINTS.eventTypes}/${eventSlug}/public`;
3240

3341
const event = useQuery({
34-
queryKey: [QUERY_KEY, username, eventSlug, isTeamEvent, teamId, organizationId],
42+
queryKey: [
43+
QUERY_KEY,
44+
username,
45+
eventSlug,
46+
isTeamEvent,
47+
teamId,
48+
organizationId,
49+
],
3550
queryFn: () => {
3651
const params: Record<string, any> = {
3752
isTeamEvent,
3853
teamId,
39-
username: getUsernameList(username ?? "").join("+")
54+
username: getUsernameList(username ?? "").join("+"),
4055
};
41-
56+
4257
// Only include orgId if it's not 0
4358
if (organizationId !== 0) {
4459
params.orgId = organizationId;
4560
}
46-
47-
return http?.get<ApiResponse<PublicEventType>>(pathname, {
48-
params,
49-
})
61+
62+
return http
63+
?.get<ApiResponse<PublicEventType>>(pathname, {
64+
params,
65+
})
5066
.then((res) => {
5167
if (res.data.status === SUCCESS_STATUS) {
5268
if (isDynamic && selectedDuration && res.data.data) {
5369
// note(Lauris): Mandatory - In case of "dynamic" event type default event duration returned by the API is 30,
5470
// but we are re-using the dynamic event type as a team event, so we must set the event length to whatever the event length is.
5571
res.data.data.length = selectedDuration;
5672
}
73+
if (isPlatformBookerEmbed && res.data.data) {
74+
if (res.data.data.profile?.image) {
75+
res.data.data.profile.image = getAbsoluteAvatarUrl(
76+
res.data.data.profile.image
77+
);
78+
}
79+
if (res.data.data.entity?.logoUrl) {
80+
res.data.data.entity.logoUrl = getAbsoluteAvatarUrl(
81+
res.data.data.entity.logoUrl
82+
);
83+
}
84+
}
5785
return res.data.data;
5886
}
5987
throw new Error(res.data.error.message);

packages/platform/atoms/vite.config.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
1+
import path, { resolve } from "node:path";
12
import react from "@vitejs/plugin-react-swc";
2-
import path from "node:path"
3-
import { resolve } from "node:path";
43
import { defineConfig, loadEnv } from "vite";
54
import dts from "vite-plugin-dts";
65

0 commit comments

Comments
 (0)