// Get router variables import { ArrowLeftIcon, CalendarIcon, ChevronDownIcon, ChevronUpIcon, ClockIcon, CreditCardIcon, GlobeIcon, InformationCircleIcon, RefreshIcon, } 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 { useRouter } from "next/router"; import { useEffect, useMemo, useState } from "react"; import { FormattedNumber, IntlProvider } from "react-intl"; import { Frequency as RRuleFrequency } from "rrule"; import { useEmbedStyles, useIsEmbed, useIsBackgroundTransparent, sdkActionManager, useEmbedType, useEmbedNonStylesConfig, } from "@calcom/embed-core"; import classNames from "@calcom/lib/classNames"; import { WEBAPP_URL } from "@calcom/lib/constants"; import { useLocale } from "@calcom/lib/hooks/useLocale"; import { localStorage } from "@calcom/lib/webstorage"; import { asStringOrNull } from "@lib/asStringOrNull"; import { timeZone } from "@lib/clock"; import { useExposePlanGlobally } from "@lib/hooks/useExposePlanGlobally"; import useTheme from "@lib/hooks/useTheme"; import { isBrandingHidden } from "@lib/isBrandingHidden"; import { parseDate } from "@lib/parseDate"; import { collectPageParameters, telemetryEventTypes, useTelemetry } from "@lib/telemetry"; import { detectBrowserTimeFormat } from "@lib/timeFormat"; import CustomBranding from "@components/CustomBranding"; import AvailableTimes from "@components/booking/AvailableTimes"; import DatePicker from "@components/booking/DatePicker"; import TimeOptions from "@components/booking/TimeOptions"; import { HeadSeo } from "@components/seo/head-seo"; import AvatarGroup from "@components/ui/AvatarGroup"; import PoweredByCal from "@components/ui/PoweredByCal"; import { AvailabilityPageProps } from "../../../pages/[user]/[type]"; import { AvailabilityTeamPageProps } from "../../../pages/team/[slug]/[type]"; dayjs.extend(utc); dayjs.extend(customParseFormat); type Props = AvailabilityTeamPageProps | AvailabilityPageProps; const AvailabilityPage = ({ profile, plan, eventType, workingHours, previousPage, booking }: Props) => { const router = useRouter(); const isEmbed = useIsEmbed(); const { rescheduleUid } = router.query; const { isReady, Theme } = useTheme(profile.theme); const { t, i18n } = useLocale(); const { contracts } = useContracts(); const availabilityDatePickerEmbedStyles = useEmbedStyles("availabilityDatePicker"); const shouldAlignCentrallyInEmbed = useEmbedNonStylesConfig("align") !== "left"; const shouldAlignCentrally = !isEmbed || shouldAlignCentrallyInEmbed; let isBackgroundTransparent = useIsBackgroundTransparent(); useExposePlanGlobally(plan); useEffect(() => { if (eventType.metadata.smartContractAddress) { const eventOwner = eventType.users[0]; if (!contracts[(eventType.metadata.smartContractAddress || null) as number]) router.replace(`/${eventOwner.username}`); } }, [contracts, eventType.metadata.smartContractAddress, router]); const selectedDate = useMemo(() => { const dateString = asStringOrNull(router.query.date); if (dateString) { const offsetString = dateString.substr(11, 14); // hhmm const offsetSign = dateString.substr(10, 1); // + or - const offsetHour = offsetString.slice(0, -2); const offsetMinute = offsetString.slice(-2); const utcOffsetInMinutes = (offsetSign === "-" ? -1 : 1) * (60 * (offsetHour !== "" ? parseInt(offsetHour) : 0) + (offsetMinute !== "" ? parseInt(offsetMinute) : 0)); const date = dayjs(dateString.substr(0, 10)).utcOffset(utcOffsetInMinutes, true); return date.isValid() ? date : null; } return null; }, [router.query.date]); if (selectedDate) { // Let iframe take the width available due to increase in max-width sdkActionManager?.fire("__refreshWidth", {}); } const [isTimeOptionsOpen, setIsTimeOptionsOpen] = useState(false); const [timeFormat, setTimeFormat] = useState(detectBrowserTimeFormat); const [recurringEventCount, setRecurringEventCount] = useState(eventType.recurringEvent?.count); const telemetry = useTelemetry(); useEffect(() => { handleToggle24hClock(localStorage.getItem("timeOption.is24hClock") === "true"); telemetry.withJitsu((jitsu) => jitsu.track( top !== window ? telemetryEventTypes.embedView : telemetryEventTypes.pageView, collectPageParameters("/availability", { isTeamBooking: document.URL.includes("team/") }) ) ); }, [telemetry]); const changeDate = (newDate: Dayjs) => { router.replace( { query: { ...router.query, date: newDate.format("YYYY-MM-DDZZ"), }, }, undefined, { shallow: true, } ); }; const handleSelectTimeZone = (selectedTimeZone: string): void => { if (selectedDate) { changeDate(selectedDate.tz(selectedTimeZone, true)); } timeZone(selectedTimeZone); setIsTimeOptionsOpen(false); }; const handleToggle24hClock = (is24hClock: boolean) => { setTimeFormat(is24hClock ? "HH:mm" : "h:mma"); }; // Recurring event sidebar requires more space const maxWidth = selectedDate ? recurringEventCount ? "max-w-6xl" : "max-w-5xl" : recurringEventCount ? "max-w-4xl" : "max-w-3xl"; return ( <>
{isReady && (
{/* mobile: details */}
user.name !== profile.name) .map((user) => ({ title: user.name, image: `${process.env.NEXT_PUBLIC_WEBSITE_URL}/${user.username}/avatar.png`, alt: user.name || undefined, })), ].filter((item) => !!item.image) as { image: string; alt?: string; title?: string }[] } size={9} truncateAfter={5} />

{profile.name}

{eventType.title}

{eventType?.description && (

{eventType.description}

)}

{eventType.length} {t("minutes")}

{eventType.price > 0 && (
)}
{booking?.startTime && rescheduleUid && (

{t("former_time")}

{typeof booking.startTime === "string" && parseDate(dayjs(booking.startTime), i18n)}

)}
user.name !== profile.name) .map((user) => ({ title: user.name, alt: user.name, image: `${process.env.NEXT_PUBLIC_WEBSITE_URL}/${user.username}/avatar.png`, })), ].filter((item) => !!item.image) as { image: string; alt?: string; title?: string }[] } size={10} truncateAfter={3} />

{profile.name}

{eventType.title}

{eventType?.description && (

{eventType.description}

)}

{eventType.length} {t("minutes")}

{!rescheduleUid && eventType.recurringEvent?.count && eventType.recurringEvent?.freq && (

{t("every_for_freq", { freq: t( `${RRuleFrequency[eventType.recurringEvent.freq].toString().toLowerCase()}` ), })}

{ setRecurringEventCount(parseInt(event?.target.value)); }} />

{t(`${RRuleFrequency[eventType.recurringEvent.freq].toString().toLowerCase()}`, { count: recurringEventCount, })}

)} {eventType.price > 0 && (

)} {previousPage === `${WEBAPP_URL}/${profile.slug}` && (
router.back()} />

Go Back

)} {booking?.startTime && rescheduleUid && (

{t("former_time")}

{typeof booking.startTime === "string" && parseDate(dayjs(booking.startTime), i18n)}

)}
{selectedDate && ( )}
)} {(!eventType.users[0] || !isBrandingHidden(eventType.users[0])) && !isEmbed && }
); function TimezoneDropdown() { return ( {timeZone()} {isTimeOptionsOpen ? ( ) : ( )} ); } }; export default AvailabilityPage;