Feature/Embed/Add Embed ui instruction config to hide event type description (#5951)

* Add embed ui instruction to hide event type description

* Add EventTypeDetails option in Embed Snippet Generator
This commit is contained in:
Hariom Balhara
2022-12-13 07:23:26 +00:00
committed by GitHub
parent b7fcf6ade1
commit 3a641e0bc1
6 changed files with 288 additions and 228 deletions
+24 -4
View File
@@ -44,6 +44,7 @@ type PreviewState = {
palette: {
brandColor: string;
};
hideEventTypeDetails: boolean;
};
const queryParamsForDialog = ["embedType", "embedTabName", "embedUrl"];
@@ -125,10 +126,12 @@ const getEmbedUIInstructionString = ({
apiName,
theme,
brandColor,
hideEventTypeDetails,
}: {
apiName: string;
theme?: string;
brandColor: string;
hideEventTypeDetails: boolean;
}) => {
theme = theme !== "auto" ? theme : undefined;
return getInstructionString({
@@ -141,6 +144,7 @@ const getEmbedUIInstructionString = ({
brandColor,
},
},
hideEventTypeDetails: hideEventTypeDetails,
},
});
};
@@ -253,18 +257,21 @@ const getEmbedTypeSpecificString = ({
apiName: string;
theme: PreviewState["theme"];
brandColor: string;
hideEventTypeDetails: boolean;
};
if (embedFramework === "react") {
uiInstructionStringArg = {
apiName: "cal",
theme: previewState.theme,
brandColor: previewState.palette.brandColor,
hideEventTypeDetails: previewState.hideEventTypeDetails,
};
} else {
uiInstructionStringArg = {
apiName: "Cal",
theme: previewState.theme,
brandColor: previewState.palette.brandColor,
hideEventTypeDetails: previewState.hideEventTypeDetails,
};
}
if (!frameworkCodes[embedType]) {
@@ -689,6 +696,7 @@ const EmbedTypeCodeAndPreviewDialogContent = ({
theme: Theme.auto,
floatingPopup: {},
elementClick: {},
hideEventTypeDetails: false,
palette: {
brandColor: "#000000",
},
@@ -753,6 +761,7 @@ const EmbedTypeCodeAndPreviewDialogContent = ({
name: "ui",
arg: {
theme: previewState.theme,
hideEventTypeDetails: previewState.hideEventTypeDetails,
styles: {
branding: {
...previewState.palette,
@@ -811,7 +820,7 @@ const EmbedTypeCodeAndPreviewDialogContent = ({
{embed.title}
</h3>
<hr className={classNames("mt-4", embedType === "element-click" ? "hidden" : "")} />
<div className="max-h-97 flex flex-col overflow-y-auto">
<div className="flex flex-col overflow-y-auto">
<div className={classNames("mt-4 font-medium", embedType === "element-click" ? "hidden" : "")}>
<Collapsible
open={isEmbedCustomizationOpen}
@@ -838,7 +847,6 @@ const EmbedTypeCodeAndPreviewDialogContent = ({
<div className="text-sm">Embed Window Sizing</div>
<div className="justify-left flex items-center">
<TextField
name="width"
labelProps={{ className: "hidden" }}
required
value={previewState.inline.width}
@@ -860,7 +868,6 @@ const EmbedTypeCodeAndPreviewDialogContent = ({
<span className="p-2">×</span>
<TextField
labelProps={{ className: "hidden" }}
name="height"
value={previewState.inline.height}
required
onChange={(e) => {
@@ -888,7 +895,6 @@ const EmbedTypeCodeAndPreviewDialogContent = ({
<div className="mb-2 text-sm">Button Text</div>
{/* Default Values should come from preview iframe */}
<TextField
name="buttonText"
labelProps={{ className: "hidden" }}
onChange={(e) => {
setPreviewState((previewState) => {
@@ -1004,6 +1010,20 @@ const EmbedTypeCodeAndPreviewDialogContent = ({
</CollapsibleTrigger>
<CollapsibleContent>
<div className="mt-6 text-sm">
<div className="mb-4 flex items-center justify-start space-x-2">
<Switch
checked={previewState.hideEventTypeDetails}
onCheckedChange={(checked) => {
setPreviewState((previewState) => {
return {
...previewState,
hideEventTypeDetails: checked,
};
});
}}
/>
<div className="text-sm">{t("hide_eventtype_details")}</div>
</div>
<Label className="">
<div className="mb-2">Theme</div>
<Select
@@ -13,6 +13,7 @@ import dayjs, { Dayjs } from "@calcom/dayjs";
import {
useEmbedNonStylesConfig,
useEmbedStyles,
useEmbedUiConfig,
useIsBackgroundTransparent,
useIsEmbed,
} from "@calcom/embed-core/embed-iframe";
@@ -253,6 +254,7 @@ const AvailabilityPage = ({ profile, eventType, ...restProps }: Props) => {
useTheme(profile.theme);
const { t } = useLocale();
const availabilityDatePickerEmbedStyles = useEmbedStyles("availabilityDatePicker");
//TODO: Plan to remove shouldAlignCentrallyInEmbed config
const shouldAlignCentrallyInEmbed = useEmbedNonStylesConfig("align") !== "left";
const shouldAlignCentrally = !isEmbed || shouldAlignCentrallyInEmbed;
const isBackgroundTransparent = useIsBackgroundTransparent();
@@ -289,7 +291,7 @@ const AvailabilityPage = ({ profile, eventType, ...restProps }: Props) => {
);
}
}, [telemetry]);
const embedUiConfig = useEmbedUiConfig();
// get dynamic user list here
const userList = eventType.users ? eventType.users.map((user) => user.username).filter(notEmpty) : [];
@@ -302,6 +304,8 @@ const AvailabilityPage = ({ profile, eventType, ...restProps }: Props) => {
const rawSlug = profile.slug ? profile.slug.split("/") : [];
if (rawSlug.length > 1) rawSlug.pop(); //team events have team name as slug, but user events have [user]/[type] as slug.
const showEventTypeDetails = (isEmbed && !embedUiConfig.hideEventTypeDetails) || !isEmbed;
// Define conditional gates here
const gates = [
// Rainbow gate is only added if the event has both a `blockchainId` and a `smartContractAddress`
@@ -335,7 +339,7 @@ const AvailabilityPage = ({ profile, eventType, ...restProps }: Props) => {
<div>
<main
className={classNames(
"flex-col md:mx-4 lg:flex",
"flex flex-col md:mx-4",
shouldAlignCentrally ? "items-center" : "items-start",
!isEmbed && classNames("mx-auto my-0 ease-in-out md:my-24")
)}>
@@ -350,54 +354,55 @@ const AvailabilityPage = ({ profile, eventType, ...restProps }: Props) => {
isEmbed && "mx-auto"
)}>
<div className="overflow-hidden md:flex">
<div
className={classNames(
"sm:dark:border-darkgray-200 flex flex-col border-gray-200 p-5 sm:border-r",
"min-w-full md:w-[230px] md:min-w-[230px]",
recurringEventCount && "xl:w-[380px] xl:min-w-[380px]"
)}>
<BookingDescription profile={profile} eventType={eventType} rescheduleUid={rescheduleUid}>
{!rescheduleUid && eventType.recurringEvent && (
<div className="flex items-start text-sm font-medium">
<Icon.FiRefreshCcw className="float-left mr-[10px] mt-[7px] ml-[2px] inline-block h-4 w-4 " />
<div>
<p className="mb-1 -ml-2 inline px-2 py-1">
{getRecurringFreq({ t, recurringEvent: eventType.recurringEvent })}
</p>
<input
type="number"
min="1"
max={eventType.recurringEvent.count}
className="w-15 dark:bg-darkgray-200 h-7 rounded-sm border-gray-300 bg-white text-sm font-medium [appearance:textfield] ltr:mr-2 rtl:ml-2 dark:border-gray-500"
defaultValue={eventType.recurringEvent.count}
onChange={(event) => {
setRecurringEventCount(parseInt(event?.target.value));
}}
/>
<p className="inline">
{t("occurrence", {
count: recurringEventCount,
})}
</p>
{showEventTypeDetails && (
<div
className={classNames(
"sm:dark:border-darkgray-200 flex flex-col border-gray-200 p-5 sm:border-r",
"min-w-full md:w-[230px] md:min-w-[230px]",
recurringEventCount && "xl:w-[380px] xl:min-w-[380px]"
)}>
<BookingDescription profile={profile} eventType={eventType} rescheduleUid={rescheduleUid}>
{!rescheduleUid && eventType.recurringEvent && (
<div className="flex items-start text-sm font-medium">
<Icon.FiRefreshCcw className="float-left mr-[10px] mt-[7px] ml-[2px] inline-block h-4 w-4 " />
<div>
<p className="mb-1 -ml-2 inline px-2 py-1">
{getRecurringFreq({ t, recurringEvent: eventType.recurringEvent })}
</p>
<input
type="number"
min="1"
max={eventType.recurringEvent.count}
className="w-15 dark:bg-darkgray-200 h-7 rounded-sm border-gray-300 bg-white text-sm font-medium [appearance:textfield] ltr:mr-2 rtl:ml-2 dark:border-gray-500"
defaultValue={eventType.recurringEvent.count}
onChange={(event) => {
setRecurringEventCount(parseInt(event?.target.value));
}}
/>
<p className="inline">
{t("occurrence", {
count: recurringEventCount,
})}
</p>
</div>
</div>
</div>
)}
{stripeAppData.price > 0 && (
<p className="-ml-2 px-2 text-sm font-medium">
<Icon.FiCreditCard className="mr-[10px] ml-[2px] -mt-1 inline-block h-4 w-4" />
<IntlProvider locale="en">
<FormattedNumber
value={stripeAppData.price / 100.0}
style="currency"
currency={stripeAppData.currency.toUpperCase()}
/>
</IntlProvider>
</p>
)}
{timezoneDropdown}
</BookingDescription>
)}
{stripeAppData.price > 0 && (
<p className="-ml-2 px-2 text-sm font-medium">
<Icon.FiCreditCard className="mr-[10px] ml-[2px] -mt-1 inline-block h-4 w-4" />
<IntlProvider locale="en">
<FormattedNumber
value={stripeAppData.price / 100.0}
style="currency"
currency={stripeAppData.currency.toUpperCase()}
/>
</IntlProvider>
</p>
)}
{timezoneDropdown}
</BookingDescription>
{/* Temporarily disabled - booking?.startTime && rescheduleUid && (
{/* Temporarily disabled - booking?.startTime && rescheduleUid && (
<div>
<p
className="mt-4 mb-3 text-gray-600 dark:text-darkgray-600"
@@ -410,7 +415,8 @@ const AvailabilityPage = ({ profile, eventType, ...restProps }: Props) => {
</p>
</div>
)*/}
</div>
</div>
)}
<SlotPicker
weekStart={
typeof profile.weekStart === "string"
@@ -26,6 +26,7 @@ import { LocationObject, LocationType } from "@calcom/core/location";
import dayjs from "@calcom/dayjs";
import {
useEmbedNonStylesConfig,
useEmbedUiConfig,
useIsBackgroundTransparent,
useIsEmbed,
} from "@calcom/embed-core/embed-iframe";
@@ -89,6 +90,7 @@ const BookingPage = ({
const { t, i18n } = useLocale();
const { duration: queryDuration } = useRouterQuery("duration");
const isEmbed = useIsEmbed(restProps.isEmbed);
const embedUiConfig = useEmbedUiConfig();
const shouldAlignCentrallyInEmbed = useEmbedNonStylesConfig("align") !== "left";
const shouldAlignCentrally = !isEmbed || shouldAlignCentrallyInEmbed;
const router = useRouter();
@@ -422,6 +424,7 @@ const BookingPage = ({
}
});
}
const showEventTypeDetails = (isEmbed && !embedUiConfig.hideEventTypeDetails) || !isEmbed;
const rainbowAppData = getEventTypeAppData(eventType, "rainbow") || {};
// Define conditional gates here
@@ -455,7 +458,7 @@ const BookingPage = ({
className={classNames(
shouldAlignCentrally ? "mx-auto" : "",
isEmbed ? "" : "sm:my-24",
"my-0 max-w-3xl "
"my-0 max-w-3xl"
)}>
<div
className={classNames(
@@ -464,95 +467,97 @@ const BookingPage = ({
"dark:border-darkgray-300 rounded-md sm:border"
)}>
<div className="sm:flex">
<div className="sm:dark:border-darkgray-300 dark:text-darkgray-600 flex flex-col px-6 pt-6 pb-0 text-gray-600 sm:w-1/2 sm:border-r sm:pb-6">
<BookingDescription isBookingPage profile={profile} eventType={eventType}>
{stripeAppData.price > 0 && (
<p className="text-bookinglight -ml-2 px-2 text-sm ">
<Icon.FiCreditCard className="mr-[10px] ml-[2px] -mt-1 inline-block h-4 w-4" />
<IntlProvider locale="en">
<FormattedNumber
value={stripeAppData.price / 100.0}
style="currency"
currency={stripeAppData.currency.toUpperCase()}
/>
</IntlProvider>
</p>
)}
{!rescheduleUid && eventType.recurringEvent?.freq && recurringEventCount && (
<div className="items-start text-sm font-medium text-gray-600 dark:text-white">
<Icon.FiRefreshCw className="mr-[10px] ml-[2px] inline-block h-4 w-4" />
<p className="-ml-2 inline-block items-center px-2">
{getEveryFreqFor({
t,
recurringEvent: eventType.recurringEvent,
recurringCount: recurringEventCount,
})}
{showEventTypeDetails && (
<div className="sm:dark:border-darkgray-300 dark:text-darkgray-600 flex flex-col px-6 pt-6 pb-0 text-gray-600 sm:w-1/2 sm:border-r sm:pb-6">
<BookingDescription isBookingPage profile={profile} eventType={eventType}>
{stripeAppData.price > 0 && (
<p className="text-bookinglight -ml-2 px-2 text-sm ">
<Icon.FiCreditCard className="mr-[10px] ml-[2px] -mt-1 inline-block h-4 w-4" />
<IntlProvider locale="en">
<FormattedNumber
value={stripeAppData.price / 100.0}
style="currency"
currency={stripeAppData.currency.toUpperCase()}
/>
</IntlProvider>
</p>
</div>
)}
<div className="text-bookinghighlight flex items-start text-sm">
<Icon.FiCalendar className="mr-[10px] ml-[2px] mt-[2px] inline-block h-4 w-4" />
<div className="text-sm font-medium">
{(rescheduleUid || !eventType.recurringEvent?.freq) && `${parseDate(date, i18n)}`}
{!rescheduleUid &&
eventType.recurringEvent?.freq &&
recurringStrings.slice(0, 5).map((timeFormatted, key) => {
return <p key={key}>{timeFormatted}</p>;
})}
{!rescheduleUid && eventType.recurringEvent?.freq && recurringStrings.length > 5 && (
<div className="flex">
<Tooltip
content={recurringStrings.slice(5).map((timeFormatted, key) => (
<p key={key}>{timeFormatted}</p>
))}>
<p className="dark:text-darkgray-600 text-sm">
+ {t("plus_more", { count: recurringStrings.length - 5 })}
</p>
</Tooltip>
</div>
)}
</div>
</div>
{booking?.startTime && rescheduleUid && (
<div>
<p className="mt-8 mb-2 text-sm " data-testid="former_time_p">
{t("former_time")}
</p>
<p className="line-through ">
<Icon.FiCalendar className="mr-[10px] ml-[2px] -mt-1 inline-block h-4 w-4" />
{typeof booking.startTime === "string" && parseDate(dayjs(booking.startTime), i18n)}
</p>
</div>
)}
{!!eventType.seatsPerTimeSlot && (
)}
{!rescheduleUid && eventType.recurringEvent?.freq && recurringEventCount && (
<div className="items-start text-sm font-medium text-gray-600 dark:text-white">
<Icon.FiRefreshCw className="mr-[10px] ml-[2px] inline-block h-4 w-4" />
<p className="-ml-2 inline-block items-center px-2">
{getEveryFreqFor({
t,
recurringEvent: eventType.recurringEvent,
recurringCount: recurringEventCount,
})}
</p>
</div>
)}
<div className="text-bookinghighlight flex items-start text-sm">
<Icon.FiUser
className={`mr-[10px] ml-[2px] mt-[2px] inline-block h-4 w-4 ${
booking && booking.attendees.length / eventType.seatsPerTimeSlot >= 0.5
? "text-rose-600"
: booking && booking.attendees.length / eventType.seatsPerTimeSlot >= 0.33
? "text-yellow-500"
: "text-bookinghighlight"
}`}
/>
<p
className={`${
booking && booking.attendees.length / eventType.seatsPerTimeSlot >= 0.5
? "text-rose-600"
: booking && booking.attendees.length / eventType.seatsPerTimeSlot >= 0.33
? "text-yellow-500"
: "text-bookinghighlight"
} mb-2 font-medium`}>
{booking
? eventType.seatsPerTimeSlot - booking.attendees.length
: eventType.seatsPerTimeSlot}{" "}
/ {eventType.seatsPerTimeSlot} {t("seats_available")}
</p>
<Icon.FiCalendar className="mr-[10px] ml-[2px] mt-[2px] inline-block h-4 w-4" />
<div className="text-sm font-medium">
{(rescheduleUid || !eventType.recurringEvent?.freq) && `${parseDate(date, i18n)}`}
{!rescheduleUid &&
eventType.recurringEvent?.freq &&
recurringStrings.slice(0, 5).map((timeFormatted, key) => {
return <p key={key}>{timeFormatted}</p>;
})}
{!rescheduleUid && eventType.recurringEvent?.freq && recurringStrings.length > 5 && (
<div className="flex">
<Tooltip
content={recurringStrings.slice(5).map((timeFormatted, key) => (
<p key={key}>{timeFormatted}</p>
))}>
<p className="dark:text-darkgray-600 text-sm">
+ {t("plus_more", { count: recurringStrings.length - 5 })}
</p>
</Tooltip>
</div>
)}
</div>
</div>
)}
</BookingDescription>
</div>
<div className="p-6 sm:w-1/2">
{booking?.startTime && rescheduleUid && (
<div>
<p className="mt-8 mb-2 text-sm " data-testid="former_time_p">
{t("former_time")}
</p>
<p className="line-through ">
<Icon.FiCalendar className="mr-[10px] ml-[2px] -mt-1 inline-block h-4 w-4" />
{typeof booking.startTime === "string" && parseDate(dayjs(booking.startTime), i18n)}
</p>
</div>
)}
{!!eventType.seatsPerTimeSlot && (
<div className="text-bookinghighlight flex items-start text-sm">
<Icon.FiUser
className={`mr-[10px] ml-[2px] mt-[2px] inline-block h-4 w-4 ${
booking && booking.attendees.length / eventType.seatsPerTimeSlot >= 0.5
? "text-rose-600"
: booking && booking.attendees.length / eventType.seatsPerTimeSlot >= 0.33
? "text-yellow-500"
: "text-bookinghighlight"
}`}
/>
<p
className={`${
booking && booking.attendees.length / eventType.seatsPerTimeSlot >= 0.5
? "text-rose-600"
: booking && booking.attendees.length / eventType.seatsPerTimeSlot >= 0.33
? "text-yellow-500"
: "text-bookinghighlight"
} mb-2 font-medium`}>
{booking
? eventType.seatsPerTimeSlot - booking.attendees.length
: eventType.seatsPerTimeSlot}{" "}
/ {eventType.seatsPerTimeSlot} {t("seats_available")}
</p>
</div>
)}
</BookingDescription>
</div>
)}
<div className={classNames("p-6", showEventTypeDetails ? "sm:w-1/2" : "w-full")}>
<Form form={bookingForm} handleSubmit={bookEvent}>
<div className="mb-4">
<label htmlFor="name" className="block text-sm font-medium text-gray-700 dark:text-white">
@@ -1438,5 +1438,6 @@
"add_an_option": "Add an option",
"radio": "Radio",
"event_type_duplicate_copy_text": "{{slug}}-copy",
"set_as_default": "Set as default"
"set_as_default": "Set as default",
"hide_eventtype_details": "Hide EventType Details"
}
+96 -85
View File
@@ -1,5 +1,6 @@
<html>
<head>
<title>Embed Playground</title>
<!-- <link rel="prerender" href="http://localhost:3000/free"> -->
<!-- <script src="./src/embed.ts" type="module"></script> -->
<script>
@@ -9,8 +10,8 @@
(()=> {
const url = new URL(document.URL);
// Only run the example specified by only=, avoids distraction and faster to test.
const only = url.searchParams.get("only");
const elementIdentifier = only ? only.replace("ns:",""): null
const only = window.only = url.searchParams.get("only");
const elementIdentifier = only !== "all" ? only.replace("ns:",""): null
if (elementIdentifier) {
location.hash="#cal-booking-place-" + elementIdentifier + "-iframe"
}
@@ -56,9 +57,10 @@
rgba(148, 232, 249, 1) 100%
);
}
.debug {
.inline-embed-container {
/* border: 1px solid black; */
margin-bottom: 5px;
border-bottom: 1px solid
}
.loader {
@@ -70,19 +72,26 @@
</style>
</head>
<body>
<h3>This page has a non responsive version accessible <a href="?nonResponsive">here</a></h3>
<h3>Pre-render test page available at <a href="?only=prerender-test">here</a></h3>
<span style="display: block;" ><a href="?nonResponsive">Non responsive version of this page here</a></span>
<span style="display: block;" ><a href="?only=prerender-test">Go to Pre-render test page only</a><small></small></span>
<div>
<button data-cal-namespace="prerendertestLightTheme" data-cal-config='{"theme":"light"}' data-cal-link="free?light&popup">Book with Free User[Light Theme]</button>
<div>
<i
>Corresponding Cal Link is being preloaded. Assuming that it would take you some time to click this
as you are reading this text, it would open up super fast[If you are running a production build on
local]. Try switching to slow 3G or create a custom Network configuration which is impossibly
slow</i
>
</div>
<h2>Other Popup Examples</h2>
<script>
if (only === "all" || only === "prerender-test") {
document.write(`
<button data-cal-namespace="prerendertestLightTheme" data-cal-config='{"theme":"light"}' data-cal-link="free?light&popup">Book with Free User[Light Theme]</button>
<i
>Corresponding Cal Link is being preloaded. Assuming that it would take you some time to click this
as you are reading this text, it would open up super fast[If you are running a production build on
local]. Try switching to slow 3G or create a custom Network configuration which is impossibly
slow</i
>`)
}
</script>
</div>
<span style="display: block;" ><a href="?only=all">Render All embeds together</a><small> - It would be slow to load</small></span>
<div>
<h2>Popup Examples</h2>
<button data-cal-namespace="popupAutoTheme" data-cal-link="free">Book with Free User[Auto Theme]</button>
<button data-cal-namespace="popupDarkTheme" data-cal-config='{"theme":"dark"}' data-cal-link="free">Book with Free User[Dark Theme]</button>
<button data-cal-namespace="popupTeamLinkLightTheme" data-cal-config='{"theme":"light"}' data-cal-link="team/seeded-team/collective-seeded-team-event">Book with Test Team[Light Theme]</button>
@@ -90,35 +99,28 @@
<button data-cal-namespace="popupTeamLinksList" data-cal-link="team/seeded-team/">See Team Links [Auto Theme]</button>
<button data-cal-namespace="popupReschedule" data-cal-link="reschedule/qm3kwt3aTnVD7vmP9tiT2f">Reschedule Event[Auto Theme]</button>
<button data-cal-namespace="popupPaidEvent" data-cal-link="pro/paid">Book Paid Event [Auto Theme]</button>
<button data-cal-namespace="popupHideEventTypeDetails" data-cal-link="free/30min">Book Free Event [Auto Theme][uiConfig.hideEventTypeDetails=true]</button>
<button data-cal-namespace="routingFormAuto" data-cal-link="forms/948ae412-d995-4865-875a-48302588de03">Book through Routing Form [Auto Theme]</button>
<button data-cal-namespace="routingFormDark" data-cal-config='{"theme":"dark"}' data-cal-link="forms/948ae412-d995-4865-875a-48302588de03">Book through Routing Form [Dark Theme]</button>
<div>
<!-- <div>
<h2>Embed for Pages behind authentication</h2>
<button data-cal-namespace="upcomingBookings" data-cal-config='{"theme":"dark"}' data-cal-link="bookings/upcoming">Show Upcoming Bookings</button>
</div>
</div> -->
</div>
<h2>Inline Embed Examples</h2>
<div id="namespaces-test">
<div class="debug" id="cal-booking-place-default">
<h2>
Default Namespace(Cal)<i>[Dark Theme][inline][Guests(janedoe@example.com and test@example.com)]</i>
</h2>
<div>
<i><a href="?only=ns:default">Test in Zen Mode</a></i>
</div>
<div class="inline-embed-container" id="cal-booking-place-default">
<h3>
<a href="?only=ns:default">[Dark Theme][Guests(janedoe@example.com and test@example.com)]</a>
</h3>
<i class="last-action"> You would see last Booking page action in my place </i>
<div >
<div class="place" style="width:100%;"></div>
<div class="loader" id="cal-booking-loader-">Loading .....</div>
<div class="loader" id="cal-booking-loader-"></div>
</div>
</div>
<div class="debug" id="cal-booking-place-second">
<h2>Namespace "second"(Cal.ns.second)[Custom Styling][inline]</h2>
<div>
<i><a href="?only=ns:second">Test in Zen Mode</a></i>
</div>
<i class="last-action">
<i>You would see last Booking page action in my place</i>
</i>
<div class="inline-embed-container" id="cal-booking-place-second">
<h3><a href="?only=ns:second">[Custom Styling]</a></h3>
<div class="place">
<div>If you render booking embed in me, I won't restrict you. The entire page is yours. Content is by default aligned center</div>
<button
@@ -143,71 +145,48 @@
Change Date Button Color
</button>
<div class="loader" id="cal-booking-loader-second">Loading .....</div>
</div>
</div>
<div class="debug" id="cal-booking-place-third">
<h2>Namespace "third"(Cal.ns.third)[inline][Custom Styling - Transparent Background]</h2>
<div>
<i><a href="?only=ns:third">Test in Zen Mode</a></i>
</div>
<i class="last-action">
<i>You would see last Booking page action in my place</i>
</i>
<div class="inline-embed-container" id="cal-booking-place-third">
<h3><a href="?only=ns:third">[Custom Styling - Transparent Background]</a></h3>
<div style="width: 30%" class="place">
<div>If you render booking embed in me, I would not let you be more than 30% wide</div>
<div class="loader" id="cal-booking-loader-third">Loading .....</div>
</div>
</div>
<div class="debug" id="cal-booking-place-fourth">
<h2>Namespace "fourth"(Cal.ns.fourth)[Team Event Test][inline taking entire width]</h2>
<div>
<i><a href="?only=ns:fourth">Test in Zen Mode</a></i>
</div>
<i class="last-action">
<i>You would see last Booking page action in my place</i>
</i>
<div class="inline-embed-container" id="cal-booking-place-fourth">
<h3><a href="?only=ns:fourth">[Team Event Test][inline taking entire width]</a></h3>
<div style="width: 30%" class="place">
<div>If you render booking embed in me, I would not let you be more than 30% wide</div>
<div class="loader" id="cal-booking-loader-third">Loading .....</div>
</div>
</div>
</div>
<div class="debug" id="cal-booking-place-fifth">
<h2>Namespace "fifth"(Cal.ns.fifth)[Team Event Test][inline along with some content]</h2>
<div>
<i><a href="?only=ns:fifth">Test in Zen Mode</a></i>
</div>
<i class="last-action">
<i>You would see last Booking page action in my place</i>
</i>
<div class="inline-embed-container" id="cal-booking-place-fifth">
<h3><a href="?only=ns:fifth">[Team Event Test][inline along with some content]</a></h3>
<div style="display:flex;align-items: center;">
<h2 style="width: 30%">
<h4 style="width: 30%">
On the right side you can book a team meeting =>
</h2>
</h4>
<div style="width: 70%" class="place">
</div>
</div>
</div>
<div class="debug" id="cal-booking-place-inline-routing-form">
<h2>Inline Routing Form</h2>
<div>
<i><a href="?only=inline-routing-form">Test in Zen Mode</a></i>
</div>
<i class="last-action">
<i>You would see last Booking page action in my place</i>
</i>
<div class="inline-embed-container" id="cal-booking-place-inline-routing-form">
<h3><a href="?only=inline-routing-form">Inline Routing Form</a></h3>
<div style="display:flex;align-items: center;">
<h2 style="width: 30%">
<h4 style="width: 30%">
On the right side you can book a team meeting =>
</h2>
</h4>
<div style="width: 70%" class="place">
</div>
</div>
</div>
<div class="inline-embed-container" id="cal-booking-place-hideEventTypeDetails">
<h3><a href="?only=hideEventTypeDetails">Hide EventType Details Test</a></h3>
<div class="place">
</div>
</div>
<script>
const callback = function (e) {
@@ -224,8 +203,8 @@
);
};
const searchParams = new URL(document.URL).searchParams;
const only = searchParams.get("only");
if (!only || only === "ns:default") {
let only = window.only
if (only === "all" || only === "ns:default") {
Cal("init", {
debug: 1,
origin: "http://localhost:3000",
@@ -251,7 +230,7 @@
callback,
});
}
if (!only || only === "ns:second") {
if (only === "all" || only === "ns:second") {
// Create a namespace "second". It can be accessed as Cal.ns.second with the exact same API as Cal
Cal("init", "second", {
debug: 1,
@@ -278,8 +257,7 @@
callback,
});
}
if (!only || only === "ns:third") {
if (only === "all" || only === "ns:third") {
// Create a namespace "third". It can be accessed as Cal.ns.second with the exact same API as Cal
Cal("init", "third", {
debug: 1,
@@ -329,8 +307,7 @@
callback,
});
}
if (!only || only === "ns:fourth") {
if (only === "all" || only === "ns:fourth") {
Cal("init", "fourth", {
debug: 1,
origin: "http://localhost:3000",
@@ -372,7 +349,7 @@
callback,
});
}
if (!only || only === "ns:fifth") {
if (only === "all" || only === "ns:fifth") {
Cal("init", "fifth", {
debug: 1,
origin: "http://localhost:3000",
@@ -396,7 +373,7 @@
callback,
});
}
if (!only || only === "prerender-test") {
if (only === "all" || only === "prerender-test") {
Cal('init', 'prerendertestLightTheme', {
debug: 1,
origin: "http://localhost:3000",
@@ -406,7 +383,7 @@
});
}
if (!only || only === "inline-routing-form") {
if (only === "all" || only === "inline-routing-form") {
Cal('init', 'inline-routing-form', {
debug: 1,
origin: "http://localhost:3000",
@@ -427,11 +404,45 @@
);
}
if (only === "all" || only === "hideEventTypeDetails") {
let identifier = "hideEventTypeDetails"
Cal('init', identifier, {
debug: 1,
origin: "http://localhost:3000",
})
Cal.ns.hideEventTypeDetails([
['inline', {
elementOrSelector: `#cal-booking-place-${identifier} .place`,
calLink: "free/30min",
config: {
iframeAttrs: {
id: `cal-booking-place-${identifier}-iframe`
},
}
}],
[
'ui', {
hideEventTypeDetails:true
}
]
]);
}
Cal('init', 'popupDarkTheme', {
debug: 1,
origin: "http://localhost:3000",
})
Cal('init', 'popupHideEventTypeDetails', {
debug: 1,
origin: "http://localhost:3000",
});
Cal.ns.popupHideEventTypeDetails('ui', {
hideEventTypeDetails:true
});
Cal('init', 'popupReschedule', {
debug: 1,
origin: "http://localhost:3000",
@@ -481,7 +492,7 @@
})
if (!only || only == "ns:floatingButton") {
if (only === "all" || only == "ns:floatingButton") {
Cal.ns.floatingButton("floatingButton", {
calLink: "pro"
})
+19 -2
View File
@@ -4,6 +4,7 @@ import { useState, useEffect, CSSProperties } from "react";
import { sdkActionManager } from "./sdk-event";
export interface UiConfig {
hideEventTypeDetails?: boolean;
theme?: "dark" | "light" | "auto";
styles?: EmbedStyles;
}
@@ -39,7 +40,9 @@ const embedStore = {
parentInformedAboutContentHeight: boolean;
windowLoadEventFired: boolean;
theme?: UiConfig["theme"];
setTheme: (arg0: string) => void;
uiConfig?: Omit<UiConfig, "styles" | "theme">;
setTheme?: (arg0: string) => void;
setUiConfig?: (arg0: UiConfig) => void;
};
let isSafariBrowser = false;
@@ -146,6 +149,12 @@ export const useEmbedTheme = () => {
return theme === "auto" ? null : theme;
};
export const useEmbedUiConfig = () => {
const [uiConfig, setUiConfig] = useState(embedStore.uiConfig || {});
embedStore.setUiConfig = setUiConfig;
return uiConfig;
};
// TODO: Make it usable as an attribute directly instead of styles value. It would allow us to go beyond styles e.g. for debugging we can add a special attribute indentifying the element on which UI config has been applied
export const useEmbedStyles = (elementName: keyof EmbedStyles) => {
const [styles, setStyles] = useState({} as EmbedStyles);
@@ -258,7 +267,15 @@ export const methods = {
if (uiConfig.theme) {
embedStore.theme = uiConfig.theme as UiConfig["theme"];
embedStore.setTheme(uiConfig.theme);
if (embedStore.setTheme) {
embedStore.setTheme(uiConfig.theme);
}
}
// Set the value here so that if setUiConfig state isn't available and later it's defined,it uses this value
embedStore.uiConfig = uiConfig;
if (embedStore.setUiConfig) {
embedStore.setUiConfig(uiConfig);
}
setEmbedStyles(stylesConfig || {});