diff --git a/apps/web/components/booking/pages/AvailabilityPage.tsx b/apps/web/components/booking/pages/AvailabilityPage.tsx
index d76aeee407..2b295d4a06 100644
--- a/apps/web/components/booking/pages/AvailabilityPage.tsx
+++ b/apps/web/components/booking/pages/AvailabilityPage.tsx
@@ -8,18 +8,22 @@ import {
CreditCardIcon,
GlobeIcon,
InformationCircleIcon,
+ LocationMarkerIcon,
RefreshIcon,
+ VideoCameraIcon,
} from "@heroicons/react/solid";
import * as Collapsible from "@radix-ui/react-collapsible";
import { useContracts } from "contexts/contractsContext";
import dayjs, { Dayjs } from "dayjs";
import customParseFormat from "dayjs/plugin/customParseFormat";
import utc from "dayjs/plugin/utc";
+import { TFunction } from "next-i18next";
import { useRouter } from "next/router";
import { useCallback, useEffect, useMemo, useState } from "react";
import { FormattedNumber, IntlProvider } from "react-intl";
import { Frequency as RRuleFrequency } from "rrule";
+import { AppStoreLocationType, LocationObject, LocationType } from "@calcom/app-store/locations";
import {
useEmbedStyles,
useIsEmbed,
@@ -57,6 +61,33 @@ dayjs.extend(customParseFormat);
type Props = AvailabilityTeamPageProps | AvailabilityPageProps;
+export const locationKeyToString = (location: LocationObject, t: TFunction) => {
+ switch (location.type) {
+ case LocationType.InPerson:
+ return location.address || "In Person"; // If disabled address won't exist on the object
+ case LocationType.Link:
+ return location.link || "Link"; // If disabled link won't exist on the object
+ case LocationType.Phone:
+ return t("phone_call");
+ case LocationType.GoogleMeet:
+ return "Google Meet";
+ case LocationType.Zoom:
+ return "Zoom";
+ case LocationType.Daily:
+ return "Cal Video";
+ case LocationType.Jitsi:
+ return "Jitsi";
+ case LocationType.Huddle01:
+ return "Huddle Video";
+ case LocationType.Tandem:
+ return "Tandem";
+ case LocationType.Teams:
+ return "Microsoft Teams";
+ default:
+ return null;
+ }
+};
+
const AvailabilityPage = ({ profile, plan, eventType, workingHours, previousPage, booking }: Props) => {
const router = useRouter();
const isEmbed = useIsEmbed();
@@ -225,6 +256,25 @@ const AvailabilityPage = ({ profile, plan, eventType, workingHours, previousPage
{eventType.description}
)}
+ {eventType.locations.length === 1 && (
+
+
+ {locationKeyToString(eventType.locations[0], t)}
+
+ )}
+ {eventType.locations.length === 1 && (
+
+ {Object.values(AppStoreLocationType).includes(
+ eventType.locations[0].type as unknown as AppStoreLocationType
+ ) ? (
+
+ ) : (
+
+ )}
+
+ {locationKeyToString(eventType.locations[0], t)}
+
+ )}
{eventType.length} {t("minutes")}
@@ -297,6 +347,36 @@ const AvailabilityPage = ({ profile, plan, eventType, workingHours, previousPage
{eventType.description}
)}
+ {eventType.locations.length === 1 && (
+
+ {Object.values(AppStoreLocationType).includes(
+ eventType.locations[0].type as unknown as AppStoreLocationType
+ ) ? (
+
+ ) : (
+
+ )}
+
+ {locationKeyToString(eventType.locations[0], t)}
+
+ )}
+ {eventType.locations.length > 1 && (
+
+
+
+
+
+ {eventType.locations.map((el, i, arr) => {
+ return (
+
+ {locationKeyToString(el, t)}{" "}
+ {arr.length - 1 !== i && or }
+
+ );
+ })}
+
+
+ )}
{eventType.length} {t("minutes")}
@@ -340,7 +420,6 @@ const AvailabilityPage = ({ profile, plan, eventType, workingHours, previousPage
)}
-
{previousPage === `${WEBAPP_URL}/${profile.slug}` && (
diff --git a/apps/web/components/booking/pages/BookingPage.tsx b/apps/web/components/booking/pages/BookingPage.tsx
index cae3c9c5f9..22b31977f6 100644
--- a/apps/web/components/booking/pages/BookingPage.tsx
+++ b/apps/web/components/booking/pages/BookingPage.tsx
@@ -37,7 +37,7 @@ import { asStringOrNull } from "@lib/asStringOrNull";
import { timeZone } from "@lib/clock";
import { ensureArray } from "@lib/ensureArray";
import useTheme from "@lib/hooks/useTheme";
-import { LocationType } from "@lib/location";
+import { LocationObject, LocationType } from "@lib/location";
import createBooking from "@lib/mutations/bookings/create-booking";
import createRecurringBooking from "@lib/mutations/bookings/create-recurring-booking";
import { parseDate, parseRecurringDates } from "@lib/parseDate";
@@ -203,10 +203,9 @@ const BookingPage = ({
const eventTypeDetail = { isWeb3Active: false, ...eventType };
- type Location = { type: LocationType; address?: string; link?: string; hostPhoneNumber?: string };
// it would be nice if Prisma at some point in the future allowed for Json; as of now this is not the case.
- const locations: Location[] = useMemo(
- () => (eventType.locations as Location[]) || [],
+ const locations: LocationObject[] = useMemo(
+ () => (eventType.locations as LocationObject[]) || [],
[eventType.locations]
);
diff --git a/apps/web/pages/[user]/[type].tsx b/apps/web/pages/[user]/[type].tsx
index d46db6244e..c6107c7625 100644
--- a/apps/web/pages/[user]/[type].tsx
+++ b/apps/web/pages/[user]/[type].tsx
@@ -3,6 +3,7 @@ import { UserPlan } from "@prisma/client";
import { GetServerSidePropsContext } from "next";
import { JSONObject } from "superjson/dist/types";
+import { AppStoreLocationType, locationHiddenFilter, LocationObject } from "@calcom/app-store/locations";
import { getDefaultEvent, getGroupName, getUsernameList } from "@calcom/lib/defaultEvents";
import { useLocale } from "@calcom/lib/hooks/useLocale";
import { RecurringEvent } from "@calcom/types/Calendar";
@@ -84,6 +85,7 @@ export const getServerSideProps = async (context: GetServerSidePropsContext) =>
periodEndDate: true,
periodDays: true,
periodCountCalendarDays: true,
+ locations: true,
schedulingType: true,
recurringEvent: true,
schedule: {
@@ -254,12 +256,14 @@ export const getServerSideProps = async (context: GetServerSidePropsContext) =>
} as const;
}
}
+ const locations = eventType.locations ? (eventType.locations as LocationObject[]) : [];
const eventTypeObject = Object.assign({}, eventType, {
metadata: (eventType.metadata || {}) as JSONObject,
periodStartDate: eventType.periodStartDate?.toString() ?? null,
periodEndDate: eventType.periodEndDate?.toString() ?? null,
recurringEvent: (eventType.recurringEvent || {}) as RecurringEvent,
+ locations: locationHiddenFilter(locations),
});
const schedule = eventType.schedule
diff --git a/apps/web/pages/d/[link]/[slug].tsx b/apps/web/pages/d/[link]/[slug].tsx
index 6721a5c8c3..147e8072c1 100644
--- a/apps/web/pages/d/[link]/[slug].tsx
+++ b/apps/web/pages/d/[link]/[slug].tsx
@@ -7,6 +7,7 @@ import { RecurringEvent } from "@calcom/types/Calendar";
import { asStringOrNull } from "@lib/asStringOrNull";
import { getWorkingHours } from "@lib/availability";
import { GetBookingType } from "@lib/getBooking";
+import { AppStoreLocationType, locationHiddenFilter, LocationObject } from "@lib/location";
import prisma from "@lib/prisma";
import { inferSSRProps } from "@lib/types/inferSSRProps";
@@ -54,6 +55,7 @@ export const getServerSideProps = async (context: GetServerSidePropsContext) =>
minimumBookingNotice: true,
beforeEventBuffer: true,
afterEventBuffer: true,
+ locations: true,
timeZone: true,
metadata: true,
slotInterval: true,
@@ -132,6 +134,11 @@ export const getServerSideProps = async (context: GetServerSidePropsContext) =>
notFound: true,
};
}
+
+ const locations = hashedLink.eventType.locations
+ ? (hashedLink.eventType.locations as LocationObject[])
+ : [];
+
const [user] = users;
const eventTypeObject = Object.assign({}, hashedLink.eventType, {
metadata: {} as JSONObject,
@@ -139,6 +146,7 @@ export const getServerSideProps = async (context: GetServerSidePropsContext) =>
periodStartDate: hashedLink.eventType.periodStartDate?.toString() ?? null,
periodEndDate: hashedLink.eventType.periodEndDate?.toString() ?? null,
slug,
+ locations: locationHiddenFilter(locations),
});
const schedule = {
diff --git a/apps/web/pages/event-types/[type].tsx b/apps/web/pages/event-types/[type].tsx
index 9ddd425979..ad38708139 100644
--- a/apps/web/pages/event-types/[type].tsx
+++ b/apps/web/pages/event-types/[type].tsx
@@ -50,7 +50,7 @@ import { asStringOrThrow, asStringOrUndefined } from "@lib/asStringOrNull";
import { getSession } from "@lib/auth";
import { HttpError } from "@lib/core/http/error";
import { isSuccessRedirectAvailable } from "@lib/isSuccessRedirectAvailable";
-import { LocationType } from "@lib/location";
+import { LocationObject, LocationType } from "@lib/location";
import prisma from "@lib/prisma";
import { slugify } from "@lib/slugify";
import { trpc } from "@lib/trpc";
@@ -118,7 +118,13 @@ export type FormValues = {
hidden: boolean;
hideCalendarNotes: boolean;
hashedLink: string | undefined;
- locations: { type: LocationType; address?: string; link?: string; hostPhoneNumber?: string }[];
+ locations: {
+ type: LocationType;
+ address?: string;
+ link?: string;
+ hostPhoneNumber?: string;
+ displayLocationPublicly?: boolean;
+ }[];
customInputs: EventTypeCustomInput[];
users: string[];
schedule: number;
@@ -422,6 +428,7 @@ const EventTypePage = (props: inferSSRProps) => {
if (!selectedLocation) {
return null;
}
+
switch (selectedLocation.value) {
case LocationType.InPerson:
return (
@@ -435,7 +442,7 @@ const EventTypePage = (props: inferSSRProps) => {
{...locationFormMethods.register("locationAddress")}
id="address"
required
- className=" block w-full rounded-sm border-gray-300 text-sm"
+ className="block w-full rounded-sm border-gray-300 text-sm"
defaultValue={
formMethods
.getValues("locations")
@@ -443,6 +450,18 @@ const EventTypePage = (props: inferSSRProps) => {
}
/>
+
+ (
+ onChange(e.target.checked)}
+ infomationIconText={t("display_location_info_badge")}>
+ )}
+ />
+
);
case LocationType.Link:
@@ -469,6 +488,18 @@ const EventTypePage = (props: inferSSRProps) => {
)}
+
+ (
+ onChange(e.target.checked)}
+ infomationIconText={t("display_location_info_badge")}>
+ )}
+ />
+
);
case LocationType.UserPhone:
@@ -584,6 +615,7 @@ const EventTypePage = (props: inferSSRProps) => {
const locationFormSchema = z.object({
locationType: z.string(),
locationAddress: z.string().optional(),
+ displayLocationPublicly: z.boolean().optional(),
locationPhoneNumber: z
.string()
.refine((val) => isValidPhoneNumber(val))
@@ -596,6 +628,7 @@ const EventTypePage = (props: inferSSRProps) => {
locationPhoneNumber?: string;
locationAddress?: string; // TODO: We should validate address or fetch the address from googles api to see if its valid?
locationLink?: string; // Currently this only accepts links that are HTTPS://
+ displayLocationPublicly?: boolean;
}>({
resolver: zodResolver(locationFormSchema),
});
@@ -2131,14 +2164,16 @@ const EventTypePage = (props: inferSSRProps) => {