diff --git a/apps/storybook/styles/globals.css b/apps/storybook/styles/globals.css
index e375a7ba752e6a..115058d60a7108 100644
--- a/apps/storybook/styles/globals.css
+++ b/apps/storybook/styles/globals.css
@@ -2,4 +2,9 @@
@tailwind components;
@tailwind utilities;
-@import "../../../packages/ui/styles/shared-globals.css"
+@import "../../../packages/ui/styles/shared-globals.css";
+
+:root {
+ --font-inter: "Inter var";
+ --font-cal: "Cal Sans";
+}
diff --git a/apps/web/components/Embed.tsx b/apps/web/components/Embed.tsx
index 503e50b8dafeff..462a8cb7daecfd 100644
--- a/apps/web/components/Embed.tsx
+++ b/apps/web/components/Embed.tsx
@@ -20,10 +20,10 @@ import {
Switch,
TextArea,
TextField,
+ ColorPicker,
} from "@calcom/ui";
import { FiCode, FiTrello, FiSun, FiArrowLeft, FiChevronRight } from "@calcom/ui/components/icon";
-import ColorPicker from "@components/ui/colorpicker";
import Select from "@components/ui/form/Select";
type EmbedType = "inline" | "floating-popup" | "element-click";
diff --git a/apps/web/components/booking/AvailableTimes.tsx b/apps/web/components/booking/AvailableTimes.tsx
index 2a05ba94e3e29a..cbd14dd0928cd0 100644
--- a/apps/web/components/booking/AvailableTimes.tsx
+++ b/apps/web/components/booking/AvailableTimes.tsx
@@ -1,3 +1,4 @@
+import { useAutoAnimate } from "@formkit/auto-animate/react";
import Link from "next/link";
import { useRouter } from "next/router";
import type { FC } from "react";
@@ -39,6 +40,7 @@ const AvailableTimes: FC = ({
seatsPerTimeSlot,
ethSignature,
}) => {
+ const [slotPickerRef] = useAutoAnimate();
const { t, i18n } = useLocale();
const router = useRouter();
const { rescheduleUid } = router.query;
@@ -49,122 +51,124 @@ const AvailableTimes: FC = ({
setBrand(getComputedStyle(document.documentElement).getPropertyValue("--brand-color").trim());
}, []);
- if (!date) return null;
-
return (
-
-
-
-
- {nameOfDay(i18n.language, Number(date.format("d")), "short")}
-
-
- , {date.toDate().toLocaleString(i18n.language, { month: "short" })} {date.format(" D ")}
-
-
-
- onTimeFormatChange(timeFormat === "24")}
- defaultValue={timeFormat === TimeFormat.TWELVE_HOUR ? "12" : "24"}
- options={[
- { value: "12", label: t("12_hour_short") },
- { value: "24", label: t("24_hour_short") },
- ]}
- />
-
-
-
- {slots.length > 0 &&
- slots.map((slot) => {
- type BookingURL = {
- pathname: string;
- query: Record
;
- };
- const bookingUrl: BookingURL = {
- pathname: router.pathname.endsWith("/embed") ? "../book" : "book",
- query: {
- ...router.query,
- date: dayjs.utc(slot.time).tz(timeZone()).format(),
- type: eventTypeId,
- slug: eventTypeSlug,
- /** Treat as recurring only when a count exist and it's not a rescheduling workflow */
- count: recurringCount && !rescheduleUid ? recurringCount : undefined,
- ...(ethSignature ? { ethSignature } : {}),
- },
- };
+
+ {!!date ? (
+
+
+
+
+ {nameOfDay(i18n.language, Number(date.format("d")), "short")}
+
+
+ , {date.toDate().toLocaleString(i18n.language, { month: "short" })} {date.format(" D ")}
+
+
+
+ onTimeFormatChange(timeFormat === "24")}
+ defaultValue={timeFormat === TimeFormat.TWELVE_HOUR ? "12" : "24"}
+ options={[
+ { value: "12", label: t("12_hour_short") },
+ { value: "24", label: t("24_hour_short") },
+ ]}
+ />
+
+
+
+ {slots.length > 0 &&
+ slots.map((slot) => {
+ type BookingURL = {
+ pathname: string;
+ query: Record
;
+ };
+ const bookingUrl: BookingURL = {
+ pathname: router.pathname.endsWith("/embed") ? "../book" : "book",
+ query: {
+ ...router.query,
+ date: dayjs.utc(slot.time).tz(timeZone()).format(),
+ type: eventTypeId,
+ slug: eventTypeSlug,
+ /** Treat as recurring only when a count exist and it's not a rescheduling workflow */
+ count: recurringCount && !rescheduleUid ? recurringCount : undefined,
+ ...(ethSignature ? { ethSignature } : {}),
+ },
+ };
- if (rescheduleUid) {
- bookingUrl.query.rescheduleUid = rescheduleUid as string;
- }
+ if (rescheduleUid) {
+ bookingUrl.query.rescheduleUid = rescheduleUid as string;
+ }
- // If event already has an attendee add booking id
- if (slot.bookingUid) {
- bookingUrl.query.bookingUid = slot.bookingUid;
- }
+ // If event already has an attendee add booking id
+ if (slot.bookingUid) {
+ bookingUrl.query.bookingUid = slot.bookingUid;
+ }
- return (
-
- {/* ^ data-slot-owner is helpful in debugging and used to identify the owners of the slot. Owners are the users which have the timeslot in their schedule. It doesn't consider if a user has that timeslot booked */}
- {/* Current there is no way to disable Next.js Links */}
- {seatsPerTimeSlot && slot.attendees && slot.attendees >= seatsPerTimeSlot ? (
-
- {dayjs(slot.time).tz(timeZone()).format(timeFormat)}
- {!!seatsPerTimeSlot &&
{t("booking_full")}
}
-
- ) : (
-
+ {/* ^ data-slot-owner is helpful in debugging and used to identify the owners of the slot. Owners are the users which have the timeslot in their schedule. It doesn't consider if a user has that timeslot booked */}
+ {/* Current there is no way to disable Next.js Links */}
+ {seatsPerTimeSlot && slot.attendees && slot.attendees >= seatsPerTimeSlot ? (
+
+ {dayjs(slot.time).tz(timeZone()).format(timeFormat)}
+ {!!seatsPerTimeSlot &&
{t("booking_full")}
}
+
+ ) : (
+
+ {dayjs(slot.time).tz(timeZone()).format(timeFormat)}
+ {!!seatsPerTimeSlot && (
+
= 0.8
+ ? "text-rose-600"
+ : slot.attendees && slot.attendees / seatsPerTimeSlot >= 0.33
+ ? "text-yellow-500"
+ : "text-emerald-400"
+ } text-sm`}>
+ {slot.attendees ? seatsPerTimeSlot - slot.attendees : seatsPerTimeSlot} /{" "}
+ {seatsPerTimeSlot} {t("seats_available")}
+
+ )}
+
)}
- data-testid="time">
- {dayjs(slot.time).tz(timeZone()).format(timeFormat)}
- {!!seatsPerTimeSlot && (
-
= 0.8
- ? "text-rose-600"
- : slot.attendees && slot.attendees / seatsPerTimeSlot >= 0.33
- ? "text-yellow-500"
- : "text-emerald-400"
- } text-sm`}>
- {slot.attendees ? seatsPerTimeSlot - slot.attendees : seatsPerTimeSlot} /{" "}
- {seatsPerTimeSlot} {t("seats_available")}
-
- )}
-
- )}
+
+ );
+ })}
+
+ {!isLoading && !slots.length && (
+
+
{t("all_booked_today")}
- );
- })}
+ )}
- {!isLoading && !slots.length && (
-
-
{t("all_booked_today")}
+ {isLoading && !slots.length && (
+ <>
+
+
+
+
+
+
+
+
+
+ >
+ )}
- )}
-
- {isLoading && !slots.length && (
- <>
-
-
-
-
-
-
-
-
-
- >
- )}
-
+
+ ) : null}
);
};
diff --git a/apps/web/components/booking/BookingDescription.tsx b/apps/web/components/booking/BookingDescription.tsx
index 2a639616b28a6d..5c9f067a4c9f88 100644
--- a/apps/web/components/booking/BookingDescription.tsx
+++ b/apps/web/components/booking/BookingDescription.tsx
@@ -3,7 +3,7 @@ import type { FC, ReactNode } from "react";
import { useEffect } from "react";
import dayjs from "@calcom/dayjs";
-import { classNames } from "@calcom/lib";
+import classNames from "@calcom/lib/classNames";
import { useLocale } from "@calcom/lib/hooks/useLocale";
import { Badge } from "@calcom/ui";
import { FiCheckSquare, FiClock, FiInfo } from "@calcom/ui/components/icon";
diff --git a/apps/web/components/booking/SlotPicker.tsx b/apps/web/components/booking/SlotPicker.tsx
new file mode 100644
index 00000000000000..3fb71b6ce0d15d
--- /dev/null
+++ b/apps/web/components/booking/SlotPicker.tsx
@@ -0,0 +1,200 @@
+import type { EventType } from "@prisma/client";
+import dynamic from "next/dynamic";
+import { useRouter } from "next/router";
+import { useEffect, useState } from "react";
+import type { z } from "zod";
+
+import type { Dayjs } from "@calcom/dayjs";
+import dayjs from "@calcom/dayjs";
+import DatePicker from "@calcom/features/calendars/DatePicker";
+import classNames from "@calcom/lib/classNames";
+import { useLocale } from "@calcom/lib/hooks/useLocale";
+import type { TimeFormat } from "@calcom/lib/timeFormat";
+import type { EventTypeMetaDataSchema } from "@calcom/prisma/zod-utils";
+import { trpc } from "@calcom/trpc/react";
+
+import useRouterQuery from "@lib/hooks/useRouterQuery";
+
+const AvailableTimes = dynamic(() => import("@components/booking/AvailableTimes"));
+
+const getRefetchInterval = (refetchCount: number): number => {
+ const intervals = [3000, 3000, 5000, 10000, 20000, 30000] as const;
+ return intervals[refetchCount] || intervals[intervals.length - 1];
+};
+
+const useSlots = ({
+ eventTypeId,
+ eventTypeSlug,
+ startTime,
+ endTime,
+ usernameList,
+ timeZone,
+ duration,
+ enabled = true,
+}: {
+ eventTypeId: number;
+ eventTypeSlug: string;
+ startTime?: Dayjs;
+ endTime?: Dayjs;
+ usernameList: string[];
+ timeZone?: string;
+ duration?: string;
+ enabled?: boolean;
+}) => {
+ const [refetchCount, setRefetchCount] = useState(0);
+ const refetchInterval = getRefetchInterval(refetchCount);
+ const { data, isLoading, isPaused, fetchStatus } = trpc.viewer.public.slots.getSchedule.useQuery(
+ {
+ eventTypeId,
+ eventTypeSlug,
+ usernameList,
+ startTime: startTime?.toISOString() || "",
+ endTime: endTime?.toISOString() || "",
+ timeZone,
+ duration,
+ },
+ {
+ enabled: !!startTime && !!endTime && enabled,
+ refetchInterval,
+ trpc: { context: { skipBatch: true } },
+ }
+ );
+ useEffect(() => {
+ if (!!data && fetchStatus === "idle") {
+ setRefetchCount(refetchCount + 1);
+ }
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ }, [fetchStatus, data]);
+
+ // The very first time isPaused is set if auto-fetch is disabled, so isPaused should also be considered a loading state.
+ return { slots: data?.slots || {}, isLoading: isLoading || isPaused };
+};
+
+export const SlotPicker = ({
+ eventType,
+ timeFormat,
+ onTimeFormatChange,
+ timeZone,
+ recurringEventCount,
+ users,
+ seatsPerTimeSlot,
+ weekStart = 0,
+ ethSignature,
+}: {
+ eventType: Pick<
+ EventType & { metadata: z.infer },
+ "id" | "schedulingType" | "slug" | "length" | "metadata"
+ >;
+ timeFormat: TimeFormat;
+ onTimeFormatChange: (is24Hour: boolean) => void;
+ timeZone?: string;
+ seatsPerTimeSlot?: number;
+ recurringEventCount?: number;
+ users: string[];
+ weekStart?: 0 | 1 | 2 | 3 | 4 | 5 | 6;
+ ethSignature?: string;
+}) => {
+ const [selectedDate, setSelectedDate] = useState();
+ const [browsingDate, setBrowsingDate] = useState();
+ let { duration = eventType.length.toString() } = useRouterQuery("duration");
+ const { date, setQuery: setDate } = useRouterQuery("date");
+ const { month, setQuery: setMonth } = useRouterQuery("month");
+ const router = useRouter();
+
+ if (!eventType.metadata?.multipleDuration) {
+ duration = eventType.length.toString();
+ }
+
+ useEffect(() => {
+ if (!router.isReady) return;
+
+ // Etc/GMT is not actually a timeZone, so handle this select option explicitly to prevent a hard crash.
+ if (timeZone === "Etc/GMT") {
+ setBrowsingDate(dayjs.utc(month).set("date", 1).set("hour", 0).set("minute", 0).set("second", 0));
+ if (date) {
+ setSelectedDate(dayjs.utc(date));
+ }
+ } else {
+ // Set the start of the month without shifting time like startOf() may do.
+ setBrowsingDate(
+ dayjs.tz(month, timeZone).set("date", 1).set("hour", 0).set("minute", 0).set("second", 0)
+ );
+ if (date) {
+ // It's important to set the date immediately to the timeZone, dayjs(date) will convert to browsertime.
+ setSelectedDate(dayjs.tz(date, timeZone));
+ }
+ }
+ }, [router.isReady, month, date, duration, timeZone]);
+
+ const { i18n, isLocaleReady } = useLocale();
+ const { slots: monthSlots, isLoading } = useSlots({
+ eventTypeId: eventType.id,
+ eventTypeSlug: eventType.slug,
+ usernameList: users,
+ startTime:
+ browsingDate === undefined || browsingDate.get("month") === dayjs.tz(undefined, timeZone).get("month")
+ ? dayjs.tz(undefined, timeZone).subtract(2, "days").startOf("day")
+ : browsingDate?.startOf("month"),
+ endTime: browsingDate?.endOf("month"),
+ timeZone,
+ duration,
+ });
+ const { slots: selectedDateSlots, isLoading: _isLoadingSelectedDateSlots } = useSlots({
+ eventTypeId: eventType.id,
+ eventTypeSlug: eventType.slug,
+ usernameList: users,
+ startTime: selectedDate?.startOf("day"),
+ endTime: selectedDate?.endOf("day"),
+ timeZone,
+ duration,
+ /** Prevent refetching is we already have this data from month slots */
+ enabled: !!selectedDate,
+ });
+
+ /** Hide skeleton if we have the slot loaded in the month query */
+ const isLoadingSelectedDateSlots = (() => {
+ if (!selectedDate) return _isLoadingSelectedDateSlots;
+ if (!!selectedDateSlots[selectedDate.format("YYYY-MM-DD")]) return false;
+ if (!!monthSlots[selectedDate.format("YYYY-MM-DD")]) return false;
+ return false;
+ })();
+
+ return (
+ <>
+ monthSlots[k].length > 0)}
+ locale={isLocaleReady ? i18n.language : "en"}
+ selected={selectedDate}
+ onChange={(newDate) => {
+ setDate(newDate.format("YYYY-MM-DD"));
+ }}
+ onMonthChange={(newMonth) => {
+ setMonth(newMonth.format("YYYY-MM"));
+ }}
+ browsingDate={browsingDate}
+ weekStart={weekStart}
+ />
+
+ >
+ );
+};
diff --git a/apps/web/components/booking/TimezoneDropdown.tsx b/apps/web/components/booking/TimezoneDropdown.tsx
new file mode 100644
index 00000000000000..195a9acec7f835
--- /dev/null
+++ b/apps/web/components/booking/TimezoneDropdown.tsx
@@ -0,0 +1,26 @@
+import { FiGlobe } from "@calcom/ui/components/icon";
+
+import { timeZone as localStorageTimeZone } from "@lib/clock";
+
+import TimeOptions from "@components/booking/TimeOptions";
+
+export function TimezoneDropdown({
+ onChangeTimeZone,
+}: {
+ onChangeTimeZone: (newTimeZone: string) => void;
+ timeZone?: string;
+}) {
+ const handleSelectTimeZone = (newTimeZone: string) => {
+ onChangeTimeZone(newTimeZone);
+ localStorageTimeZone(newTimeZone);
+ };
+
+ return (
+ <>
+
+
+
+
+ >
+ );
+}
diff --git a/apps/web/components/booking/pages/AvailabilityPage.tsx b/apps/web/components/booking/pages/AvailabilityPage.tsx
index 5a76522b8e71e3..7ba03a4e717461 100644
--- a/apps/web/components/booking/pages/AvailabilityPage.tsx
+++ b/apps/web/components/booking/pages/AvailabilityPage.tsx
@@ -1,15 +1,11 @@
-import { useAutoAnimate } from "@formkit/auto-animate/react";
-import type { EventType } from "@prisma/client";
import dynamic from "next/dynamic";
import { useRouter } from "next/router";
import { useEffect, useMemo, useReducer, useState } from "react";
-import { Toaster } from "react-hot-toast";
import { FormattedNumber, IntlProvider } from "react-intl";
import { z } from "zod";
import BookingPageTagManager from "@calcom/app-store/BookingPageTagManager";
import { getEventTypeAppData } from "@calcom/app-store/utils";
-import type { Dayjs } from "@calcom/dayjs";
import dayjs from "@calcom/dayjs";
import {
useEmbedNonStylesConfig,
@@ -18,7 +14,6 @@ import {
useIsBackgroundTransparent,
useIsEmbed,
} from "@calcom/embed-core/embed-iframe";
-import DatePicker from "@calcom/features/calendars/DatePicker";
import CustomBranding from "@calcom/lib/CustomBranding";
import classNames from "@calcom/lib/classNames";
import getPaymentAppData from "@calcom/lib/getPaymentAppData";
@@ -28,222 +23,30 @@ import notEmpty from "@calcom/lib/notEmpty";
import { getRecurringFreq } from "@calcom/lib/recurringStrings";
import { collectPageParameters, telemetryEventTypes, useTelemetry } from "@calcom/lib/telemetry";
import { detectBrowserTimeFormat, setIs24hClockInLocalStorage, TimeFormat } from "@calcom/lib/timeFormat";
-import type { EventTypeMetaDataSchema } from "@calcom/prisma/zod-utils";
-import { trpc } from "@calcom/trpc/react";
import { HeadSeo } from "@calcom/ui";
-import { FiCreditCard, FiGlobe, FiRefreshCcw } from "@calcom/ui/components/icon";
+import { FiCreditCard, FiRefreshCcw } from "@calcom/ui/components/icon";
import { timeZone as localStorageTimeZone } from "@lib/clock";
-import useRouterQuery from "@lib/hooks/useRouterQuery";
import type { Gate, GateState } from "@components/Gates";
import Gates from "@components/Gates";
import BookingDescription from "@components/booking/BookingDescription";
-import TimeOptions from "@components/booking/TimeOptions";
+import { SlotPicker } from "@components/booking/SlotPicker";
import type { AvailabilityPageProps } from "../../../pages/[user]/[type]";
import type { DynamicAvailabilityPageProps } from "../../../pages/d/[link]/[slug]";
import type { AvailabilityTeamPageProps } from "../../../pages/team/[slug]/[type]";
const PoweredByCal = dynamic(() => import("@components/ui/PoweredByCal"));
-const AvailableTimes = dynamic(() => import("@components/booking/AvailableTimes"));
-const useSlots = ({
- eventTypeId,
- eventTypeSlug,
- startTime,
- endTime,
- usernameList,
- timeZone,
- duration,
- enabled = true,
-}: {
- eventTypeId: number;
- eventTypeSlug: string;
- startTime?: Dayjs;
- endTime?: Dayjs;
- usernameList: string[];
- timeZone?: string;
- duration?: string;
- enabled?: boolean;
-}) => {
- const { data, isLoading, isPaused } = trpc.viewer.public.slots.getSchedule.useQuery(
- {
- eventTypeId,
- eventTypeSlug,
- usernameList,
- startTime: startTime?.toISOString() || "",
- endTime: endTime?.toISOString() || "",
- timeZone,
- duration,
- },
- {
- enabled: !!startTime && !!endTime && enabled,
- refetchInterval: 3000,
- trpc: { context: { skipBatch: true } },
- }
- );
-
- // The very first time isPaused is set if auto-fetch is disabled, so isPaused should also be considered a loading state.
- return { slots: data?.slots || {}, isLoading: isLoading || isPaused };
-};
-
-const SlotPicker = ({
- eventType,
- timeFormat,
- onTimeFormatChange,
- timeZone,
- recurringEventCount,
- users,
- seatsPerTimeSlot,
- weekStart = 0,
- ethSignature,
-}: {
- eventType: Pick<
- EventType & { metadata: z.infer },
- "id" | "schedulingType" | "slug" | "length" | "metadata"
- >;
- timeFormat: TimeFormat;
- onTimeFormatChange: (is24Hour: boolean) => void;
- timeZone?: string;
- seatsPerTimeSlot?: number;
- recurringEventCount?: number;
- users: string[];
- weekStart?: 0 | 1 | 2 | 3 | 4 | 5 | 6;
- ethSignature?: string;
-}) => {
- const [selectedDate, setSelectedDate] = useState();
- const [browsingDate, setBrowsingDate] = useState();
- let { duration = eventType.length.toString() } = useRouterQuery("duration");
- const { date, setQuery: setDate } = useRouterQuery("date");
- const { month, setQuery: setMonth } = useRouterQuery("month");
- const router = useRouter();
-
- if (!eventType.metadata?.multipleDuration) {
- duration = eventType.length.toString();
- }
-
- const [slotPickerRef] = useAutoAnimate();
-
- useEffect(() => {
- if (!router.isReady) return;
-
- // Etc/GMT is not actually a timeZone, so handle this select option explicitly to prevent a hard crash.
- if (timeZone === "Etc/GMT") {
- setBrowsingDate(dayjs.utc(month).set("date", 1).set("hour", 0).set("minute", 0).set("second", 0));
- if (date) {
- setSelectedDate(dayjs.utc(date));
- }
- } else {
- // Set the start of the month without shifting time like startOf() may do.
- setBrowsingDate(
- dayjs.tz(month, timeZone).set("date", 1).set("hour", 0).set("minute", 0).set("second", 0)
- );
- if (date) {
- // It's important to set the date immediately to the timeZone, dayjs(date) will convert to browsertime.
- setSelectedDate(dayjs.tz(date, timeZone));
- }
- }
- }, [router.isReady, month, date, duration, timeZone]);
-
- const { i18n, isLocaleReady } = useLocale();
- const { slots: monthSlots, isLoading } = useSlots({
- eventTypeId: eventType.id,
- eventTypeSlug: eventType.slug,
- usernameList: users,
- startTime:
- browsingDate === undefined || browsingDate.get("month") === dayjs.tz(undefined, timeZone).get("month")
- ? dayjs.tz(undefined, timeZone).subtract(2, "days").startOf("day")
- : browsingDate?.startOf("month"),
- endTime: browsingDate?.endOf("month"),
- timeZone,
- duration,
- });
- const { slots: selectedDateSlots, isLoading: _isLoadingSelectedDateSlots } = useSlots({
- eventTypeId: eventType.id,
- eventTypeSlug: eventType.slug,
- usernameList: users,
- startTime: selectedDate?.startOf("day"),
- endTime: selectedDate?.endOf("day"),
- timeZone,
- duration,
- /** Prevent refetching is we already have this data from month slots */
- enabled: !!selectedDate,
- });
-
- /** Hide skeleton if we have the slot loaded in the month query */
- const isLoadingSelectedDateSlots = (() => {
- if (!selectedDate) return _isLoadingSelectedDateSlots;
- if (!!selectedDateSlots[selectedDate.format("YYYY-MM-DD")]) return false;
- if (!!monthSlots[selectedDate.format("YYYY-MM-DD")]) return false;
- return false;
- })();
-
- return (
- <>
- monthSlots[k].length > 0)}
- locale={isLocaleReady ? i18n.language : "en"}
- selected={selectedDate}
- onChange={(newDate) => {
- setDate(newDate.format("YYYY-MM-DD"));
- }}
- onMonthChange={(newMonth) => {
- setMonth(newMonth.format("YYYY-MM"));
- }}
- browsingDate={browsingDate}
- weekStart={weekStart}
- />
-
-
- {selectedDate ? (
-
- ) : null}
-
- >
- );
-};
-
-function TimezoneDropdown({
- onChangeTimeZone,
-}: {
- onChangeTimeZone: (newTimeZone: string) => void;
- timeZone?: string;
-}) {
- const handleSelectTimeZone = (newTimeZone: string) => {
- onChangeTimeZone(newTimeZone);
- localStorageTimeZone(newTimeZone);
- };
-
- return (
- <>
-
-
-
-
- >
- );
-}
+const Toaster = dynamic(() => import("react-hot-toast").then((mod) => mod.Toaster), { ssr: false });
+/*const SlotPicker = dynamic(() => import("../SlotPicker").then((mod) => mod.SlotPicker), {
+ ssr: false,
+ loading: () =>
,
+});*/
+const TimezoneDropdown = dynamic(() => import("../TimezoneDropdown").then((mod) => mod.TimezoneDropdown), {
+ ssr: false,
+});
const dateQuerySchema = z.object({
rescheduleUid: z.string().optional().default(""),
diff --git a/apps/web/components/ui/colorpicker.tsx b/apps/web/components/ui/colorpicker.tsx
deleted file mode 100644
index 214ed6a6f88ca1..00000000000000
--- a/apps/web/components/ui/colorpicker.tsx
+++ /dev/null
@@ -1,102 +0,0 @@
-import { useCallback, useRef, useState } from "react";
-import { useEffect } from "react";
-import { HexColorInput, HexColorPicker } from "react-colorful";
-
-import { isValidHexCode, fallBackHex } from "@calcom/lib/CustomBranding";
-import { Swatch } from "@calcom/ui";
-
-type Handler = (event: MouseEvent | Event) => void;
-function useEventListener<
- KW extends keyof WindowEventMap,
- KH extends keyof HTMLElementEventMap,
- T extends HTMLElement | void = void
->(
- eventName: KW | KH,
- handler: (event: WindowEventMap[KW] | HTMLElementEventMap[KH] | Event) => void,
- element?: React.RefObject
-) {
- // Create a ref that stores handler
- const savedHandler = useRef();
- useEffect(() => {
- // Define the listening target
- const targetElement: T | Window = element?.current || window;
- if (!(targetElement && targetElement.addEventListener)) {
- return;
- }
- // Update saved handler if necessary
- if (savedHandler.current !== handler) {
- savedHandler.current = handler;
- }
- // Create event listener that calls handler function stored in ref
- const eventListener: typeof handler = (event) => {
- // eslint-disable-next-line no-extra-boolean-cast
- if (!!savedHandler?.current) {
- savedHandler.current(event);
- }
- };
- targetElement.addEventListener(eventName, eventListener);
- // Remove event listener on cleanup
- return () => {
- targetElement.removeEventListener(eventName, eventListener);
- };
- }, [eventName, element, handler]);
-}
-
-function useOnClickOutside(
- ref: React.RefObject,
- handler: Handler,
- mouseEvent: "mousedown" | "mouseup" = "mousedown"
-): void {
- useEventListener(mouseEvent, (event) => {
- const el = ref?.current;
- // Do nothing if clicking ref's element or descendent elements
- if (!el || el.contains(event.target as Node)) {
- return;
- }
- handler(event);
- });
-}
-export type ColorPickerProps = {
- defaultValue: string;
- onChange: (text: string) => void;
-};
-
-const ColorPicker = (props: ColorPickerProps) => {
- const init = !isValidHexCode(props.defaultValue)
- ? fallBackHex(props.defaultValue, false)
- : props.defaultValue;
- const [color, setColor] = useState(init);
- const [isOpen, toggle] = useState(false);
- const popover = useRef() as React.MutableRefObject;
- const close = useCallback(() => toggle(false), []);
- useOnClickOutside(popover, close);
- return (
-
-
toggle(!isOpen)} />
-
- {isOpen && (
-
- {
- setColor(val);
- props.onChange(val);
- }}
- />
-
- )}
- {
- setColor(val);
- props.onChange(val);
- }}
- type="text"
- />
-
- );
-};
-
-export default ColorPicker;
diff --git a/apps/web/fonts/CalSans-SemiBold.woff2 b/apps/web/fonts/CalSans-SemiBold.woff2
new file mode 100644
index 00000000000000..36d71b70d0c15e
Binary files /dev/null and b/apps/web/fonts/CalSans-SemiBold.woff2 differ
diff --git a/apps/web/package.json b/apps/web/package.json
index a85770f5089d46..ee9298b83204ad 100644
--- a/apps/web/package.json
+++ b/apps/web/package.json
@@ -44,7 +44,8 @@
"@hookform/error-message": "^2.0.0",
"@hookform/resolvers": "^2.9.7",
"@next-auth/prisma-adapter": "^1.0.4",
- "@next/bundle-analyzer": "^12.2.5",
+ "@next/bundle-analyzer": "^13.1.6",
+ "@next/font": "^13.1.1",
"@radix-ui/react-avatar": "^1.0.0",
"@radix-ui/react-collapsible": "^1.0.0",
"@radix-ui/react-dialog": "^1.0.0",
@@ -80,6 +81,7 @@
"lodash": "^4.17.21",
"lottie-react": "^2.3.1",
"markdown-it": "^13.0.1",
+ "md5": "^2.3.0",
"memory-cache": "^0.2.0",
"micro": "^10.0.1",
"mime-types": "^2.1.35",
@@ -139,6 +141,7 @@
"@types/glidejs__glide": "^3.4.2",
"@types/lodash": "^4.14.182",
"@types/markdown-it": "^12.2.3",
+ "@types/md5": "^2.3.2",
"@types/memory-cache": "^0.2.2",
"@types/micro": "7.3.7",
"@types/mime-types": "^2.1.1",
diff --git a/apps/web/pages/[user]/[type].tsx b/apps/web/pages/[user]/[type].tsx
index 11c4da78a447f8..42bd29f017d50b 100644
--- a/apps/web/pages/[user]/[type].tsx
+++ b/apps/web/pages/[user]/[type].tsx
@@ -1,21 +1,10 @@
-import MarkdownIt from "markdown-it";
import type { GetStaticPaths, GetStaticPropsContext } from "next";
import { z } from "zod";
import type { LocationObject } from "@calcom/app-store/locations";
-import { privacyFilteredLocations } from "@calcom/app-store/locations";
-import { getAppFromSlug } from "@calcom/app-store/utils";
import { IS_TEAM_BILLING_ENABLED, WEBAPP_URL } from "@calcom/lib/constants";
-import { getDefaultEvent, getGroupName, getUsernameList } from "@calcom/lib/defaultEvents";
import { useLocale } from "@calcom/lib/hooks/useLocale";
-import { parseRecurringEvent } from "@calcom/lib/isRecurringEvent";
-import prisma from "@calcom/prisma";
import type { User } from "@calcom/prisma/client";
-import {
- EventTypeMetaDataSchema,
- teamMetadataSchema,
- userMetadata as userMetadataSchema,
-} from "@calcom/prisma/zod-utils";
import { isBrandingHidden } from "@lib/isBrandingHidden";
import type { inferSSRProps } from "@lib/types/inferSSRProps";
@@ -65,10 +54,19 @@ export default function Type(props: AvailabilityPageProps) {
Type.isThemeSupported = true;
+const paramsSchema = z.object({ type: z.string(), user: z.string() });
async function getUserPageProps(context: GetStaticPropsContext) {
- const { type: slug, user: username } = paramsSchema.parse(context.params);
+ // load server side dependencies
+ const MarkdownIt = await import("markdown-it").then((mod) => mod.default);
+ const prisma = await import("@calcom/prisma").then((mod) => mod.default);
+ const { privacyFilteredLocations } = await import("@calcom/app-store/locations");
+ const { parseRecurringEvent } = await import("@calcom/lib/isRecurringEvent");
+ const { EventTypeMetaDataSchema, teamMetadataSchema } = await import("@calcom/prisma/zod-utils");
const { ssgInit } = await import("@server/lib/ssg");
+
+ const { type: slug, user: username } = paramsSchema.parse(context.params);
const ssg = await ssgInit(context);
+
const user = await prisma.user.findUnique({
where: {
username,
@@ -191,7 +189,17 @@ async function getUserPageProps(context: GetStaticPropsContext) {
}
async function getDynamicGroupPageProps(context: GetStaticPropsContext) {
+ // load server side dependencies
+ const { getDefaultEvent, getGroupName, getUsernameList } = await import("@calcom/lib/defaultEvents");
+ const { privacyFilteredLocations } = await import("@calcom/app-store/locations");
+ const { parseRecurringEvent } = await import("@calcom/lib/isRecurringEvent");
+ const prisma = await import("@calcom/prisma").then((mod) => mod.default);
+ const { EventTypeMetaDataSchema, userMetadata: userMetadataSchema } = await import(
+ "@calcom/prisma/zod-utils"
+ );
const { ssgInit } = await import("@server/lib/ssg");
+ const { getAppFromSlug } = await import("@calcom/app-store/utils");
+
const ssg = await ssgInit(context);
const { type: typeParam, user: userParam } = paramsSchema.parse(context.params);
const usernameList = getUsernameList(userParam);
@@ -310,8 +318,6 @@ async function getDynamicGroupPageProps(context: GetStaticPropsContext) {
};
}
-const paramsSchema = z.object({ type: z.string(), user: z.string() });
-
export const getStaticProps = async (context: GetStaticPropsContext) => {
const { user: userParam } = paramsSchema.parse(context.params);
// dynamic groups are not generated at build time, but otherwise are probably cached until infinity.
diff --git a/apps/web/pages/_app.tsx b/apps/web/pages/_app.tsx
index a086947b011339..5528fdd1452e49 100644
--- a/apps/web/pages/_app.tsx
+++ b/apps/web/pages/_app.tsx
@@ -1,3 +1,5 @@
+import { Inter } from "@next/font/google";
+import localFont from "@next/font/local";
import { DefaultSeo } from "next-seo";
import Head from "next/head";
import Script from "next/script";
@@ -14,6 +16,14 @@ import I18nLanguageHandler from "@components/I18nLanguageHandler";
import "../styles/globals.css";
+const interFont = Inter({ subsets: ["latin"], variable: "--font-inter", preload: true, display: "swap" });
+const calFont = localFont({
+ src: "../fonts/CalSans-SemiBold.woff2",
+ variable: "--font-cal",
+ preload: true,
+ display: "swap",
+});
+
function MyApp(props: AppProps) {
const { Component, pageProps, err, router } = props;
let pageStatus = "200";
@@ -46,6 +56,12 @@ function MyApp(props: AppProps) {
id="page-status"
dangerouslySetInnerHTML={{ __html: `window.CalComPageStatus = '${pageStatus}'` }}
/>
+
diff --git a/apps/web/pages/_document.tsx b/apps/web/pages/_document.tsx
index eddbff9943a3bd..cd0201dc549f1a 100644
--- a/apps/web/pages/_document.tsx
+++ b/apps/web/pages/_document.tsx
@@ -39,14 +39,6 @@ class MyDocument extends Document {
-
-
diff --git a/apps/web/pages/api/auth/[...nextauth].tsx b/apps/web/pages/api/auth/[...nextauth].tsx
index 4030bdbd6d1d02..961c2e2ae1e052 100644
--- a/apps/web/pages/api/auth/[...nextauth].tsx
+++ b/apps/web/pages/api/auth/[...nextauth].tsx
@@ -507,6 +507,10 @@ export default NextAuth({
existingUserWithEmail.identityProvider === IdentityProvider.CAL &&
(idP === IdentityProvider.GOOGLE || idP === IdentityProvider.SAML)
) {
+ await prisma.user.update({
+ where: { email: existingUserWithEmail.email },
+ data: { password: null },
+ });
return true;
} else if (existingUserWithEmail.identityProvider === IdentityProvider.CAL) {
return "/auth/error?error=use-password-login";
diff --git a/apps/web/pages/event-types/index.tsx b/apps/web/pages/event-types/index.tsx
index 430a5975f5b2f5..eb9e00da312ac1 100644
--- a/apps/web/pages/event-types/index.tsx
+++ b/apps/web/pages/event-types/index.tsx
@@ -128,11 +128,17 @@ const Item = ({ type, group, readOnly }: { type: EventType; group: EventTypeGrou
data-testid={"event-type-title-" + type.id}>
{type.title}
- {`/${group.profile.slug}/${type.slug}`}
+ {group.profile.slug ? (
+
+ {`/${group.profile.slug}/${type.slug}`}
+
+ ) : (
+ <>>
+ )}
{readOnly && (
-
+
{t("readonly")}
)}
@@ -557,6 +563,18 @@ const EventTypeListHeading = ({
membershipCount,
teamId,
}: EventTypeListHeadingProps): JSX.Element => {
+ const { t } = useLocale();
+ const router = useRouter();
+
+ const publishTeamMutation = trpc.viewer.teams.publish.useMutation({
+ onSuccess(data) {
+ router.push(data.url);
+ },
+ onError: (error) => {
+ showToast(error.message, "error");
+ },
+ });
+
return (
+ {!profile?.slug && !!teamId && (
+ publishTeamMutation.mutate({ teamId })}>
+
+ {t("upgrade")}
+
+
+ )}
);
};
diff --git a/apps/web/styles/globals.css b/apps/web/styles/globals.css
index f538905811089f..8ecebefc0637b8 100644
--- a/apps/web/styles/globals.css
+++ b/apps/web/styles/globals.css
@@ -2,7 +2,7 @@
@tailwind components;
@tailwind utilities;
-@import "../../../packages/ui/styles/shared-globals.css";
+
body {
text-rendering: optimizeLegibility;
diff --git a/packages/app-store/BookingPageTagManager.tsx b/packages/app-store/BookingPageTagManager.tsx
index 72abf76c595618..8d7b744b387dab 100644
--- a/packages/app-store/BookingPageTagManager.tsx
+++ b/packages/app-store/BookingPageTagManager.tsx
@@ -1,7 +1,7 @@
import Script from "next/script";
+import { getEventTypeAppData } from "@calcom/app-store/_utils/getEventTypeAppData";
import { appStoreMetadata } from "@calcom/app-store/appStoreMetaData";
-import { getEventTypeAppData } from "@calcom/app-store/utils";
import type { appDataSchemas } from "./apps.schemas.generated";
diff --git a/packages/app-store/_utils/getEventTypeAppData.ts b/packages/app-store/_utils/getEventTypeAppData.ts
new file mode 100644
index 00000000000000..0b1d757b9a0986
--- /dev/null
+++ b/packages/app-store/_utils/getEventTypeAppData.ts
@@ -0,0 +1,47 @@
+import type { z } from "zod";
+
+import type { EventTypeModel } from "@calcom/prisma/zod";
+import type { EventTypeMetaDataSchema } from "@calcom/prisma/zod-utils";
+
+export type EventTypeApps = NonNullable
>["apps"]>;
+export type EventTypeAppsList = keyof EventTypeApps;
+
+export const getEventTypeAppData = (
+ eventType: Pick, "price" | "currency" | "metadata">,
+ appId: T,
+ forcedGet?: boolean
+): EventTypeApps[T] => {
+ const metadata = eventType.metadata;
+ const appMetadata = metadata?.apps && metadata.apps[appId];
+ if (appMetadata) {
+ const allowDataGet = forcedGet ? true : appMetadata.enabled;
+ return allowDataGet ? appMetadata : null;
+ }
+
+ // Backward compatibility for existing event types.
+ // TODO: After the new AppStore EventType App flow is stable, write a migration to migrate metadata to new format which will let us remove this compatibility code
+ // Migration isn't being done right now, to allow a revert if needed
+ const legacyAppsData = {
+ stripe: {
+ enabled: eventType.price > 0,
+ // Price default is 0 in DB. So, it would always be non nullish.
+ price: eventType.price,
+ // Currency default is "usd" in DB.So, it would also be available always
+ currency: eventType.currency,
+ },
+ rainbow: {
+ enabled: !!(eventType.metadata?.smartContractAddress && eventType.metadata?.blockchainId),
+ smartContractAddress: eventType.metadata?.smartContractAddress || "",
+ blockchainId: eventType.metadata?.blockchainId || 0,
+ },
+ giphy: {
+ enabled: !!eventType.metadata?.giphyThankYouPage,
+ thankYouPage: eventType.metadata?.giphyThankYouPage || "",
+ },
+ } as const;
+
+ // TODO: This assertion helps typescript hint that only one of the app's data can be returned
+ const legacyAppData = legacyAppsData[appId as Extract];
+ const allowDataGet = forcedGet ? true : legacyAppData?.enabled;
+ return allowDataGet ? legacyAppData : null;
+};
diff --git a/packages/app-store/apps.metadata.generated.ts b/packages/app-store/apps.metadata.generated.ts
index 5bf5cf5637fa42..3733ff0d8d38bd 100644
--- a/packages/app-store/apps.metadata.generated.ts
+++ b/packages/app-store/apps.metadata.generated.ts
@@ -13,6 +13,7 @@ import routing_forms_config_json from "./ee/routing-forms/config.json";
import { metadata as exchange2013calendar__metadata_ts } from "./exchange2013calendar/_metadata";
import { metadata as exchange2016calendar__metadata_ts } from "./exchange2016calendar/_metadata";
import exchangecalendar_config_json from "./exchangecalendar/config.json";
+import facetime_config_json from "./facetime/config.json";
import fathom_config_json from "./fathom/config.json";
import ga4_config_json from "./ga4/config.json";
import { metadata as giphy__metadata_ts } from "./giphy/_metadata";
@@ -68,6 +69,7 @@ export const appStoreMetadata = {
exchange2013calendar: exchange2013calendar__metadata_ts,
exchange2016calendar: exchange2016calendar__metadata_ts,
exchangecalendar: exchangecalendar_config_json,
+ facetime: facetime_config_json,
fathom: fathom_config_json,
ga4: ga4_config_json,
giphy: giphy__metadata_ts,
diff --git a/packages/app-store/apps.server.generated.ts b/packages/app-store/apps.server.generated.ts
index 66ed6541b83bc4..9ea61df5633898 100644
--- a/packages/app-store/apps.server.generated.ts
+++ b/packages/app-store/apps.server.generated.ts
@@ -13,6 +13,7 @@ export const apiHandlers = {
exchange2013calendar: import("./exchange2013calendar/api"),
exchange2016calendar: import("./exchange2016calendar/api"),
exchangecalendar: import("./exchangecalendar/api"),
+ facetime: import("./facetime/api"),
fathom: import("./fathom/api"),
ga4: import("./ga4/api"),
giphy: import("./giphy/api"),
diff --git a/packages/app-store/facetime/DESCRIPTION.md b/packages/app-store/facetime/DESCRIPTION.md
new file mode 100644
index 00000000000000..6dbf65a2d2a379
--- /dev/null
+++ b/packages/app-store/facetime/DESCRIPTION.md
@@ -0,0 +1,7 @@
+---
+items:
+ - /api/app-store/facetime/facetime1.png
+ - /api/app-store/facetime/facetime2.png
+---
+
+With FaceTime, it’s easy to stay in touch. You can make audio and video calls with up to 32 people, share your screen, enjoy films and music together, and more.
diff --git a/packages/app-store/facetime/api/add.ts b/packages/app-store/facetime/api/add.ts
new file mode 100644
index 00000000000000..44d56bb0fa6d87
--- /dev/null
+++ b/packages/app-store/facetime/api/add.ts
@@ -0,0 +1,16 @@
+import type { AppDeclarativeHandler } from "@calcom/types/AppHandler";
+
+import { createDefaultInstallation } from "../../_utils/installation";
+import appConfig from "../config.json";
+
+const handler: AppDeclarativeHandler = {
+ appType: appConfig.type,
+ variant: appConfig.variant,
+ slug: appConfig.slug,
+ supportsMultipleInstalls: false,
+ handlerType: "add",
+ createCredential: ({ appType, user, slug }) =>
+ createDefaultInstallation({ appType, userId: user.id, slug, key: {} }),
+};
+
+export default handler;
diff --git a/packages/app-store/facetime/api/index.ts b/packages/app-store/facetime/api/index.ts
new file mode 100644
index 00000000000000..4c0d2ead01e1f9
--- /dev/null
+++ b/packages/app-store/facetime/api/index.ts
@@ -0,0 +1 @@
+export { default as add } from "./add";
diff --git a/packages/app-store/facetime/config.json b/packages/app-store/facetime/config.json
new file mode 100644
index 00000000000000..d652a2451995c5
--- /dev/null
+++ b/packages/app-store/facetime/config.json
@@ -0,0 +1,26 @@
+{
+ "/*": "Don't modify slug - If required, do it using cli edit command",
+ "name": "Facetime",
+ "title": "Facetime",
+ "slug": "facetime",
+ "type": "facetime_video",
+ "imageSrc": "/api/app-store/facetime/icon.svg",
+ "logo": "/api/app-store/facetime/icon.svg",
+ "url": "https://cal.com/apps/facetime",
+ "variant": "conferencing",
+ "categories": ["video"],
+ "publisher": "Mythie",
+ "email": "help@cal.com",
+ "description": "Facetime makes it super simple for collaborating teams to jump on a video call.",
+ "__createdUsingCli": true,
+ "appData": {
+ "location": {
+ "linkType": "static",
+ "type": "integrations:facetime_video",
+ "label": "Facetime",
+ "organizerInputPlaceholder": "https://facetime.apple.com/join... link copied from the FaceTime app",
+ "urlRegExp": "^https?:\\/\\/facetime\\.apple\\.com\\/join.+$"
+ }
+ },
+ "isTemplate": false
+}
diff --git a/packages/app-store/facetime/index.ts b/packages/app-store/facetime/index.ts
new file mode 100644
index 00000000000000..d7f36022040096
--- /dev/null
+++ b/packages/app-store/facetime/index.ts
@@ -0,0 +1 @@
+export * as api from "./api";
diff --git a/packages/app-store/facetime/package.json b/packages/app-store/facetime/package.json
new file mode 100644
index 00000000000000..7157e96e021da4
--- /dev/null
+++ b/packages/app-store/facetime/package.json
@@ -0,0 +1,14 @@
+{
+ "$schema": "https://json.schemastore.org/package.json",
+ "private": true,
+ "name": "@calcom/facetime",
+ "version": "0.0.0",
+ "main": "./index.ts",
+ "description": "Facetime makes it super simple for collaborating teams to jump on a video call.",
+ "dependencies": {
+ "@calcom/lib": "*"
+ },
+ "devDependencies": {
+ "@calcom/types": "*"
+ }
+}
diff --git a/packages/app-store/facetime/static/facetime1.png b/packages/app-store/facetime/static/facetime1.png
new file mode 100644
index 00000000000000..53f91dd46ddba9
Binary files /dev/null and b/packages/app-store/facetime/static/facetime1.png differ
diff --git a/packages/app-store/facetime/static/facetime2.png b/packages/app-store/facetime/static/facetime2.png
new file mode 100644
index 00000000000000..84684665a4e940
Binary files /dev/null and b/packages/app-store/facetime/static/facetime2.png differ
diff --git a/packages/app-store/facetime/static/icon.svg b/packages/app-store/facetime/static/icon.svg
new file mode 100644
index 00000000000000..48de5172eb60ff
--- /dev/null
+++ b/packages/app-store/facetime/static/icon.svg
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
diff --git a/packages/app-store/facetime/static/logo.svg b/packages/app-store/facetime/static/logo.svg
new file mode 100644
index 00000000000000..48de5172eb60ff
--- /dev/null
+++ b/packages/app-store/facetime/static/logo.svg
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
diff --git a/packages/app-store/index.ts b/packages/app-store/index.ts
index 0d8277a07cc216..f639df57b9c713 100644
--- a/packages/app-store/index.ts
+++ b/packages/app-store/index.ts
@@ -6,6 +6,7 @@ import * as dailyvideo from "./dailyvideo";
import * as exchange2013calendar from "./exchange2013calendar";
import * as exchange2016calendar from "./exchange2016calendar";
import * as exchangecalendar from "./exchangecalendar";
+import * as facetime from "./facetime";
import * as giphy from "./giphy";
import * as googlecalendar from "./googlecalendar";
import * as googlevideo from "./googlevideo";
@@ -52,6 +53,7 @@ const appStore = {
exchange2013calendar,
exchange2016calendar,
exchangecalendar,
+ facetime,
};
export default appStore;
diff --git a/packages/app-store/utils.ts b/packages/app-store/utils.ts
index 4ef88f073e605c..e0d113eba3ed0e 100644
--- a/packages/app-store/utils.ts
+++ b/packages/app-store/utils.ts
@@ -1,16 +1,15 @@
import { Prisma } from "@prisma/client";
import type { TFunction } from "next-i18next";
-import type { z } from "zod";
// If you import this file on any app it should produce circular dependency
// import appStore from "./index";
import { appStoreMetadata } from "@calcom/app-store/appStoreMetaData";
import type { EventLocationType } from "@calcom/app-store/locations";
import { defaultLocations } from "@calcom/app-store/locations";
-import type { EventTypeModel } from "@calcom/prisma/zod";
-import type { EventTypeMetaDataSchema } from "@calcom/prisma/zod-utils";
import type { App, AppMeta } from "@calcom/types/App";
+export * from "./_utils/getEventTypeAppData";
+
type LocationOption = {
label: string;
value: EventLocationType["type"];
@@ -18,9 +17,6 @@ type LocationOption = {
disabled?: boolean;
};
-export type EventTypeApps = NonNullable>["apps"]>;
-export type EventTypeAppsList = keyof EventTypeApps;
-
const ALL_APPS_MAP = Object.keys(appStoreMetadata).reduce((store, key) => {
const metadata = appStoreMetadata[key as keyof typeof appStoreMetadata] as AppMeta;
if (metadata.logo && !metadata.logo.includes("/")) {
@@ -193,44 +189,4 @@ export function getAppFromSlug(slug: string | undefined): AppMeta | undefined {
return ALL_APPS.find((app) => app.slug === slug);
}
-export const getEventTypeAppData = (
- eventType: Pick, "price" | "currency" | "metadata">,
- appId: T,
- forcedGet?: boolean
-): EventTypeApps[T] => {
- const metadata = eventType.metadata;
- const appMetadata = metadata?.apps && metadata.apps[appId];
- if (appMetadata) {
- const allowDataGet = forcedGet ? true : appMetadata.enabled;
- return allowDataGet ? appMetadata : null;
- }
-
- // Backward compatibility for existing event types.
- // TODO: After the new AppStore EventType App flow is stable, write a migration to migrate metadata to new format which will let us remove this compatibility code
- // Migration isn't being done right now, to allow a revert if needed
- const legacyAppsData = {
- stripe: {
- enabled: eventType.price > 0,
- // Price default is 0 in DB. So, it would always be non nullish.
- price: eventType.price,
- // Currency default is "usd" in DB.So, it would also be available always
- currency: eventType.currency,
- },
- rainbow: {
- enabled: !!(eventType.metadata?.smartContractAddress && eventType.metadata?.blockchainId),
- smartContractAddress: eventType.metadata?.smartContractAddress || "",
- blockchainId: eventType.metadata?.blockchainId || 0,
- },
- giphy: {
- enabled: !!eventType.metadata?.giphyThankYouPage,
- thankYouPage: eventType.metadata?.giphyThankYouPage || "",
- },
- } as const;
-
- // TODO: This assertion helps typescript hint that only one of the app's data can be returned
- const legacyAppData = legacyAppsData[appId as Extract];
- const allowDataGet = forcedGet ? true : legacyAppData?.enabled;
- return allowDataGet ? legacyAppData : null;
-};
-
export default getApps;
diff --git a/packages/config/tailwind-preset.js b/packages/config/tailwind-preset.js
index 780e9a5796c2a9..15d9f2ef215f6a 100644
--- a/packages/config/tailwind-preset.js
+++ b/packages/config/tailwind-preset.js
@@ -1,4 +1,5 @@
const plugin = require("tailwindcss/plugin");
+const { fontFamily } = require("tailwindcss/defaultTheme");
/** @type {import('tailwindcss').Config} */
@@ -12,10 +13,6 @@ module.exports = {
],
darkMode: "class",
theme: {
- fontFamily: {
- cal: ['"Cal Sans"', "sans-serif"],
- sans: ['"Inter var"', "sans-serif"],
- },
extend: {
colors: {
/* your primary brand color */
@@ -162,9 +159,9 @@ module.exports = {
dropdown: "0px 2px 6px -1px rgba(0, 0, 0, 0.08)",
},
fontFamily: {
- cal: ['"Cal Sans"', "sans-serif"],
+ cal: ["var(--font-cal)", ...fontFamily.serif],
+ sans: ["var(--font-inter)", ...fontFamily.sans],
mono: ["Roboto Mono", "monospace"],
- sans: ['"Inter var"', "sans-serif"],
},
maxHeight: (theme) => ({
0: "0",
diff --git a/packages/core/EventManager.ts b/packages/core/EventManager.ts
index 51eae74e049161..97f95b201ba8c8 100644
--- a/packages/core/EventManager.ts
+++ b/packages/core/EventManager.ts
@@ -8,14 +8,8 @@ import { getEventLocationTypeFromApp } from "@calcom/app-store/locations";
import { MeetLocationType } from "@calcom/app-store/locations";
import getApps from "@calcom/app-store/utils";
import prisma from "@calcom/prisma";
-import { Attendee } from "@calcom/prisma/client";
import { createdEventSchema } from "@calcom/prisma/zod-utils";
-import type {
- AdditionalInformation,
- CalendarEvent,
- NewCalendarEventType,
- Person,
-} from "@calcom/types/Calendar";
+import type { AdditionalInformation, CalendarEvent, NewCalendarEventType } from "@calcom/types/Calendar";
import { CredentialPayload, CredentialWithAppName } from "@calcom/types/Credential";
import type { Event } from "@calcom/types/Event";
import type {
diff --git a/packages/core/getBusyTimes.ts b/packages/core/getBusyTimes.ts
index cd176aa6a3ebd3..fe609bf4c417eb 100644
--- a/packages/core/getBusyTimes.ts
+++ b/packages/core/getBusyTimes.ts
@@ -1,4 +1,4 @@
-import { BookingStatus, Credential, SelectedCalendar } from "@prisma/client";
+import { BookingStatus, Credential } from "@prisma/client";
import { getBusyCalendarTimes } from "@calcom/core/CalendarManager";
import dayjs from "@calcom/dayjs";
diff --git a/packages/emails/src/templates/ForgotPasswordEmail.tsx b/packages/emails/src/templates/ForgotPasswordEmail.tsx
index b94c32c1215c8c..e04c336dd1207f 100644
--- a/packages/emails/src/templates/ForgotPasswordEmail.tsx
+++ b/packages/emails/src/templates/ForgotPasswordEmail.tsx
@@ -1,6 +1,6 @@
import type { TFunction } from "next-i18next";
-import { APP_NAME } from "@calcom/lib/constants";
+import { APP_NAME, SUPPORT_MAIL_ADDRESS } from "@calcom/lib/constants";
import { BaseEmailHtml, CallToAction } from "../components";
@@ -34,7 +34,11 @@ export const ForgotPasswordEmail = (
<>
{props.language("have_any_questions")}{" "}
-
+
<>{props.language("contact_our_support_team")}>
>
diff --git a/packages/emails/src/templates/TeamInviteEmail.tsx b/packages/emails/src/templates/TeamInviteEmail.tsx
index 14a0cbc0ebc023..f6e0a5c92eafb4 100644
--- a/packages/emails/src/templates/TeamInviteEmail.tsx
+++ b/packages/emails/src/templates/TeamInviteEmail.tsx
@@ -1,5 +1,4 @@
import type { TFunction } from "next-i18next";
-import { ReactNode } from "react";
import { APP_NAME, WEBAPP_URL, IS_PRODUCTION } from "@calcom/lib/constants";
diff --git a/packages/features/ee/teams/api/upgrade.ts b/packages/features/ee/teams/api/upgrade.ts
index ec20b35199f942..eec6050f34b382 100644
--- a/packages/features/ee/teams/api/upgrade.ts
+++ b/packages/features/ee/teams/api/upgrade.ts
@@ -37,26 +37,27 @@ async function handler(req: NextApiRequest, res: NextApiResponse) {
if (!team) {
const prevTeam = await prisma.team.findFirstOrThrow({ where: { id } });
const metadata = teamMetadataSchema.parse(prevTeam.metadata);
+ /** We save the metadata first to prevent duplicate payments */
+ team = await prisma.team.update({
+ where: { id },
+ data: {
+ metadata: {
+ paymentId: checkoutSession.id,
+ subscriptionId: subscription.id || null,
+ subscriptionItemId: subscription.items.data[0].id || null,
+ },
+ },
+ });
/** Legacy teams already have a slug, this will allow them to upgrade as well */
const slug = prevTeam.slug || metadata?.requestedSlug;
- if (!slug) throw new HttpError({ statusCode: 400, message: "Missing team slug" });
- try {
- /** We save the metadata first to prevent duplicate payments */
- await prisma.team.update({
- where: { id },
- data: {
- metadata: {
- paymentId: checkoutSession.id,
- subscriptionId: subscription.id || null,
- subscriptionItemId: subscription.items.data[0].id || null,
- },
- },
- });
- /** Then we try to upgrade the slug, which may fail if a conflict came up since team creation */
- team = await prisma.team.update({ where: { id }, data: { slug } });
- } catch (error) {
- const { message, statusCode } = getRequestedSlugError(error, slug);
- return res.status(statusCode).json({ message });
+ if (slug) {
+ try {
+ /** Then we try to upgrade the slug, which may fail if a conflict came up since team creation */
+ team = await prisma.team.update({ where: { id }, data: { slug } });
+ } catch (error) {
+ const { message, statusCode } = getRequestedSlugError(error, slug);
+ return res.status(statusCode).json({ message });
+ }
}
// Sync Services: Close.com
diff --git a/packages/features/ee/teams/components/TeamList.tsx b/packages/features/ee/teams/components/TeamList.tsx
index cbf78f6f43ced8..02fab0dac2e842 100644
--- a/packages/features/ee/teams/components/TeamList.tsx
+++ b/packages/features/ee/teams/components/TeamList.tsx
@@ -3,7 +3,7 @@ import { useState } from "react";
import { useLocale } from "@calcom/lib/hooks/useLocale";
import { RouterOutputs, trpc } from "@calcom/trpc/react";
import { Card, showToast } from "@calcom/ui";
-import { FiUserPlus, FiUsers, FiUnlock, FiEdit } from "@calcom/ui/components/icon";
+import { FiUserPlus, FiUsers, FiEdit } from "@calcom/ui/components/icon";
import TeamListItem from "./TeamListItem";
diff --git a/packages/features/ee/workflows/lib/reminders/smsReminderManager.ts b/packages/features/ee/workflows/lib/reminders/smsReminderManager.ts
index b79dd391c61159..fad4d945bcd4de 100644
--- a/packages/features/ee/workflows/lib/reminders/smsReminderManager.ts
+++ b/packages/features/ee/workflows/lib/reminders/smsReminderManager.ts
@@ -10,7 +10,6 @@ import dayjs from "@calcom/dayjs";
import prisma from "@calcom/prisma";
import { Prisma } from "@calcom/prisma/client";
import { bookingMetadataSchema } from "@calcom/prisma/zod-utils";
-import { Person } from "@calcom/types/Calendar";
import { getSenderId } from "../alphanumericSenderIdSupport";
import * as twilio from "./smsProviders/twilioProvider";
diff --git a/packages/features/eventtypes/components/CreateEventTypeButton.tsx b/packages/features/eventtypes/components/CreateEventTypeButton.tsx
index 01aff2ebde540e..331afe9e0ca046 100644
--- a/packages/features/eventtypes/components/CreateEventTypeButton.tsx
+++ b/packages/features/eventtypes/components/CreateEventTypeButton.tsx
@@ -32,7 +32,7 @@ import {
TextAreaField,
TextField,
} from "@calcom/ui";
-import { FiPlus, FiChevronDown } from "@calcom/ui/components/icon";
+import { FiPlus } from "@calcom/ui/components/icon";
import { DuplicateDialog } from "./DuplicateDialog";
diff --git a/packages/features/schedules/components/ScheduleListItem.tsx b/packages/features/schedules/components/ScheduleListItem.tsx
index 610e747ae91dba..ccd8575c4598ef 100644
--- a/packages/features/schedules/components/ScheduleListItem.tsx
+++ b/packages/features/schedules/components/ScheduleListItem.tsx
@@ -51,6 +51,12 @@ export function ScheduleListItem({
)}
+ {(schedule.timeZone || displayOptions?.timeZone) && (
+
+
+ {schedule.timeZone ?? displayOptions?.timeZone}
+
+ )}
{schedule.availability
.filter((availability) => !!availability.days.length)
.map((availability) => (
@@ -62,12 +68,6 @@ export function ScheduleListItem({
))}
- {schedule.timeZone && schedule.timeZone !== displayOptions?.timeZone && (
-
-
- {schedule.timeZone}
-
- )}
diff --git a/packages/features/settings/layouts/SettingsLayout.tsx b/packages/features/settings/layouts/SettingsLayout.tsx
index 7655b66d90beae..2cb65d889283ae 100644
--- a/packages/features/settings/layouts/SettingsLayout.tsx
+++ b/packages/features/settings/layouts/SettingsLayout.tsx
@@ -32,7 +32,6 @@ import {
FiChevronRight,
FiPlus,
FiMenu,
- FiExternalLink,
} from "@calcom/ui/components/icon";
const tabs: VerticalTabItemProps[] = [
diff --git a/packages/features/tips/UpgradeTip.tsx b/packages/features/tips/UpgradeTip.tsx
index 028a9f484a0c24..55be04ed37f96c 100644
--- a/packages/features/tips/UpgradeTip.tsx
+++ b/packages/features/tips/UpgradeTip.tsx
@@ -1,9 +1,9 @@
import type { ReactNode } from "react";
import { classNames } from "@calcom/lib";
-import { useHasPaidPlan } from "@calcom/lib/hooks/useHasPaidPlan";
+import { IS_SELF_HOSTED } from "@calcom/lib/constants";
+import { useHasTeamPlan } from "@calcom/lib/hooks/useHasPaidPlan";
import { useLocale } from "@calcom/lib/hooks/useLocale";
-import isCalcom from "@calcom/lib/isCalcom";
import { EmptyScreen } from "@calcom/ui";
import { FiUsers } from "@calcom/ui/components/icon";
@@ -33,13 +33,13 @@ export function UpgradeTip({
isParentLoading?: ReactNode;
}) {
const { t } = useLocale();
- const { isLoading, hasPaidPlan } = useHasPaidPlan();
+ const { isLoading, hasTeamPlan } = useHasTeamPlan();
- if (hasPaidPlan) return children;
+ if (hasTeamPlan) return children;
if (isParentLoading || isLoading) return <>{isParentLoading}>;
- if (!isCalcom)
+ if (IS_SELF_HOSTED)
return (
& {
+ displayName?: string | Record;
+ })[];
return calendars.reduce((newCalendars, calendar) => {
if (!calendar.components?.includes("VEVENT")) return newCalendars;
newCalendars.push({
externalId: calendar.url,
- name: calendar.displayName ?? "",
+ /** @url https://github.com/calcom/cal.com/issues/7186 */
+ name: typeof calendar.displayName === "string" ? calendar.displayName : "",
primary: event?.destinationCalendar?.externalId
? event.destinationCalendar.externalId === calendar.url
: false,
diff --git a/packages/lib/defaultAvatarImage.ts b/packages/lib/defaultAvatarImage.ts
index 316c2d5b1e6025..6f9076ac22cc40 100644
--- a/packages/lib/defaultAvatarImage.ts
+++ b/packages/lib/defaultAvatarImage.ts
@@ -1,10 +1,10 @@
-import crypto from "crypto";
+import md5Parser from "md5";
export const defaultAvatarSrc = function ({ email, md5 }: { md5?: string; email?: string }) {
if (!email && !md5) return "";
if (email && !md5) {
- md5 = crypto.createHash("md5").update(email).digest("hex");
+ md5 = md5Parser(email);
}
return `https://www.gravatar.com/avatar/${md5}?s=160&d=mp&r=PG`;
diff --git a/packages/lib/getPaymentAppData.ts b/packages/lib/getPaymentAppData.ts
index fa9ccc4d6a10d1..4653a346ed34e0 100644
--- a/packages/lib/getPaymentAppData.ts
+++ b/packages/lib/getPaymentAppData.ts
@@ -1,9 +1,9 @@
import type { z } from "zod";
+import { getEventTypeAppData } from "@calcom/app-store/_utils/getEventTypeAppData";
import type { appDataSchemas } from "@calcom/app-store/apps.schemas.generated";
import type { appDataSchema } from "@calcom/app-store/stripepayment/zod";
import type { EventTypeAppsList } from "@calcom/app-store/utils";
-import { getEventTypeAppData } from "@calcom/app-store/utils";
export default function getPaymentAppData(
eventType: Parameters[0],
diff --git a/packages/lib/hooks/useHasPaidPlan.ts b/packages/lib/hooks/useHasPaidPlan.ts
index a8e13c82d0f1cb..e0509d4d95bae6 100644
--- a/packages/lib/hooks/useHasPaidPlan.ts
+++ b/packages/lib/hooks/useHasPaidPlan.ts
@@ -1,8 +1,11 @@
import { trpc } from "@calcom/trpc/react";
+import { IS_SELF_HOSTED } from "../constants";
import hasKeyInMetadata from "../hasKeyInMetadata";
export function useHasPaidPlan() {
+ if (IS_SELF_HOSTED) return { isLoading: false, hasPaidPlan: true };
+
const { data: hasTeamPlan, isLoading: isLoadingTeamQuery } = trpc.viewer.teams.hasTeamPlan.useQuery();
const { data: user, isLoading: isLoadingUserQuery } = trpc.viewer.me.useQuery();
@@ -22,4 +25,10 @@ export function useTeamInvites() {
return { isLoading: listInvites.isLoading, listInvites: listInvites.data };
}
+export function useHasTeamPlan() {
+ const { data: hasTeamPlan, isLoading } = trpc.viewer.teams.hasTeamPlan.useQuery();
+
+ return { isLoading, hasTeamPlan: hasTeamPlan?.hasTeamPlan };
+}
+
export default useHasPaidPlan;
diff --git a/packages/prisma/seed-app-store.config.json b/packages/prisma/seed-app-store.config.json
index e0c669cb61edaf..f93db4f144874a 100644
--- a/packages/prisma/seed-app-store.config.json
+++ b/packages/prisma/seed-app-store.config.json
@@ -197,5 +197,12 @@
"slug": "basic",
"type": "basic_other",
"isTemplate": true
+ },
+ {
+ "dirName": "facetime",
+ "categories": ["video"],
+ "slug": "facetime",
+ "type": "facetime_video",
+ "isTemplate": false
}
]
diff --git a/packages/trpc/server/routers/viewer/eventTypes.ts b/packages/trpc/server/routers/viewer/eventTypes.ts
index 3e28821f4d42e6..a8b8081105242b 100644
--- a/packages/trpc/server/routers/viewer/eventTypes.ts
+++ b/packages/trpc/server/routers/viewer/eventTypes.ts
@@ -338,7 +338,7 @@ export const eventTypesRouter = router({
profile: {
name: membership.team.name,
image: `${CAL_URL}/team/${membership.team.slug}/avatar.png`,
- slug: "team/" + membership.team.slug,
+ slug: membership.team.slug ? "team/" + membership.team.slug : null,
},
metadata: {
membershipCount: membership.team.members.length,
diff --git a/packages/trpc/server/routers/viewer/workflows.tsx b/packages/trpc/server/routers/viewer/workflows.tsx
index 5d279763e5582c..c3441ea713a1f7 100644
--- a/packages/trpc/server/routers/viewer/workflows.tsx
+++ b/packages/trpc/server/routers/viewer/workflows.tsx
@@ -1,6 +1,5 @@
+import type { Prisma, PrismaPromise } from "@prisma/client";
import {
- Prisma,
- PrismaPromise,
WorkflowTemplates,
WorkflowActions,
WorkflowTriggerEvents,
@@ -32,15 +31,15 @@ import {
verifyPhoneNumber,
sendVerificationCode,
} from "@calcom/features/ee/workflows/lib/reminders/verifyPhoneNumber";
-import { SENDER_ID } from "@calcom/lib/constants";
+import { IS_SELF_HOSTED, SENDER_ID } from "@calcom/lib/constants";
import { SENDER_NAME } from "@calcom/lib/constants";
// import { getErrorFromUnknown } from "@calcom/lib/errors";
import { getTranslation } from "@calcom/lib/server/i18n";
-import { WorkflowStep } from "@calcom/prisma/client";
+import type { WorkflowStep } from "@calcom/prisma/client";
import { TRPCError } from "@trpc/server";
-import { router, authedProcedure, authedRateLimitedProcedure } from "../../trpc";
+import { router, authedProcedure } from "../../trpc";
import { viewerTeamsRouter } from "./teams";
function getSender(
@@ -1127,6 +1126,6 @@ action === WorkflowActions.EMAIL_ADDRESS*/
getWorkflowActionOptions: authedProcedure.query(async ({ ctx }) => {
const { hasTeamPlan } = await viewerTeamsRouter.createCaller(ctx).hasTeamPlan();
const t = await getTranslation(ctx.user.locale, "common");
- return getWorkflowActionOptions(t, !!hasTeamPlan);
+ return getWorkflowActionOptions(t, IS_SELF_HOSTED || !!hasTeamPlan);
}),
});
diff --git a/packages/ui/components/apps/Slider.tsx b/packages/ui/components/apps/Slider.tsx
index 76ccda870b9b89..582fd3828daed0 100644
--- a/packages/ui/components/apps/Slider.tsx
+++ b/packages/ui/components/apps/Slider.tsx
@@ -50,13 +50,6 @@ export const Slider = ({
return (
-
{isLocaleReady ? (
diff --git a/packages/ui/components/form/color-picker/colorpicker.tsx b/packages/ui/components/form/color-picker/colorpicker.tsx
index 93ef5da340cd4d..e12da54ce89597 100644
--- a/packages/ui/components/form/color-picker/colorpicker.tsx
+++ b/packages/ui/components/form/color-picker/colorpicker.tsx
@@ -1,61 +1,9 @@
-import { useCallback, useEffect, useRef, useState } from "react";
+import * as Popover from "@radix-ui/react-popover";
+import { useState } from "react";
import { HexColorInput, HexColorPicker } from "react-colorful";
import { fallBackHex, isValidHexCode } from "@calcom/lib/CustomBranding";
-import { Swatch } from "../../..";
-
-type Handler = (event: MouseEvent | Event) => void;
-function useEventListener<
- KW extends keyof WindowEventMap,
- KH extends keyof HTMLElementEventMap,
- T extends HTMLElement | void = void
->(
- eventName: KW | KH,
- handler: (event: WindowEventMap[KW] | HTMLElementEventMap[KH] | Event) => void,
- element?: React.RefObject
-) {
- // Create a ref that stores handler
- const savedHandler = useRef();
- useEffect(() => {
- // Define the listening target
- const targetElement: T | Window = element?.current || window;
- if (!(targetElement && targetElement.addEventListener)) {
- return;
- }
- // Update saved handler if necessary
- if (savedHandler.current !== handler) {
- savedHandler.current = handler;
- }
- // Create event listener that calls handler function stored in ref
- const eventListener: typeof handler = (event) => {
- // eslint-disable-next-line no-extra-boolean-cast
- if (!!savedHandler?.current) {
- savedHandler.current(event);
- }
- };
- targetElement.addEventListener(eventName, eventListener);
- // Remove event listener on cleanup
- return () => {
- targetElement.removeEventListener(eventName, eventListener);
- };
- }, [eventName, element, handler]);
-}
-
-function useOnClickOutside(
- ref: React.RefObject,
- handler: Handler,
- mouseEvent: "mousedown" | "mouseup" = "mousedown"
-): void {
- useEventListener(mouseEvent, (event) => {
- const el = ref?.current;
- // Do nothing if clicking ref's element or descendent elements
- if (!el || el.contains(event.target as Node)) {
- return;
- }
- handler(event);
- });
-}
export type ColorPickerProps = {
defaultValue: string;
onChange: (text: string) => void;
@@ -66,27 +14,35 @@ const ColorPicker = (props: ColorPickerProps) => {
? fallBackHex(props.defaultValue, false)
: props.defaultValue;
const [color, setColor] = useState(init);
- const [isOpen, toggle] = useState(false);
- const popover = useRef() as React.MutableRefObject;
- const close = useCallback(() => toggle(false), []);
- useOnClickOutside(popover, close);
+
return (
-
-
toggle(!isOpen)} />
- {isOpen && (
-
-
{
- setColor(val);
- props.onChange(val);
- }}
- />
+
+
+
- )}
+
+
+ {
+ setColor(val);
+ props.onChange(val);
+ }}
+ />
+
+
+
+
{
setColor(val);
diff --git a/packages/ui/components/swatch/Swatch.tsx b/packages/ui/components/swatch/Swatch.tsx
deleted file mode 100644
index 79f2beb1cb67ff..00000000000000
--- a/packages/ui/components/swatch/Swatch.tsx
+++ /dev/null
@@ -1,27 +0,0 @@
-import classNames from "@calcom/lib/classNames";
-
-export type SwatchProps = {
- size?: "base" | "sm" | "lg";
- backgroundColor: string;
- onClick: () => void;
-};
-
-const Swatch = (props: SwatchProps) => {
- const { size, backgroundColor, onClick } = props;
- return (
-
- );
-};
-
-export default Swatch;
diff --git a/packages/ui/components/swatch/index.ts b/packages/ui/components/swatch/index.ts
deleted file mode 100644
index c7ce1e2c103bb7..00000000000000
--- a/packages/ui/components/swatch/index.ts
+++ /dev/null
@@ -1 +0,0 @@
-export { default as Swatch } from "./Swatch";
diff --git a/packages/ui/index.tsx b/packages/ui/index.tsx
index 7f4ab4d00b2fb1..95d1d429345c0f 100644
--- a/packages/ui/index.tsx
+++ b/packages/ui/index.tsx
@@ -109,7 +109,6 @@ export {
export type { DialogProps, ConfirmationDialogContentProps } from "./components/dialog";
export { showToast } from "./components/toast"; // We don't export the toast components as they are only used in local storybook file
export { Meta, MetaProvider, useMeta } from "./components/meta";
-export { Swatch } from "./components/swatch";
export { ShellSubHeading } from "./components/layout";
/** ⬇️ TODO - Move these to components */
diff --git a/yarn.lock b/yarn.lock
index e27ebdb51f0193..2e27c6e660b407 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -3802,10 +3802,10 @@
resolved "https://registry.yarnpkg.com/@floating-ui/core/-/core-0.7.3.tgz#d274116678ffae87f6b60e90f88cc4083eefab86"
integrity sha512-buc8BXHmG9l82+OQXOFU3Kr2XQx9ys01U/Q9HMIrZ300iLc8HLMgh7dcCqgYzAzf4BkoQvDcXf5Y+CuEZ5JBYg==
-"@floating-ui/core@^1.2.0":
- version "1.2.0"
- resolved "https://registry.yarnpkg.com/@floating-ui/core/-/core-1.2.0.tgz#ae7ae7923d41f3d84cb2fd88740a89436610bbec"
- integrity sha512-GHUXPEhMEmTpnpIfesFA2KAoMJPb1SPQw964tToQwt+BbGXdhqTCWT1rOb0VURGylsxsYxiGMnseJ3IlclVpVA==
+"@floating-ui/core@^1.2.1":
+ version "1.2.1"
+ resolved "https://registry.yarnpkg.com/@floating-ui/core/-/core-1.2.1.tgz#074182a1d277f94569c50a6b456e62585d463c8e"
+ integrity sha512-LSqwPZkK3rYfD7GKoIeExXOyYx6Q1O4iqZWwIehDNuv3Dv425FIAE8PRwtAx1imEolFTHgBEcoFHm9MDnYgPCg==
"@floating-ui/dom@^0.5.3":
version "0.5.4"
@@ -3814,12 +3814,12 @@
dependencies:
"@floating-ui/core" "^0.7.3"
-"@floating-ui/dom@^1.1.1":
- version "1.2.0"
- resolved "https://registry.yarnpkg.com/@floating-ui/dom/-/dom-1.2.0.tgz#a60212069cc58961c478037c30eba4b191c75316"
- integrity sha512-QXzg57o1cjLz3cGETzKXjI3kx1xyS49DW9l7kV2jw2c8Yftd434t2hllX0sVGn2Q8MtcW/4pNm8bfE1/4n6mng==
+"@floating-ui/dom@^1.2.1":
+ version "1.2.1"
+ resolved "https://registry.yarnpkg.com/@floating-ui/dom/-/dom-1.2.1.tgz#8f93906e1a3b9f606ce78afb058e874344dcbe07"
+ integrity sha512-Rt45SmRiV8eU+xXSB9t0uMYiQ/ZWGE/jumse2o3i5RGlyvcbqOF4q+1qBnzLE2kZ5JGhq0iMkcGXUKbFe7MpTA==
dependencies:
- "@floating-ui/core" "^1.2.0"
+ "@floating-ui/core" "^1.2.1"
"@floating-ui/react-dom@0.7.2":
version "0.7.2"
@@ -3830,11 +3830,11 @@
use-isomorphic-layout-effect "^1.1.1"
"@floating-ui/react-dom@^1.0.0":
- version "1.2.2"
- resolved "https://registry.yarnpkg.com/@floating-ui/react-dom/-/react-dom-1.2.2.tgz#ed256992fd44fcfcddc96da68b4b92f123d61871"
- integrity sha512-DbmFBLwFrZhtXgCI2ra7wXYT8L2BN4/4AMQKyu05qzsVji51tXOfF36VE2gpMB6nhJGHa85PdEg75FB4+vnLFQ==
+ version "1.3.0"
+ resolved "https://registry.yarnpkg.com/@floating-ui/react-dom/-/react-dom-1.3.0.tgz#4d35d416eb19811c2b0e9271100a6aa18c1579b3"
+ integrity sha512-htwHm67Ji5E/pROEAr7f8IKFShuiCKHwUC/UY4vC3I5jiSvGFAYnSYiZO5MlGmads+QqvUkR9ANHEguGrDv72g==
dependencies:
- "@floating-ui/dom" "^1.1.1"
+ "@floating-ui/dom" "^1.2.1"
"@formatjs/ecma402-abstract@1.11.4":
version "1.11.4"
@@ -3934,9 +3934,9 @@
"@hapi/hoek" "^9.0.0"
"@headlessui/react@^1.5.0":
- version "1.7.10"
- resolved "https://registry.yarnpkg.com/@headlessui/react/-/react-1.7.10.tgz#0971a33843a76f2bf4b801a43f76e3730fe15884"
- integrity sha512-1m66h/5eayTEZVT2PI13/2PG3EVC7a9XalmUtVSC8X76pcyKYMuyX1XAL2RUtCr8WhoMa/KrDEyoeU5v+kSQOw==
+ version "1.7.11"
+ resolved "https://registry.yarnpkg.com/@headlessui/react/-/react-1.7.11.tgz#1cc5750226abe5af2c94f72e975c0c8d2f5cc5a6"
+ integrity sha512-EaDbVgcyiylhtskZZf4Qb/JiiByY7cYbd0qgZ9xm2pm2X7hKojG0P4TaQYKgPOV3vojPhd/pZyQh3nmRkkcSyw==
dependencies:
client-only "^0.0.1"
@@ -4944,12 +4944,19 @@
integrity sha512-jIOM6CzCbl2/Mzbx9kb2IjtHoJOeRN9wtQgLk4EUm5bhneSVGv1rtz5TDskvp2UfCa+EK9nDmug+lje41z80Gg==
"@next/bundle-analyzer@^12.2.5":
- version "12.3.1"
- resolved "https://registry.yarnpkg.com/@next/bundle-analyzer/-/bundle-analyzer-12.3.1.tgz#df168652c43ed0dc3e91a5108e34cdcc8fc7f05a"
- integrity sha512-2f/eei0YqZZBMTs4g1+HbgHyAFH5MbI/w9wLXmE8ly9SFze2D40sRH46JcC//EFVM/TIynVBh5sxn9CVO/vtxg==
+ version "12.3.4"
+ resolved "https://registry.yarnpkg.com/@next/bundle-analyzer/-/bundle-analyzer-12.3.4.tgz#37c587525288a3dea64213c991590532246e8bb8"
+ integrity sha512-eKjgRICzbLTmod0UnJcArFVs5uEAiuZwB6NCf84m+btW7jdylUVoOYf1wi5tA14xk5L9Lho7Prm6/XJ8gxYzfQ==
dependencies:
webpack-bundle-analyzer "4.3.0"
+"@next/bundle-analyzer@^13.1.6":
+ version "13.1.6"
+ resolved "https://registry.yarnpkg.com/@next/bundle-analyzer/-/bundle-analyzer-13.1.6.tgz#36ff2f9c4b19aa75cd589ee080b1e2edb24f1192"
+ integrity sha512-rJS9CtLoGT58mL+v2ISKANosFFWP/0YKYByHQ3vTaZrbQP8b1rYRxd2QVMJmnSXaFkiP9URt1XJ6OdGyVq5b6g==
+ dependencies:
+ webpack-bundle-analyzer "4.7.0"
+
"@next/env@13.1.1":
version "13.1.1"
resolved "https://registry.yarnpkg.com/@next/env/-/env-13.1.1.tgz#6ff26488dc7674ef2bfdd1ca28fe43eed1113bea"
@@ -4962,6 +4969,11 @@
dependencies:
glob "7.1.7"
+"@next/font@^13.1.1":
+ version "13.1.6"
+ resolved "https://registry.yarnpkg.com/@next/font/-/font-13.1.6.tgz#2bf99e3321ec9b4d65781c0d0ebff072e8752e1a"
+ integrity sha512-AITjmeb1RgX1HKMCiA39ztx2mxeAyxl4ljv2UoSBUGAbFFMg8MO7YAvjHCgFhD39hL7YTbFjol04e/BPBH5RzQ==
+
"@next/swc-android-arm-eabi@13.1.1":
version "13.1.1"
resolved "https://registry.yarnpkg.com/@next/swc-android-arm-eabi/-/swc-android-arm-eabi-13.1.1.tgz#b5c3cd1f79d5c7e6a3b3562785d4e5ac3555b9e1"
@@ -5183,10 +5195,10 @@
ms "2.1.3"
strip-ansi "6.0.1"
-"@prisma/debug@4.10.0":
- version "4.10.0"
- resolved "https://registry.yarnpkg.com/@prisma/debug/-/debug-4.10.0.tgz#5b1ab6b6d4812765a60ad8cccb7b5d38afb3b802"
- integrity sha512-rxVOZKsEyjlQCwN/pkkJO7wEdARt1yRyukSjLa+BF2QTvy2+VgtBmrfys4WDQSnj3jVWeHMpi5GeAoJjKkSKyA==
+"@prisma/debug@4.10.1":
+ version "4.10.1"
+ resolved "https://registry.yarnpkg.com/@prisma/debug/-/debug-4.10.1.tgz#02d0f98aec5b0bb8b5358e1fcf6cb9462fbb6de2"
+ integrity sha512-NCWX+uJiEItzQsOS/4kiAKsT1hgSbN7n+1cNCmzoA6TsEn+WKzN0ZjBKyKuR937z57n2WVGXo5DfnCiW9ClqUg==
dependencies:
"@types/debug" "4.1.7"
debug "4.3.4"
@@ -5203,11 +5215,11 @@
integrity sha512-93tctjNXcIS+i/e552IO6tqw17sX8liivv8WX9lDMCpEEe3ci+nT9F+1oHtAafqruXLepKF80i/D20Mm+ESlOw==
"@prisma/generator-helper@^4.0.0":
- version "4.10.0"
- resolved "https://registry.yarnpkg.com/@prisma/generator-helper/-/generator-helper-4.10.0.tgz#dc47265cbd55dc14ce08822f99c14d08f7e2cdb7"
- integrity sha512-NkQOfZpHUjVjqJ7NN2FymHSLkGd/E0fz5c3RkyESKvQqBy2sFBxt+aFxGsUbUy3FfwvkckC04HdQOXpisAko0A==
+ version "4.10.1"
+ resolved "https://registry.yarnpkg.com/@prisma/generator-helper/-/generator-helper-4.10.1.tgz#6a71043855ec670d9b8a497e4a77f181cedfbc20"
+ integrity sha512-OS2hAnRAiWpy+icccG6wp/yx/2jaeLdfYG6ZwD8RR0vZC2PC5VsrJz8tv6kYmuOs3qQwzVcPt9YSj3frWfD5WA==
dependencies:
- "@prisma/debug" "4.10.0"
+ "@prisma/debug" "4.10.1"
"@types/cross-spawn" "6.0.2"
chalk "4.1.2"
cross-spawn "7.0.3"
@@ -6311,7 +6323,7 @@
dependencies:
"@hapi/hoek" "^9.0.0"
-"@sideway/formula@^3.0.0":
+"@sideway/formula@^3.0.1":
version "3.0.1"
resolved "https://registry.yarnpkg.com/@sideway/formula/-/formula-3.0.1.tgz#80fcbcbaf7ce031e0ef2dd29b1bfc7c3f583611f"
integrity sha512-/poHZJJVjx3L+zVD6g9KgHfYnb443oi7wLu/XKojDviHy6HOEOA6z1Trk5aR1dGcmPenJEgb2sK2I80LeS3MIg==
@@ -8248,6 +8260,11 @@
"@types/linkify-it" "*"
"@types/mdurl" "*"
+"@types/md5@^2.3.2":
+ version "2.3.2"
+ resolved "https://registry.yarnpkg.com/@types/md5/-/md5-2.3.2.tgz#529bb3f8a7e9e9f621094eb76a443f585d882528"
+ integrity sha512-v+JFDu96+UYJ3/UWzB0mEglIS//MZXgRaJ4ubUPwOM0gvLc/kcQ3TWNYwENEK7/EcXGQVrW8h/XqednSjBd/Og==
+
"@types/mdast@^3.0.0":
version "3.0.10"
resolved "https://registry.yarnpkg.com/@types/mdast/-/mdast-3.0.10.tgz#4724244a82a4598884cbbe9bcfd73dff927ee8af"
@@ -8812,9 +8829,9 @@
integrity sha512-aW6CfMMToX4a+baLuVxwcT0FSACjX3xrNt8wdi/3LLRlLAfhyue8OK7kJxhcYNZfydBeWTP59aRy8p5FUTIeew==
"@vercel/analytics@^0.1.6":
- version "0.1.8"
- resolved "https://registry.yarnpkg.com/@vercel/analytics/-/analytics-0.1.8.tgz#71f1f8c7bb98ac0c5c47eb3fb8ccbe8141b9fe47"
- integrity sha512-PQrOI8BJ9qUiVJuQfnKiJd15eDjDJH9TBKsNeMrtelT4NAk7d9mBVz1CoZkvoFnHQ0OW7Xnqmr1F2nScfAnznQ==
+ version "0.1.9"
+ resolved "https://registry.yarnpkg.com/@vercel/analytics/-/analytics-0.1.9.tgz#434f14a0dbe635a6d92c693a3607dbac0468dd47"
+ integrity sha512-Lfus/6HAZXQBr4uv5eCtNKrEvthKWQFFcUNh5wC3fWn+4PbHxT8bqcm1TMQfYvGJ8O4TWzn0IfrQFNWh1DHDbQ==
"@vercel/edge-config@^0.1.1":
version "0.1.1"
@@ -11775,6 +11792,11 @@ commander@^6.2.0, commander@^6.2.1:
resolved "https://registry.yarnpkg.com/commander/-/commander-6.2.1.tgz#0792eb682dfbc325999bb2b84fddddba110ac73c"
integrity sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA==
+commander@^7.2.0:
+ version "7.2.0"
+ resolved "https://registry.yarnpkg.com/commander/-/commander-7.2.0.tgz#a36cb57d0b501ce108e4d20559a150a391d97ab7"
+ integrity sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==
+
commander@^8.3.0:
version "8.3.0"
resolved "https://registry.yarnpkg.com/commander/-/commander-8.3.0.tgz#4837ea1b2da67b9c616a67afbb0fafee567bca66"
@@ -15443,9 +15465,9 @@ gifwrap@^0.9.2:
omggif "^1.0.10"
github-buttons@^2.22.0:
- version "2.22.3"
- resolved "https://registry.yarnpkg.com/github-buttons/-/github-buttons-2.22.3.tgz#ad0766618dadfbb46c12c5dca1f8c14c1e7d90f3"
- integrity sha512-09/pJ7X6D1whEeFz+fKSjOBEEDnY/nxbPN7zduxAU5zGwo4RkXjL86AiOVHgIYDothbHAS43eaVk76a8Lp4YYw==
+ version "2.23.0"
+ resolved "https://registry.yarnpkg.com/github-buttons/-/github-buttons-2.23.0.tgz#b113ec9ed733f55bf5ab07652015bd0e5128dd1d"
+ integrity sha512-2REUOV3ue6NmT0QThhfzfYmeSoYpCG73+tL7Ir2C7P+gshRerI05WuIQuhDkE2Zlg5Wc39hc2DHj+pE23mGJvw==
github-slugger@^1.0.0, github-slugger@^1.3.0:
version "1.4.0"
@@ -15999,9 +16021,9 @@ hast-util-from-parse5@^6.0.0:
web-namespaces "^1.0.0"
hast-util-from-parse5@^7.0.0:
- version "7.1.1"
- resolved "https://registry.yarnpkg.com/hast-util-from-parse5/-/hast-util-from-parse5-7.1.1.tgz#1887b4dd4e19f29d9c48c2e1c8bfeaac13a1f3a0"
- integrity sha512-R6PoNcUs89ZxLJmMWsVbwSWuz95/9OriyQZ3e2ybwqGsRXzhA6gv49rgGmQvLbZuSNDv9fCg7vV7gXUsvtUFaA==
+ version "7.1.2"
+ resolved "https://registry.yarnpkg.com/hast-util-from-parse5/-/hast-util-from-parse5-7.1.2.tgz#aecfef73e3ceafdfa4550716443e4eb7b02e22b0"
+ integrity sha512-Nz7FfPBuljzsN3tCQ4kCBKqdNhQE2l0Tn+X1ubgKBPRoiDIu1mL08Cfw4k7q71+Duyaw7DXDN+VTAp4Vh3oCOw==
dependencies:
"@types/hast" "^2.0.0"
"@types/unist" "^2.0.0"
@@ -17951,14 +17973,14 @@ jimp@^0.16.1:
regenerator-runtime "^0.13.3"
joi@^17.7.0:
- version "17.7.0"
- resolved "https://registry.yarnpkg.com/joi/-/joi-17.7.0.tgz#591a33b1fe1aca2bc27f290bcad9b9c1c570a6b3"
- integrity sha512-1/ugc8djfn93rTE3WRKdCzGGt/EtiYKxITMO4Wiv6q5JL1gl9ePt4kBsl1S499nbosspfctIQTpYIhSmHA3WAg==
+ version "17.7.1"
+ resolved "https://registry.yarnpkg.com/joi/-/joi-17.7.1.tgz#854fc85c7fa3cfc47c91124d30bffdbb58e06cec"
+ integrity sha512-teoLhIvWE298R6AeJywcjR4sX2hHjB3/xJX4qPjg+gTg+c0mzUDsziYlqPmLomq9gVsfaMcgPaGc7VxtD/9StA==
dependencies:
"@hapi/hoek" "^9.0.0"
"@hapi/topo" "^5.0.0"
"@sideway/address" "^4.1.3"
- "@sideway/formula" "^3.0.0"
+ "@sideway/formula" "^3.0.1"
"@sideway/pinpoint" "^2.0.0"
jose@4.11.1, jose@^4.9.3:
@@ -19939,11 +19961,16 @@ minimist-options@4.1.0:
is-plain-obj "^1.1.0"
kind-of "^6.0.3"
-minimist@^1.1.1, minimist@^1.1.3, minimist@^1.2.0, minimist@^1.2.5, minimist@^1.2.6, minimist@^1.2.7:
+minimist@^1.1.1, minimist@^1.1.3, minimist@^1.2.0, minimist@^1.2.5, minimist@^1.2.6:
version "1.2.7"
resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.7.tgz#daa1c4d91f507390437c6a8bc01078e7000c4d18"
integrity sha512-bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g==
+minimist@^1.2.7:
+ version "1.2.8"
+ resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.8.tgz#c1a464e7693302e082a075cee0c057741ac4772c"
+ integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==
+
minipass-collect@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/minipass-collect/-/minipass-collect-1.0.2.tgz#22b813bf745dc6edba2576b940022ad6edc8c617"
@@ -22121,9 +22148,9 @@ prism-react-renderer@^1.3.5:
integrity sha512-IJ+MSwBWKG+SM3b2SUfdrhC+gu01QkV2KmRQgREThBfSQRoufqRfxfHUxpG1WcaFjP+kojcFyO9Qqtpgt3qLCg==
prisma-field-encryption@^1.4.0:
- version "1.4.0"
- resolved "https://registry.yarnpkg.com/prisma-field-encryption/-/prisma-field-encryption-1.4.0.tgz#fb644cf98b782c81e443f022e27b0108fe31c7ed"
- integrity sha512-ZJLIZL4IzdkZSmeVnpvW7E4/P74txf2OLZWzzfHQlkLcDJOddfIcXPytCxwHiPZX12aXfsVt0bA2T11mdA/lMw==
+ version "1.4.1"
+ resolved "https://registry.yarnpkg.com/prisma-field-encryption/-/prisma-field-encryption-1.4.1.tgz#caec1712d0d1ac1525f64eaae3d76501f0e33a7f"
+ integrity sha512-J9uOdp/biLw4Gb3Z2dmXpDYXWG6jmqn0Wnp9/ga0Adg53jP0jVeIfO6+iIIY+H07xDUZa635seYs0pTMqYzyhA==
dependencies:
"@47ng/cloak" "^1.1.0"
"@prisma/generator-helper" "^4.0.0"
@@ -22613,11 +22640,11 @@ react-debounce-input@=3.2.4:
prop-types "^15.7.2"
react-device-detect@^2.2.2:
- version "2.2.2"
- resolved "https://registry.yarnpkg.com/react-device-detect/-/react-device-detect-2.2.2.tgz#dbabbce798ec359c83f574c3edb24cf1cca641a5"
- integrity sha512-zSN1gIAztUekp5qUT/ybHwQ9fmOqVT1psxpSlTn1pe0CO+fnJHKRLOWWac5nKxOxvOpD/w84hk1I+EydrJp7SA==
+ version "2.2.3"
+ resolved "https://registry.yarnpkg.com/react-device-detect/-/react-device-detect-2.2.3.tgz#97a7ae767cdd004e7c3578260f48cf70c036e7ca"
+ integrity sha512-buYY3qrCnQVlIFHrC5UcUoAj7iANs/+srdkwsnNjI7anr3Tt7UY6MqNxtMLlr0tMBied0O49UZVK8XKs3ZIiPw==
dependencies:
- ua-parser-js "^1.0.2"
+ ua-parser-js "^1.0.33"
react-devtools-core@^4.19.1:
version "4.24.6"
@@ -26318,7 +26345,7 @@ tzdata@^1.0.30:
resolved "https://registry.yarnpkg.com/tzdata/-/tzdata-1.0.36.tgz#e5f3998d5e95e0e65dee417ae917a16314df69e9"
integrity sha512-QxRODDsXS8UVxlPazCZXplqVuD6mCe7tSyDE5SCSHXv1nmrfflXxNH4pD+fjU8KJwePhWqhp6n+FpygQeGLv7w==
-ua-parser-js@^1.0.2:
+ua-parser-js@^1.0.33:
version "1.0.33"
resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-1.0.33.tgz#f21f01233e90e7ed0f059ceab46eb190ff17f8f4"
integrity sha512-RqshF7TPTE0XLYAqmjlu5cLLuGdKrNu9O1KLA/qp39QtbZwuzwv1dT46DZSopoUMsYgXpB3Cv8a03FI8b74oFQ==
@@ -27389,6 +27416,21 @@ webpack-bundle-analyzer@4.3.0:
sirv "^1.0.7"
ws "^7.3.1"
+webpack-bundle-analyzer@4.7.0:
+ version "4.7.0"
+ resolved "https://registry.yarnpkg.com/webpack-bundle-analyzer/-/webpack-bundle-analyzer-4.7.0.tgz#33c1c485a7fcae8627c547b5c3328b46de733c66"
+ integrity sha512-j9b8ynpJS4K+zfO5GGwsAcQX4ZHpWV+yRiHDiL+bE0XHJ8NiPYLTNVQdlFYWxtpg9lfAQNlwJg16J9AJtFSXRg==
+ dependencies:
+ acorn "^8.0.4"
+ acorn-walk "^8.0.0"
+ chalk "^4.1.0"
+ commander "^7.2.0"
+ gzip-size "^6.0.0"
+ lodash "^4.17.20"
+ opener "^1.5.2"
+ sirv "^1.0.7"
+ ws "^7.3.1"
+
webpack-dev-middleware@^3.7.3:
version "3.7.3"
resolved "https://registry.yarnpkg.com/webpack-dev-middleware/-/webpack-dev-middleware-3.7.3.tgz#0639372b143262e2b84ab95d3b91a7597061c2c5"
@@ -28118,7 +28160,12 @@ zod-prisma@^0.5.4:
parenthesis "^3.1.8"
ts-morph "^13.0.2"
-zod@^3.17.3, zod@^3.20.2:
+zod@^3.17.3:
+ version "3.20.6"
+ resolved "https://registry.yarnpkg.com/zod/-/zod-3.20.6.tgz#2f2f08ff81291d47d99e86140fedb4e0db08361a"
+ integrity sha512-oyu0m54SGCtzh6EClBVqDDlAYRz4jrVtKwQ7ZnsEmMI9HnzuZFj8QFwAY1M5uniIYACdGvv0PBWPF2kO0aNofA==
+
+zod@^3.20.2:
version "3.20.2"
resolved "https://registry.yarnpkg.com/zod/-/zod-3.20.2.tgz#068606642c8f51b3333981f91c0a8ab37dfc2807"
integrity sha512-1MzNQdAvO+54H+EaK5YpyEy0T+Ejo/7YLHS93G3RnYWh5gaotGHwGeN/ZO687qEDU2y4CdStQYXVHIgrUl5UVQ==