patch applied

This commit is contained in:
zomars 2022-02-15 15:48:19 -07:00
parent ecbdfea818
commit 801e4c4600
83 changed files with 3017 additions and 1293 deletions

229
apps/web/components/App.tsx Normal file
View File

@ -0,0 +1,229 @@
import {
BookOpenIcon,
DocumentTextIcon,
ExternalLinkIcon,
FlagIcon,
MailIcon,
ShieldCheckIcon,
} from "@heroicons/react/outline";
import { ChevronLeftIcon } from "@heroicons/react/solid";
import Link from "next/link";
import React from "react";
import { useLocale } from "@lib/hooks/useLocale";
//import NavTabs from "@components/NavTabs";
import Shell from "@components/Shell";
import Badge from "@components/ui/Badge";
import Button from "@components/ui/Button";
export default function App({
name,
logo,
body,
categories,
author,
price,
commission,
type,
docs,
website,
email,
tos,
privacy,
}: {
name: string;
logo: string;
body: React.ReactNode;
categories: string[];
author: string;
pro?: boolean;
price: number;
commission?: number;
type?: "monthly" | "usage-based" | "one-time" | "free";
docs?: string;
website?: string;
email: string; // required
tos?: string;
privacy?: string;
}) {
const { t } = useLocale();
/*const tabs = [
{
name: t("description"),
href: "?description",
},
{
name: t("features"),
href: "?features",
},
{
name: t("permissions"),
href: "?permissions",
},
];*/
const priceInDollar = Intl.NumberFormat("en-US", {
style: "currency",
currency: "USD",
useGrouping: false,
}).format(price);
return (
<>
<Shell large>
<div className="-mx-8">
<div className="px-10 bg-gray-50">
<Link href="/apps">
<a className="inline-flex px-1 py-2 mt-2 text-sm text-gray-500 hover:bg-gray-100 hover:text-gray-800">
<ChevronLeftIcon className="w-5 h-5" /> {t("browse_apps")}
</a>
</Link>
<div className="flex items-center justify-between py-8">
<div className="flex">
<img className="w-16 h-16" src={logo} />
<header className="px-4 py-2">
<h1 className="text-xl text-gray-900 font-cal">{name}</h1>
<h2 className="text-sm text-gray-500">
<span className="capitalize">{categories[0]}</span> {t("build_by", { author })}
</h2>
</header>
</div>
<div className="text-right">
{type === "free" && (
<Button onClick={() => alert("TODO: installed free app")}>{t("install_app")}</Button>
)}
{type === "usage-based" && (
<Button onClick={() => alert("TODO: installed usage based app")}>{t("install_app")}</Button>
)}
{type === "monthly" && (
<Button onClick={() => alert("TODO: installed monthly billed app")}>
{t("subscribe")}
</Button>
)}
{price !== 0 && (
<small className="block text-right">
{type === "usage-based"
? commission + "% + " + priceInDollar + "/booking"
: priceInDollar}
{type === "monthly" && "/" + t("month")}
</small>
)}
</div>
</div>
{/* reintroduce once we show permissions and features
<NavTabs tabs={tabs} linkProps={{ shallow: true }} /> */}
</div>
<div className="flex justify-between px-10 py-10">
<div className="prose-sm prose">{body}</div>
<div className="flex-1 max-w-80">
<h4 className="font-medium text-gray-900 ">{t("categories")}</h4>
<div className="space-x-2">
{categories.map((category) => (
<Link href={"/apps/categories/" + category} key={category}>
<a>
<Badge variant="success">{category}</Badge>
</a>
</Link>
))}
</div>
<h4 className="mt-8 font-medium text-gray-900 ">{t("pricing")}</h4>
<small>
{price === 0 ? (
"Free"
) : (
<>
{Intl.NumberFormat("en-US", {
style: "currency",
currency: "USD",
useGrouping: false,
}).format(price)}
{type === "monthly" && "/" + t("month")}
</>
)}
</small>
<h4 className="mt-8 mb-2 font-medium text-gray-900 ">{t("learn_more")}</h4>
<ul className="-ml-1 -mr-1 text-xs leading-5 prose">
{docs && (
<li>
<a
target="_blank"
rel="noreferrer"
className="text-blue-500 no-underline hover:underline"
href={docs}>
<BookOpenIcon className="inline w-4 h-4 mr-1 -mt-1" />
{t("documentation")}
</a>
</li>
)}
{website && (
<li>
<a
target="_blank"
rel="noreferrer"
className="text-blue-500 no-underline hover:underline"
href={website}>
<ExternalLinkIcon className="inline w-4 h-4 mr-1 -mt-px" />
{website.replace("https://", "")}
</a>
</li>
)}
{email && (
<li>
<a
target="_blank"
rel="noreferrer"
className="text-blue-500 no-underline hover:underline"
href={"mailto:" + email}>
<MailIcon className="inline w-4 h-4 mr-1 -mt-px" />
{email}
</a>
</li>
)}
{tos && (
<li>
<a
target="_blank"
rel="noreferrer"
className="text-blue-500 no-underline hover:underline"
href={tos}>
<DocumentTextIcon className="inline w-4 h-4 mr-1 -mt-px" />
{t("terms_of_service")}
</a>
</li>
)}
{privacy && (
<li>
<a
target="_blank"
rel="noreferrer"
className="text-blue-500 no-underline hover:underline"
href={privacy}>
<ShieldCheckIcon className="inline w-4 h-4 mr-1 -mt-px" />
{t("privacy_policy")}
</a>
</li>
)}
</ul>
<hr className="my-6" />
<small className="block text-gray-500 leading-1">
Every app published on the Cal.com App Store is open source and thoroughly tested via peer
reviews. Nevertheless, Cal.com, Inc. does not endorse or certify these apps unless they are
published by Cal.com. If you encounter inappropriate content or behaviour please report it.
</small>
<a className="block mt-2 text-xs text-red-500" href="mailto:help@cal.com">
<FlagIcon className="inline w-3 h-3" /> Report App
</a>
</div>
</div>
</div>
</Shell>
</>
);
}

View File

@ -0,0 +1,30 @@
import { useSession } from "next-auth/react";
import React from "react";
import { useLocale } from "@lib/hooks/useLocale";
import NavTabs from "./NavTabs";
export default function AppsShell({ children }: { children: React.ReactNode }) {
const { t } = useLocale();
const { status } = useSession();
const tabs = [
{
name: t("app_store"),
href: "/apps",
},
{
name: t("installed_apps"),
href: "/apps/installed",
},
];
return (
<>
<div className="block mb-12 lg:hidden">
{status === "authenticated" && <NavTabs tabs={tabs} linkProps={{ shallow: true }} />}
</div>
<main>{children}</main>
</>
);
}

View File

@ -1,20 +1,20 @@
import { SelectorIcon } from "@heroicons/react/outline";
import {
CalendarIcon,
ArrowLeftIcon,
ClockIcon,
CogIcon,
ExternalLinkIcon,
LinkIcon,
LogoutIcon,
PuzzleIcon,
ViewGridIcon,
MoonIcon,
MapIcon,
ArrowLeftIcon,
} from "@heroicons/react/solid";
import { signOut, useSession } from "next-auth/react";
import Link from "next/link";
import { useRouter } from "next/router";
import React, { ReactNode, useEffect, useState } from "react";
import React, { Fragment, ReactNode, useEffect, useState } from "react";
import { Toaster } from "react-hot-toast";
import LicenseBanner from "@ee/components/LicenseBanner";
@ -58,6 +58,10 @@ function useRedirectToLoginIfUnauthenticated() {
const router = useRouter();
useEffect(() => {
if (router.pathname.startsWith("/apps")) {
return;
}
if (!loading && !session) {
router.replace({
pathname: "/auth/login",
@ -120,10 +124,11 @@ export function ShellSubHeading(props: {
export default function Shell(props: {
centered?: boolean;
title?: string;
heading: ReactNode;
heading?: ReactNode;
subtitle?: ReactNode;
children: ReactNode;
CTA?: ReactNode;
large?: boolean;
HeadingLeftIcon?: ReactNode;
backPath?: string; // renders back button to specified path
// use when content needs to expand with flex
@ -156,10 +161,22 @@ export default function Shell(props: {
current: router.asPath.startsWith("/availability"),
},
{
name: t("integrations"),
href: "/integrations",
icon: PuzzleIcon,
current: router.asPath.startsWith("/integrations"),
name: t("apps"),
href: "/apps",
icon: ViewGridIcon,
current: router.asPath.startsWith("/apps"),
child: [
{
name: t("app_store"),
href: "/apps",
current: router.asPath === "/apps",
},
{
name: t("installed_apps"),
href: "/apps/installed",
current: router.asPath === "/apps/installed",
},
],
},
{
name: t("settings"),
@ -181,6 +198,7 @@ export default function Shell(props: {
const user = query.data;
const i18n = useViewerI18n();
const { status } = useSession();
if (i18n.status === "loading" || isRedirectingToOnboarding || loading) {
// show spinner whilst i18n is loading to avoid language flicker
@ -205,59 +223,82 @@ export default function Shell(props: {
<Toaster position="bottom-right" />
</div>
<div className="flex h-screen overflow-hidden bg-gray-100" data-testid="dashboard-shell">
<div className="hidden md:flex lg:flex-shrink-0">
<div className="flex w-14 flex-col lg:w-56">
<div className="flex h-0 flex-1 flex-col border-r border-gray-200 bg-white">
<div className="flex flex-1 flex-col overflow-y-auto pt-3 pb-4 lg:pt-5">
<Link href="/event-types">
<a className="px-4 md:hidden lg:inline">
<Logo small />
</a>
</Link>
{/* logo icon for tablet */}
<Link href="/event-types">
<a className="md:inline lg:hidden">
<Logo small icon />
</a>
</Link>
<nav className="mt-2 flex-1 space-y-1 bg-white px-2 lg:mt-5">
{navigation.map((item) => (
<Link key={item.name} href={item.href}>
<a
className={classNames(
item.current
? "bg-neutral-100 text-neutral-900"
: "text-neutral-500 hover:bg-gray-50 hover:text-neutral-900",
"group flex items-center rounded-sm px-2 py-2 text-sm font-medium"
)}>
<item.icon
className={classNames(
item.current
? "text-neutral-500"
: "text-neutral-400 group-hover:text-neutral-500",
"h-5 w-5 flex-shrink-0 ltr:mr-3 rtl:ml-3"
)}
aria-hidden="true"
/>
<span className="hidden lg:inline">{item.name}</span>
</a>
</Link>
))}
</nav>
</div>
<TrialBanner />
<div className="m-2 rounded-sm p-2 pt-2 pr-2 hover:bg-gray-100">
<span className="hidden lg:inline">
<UserDropdown />
</span>
<span className="hidden md:inline lg:hidden">
<UserDropdown small />
</span>
<div
className={classNames("flex h-screen overflow-hidden", props.large ? "bg-white" : "bg-gray-100")}
data-testid="dashboard-shell">
{status === "authenticated" && (
<div className="hidden md:flex lg:flex-shrink-0">
<div className="flex w-14 flex-col lg:w-56">
<div className="flex h-0 flex-1 flex-col border-r border-gray-200 bg-white">
<div className="flex flex-1 flex-col overflow-y-auto pt-3 pb-4 lg:pt-5">
<Link href="/event-types">
<a className="px-4 md:hidden lg:inline">
<Logo small />
</a>
</Link>
{/* logo icon for tablet */}
<Link href="/event-types">
<a className="md:inline lg:hidden">
<Logo small icon />
</a>
</Link>
<nav className="mt-2 flex-1 space-y-1 bg-white px-2 lg:mt-5">
{navigation.map((item) => (
<Fragment key={item.name}>
<Link href={item.href}>
<a
className={classNames(
item.current
? "bg-neutral-100 text-neutral-900"
: "text-neutral-500 hover:bg-gray-50 hover:text-neutral-900",
"group flex items-center rounded-sm px-2 py-2 text-sm font-medium"
)}>
<item.icon
className={classNames(
item.current
? "text-neutral-500"
: "text-neutral-400 group-hover:text-neutral-500",
"h-5 w-5 flex-shrink-0 ltr:mr-3 rtl:ml-3"
)}
aria-hidden="true"
/>
<span className="hidden lg:inline">{item.name}</span>
</a>
</Link>
{item.child &&
router.asPath.startsWith(item.href) &&
item.child.map((item) => {
return (
<Link key={item.name} href={item.href}>
<a
className={classNames(
item.current
? "text-neutral-900"
: "text-neutral-500 hover:text-neutral-900",
"group hidden items-center rounded-sm px-2 py-2 pl-10 text-sm font-medium lg:flex"
)}>
<span className="hidden lg:inline">{item.name}</span>
</a>
</Link>
);
})}
</Fragment>
))}
</nav>
</div>
<TrialBanner />
<div className="m-2 rounded-sm p-2 pt-2 pr-2 hover:bg-gray-100">
<span className="hidden lg:inline">
<UserDropdown />
</span>
<span className="hidden md:inline lg:hidden">
<UserDropdown small />
</span>
</div>
</div>
</div>
</div>
</div>
)}
<div className="flex w-0 flex-1 flex-col overflow-hidden">
<main
@ -266,29 +307,31 @@ export default function Shell(props: {
props.flexChildrenContainer && "flex flex-col"
)}>
{/* show top navigation for md and smaller (tablet and phones) */}
<nav className="flex items-center justify-between border-b border-gray-200 bg-white p-4 md:hidden">
<Link href="/event-types">
<a>
<Logo />
</a>
</Link>
<div className="flex items-center gap-3 self-center">
<button className="rounded-full bg-white p-2 text-gray-400 hover:bg-gray-50 hover:text-gray-500 focus:outline-none focus:ring-2 focus:ring-black focus:ring-offset-2">
<span className="sr-only">{t("view_notifications")}</span>
<Link href="/settings/profile">
<a>
<CogIcon className="h-6 w-6" aria-hidden="true" />
</a>
</Link>
</button>
<UserDropdown small />
</div>
</nav>
{status === "authenticated" && (
<nav className="flex items-center justify-between border-b border-gray-200 bg-white p-4 md:hidden">
<Link href="/event-types">
<a>
<Logo />
</a>
</Link>
<div className="flex items-center gap-3 self-center">
<button className="rounded-full bg-white p-2 text-gray-400 hover:bg-gray-50 hover:text-gray-500 focus:outline-none focus:ring-2 focus:ring-black focus:ring-offset-2">
<span className="sr-only">{t("view_notifications")}</span>
<Link href="/settings/profile">
<a>
<CogIcon className="h-6 w-6" aria-hidden="true" />
</a>
</Link>
</button>
<UserDropdown small />
</div>
</nav>
)}
<div
className={classNames(
props.centered && "mx-auto md:max-w-5xl",
props.flexChildrenContainer && "flex flex-1 flex-col",
"py-8"
!props.large && "py-8"
)}>
{!!props.backPath && (
<div className="mx-3 mb-8 sm:mx-8">
@ -300,16 +343,22 @@ export default function Shell(props: {
</Button>
</div>
)}
<div className="block min-h-[80px] justify-between px-4 sm:flex sm:px-6 md:px-8">
{props.HeadingLeftIcon && <div className="ltr:mr-4">{props.HeadingLeftIcon}</div>}
<div className="mb-8 w-full">
<h1 className="font-cal mb-1 text-xl font-bold tracking-wide text-gray-900">
{props.heading}
</h1>
<p className="text-sm text-neutral-500 ltr:mr-4 rtl:ml-4">{props.subtitle}</p>
{props.heading && props.subtitle && (
<div
className={classNames(
props.large && "bg-gray-100 py-8 lg:mb-8 lg:pt-16 lg:pb-7",
"block min-h-[80px] justify-between px-4 sm:flex sm:px-6 md:px-8"
)}>
{props.HeadingLeftIcon && <div className="ltr:mr-4">{props.HeadingLeftIcon}</div>}
<div className="mb-8 w-full">
<h1 className="font-cal mb-1 text-xl font-bold tracking-wide text-gray-900">
{props.heading}
</h1>
<p className="text-sm text-neutral-500 ltr:mr-4 rtl:ml-4">{props.subtitle}</p>
</div>
{props.CTA && <div className="mb-4 flex-shrink-0">{props.CTA}</div>}
</div>
<div className="mb-4 flex-shrink-0">{props.CTA}</div>
</div>
)}
<div
className={classNames(
"px-4 sm:px-6 md:px-8",
@ -318,34 +367,36 @@ export default function Shell(props: {
{props.children}
</div>
{/* show bottom navigation for md and smaller (tablet and phones) */}
<nav className="bottom-nav fixed bottom-0 z-30 flex w-full bg-white shadow md:hidden">
{/* note(PeerRich): using flatMap instead of map to remove settings from bottom nav */}
{navigation.flatMap((item, itemIdx) =>
item.href === "/settings/profile" ? (
[]
) : (
<Link key={item.name} href={item.href}>
<a
className={classNames(
item.current ? "text-gray-900" : "text-neutral-400 hover:text-gray-700",
itemIdx === 0 ? "rounded-l-lg" : "",
itemIdx === navigation.length - 1 ? "rounded-r-lg" : "",
"group relative min-w-0 flex-1 overflow-hidden bg-white py-2 px-2 text-center text-xs font-medium hover:bg-gray-50 focus:z-10 sm:text-sm"
)}
aria-current={item.current ? "page" : undefined}>
<item.icon
{status === "authenticated" && (
<nav className="bottom-nav fixed bottom-0 z-30 flex w-full bg-white shadow md:hidden">
{/* note(PeerRich): using flatMap instead of map to remove settings from bottom nav */}
{navigation.flatMap((item, itemIdx) =>
item.href === "/settings/profile" ? (
[]
) : (
<Link key={item.name} href={item.href}>
<a
className={classNames(
item.current ? "text-gray-900" : "text-gray-400 group-hover:text-gray-500",
"mx-auto mb-1 block h-5 w-5 flex-shrink-0 text-center"
item.current ? "text-gray-900" : "text-neutral-400 hover:text-gray-700",
itemIdx === 0 ? "rounded-l-lg" : "",
itemIdx === navigation.length - 1 ? "rounded-r-lg" : "",
"group relative min-w-0 flex-1 overflow-hidden bg-white py-2 px-2 text-center text-xs font-medium hover:bg-gray-50 focus:z-10 sm:text-sm"
)}
aria-hidden="true"
/>
<span className="truncate">{item.name}</span>
</a>
</Link>
)
)}
</nav>
aria-current={item.current ? "page" : undefined}>
<item.icon
className={classNames(
item.current ? "text-gray-900" : "text-gray-400 group-hover:text-gray-500",
"mx-auto mb-1 block h-5 w-5 flex-shrink-0 text-center"
)}
aria-hidden="true"
/>
<span className="truncate">{item.name}</span>
</a>
</Link>
)
)}
</nav>
)}
{/* add padding to content for mobile navigation*/}
<div className="block pt-12 md:hidden" />
</div>

View File

@ -0,0 +1,29 @@
import { appRegistry } from "pages/apps/appRegistry";
import { useLocale } from "@lib/hooks/useLocale";
import AppCard from "./AppCard";
export default function AllApps() {
const { t } = useLocale();
const apps = appRegistry();
return (
<div className="mb-16">
<h2 className="mb-2 text-lg font-semibold text-gray-900">{t("all_apps")}</h2>
<div className="grid gap-3 grid-col-1 md:grid-cols-3">
{apps.map((app) => (
<AppCard
key={app.name}
name={app.name}
slug={app.slug}
description={app.description}
logo={app.logo}
rating={app.rating}
reviews={app.reviews}
/>
))}
</div>
</div>
);
}

View File

@ -0,0 +1,41 @@
import { StarIcon } from "@heroicons/react/solid";
import Link from "next/link";
import Button from "@components/ui/Button";
interface AppCardProps {
logo: string;
name: string;
slug?: string;
category?: string;
description: string;
rating: number;
reviews?: number;
}
export default function AppCard(props: AppCardProps) {
return (
<Link href={"/apps/" + props.slug}>
<a className="block p-5 border border-gray-300 rounded-sm hover:bg-neutral-50">
<div className="flex">
<img src={props.logo} alt={props.name + " Logo"} className="w-12 h-12 mb-4 rounded-sm" />
<Button
color="secondary"
className="flex self-start ml-auto"
onClick={() => {
// TODO: Actually add the integration
console.log("The magic is supposed to happen here");
}}>
Add
</Button>
</div>
<h3 className="font-medium">{props.name}</h3>
<div className="flex text-sm text-gray-800">
<span>{props.rating} stars</span> <StarIcon className="w-4 h-4 ml-1 text-yellow-600 mt-0.5" />
<span className="pl-1 text-gray-500">{props.reviews} reviews</span>
</div>
<p className="mt-2 text-sm text-gray-500">{props.description}</p>
</a>
</Link>
);
}

View File

@ -0,0 +1,28 @@
import { CreditCardIcon } from "@heroicons/react/outline";
import Link from "next/link";
import { useLocale } from "@lib/hooks/useLocale";
export default function AppStoreCategories(props: any) {
const { t } = useLocale();
return (
<div className="mb-16">
<h2 className="mb-2 text-lg font-semibold text-gray-900">{t("popular_categories")}</h2>
<div className="grid grid-cols-1 gap-3 md:grid-cols-3">
{props.categories.map((category: any) => (
<Link key={category.name} href={"/apps/categories/" + category.name}>
<a className="flex px-6 py-4 bg-gray-100 rounded-sm">
<div className="flex w-12 h-12 mr-4 bg-white rounded-sm">
<CreditCardIcon className="self-center w-6 h-6 mx-auto" />
</div>
<div>
<h3 className="font-medium">{category.name}</h3>
<p className="text-sm text-gray-500">{category.count} apps</p>
</div>
</a>
</Link>
))}
</div>
</div>
);
}

View File

@ -0,0 +1,72 @@
import Glide from "@glidejs/glide";
import { ArrowLeftIcon, ArrowRightIcon } from "@heroicons/react/solid";
import { appRegistry } from "pages/apps/appRegistry";
import { useEffect, useState } from "react";
import { useLocale } from "@lib/hooks/useLocale";
import useMediaQuery from "@lib/hooks/useMediaQuery";
import AppCard from "./AppCard";
export default function Slider() {
const apps = appRegistry();
const { t } = useLocale();
const isMobile = useMediaQuery("(max-width: 767px)");
const [size, setSize] = useState(3);
useEffect(() => {
if (isMobile) {
setSize(1);
} else {
setSize(3);
}
}, [isMobile]);
useEffect(() => {
new Glide(".glide", {
type: "carousel",
perView: size,
}).mount();
});
return (
<div className="mb-16">
<div className="glide">
<div className="flex cursor-default">
<div>
<h2 className="mb-2 text-lg font-semibold text-gray-900">{t("trending_apps")}</h2>
</div>
<div className="ml-auto glide__arrows" data-glide-el="controls">
<button data-glide-dir="<" className="mr-4">
<ArrowLeftIcon className="w-5 h-5 text-gray-600 hover:text-black" />
</button>
<button data-glide-dir=">">
<ArrowRightIcon className="w-5 h-5 text-gray-600 hover:text-black" />
</button>
</div>
</div>
<div className="glide__track" data-glide-el="track">
<ul className="glide__slides">
{apps.map((app) => {
return (
app.trending && (
<li key={app.name} className="glide__slide">
<AppCard
key={app.name}
name={app.name}
slug={app.slug}
description={app.description}
logo={app.logo}
rating={app.rating}
reviews={app.reviews}
/>
</li>
)
);
})}
</ul>
</div>
</div>
</div>
);
}

View File

@ -94,7 +94,7 @@ const CryptoSection = (props: CryptoSectionProps) => {
const verifyButton = useMemo(() => {
return (
<Button color="secondary" onClick={verifyWallet} type="button" id="hasToken" name="hasToken">
<img className="mr-1 h-5" src="/integrations/metamask.svg" />
<img className="mr-1 h-5" src="/apps/metamask.svg" />
{t("verify_wallet")}
</Button>
);
@ -103,7 +103,7 @@ const CryptoSection = (props: CryptoSectionProps) => {
const connectButton = useMemo(() => {
return (
<Button color="secondary" onClick={connectMetamask} type="button">
<img className="mr-1 h-5" src="/integrations/metamask.svg" />
<img className="mr-1 h-5" src="/apps/metamask.svg" />
{t("connect_metamask")}
</Button>
);
@ -118,7 +118,7 @@ const CryptoSection = (props: CryptoSectionProps) => {
await connectMetamask();
await verifyWallet();
}}>
<img className="mr-1 h-5" src="/integrations/metamask.svg" />
<img className="mr-1 h-5" src="/apps/metamask.svg" />
{t("verify_wallet")}
</Button>
);

View File

@ -2,9 +2,9 @@ import { PaymentType, Prisma } from "@prisma/client";
import Stripe from "stripe";
import { v4 as uuidv4 } from "uuid";
import { CalendarEvent } from "@lib/apps/calendar/interfaces/Calendar";
import { sendAwaitingPaymentEmail, sendOrganizerPaymentRefundFailedEmail } from "@lib/emails/email-manager";
import { getErrorFromUnknown } from "@lib/errors";
import { CalendarEvent } from "@lib/integrations/calendar/interfaces/Calendar";
import prisma from "@lib/prisma";
import { createPaymentLink } from "./client";

View File

@ -4,11 +4,11 @@ import Stripe from "stripe";
import stripe from "@ee/lib/stripe/server";
import { CalendarEvent } from "@lib/apps/calendar/interfaces/Calendar";
import { IS_PRODUCTION } from "@lib/config/constants";
import { HttpError as HttpCode } from "@lib/core/http/error";
import { getErrorFromUnknown } from "@lib/errors";
import EventManager from "@lib/events/EventManager";
import { CalendarEvent } from "@lib/integrations/calendar/interfaces/Calendar";
import prisma from "@lib/prisma";
import { getTranslation } from "@server/lib/i18n";

View File

@ -15,6 +15,7 @@ const config: Config.InitialOptions = {
"^@lib(.*)$": "<rootDir>/lib$1",
"^@server(.*)$": "<rootDir>/server$1",
"^@ee(.*)$": "<rootDir>/ee$1",
"^@apps(.*)$": "<rootDir>/lib/apps$1",
},
};

View File

@ -2,10 +2,10 @@ import { Person } from "ics";
import short from "short-uuid";
import { v5 as uuidv5 } from "uuid";
import { getIntegrationName } from "@lib/integrations";
import { getAppName } from "@lib/apps/utils/AppUtils";
import { CalendarEvent } from "./apps/calendar/interfaces/Calendar";
import { BASE_URL } from "./config/constants";
import { CalendarEvent } from "./integrations/calendar/interfaces/Calendar";
const translator = short();
@ -54,7 +54,7 @@ ${calEvent.description}
};
export const getLocation = (calEvent: CalendarEvent) => {
let providerName = calEvent.location ? getIntegrationName(calEvent.location) : "";
let providerName = calEvent.location ? getAppName(calEvent.location) : "";
if (calEvent.location && calEvent.location.includes("integrations:")) {
const location = calEvent.location.split(":")[1];

View File

@ -13,9 +13,9 @@ import { Form, TextField } from "@components/form/fields";
import { Alert } from "@components/ui/Alert";
import Button from "@components/ui/Button";
export const ADD_APPLE_INTEGRATION_FORM_TITLE = "addAppleIntegration";
export const ADD_INTEGRATION_FORM_TITLE = "addAppleIntegration";
export function AddAppleIntegrationModal(props: DialogProps) {
export function AddIntegrationModal(props: DialogProps) {
const form = useForm({
defaultValues: {
username: "",

View File

@ -0,0 +1 @@
export const APPLE_CALENDAR_URL = "https://caldav.icloud.com";

View File

@ -0,0 +1,11 @@
import { Credential } from "@prisma/client";
import { APPS_TYPES } from "../../calendar/constants/general";
import CalendarService from "../../calendar/services/CalendarService";
import { APPLE_CALENDAR_URL } from "../constants/general";
export default class AppleCalendarService extends CalendarService {
constructor(credential: Credential) {
super(credential, APPS_TYPES.apple, APPLE_CALENDAR_URL);
}
}

View File

@ -17,14 +17,15 @@ type Props = {
onSubmit: () => void;
};
export const ADD_CALDAV_INTEGRATION_FORM_TITLE = "addCalDav";
export type AddCalDavIntegrationRequest = {
export const ADD_INTEGRATION_FORM_TITLE = "addCalDav";
export type AddIntegrationRequest = {
url: string;
username: string;
password: string;
};
export function AddCalDavIntegrationModal(props: DialogProps) {
export function AddIntegrationModal(props: DialogProps) {
const form = useForm({
defaultValues: {
url: "",
@ -118,7 +119,7 @@ const AddCalDavIntegration = React.forwardRef<HTMLFormElement, Props>((props, re
};
return (
<form id={ADD_CALDAV_INTEGRATION_FORM_TITLE} ref={ref} onSubmit={onSubmit}>
<form id={ADD_INTEGRATION_FORM_TITLE} ref={ref} onSubmit={onSubmit}>
<div className="mb-2">
<label htmlFor="url" className="block text-sm font-medium text-gray-700">
Calendar URL

View File

@ -0,0 +1,10 @@
import { Credential } from "@prisma/client";
import { APPS_TYPES } from "../../calendar/constants/general";
import CalendarService from "../../calendar/services/CalendarService";
export default class CalDavCalendarService extends CalendarService {
constructor(credential: Credential) {
super(credential, APPS_TYPES.caldav);
}
}

View File

@ -13,10 +13,10 @@ import { Alert } from "@components/ui/Alert";
import Button from "@components/ui/Button";
import Switch from "@components/ui/Switch";
import ConnectIntegration from "./ConnectIntegrations";
import DisconnectIntegration from "./DisconnectIntegration";
import IntegrationListItem from "./IntegrationListItem";
import SubHeadingTitleWithConnections from "./SubHeadingTitleWithConnections";
import ConnectIntegration from "../../../../components/integrations/ConnectIntegrations";
import DisconnectIntegration from "../../../../components/integrations/DisconnectIntegration";
import IntegrationListItem from "../../../../components/integrations/IntegrationListItem";
import SubHeadingTitleWithConnections from "../../../../components/integrations/SubHeadingTitleWithConnections";
type Props = {
onChanged: () => unknown | Promise<unknown>;
@ -105,7 +105,7 @@ function ConnectedCalendarsList(props: Props) {
}
return (
<List>
{data.connectedCalendars.map((item) => (
{data.connectedCalendars.map((item: any) => (
<Fragment key={item.credentialId}>
{item.calendars ? (
<IntegrationListItem
@ -170,7 +170,7 @@ function CalendarList(props: Props) {
query={query}
success={({ data }) => (
<List>
{data.calendar.items.map((item) => (
{data.calendar.items.map((item: any) => (
<IntegrationListItem
key={item.title}
{...item}

View File

@ -0,0 +1,41 @@
import { validJson } from "../../jsonUtils";
import { App } from "../interfaces/App";
export const APPS = {
google_calendar: {
installed: !!(process.env.GOOGLE_API_CREDENTIALS && validJson(process.env.GOOGLE_API_CREDENTIALS)),
type: "google_calendar",
title: "Google Calendar",
name: "Google Calendar",
description: "For personal and business calendars",
imageSrc: "apps/google-calendar.svg",
variant: "calendar",
},
office365_calendar: {
installed: !!(process.env.MS_GRAPH_CLIENT_ID && process.env.MS_GRAPH_CLIENT_SECRET),
type: "office365_calendar",
title: "Office 365 / Outlook.com Calendar",
name: "Office 365 Calendar",
description: "For personal and business calendars",
imageSrc: "apps/outlook.svg",
variant: "calendar",
},
caldav_calendar: {
installed: true,
type: "caldav_calendar",
title: "CalDav Server",
name: "CalDav Server",
imageSrc: "apps/caldav.svg",
description: "For personal and business calendars",
variant: "calendar",
},
apple_calendar: {
installed: true,
type: "apple_calendar",
title: "Apple Calendar",
name: "Apple Calendar",
description: "For personal and business calendars",
imageSrc: "apps/apple-calendar.svg",
variant: "calendar",
},
} as Record<string, App>;

View File

@ -0,0 +1,8 @@
export const DEFAULT_CALENDAR_TYPE = "caldav";
export const APPS_TYPES = {
apple: "apple_calendar",
caldav: "caldav_calendar",
google: "google_calendar",
office365: "office365_calendar",
};

View File

@ -7,20 +7,20 @@ import { EventResult } from "@lib/events/EventManager";
import logger from "@lib/logger";
import notEmpty from "@lib/notEmpty";
import { ALL_INTEGRATIONS } from "../getIntegrations";
import { CALENDAR_INTEGRATIONS_TYPES } from "./constants/generals";
import { CalendarServiceType, EventBusyDate } from "./constants/types";
import { Calendar, CalendarEvent } from "./interfaces/Calendar";
import AppleCalendarService from "./services/AppleCalendarService";
import CalDavCalendarService from "./services/CalDavCalendarService";
import GoogleCalendarService from "./services/GoogleCalendarService";
import Office365CalendarService from "./services/Office365CalendarService";
import AppleCalendarService from "../../apple_calendar/services/CalendarService";
import CalDavCalendarService from "../../caldav_calendar/services/CalendarService";
import GoogleCalendarService from "../../google_calendar/services/CalendarService";
import Office365CalendarService from "../../office365_calendar/services/CalendarService";
import { APPS } from "../config";
import { APPS_TYPES } from "../constants/general";
import { Calendar, CalendarEvent } from "../interfaces/Calendar";
import { CalendarServiceType, EventBusyDate } from "../types/CalendarTypes";
const CALENDARS: Record<string, CalendarServiceType> = {
[CALENDAR_INTEGRATIONS_TYPES.apple]: AppleCalendarService,
[CALENDAR_INTEGRATIONS_TYPES.caldav]: CalDavCalendarService,
[CALENDAR_INTEGRATIONS_TYPES.google]: GoogleCalendarService,
[CALENDAR_INTEGRATIONS_TYPES.office365]: Office365CalendarService,
[APPS_TYPES.apple]: AppleCalendarService,
[APPS_TYPES.caldav]: CalDavCalendarService,
[APPS_TYPES.google]: GoogleCalendarService,
[APPS_TYPES.office365]: Office365CalendarService,
};
const log = logger.getChildLogger({ prefix: ["CalendarManager"] });
@ -41,7 +41,7 @@ export const getCalendarCredentials = (credentials: Array<Omit<Credential, "user
const calendarCredentials = credentials
.filter((credential) => credential.type.endsWith("_calendar"))
.flatMap((credential) => {
const integration = ALL_INTEGRATIONS.find((integration) => integration.type === credential.type);
const integration = APPS[credential.type];
const calendar = getCalendar({
...credential,

View File

@ -360,7 +360,7 @@ export default abstract class BaseCalendarService implements Calendar {
return createAccount({
account: {
serverUrl: this.url,
accountType: CALDAV_CALENDAR_TYPE,
accountType: DEFAULT_CALENDAR_TYPE,
credentials: this.credentials,
},
headers: this.headers,

View File

@ -1,10 +1,18 @@
import dayjs from "dayjs";
import ICAL from "ical.js";
import { TFunction } from "next-i18next";
import AppleCalendarService from "../services/AppleCalendarService";
import CalDavCalendarService from "../services/CalDavCalendarService";
import GoogleCalendarService from "../services/GoogleCalendarService";
import Office365CalendarService from "../services/Office365CalendarService";
import AppleCalendarService from "../../apple_calendar/services/CalendarService";
import CalDavCalendarService from "../../apple_calendar/services/CalendarService";
import GoogleCalendarService from "../../google_calendar/services/CalendarService";
import Office365CalendarService from "../../office365_calendar/services/CalendarService";
export type Person = {
name: string;
email: string;
timeZone: string;
language: { translate: TFunction; locale: string };
};
export type EventBusyDate = Record<"start" | "end", Date | string>;

View File

@ -0,0 +1,22 @@
import { App } from "../interfaces/App";
export const APPS = {
zoom_video: {
installed: !!(process.env.ZOOM_CLIENT_ID && process.env.ZOOM_CLIENT_SECRET),
type: "zoom_video",
title: "Zoom",
name: "Zoom",
description: "Video Conferencing",
imageSrc: "apps/zoom.svg",
variant: "conferencing",
},
daily_video: {
installed: !!process.env.DAILY_API_KEY,
type: "daily_video",
title: "Daily.co Video",
name: "Daily",
description: "Video Conferencing",
imageSrc: "apps/daily.svg",
variant: "conferencing",
},
} as Record<string, App>;

View File

@ -3,13 +3,13 @@ import { GetTokenResponse } from "google-auth-library/build/src/auth/oauth2clien
import { Auth, calendar_v3, google } from "googleapis";
import { getLocation, getRichDescription } from "@lib/CalEventParser";
import { CALENDAR_INTEGRATIONS_TYPES } from "@lib/integrations/calendar/constants/generals";
import logger from "@lib/logger";
import prisma from "@lib/prisma";
import { EventBusyDate, NewCalendarEventType } from "../constants/types";
import { Calendar, CalendarEvent, IntegrationCalendar } from "../interfaces/Calendar";
import CalendarService from "./BaseCalendarService";
import { APPS_TYPES } from "../../calendar/constants/general";
import { Calendar, CalendarEvent, IntegrationCalendar } from "../../calendar/interfaces/Calendar";
import CalendarService from "../../calendar/services/CalendarService";
import { EventBusyDate, NewCalendarEventType } from "../../calendar/types/CalendarTypes";
const GOOGLE_API_CREDENTIALS = process.env.GOOGLE_API_CREDENTIALS || "";
@ -20,7 +20,7 @@ export default class GoogleCalendarService implements Calendar {
private log: typeof logger;
constructor(credential: Credential) {
this.integrationName = CALENDAR_INTEGRATIONS_TYPES.google;
this.integrationName = APPS_TYPES.google;
this.auth = this.googleAuth(credential);

View File

@ -0,0 +1,21 @@
/**
* Let define an App Integration.
*
* @type - App
* @member {boolean} installed is used to indicate if the app is installed or not.
* @member {string} type is used to indicate which type the app is.
* @member {string} title is used to add a distinctive name
* @member {string} name is the app's name.
* @member {string} description is to add information about the app.
* @member {string} imageSrc is to indicate where the app's logo is located.
* @member {string} variant is to indicate to which classification the app belongs. It can be a `calendar`, `payment` or `conferencing` integration.
*/
export type App = {
installed: boolean;
type: `${string}_calendar` | `${string}_payment` | `${string}_video`;
title: string;
name: string;
description: string;
imageSrc: string;
variant: "calendar" | "payment" | "conferencing";
};

View File

@ -3,13 +3,13 @@ import { Credential } from "@prisma/client";
import { getLocation, getRichDescription } from "@lib/CalEventParser";
import { handleErrorsJson, handleErrorsRaw } from "@lib/errors";
import { CALENDAR_INTEGRATIONS_TYPES } from "@lib/integrations/calendar/constants/generals";
import logger from "@lib/logger";
import prisma from "@lib/prisma";
import { BatchResponse, EventBusyDate, NewCalendarEventType } from "../constants/types";
import { Calendar, CalendarEvent, IntegrationCalendar } from "../interfaces/Calendar";
import { BufferedBusyTime, O365AuthCredentials } from "../interfaces/Office365Calendar";
import { APPS_TYPES } from "../../calendar/constants/general";
import { Calendar, CalendarEvent, IntegrationCalendar } from "../../calendar/interfaces/Calendar";
import { BatchResponse, EventBusyDate, NewCalendarEventType } from "../../calendar/types/CalendarTypes";
import { BufferedBusyTime, O365AuthCredentials } from "../types/Office365Calendar";
const MS_GRAPH_CLIENT_ID = process.env.MS_GRAPH_CLIENT_ID || "";
const MS_GRAPH_CLIENT_SECRET = process.env.MS_GRAPH_CLIENT_SECRET || "";
@ -21,7 +21,7 @@ export default class Office365CalendarService implements Calendar {
auth: { getToken: () => Promise<string> };
constructor(credential: Credential) {
this.integrationName = CALENDAR_INTEGRATIONS_TYPES.office365;
this.integrationName = APPS_TYPES.office365;
this.auth = this.o365Auth(credential);
this.log = logger.getChildLogger({ prefix: [`[[lib] ${this.integrationName}`] });

View File

@ -0,0 +1,17 @@
import { App } from "../interfaces/App";
export const APPS = {
stripe_payment: {
installed: !!(
process.env.STRIPE_CLIENT_ID &&
process.env.NEXT_PUBLIC_STRIPE_PUBLIC_KEY &&
process.env.STRIPE_PRIVATE_KEY
),
type: "stripe_payment",
title: "Stripe",
name: "Stripe",
imageSrc: "apps/stripe.svg",
description: "Collect payments",
variant: "payment",
},
} as Record<string, App>;

View File

@ -0,0 +1,70 @@
import { Prisma } from "@prisma/client";
import _ from "lodash";
import { APPS as CalendarApps } from "@lib/apps/calendar/config";
import { APPS as ConferencingApps } from "@lib/apps/conferencing/config";
import { App } from "@lib/apps/interfaces/App";
import { APPS as PaymentApps } from "@lib/apps/payment/config";
const ALL_APPS_MAP = { ...CalendarApps, ...ConferencingApps, ...PaymentApps };
/**
* We can't use aliases in playwright tests (yet)
* https://github.com/microsoft/playwright/issues/7121
*/
const credentialData = Prisma.validator<Prisma.CredentialArgs>()({
select: { id: true, type: true },
});
type CredentialData = Prisma.CredentialGetPayload<typeof credentialData>;
export const ALL_APPS = Object.entries(ALL_APPS_MAP).map((app) => app[1]);
function getApps(userCredentials: CredentialData[]) {
const apps = ALL_APPS.map((app) => {
const credentials = userCredentials
.filter((credential) => credential.type === app.type)
.map((credential) => _.pick(credential, ["id", "type"])); // ensure we don't leak `key` to frontend
const credential: typeof credentials[number] | null = credentials[0] || null;
return {
...app,
/**
* @deprecated use `credentials`
*/
credential,
credentials,
};
});
return apps;
}
export type AppMeta = ReturnType<typeof getApps>;
export function hasIntegration(apps: AppMeta, type: string): boolean {
return !!apps.find(
(app) => app.type === type && !!app.installed && (type === "daily_video" || app.credentials.length > 0)
);
}
export function hasIntegrationInstalled(type: App["type"]): boolean {
return ALL_APPS.some((app) => app.type === type && !!app.installed);
}
export function getAppName(name: string) {
return ALL_APPS_MAP[name].name;
}
export function getAppType(name: string): string {
const type = ALL_APPS_MAP[name].type;
if (type.endsWith("_calendar")) {
return "Calendar";
}
if (type.endsWith("_payment")) {
return "Payment";
}
return "Unknown";
}
export default getApps;

View File

@ -1,3 +1,4 @@
import { CalendarEvent } from "@lib/calendar/interfaces/Calendar";
import AttendeeAwaitingPaymentEmail from "@lib/emails/templates/attendee-awaiting-payment-email";
import AttendeeCancelledEmail from "@lib/emails/templates/attendee-cancelled-email";
import AttendeeDeclinedEmail from "@lib/emails/templates/attendee-declined-email";

View File

@ -308,7 +308,7 @@ ${getRichDescription(this.calEvent)}
}
protected getLocation(): string {
let providerName = this.calEvent.location ? getIntegrationName(this.calEvent.location) : "";
let providerName = this.calEvent.location ? getAppName(this.calEvent.location) : "";
if (this.calEvent.location && this.calEvent.location.includes("integrations:")) {
const location = this.calEvent.location.split(":")[1];

View File

@ -7,9 +7,9 @@ import { createEvent, DateArray, Person } from "ics";
import nodemailer from "nodemailer";
import { getCancelLink, getRichDescription } from "@lib/CalEventParser";
import { CalendarEvent } from "@lib/apps/calendar/interfaces/Calendar";
import { getAppName } from "@lib/apps/utils/AppUtils";
import { getErrorFromUnknown } from "@lib/errors";
import { getIntegrationName } from "@lib/integrations";
import { CalendarEvent } from "@lib/integrations/calendar/interfaces/Calendar";
import { serverConfig } from "@lib/serverConfig";
import {
@ -299,7 +299,7 @@ ${getRichDescription(this.calEvent)}
}
protected getLocation(): string {
let providerName = this.calEvent.location ? getIntegrationName(this.calEvent.location) : "";
let providerName = this.calEvent.location ? getAppName(this.calEvent.location) : "";
if (this.calEvent.location && this.calEvent.location.includes("integrations:")) {
const location = this.calEvent.location.split(":")[1];

View File

@ -0,0 +1,19 @@
import { useState, useEffect } from "react";
const useMediaQuery = (query: string) => {
const [matches, setMatches] = useState(false);
useEffect(() => {
const media = window.matchMedia(query);
if (media.matches !== matches) {
setMatches(media.matches);
}
const listener = () => setMatches(media.matches);
window.addEventListener("resize", listener);
return () => window.removeEventListener("resize", listener);
}, [matches, query]);
return matches;
};
export default useMediaQuery;

View File

@ -1,10 +0,0 @@
export const CALDAV_CALENDAR_TYPE = "caldav";
export const APPLE_CALENDAR_URL = "https://caldav.icloud.com";
export const CALENDAR_INTEGRATIONS_TYPES = {
apple: "apple_calendar",
caldav: "caldav_calendar",
google: "google_calendar",
office365: "office365_calendar",
};

View File

@ -1,10 +0,0 @@
import { Credential } from "@prisma/client";
import { APPLE_CALENDAR_URL, CALENDAR_INTEGRATIONS_TYPES } from "../constants/generals";
import CalendarService from "./BaseCalendarService";
export default class AppleCalendarService extends CalendarService {
constructor(credential: Credential) {
super(credential, CALENDAR_INTEGRATIONS_TYPES.apple, APPLE_CALENDAR_URL);
}
}

View File

@ -1,10 +0,0 @@
import { Credential } from "@prisma/client";
import { CALENDAR_INTEGRATIONS_TYPES } from "../constants/generals";
import CalendarService from "./BaseCalendarService";
export default class CalDavCalendarService extends CalendarService {
constructor(credential: Credential) {
super(credential, CALENDAR_INTEGRATIONS_TYPES.caldav);
}
}

View File

@ -2,9 +2,9 @@
import { Prisma } from "@prisma/client";
import dayjs from "dayjs";
import { getBusyCalendarTimes } from "@lib/apps/calendar/managers/CalendarManager";
import { asStringOrNull } from "@lib/asStringOrNull";
import { getWorkingHours } from "@lib/availability";
import { getBusyCalendarTimes } from "@lib/integrations/calendar/CalendarManager";
import prisma from "@lib/prisma";
export async function getUserAvailability(query: {

View File

@ -1,6 +1,6 @@
import { compile } from "handlebars";
import { CalendarEvent } from "@lib/integrations/calendar/interfaces/Calendar";
import { CalendarEvent } from "@lib/apps/calendar/interfaces/Calendar";
type ContentType = "application/json" | "application/x-www-form-urlencoded";

View File

@ -5,9 +5,9 @@ import timezone from "dayjs/plugin/timezone";
import utc from "dayjs/plugin/utc";
import type { NextApiRequest, NextApiResponse } from "next";
import { getBusyCalendarTimes } from "@lib/apps/calendar/managers/CalendarManager";
import { asStringOrNull } from "@lib/asStringOrNull";
import { getWorkingHours } from "@lib/availability";
import { getBusyCalendarTimes } from "@lib/integrations/calendar/CalendarManager";
import prisma from "@lib/prisma";
dayjs.extend(utc);

View File

@ -1,7 +1,7 @@
import type { NextApiRequest, NextApiResponse } from "next";
import { getCalendarCredentials, getConnectedCalendars } from "@lib/apps/calendar/managers/CalendarManager";
import { getSession } from "@lib/auth";
import { getCalendarCredentials, getConnectedCalendars } from "@lib/integrations/calendar/CalendarManager";
import notEmpty from "@lib/notEmpty";
import prisma from "@lib/prisma";

View File

@ -11,6 +11,9 @@ import { v5 as uuidv5 } from "uuid";
import { handlePayment } from "@ee/lib/stripe/server";
import { CalendarEvent, AdditionInformation } from "@lib/apps/calendar/interfaces/Calendar";
import { getBusyCalendarTimes } from "@lib/apps/calendar/managers/CalendarManager";
import { BufferedBusyTime } from "@lib/apps/office365_calendar/types/Office365Calendar";
import {
sendScheduledEmails,
sendRescheduledEmails,
@ -20,9 +23,6 @@ import { ensureArray } from "@lib/ensureArray";
import { getErrorFromUnknown } from "@lib/errors";
import { getEventName } from "@lib/event";
import EventManager, { EventResult, PartialReference } from "@lib/events/EventManager";
import { getBusyCalendarTimes } from "@lib/integrations/calendar/CalendarManager";
import { CalendarEvent, AdditionInformation } from "@lib/integrations/calendar/interfaces/Calendar";
import { BufferedBusyTime } from "@lib/integrations/calendar/interfaces/Office365Calendar";
import logger from "@lib/logger";
import notEmpty from "@lib/notEmpty";
import prisma from "@lib/prisma";

View File

@ -5,12 +5,12 @@ import { NextApiRequest, NextApiResponse } from "next";
import { refund } from "@ee/lib/stripe/server";
import { CalendarEvent } from "@lib/apps/calendar/interfaces/Calendar";
import { getCalendar } from "@lib/apps/calendar/managers/CalendarManager";
import { asStringOrNull } from "@lib/asStringOrNull";
import { getSession } from "@lib/auth";
import { sendCancelledEmails } from "@lib/emails/email-manager";
import { FAKE_DAILY_CREDENTIAL } from "@lib/integrations/Daily/DailyVideoApiAdapter";
import { getCalendar } from "@lib/integrations/calendar/CalendarManager";
import { CalendarEvent } from "@lib/integrations/calendar/interfaces/Calendar";
import prisma from "@lib/prisma";
import { deleteMeeting } from "@lib/videoClient";
import sendPayload from "@lib/webhooks/sendPayload";
@ -158,7 +158,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
bookingToDelete.user.credentials.push(FAKE_DAILY_CREDENTIAL);
}
const apiDeletes = async.mapLimit(bookingToDelete.user.credentials, 5, async (credential) => {
const apiDeletes = async.mapLimit(bookingToDelete.user.credentials, 5, async (credential: any) => {
const bookingRefUid = bookingToDelete.references.filter((ref) => ref.type === credential.type)[0]?.uid;
if (bookingRefUid) {
if (credential.type.endsWith("_calendar")) {

View File

@ -2,8 +2,8 @@ import { ReminderType } from "@prisma/client";
import dayjs from "dayjs";
import type { NextApiRequest, NextApiResponse } from "next";
import { CalendarEvent } from "@lib/apps/calendar/interfaces/Calendar";
import { sendOrganizerRequestReminderEmail } from "@lib/emails/email-manager";
import { CalendarEvent } from "@lib/integrations/calendar/interfaces/Calendar";
import prisma from "@lib/prisma";
import { getTranslation } from "@server/lib/i18n";

View File

@ -1,8 +1,8 @@
import type { NextApiRequest, NextApiResponse } from "next";
import { getCalendar } from "@lib/apps/calendar/managers/CalendarManager";
import { getSession } from "@lib/auth";
import { symmetricEncrypt } from "@lib/crypto";
import { getCalendar } from "@lib/integrations/calendar/CalendarManager";
import logger from "@lib/logger";
import prisma from "@lib/prisma";

View File

@ -1,8 +1,8 @@
import type { NextApiRequest, NextApiResponse } from "next";
import { getCalendar } from "@lib/apps/calendar/managers/CalendarManager";
import { getSession } from "@lib/auth";
import { symmetricEncrypt } from "@lib/crypto";
import { getCalendar } from "@lib/integrations/calendar/CalendarManager";
import logger from "@lib/logger";
import prisma from "@lib/prisma";

View File

@ -0,0 +1,92 @@
// TODO: maybe we wanna do this dynamically later based on folder structure
export function appRegistry() {
return [
{
name: "Zoom",
slug: "zoom", // needs to be the same as the folder name
category: "Video Conferencing",
description:
"Zoom is the most popular video conferencing platform, joinable on the web or via desktop/mobile apps.",
logo: "/apps/zoom.svg",
publisher: "Cal.com",
url: "https://zoom.us/",
verified: true,
rating: 4.3, // TODO: placeholder for now, pull this from TrustPilot or G2
reviews: 69, // TODO: placeholder for now, pull this from TrustPilot or G2
},
{
name: "Cal Video",
slug: "cal-video",
category: "Video Conferencing",
description:
"Cal Video is the in-house web-based video conferencing platform powered by Daily.co, which is minimalistic and lightweight, but has most of the features you need.",
logo: "/apps/daily.svg",
publisher: "Cal.com",
url: "https://cal.com",
verified: true,
rating: 4.8,
trending: true,
reviews: 69,
},
{
name: "Google Meet",
slug: "google-meet",
category: "Video Conferencing",
description:
"Google Meet is Google's web-based video conferencing platform, designed to compete with major conferencing platforms.",
logo: "https://cdn.iconscout.com/icon/free/png-256/google-meet-2923654-2416657.png",
rating: 4.4,
trending: true,
reviews: 69,
},
{
name: "Stripe",
slug: "stripe",
category: "Payments",
description: "Stripe is the world's leading payment provider. Start charging for your bookings today.",
logo: "/apps/stripe.svg",
rating: 4.6,
trending: true,
reviews: 69,
},
{
name: "Google Calendar",
slug: "google-calendar",
category: "Calendar",
description:
"Google Calendar is the most popular calendar platform for personal and business calendars.",
logo: "/apps/google-calendar.svg",
rating: 4.9,
reviews: 69,
},
{
name: "Microsoft 365/Outlook Calendar",
slug: "microsoft-365",
category: "Calendar",
description:
"Microsoft 365 calendars for business users, and Outlook is a popular calendar platform for personal users.",
logo: "/apps/outlook.svg",
rating: 4.2,
reviews: 69,
},
{
name: "CalDAV",
slug: "caldav",
category: "Calendar",
description: "CalDAV is an open calendar standard which connects to virtually every calendar.",
logo: "/apps/caldav.svg",
rating: 3.6,
reviews: 69,
},
{
name: "iCloud Calendar",
slug: "icloud-calendar",
category: "Calendar",
description:
"iCloud Calendar is Apple's calendar platform for users of iCloud, and is used in the Apple Calendar app on iOS and macOS.",
logo: "/apps/apple-calendar.svg",
rating: 3.8,
reviews: 69,
},
];
}

View File

@ -0,0 +1,48 @@
import { ChevronLeftIcon } from "@heroicons/react/solid";
import { useRouter } from "next/router";
import { useLocale } from "@lib/hooks/useLocale";
import Shell from "@components/Shell";
import AppCard from "@components/apps/AppCard";
import Button from "@components/ui/Button";
import { appRegistry } from "../appRegistry";
export default function Apps() {
const { t } = useLocale();
const router = useRouter();
const apps = appRegistry();
return (
<Shell
heading={router.query.category + " - " + t("app_store")}
subtitle={t("app_store_description")}
large>
<div className="mb-8">
<Button color="secondary" href="/apps">
<ChevronLeftIcon className="w-5 h-5" />
</Button>
</div>
<div className="mb-16">
<h2 className="mb-2 text-lg font-semibold text-gray-900">All {router.query.category} apps</h2>
<div className="grid grid-cols-3 gap-3">
{apps.map((app) => {
return (
app.category === router.query.category && (
<AppCard
key={app.name}
slug={app.slug}
name={app.name}
description={app.description}
logo={app.logo}
rating={app.rating}
/>
)
);
})}
</div>
</div>
</Shell>
);
}

View File

@ -0,0 +1,36 @@
import { useLocale } from "@lib/hooks/useLocale";
import AppsShell from "@components/AppsShell";
import Shell from "@components/Shell";
import AllApps from "@components/apps/AllApps";
import AppStoreCategories from "@components/apps/Categories";
import Slider from "@components/apps/Slider";
export default function Apps() {
const { t } = useLocale();
const popularCategories = [
{
name: "Payments",
count: 1,
},
{
name: "Video",
count: 3,
},
{
name: "Calendar",
count: 4,
},
];
return (
<Shell heading={t("app_store")} subtitle={t("app_store_description")} large>
<AppsShell>
<AppStoreCategories categories={popularCategories} />
<Slider />
<AllApps />
</AppsShell>
</Shell>
);
}

View File

@ -22,7 +22,6 @@ import Shell, { ShellSubHeading } from "@components/Shell";
import { Tooltip } from "@components/Tooltip";
import ConfirmationDialogContent from "@components/dialog/ConfirmationDialogContent";
import { FieldsetLegend, Form, InputGroupBox, TextField, TextArea } from "@components/form/fields";
import { CalendarListContainer } from "@components/integrations/CalendarListContainer";
import ConnectIntegration from "@components/integrations/ConnectIntegrations";
import DisconnectIntegration from "@components/integrations/DisconnectIntegration";
import IntegrationListItem from "@components/integrations/IntegrationListItem";
@ -31,6 +30,8 @@ import { Alert } from "@components/ui/Alert";
import Button from "@components/ui/Button";
import Switch from "@components/ui/Switch";
import { CalendarListContainer } from "../../lib/apps/calendar/components/CalendarListContainer";
type TWebhook = inferQueryOutput<"viewer.webhook.list">[number];
function WebhookListItem(props: { webhook: TWebhook; onEditWebhook: () => void }) {
@ -653,7 +654,7 @@ export default function IntegrationsPage() {
const { t } = useLocale();
return (
<Shell heading={t("integrations")} subtitle={t("connect_your_favourite_apps")}>
<Shell heading={t("installed_apps")} subtitle={t("manage_your_connected_apps")}>
<ClientSuspense fallback={<Loader />}>
<IntegrationsContainer />
<CalendarListContainer />

View File

@ -0,0 +1,117 @@
import showToast from "@lib/notification";
import App from "@components/App";
export default function NukeMyCal() {
return (
<App
name="Nuke my Cal"
logo="/apps/nuke-my-cal.svg"
categories={["fun", "productivity"]}
author="/peer"
type="free" // "usage-based", "monthly", "one-time" or "free"
price={0} // 0 = free. if type="usage-based" it's the price per booking
commission={0} // only required for "usage-based" billing. % of commission for paid bookings
website="https://cal.com"
email="help@cal.com"
tos="https://cal.com/terms"
privacy="https://cal.com/privacy"
body={
<>
<style jsx>
{`
.pushable {
position: relative;
border: none;
background: transparent;
padding: 0;
cursor: pointer;
outline-offset: 4px;
transition: filter 250ms;
}
.shadow {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
border-radius: 12px;
background: hsl(0deg 0% 0% / 0.25);
will-change: transform;
transform: translateY(2px);
transition: transform 600ms cubic-bezier(0.3, 0.7, 0.4, 1);
}
.edge {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
border-radius: 12px;
background: linear-gradient(
to left,
hsl(340deg 100% 16%) 0%,
hsl(340deg 100% 32%) 8%,
hsl(340deg 100% 32%) 92%,
hsl(340deg 100% 16%) 100%
);
}
.front {
display: block;
position: relative;
padding: 12px 42px;
border-radius: 12px;
font-size: 1.25rem;
color: white;
background: hsl(345deg 100% 47%);
will-change: transform;
transform: translateY(-4px);
transition: transform 600ms cubic-bezier(0.3, 0.7, 0.4, 1);
}
.pushable:hover {
filter: brightness(110%);
}
.pushable:hover .front {
transform: translateY(-6px);
transition: transform 250ms cubic-bezier(0.3, 0.7, 0.4, 1.5);
}
.pushable:active .front {
transform: translateY(-2px);
transition: transform 34ms;
}
.pushable:hover .shadow {
transform: translateY(4px);
transition: transform 250ms cubic-bezier(0.3, 0.7, 0.4, 1.5);
}
.pushable:active .shadow {
transform: translateY(1px);
transition: transform 34ms;
}
.pushable:focus:not(:focus-visible) {
outline: none;
}
`}
</style>
<div>
Have an emergency? Need to reschedule all of your upcoming calendar events? Just click{" "}
<strong>Nuke my Cal</strong> and auto-reschedule the entire day. Give it a try!
<br />
<br />
Demo: <br />
<br />
</div>
<button
onClick={() => (
new Audio("/apps/nuke-my-cal.wav").play(),
showToast("All of your calendar events for today have been rescheduled", "success")
)}
className="pushable">
<span className="shadow"></span>
<span className="edge"></span>
<span className="front">Nuke my Cal</span>
</button>
</>
}
/>
);
}

View File

@ -0,0 +1,30 @@
import App from "@components/App";
export default function Stripe() {
return (
<App
name="Stripe"
logo="/apps/stripe.svg"
categories={["payments"]}
author="Cal.com"
type="usage-based" // "usage-based" or "monthly" or "one-time"
price={0.1} // price per installation. if "monthly" = price per month. if type="usage-based" = price per booking
commission={0} // only required for "usage-based" billing. % of commission for paid bookings
docs="https://stripe.com/docs"
website="https://zoom.us"
email="support@zoom.us"
tos="https://zoom.us/terms"
privacy="https://zoom.us/privacy"
body={
<>
Stripe provides payments infrastructure for the internet. Millions of businesses of all sizesfrom
startups to large enterprisesuse Stripe&apos;s software and APIs to accept payments, send payouts,
and manage their businesses online.
<br />
<br />
Use this Stripe App, build by the Cal.com team to start charging for your bookings today.
</>
}
/>
);
}

View File

@ -0,0 +1,31 @@
import App from "@components/App";
export default function Zoom() {
return (
<App
name="Zoom"
logo="/apps/zoom.svg"
categories={["video", "communication"]}
author="Cal.com"
type="usage-based" // "usage-based" or "monthly" or "one-time"
price={0} // 0 = free. if type="usage-based" it's the price per booking
commission={0.5} // only required for "usage-based" billing. % of commission for paid bookings
docs="https://zoom.us/download"
website="https://zoom.us"
email="support@zoom.us"
tos="https://zoom.us/terms"
privacy="https://zoom.us/privacy"
body={
<>
Start Zoom Meetings and make Zoom Phone calls with flawless video, crystal clear audio, and instant
screen sharing from any Slack channel, private group, or direct message using the /zoom slash
command.
<br />
<br />
The Zoom app for Slack can be installed individually by any Slack user with a Zoom account or be
deployed to the whole organization centrally by the Zoom account admin with a few simple steps.
</>
}
/>
);
}

View File

@ -28,11 +28,11 @@ import { JSONObject } from "superjson/dist/types";
import { StripeData } from "@ee/lib/stripe/server";
import getApps, { hasIntegration } from "@lib/apps/utils/AppUtils";
import { asStringOrThrow, asStringOrUndefined } from "@lib/asStringOrNull";
import { getSession } from "@lib/auth";
import { HttpError } from "@lib/core/http/error";
import { useLocale } from "@lib/hooks/useLocale";
import getIntegrations, { hasIntegration } from "@lib/integrations/getIntegrations";
import { LocationType } from "@lib/location";
import showToast from "@lib/notification";
import prisma from "@lib/prisma";
@ -1664,7 +1664,7 @@ export const getServerSideProps = async (context: GetServerSidePropsContext) =>
eventType.users.push(fallbackUser);
}
const integrations = getIntegrations(credentials);
const integrations = getApps(credentials);
const locationOptions: OptionTypeBase[] = [];

View File

@ -21,8 +21,6 @@ import { asStringOrNull } from "@lib/asStringOrNull";
import { getSession } from "@lib/auth";
import { DEFAULT_SCHEDULE } from "@lib/availability";
import { useLocale } from "@lib/hooks/useLocale";
import { getCalendarCredentials, getConnectedCalendars } from "@lib/integrations/calendar/CalendarManager";
import getIntegrations from "@lib/integrations/getIntegrations";
import prisma from "@lib/prisma";
import { collectPageParameters, telemetryEventTypes, useTelemetry } from "@lib/telemetry";
import { trpc } from "@lib/trpc";
@ -32,12 +30,14 @@ import { Schedule as ScheduleType } from "@lib/types/schedule";
import { ClientSuspense } from "@components/ClientSuspense";
import Loader from "@components/Loader";
import { Form } from "@components/form/fields";
import { CalendarListContainer } from "@components/integrations/CalendarListContainer";
import { Alert } from "@components/ui/Alert";
import Button from "@components/ui/Button";
import Text from "@components/ui/Text";
import Schedule from "@components/ui/form/Schedule";
import { CalendarListContainer } from "../lib/apps/calendar/components/CalendarListContainer";
import { getCalendarCredentials, getConnectedCalendars } from "../lib/apps/calendar/managers/CalendarManager";
import getApps from "../lib/apps/utils/AppUtils";
import getEventTypes from "../lib/queries/event-types/get-event-types";
dayjs.extend(utc);

View File

@ -1,9 +0,0 @@
function RedirectPage() {
return null;
}
export async function getServerSideProps() {
return { redirect: { permanent: false, destination: "/integrations" } };
}
export default RedirectPage;

View File

@ -1,6 +1,6 @@
import { expect, test } from "@playwright/test";
import { hasIntegrationInstalled } from "../lib/integrations/getIntegrations";
import { hasIntegrationInstalled } from "../lib/apps/utils/AppUtils";
import { todo } from "./lib/testUtils";
test.describe.serial("Stripe integration", () => {

View File

Before

Width:  |  Height:  |  Size: 3.0 KiB

After

Width:  |  Height:  |  Size: 3.0 KiB

View File

Before

Width:  |  Height:  |  Size: 264 B

After

Width:  |  Height:  |  Size: 264 B

View File

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 16 KiB

View File

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

Before

Width:  |  Height:  |  Size: 3.9 KiB

After

Width:  |  Height:  |  Size: 3.9 KiB

View File

Before

Width:  |  Height:  |  Size: 4.5 KiB

After

Width:  |  Height:  |  Size: 4.5 KiB

View File

@ -0,0 +1,77 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:cc="http://web.resource.org/cc/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" version="1.1" width="720" height="720" id="svg2">
<defs id="defs4">
<inkscape:path-effect effect="spiro" id="path-effect3201"/>
<inkscape:path-effect effect="spiro" id="path-effect3197"/>
<inkscape:path-effect effect="spiro" id="path-effect3193"/>
<inkscape:path-effect effect="spiro" id="path-effect3189"/>
<inkscape:path-effect effect="spiro" id="path-effect3185"/>
<inkscape:path-effect effect="spiro" id="path-effect3181"/>
<inkscape:path-effect effect="spiro" id="path-effect3177"/>
<inkscape:path-effect effect="spiro" id="path-effect3173"/>
<inkscape:path-effect effect="spiro" id="path-effect3169"/>
<inkscape:path-effect effect="spiro" id="path-effect3165"/>
<inkscape:path-effect effect="spiro" id="path-effect3161"/>
<inkscape:path-effect effect="spiro" id="path-effect3157"/>
<inkscape:path-effect effect="spiro" id="path-effect3153"/>
<inkscape:path-effect effect="spiro" id="path-effect3149"/>
<inkscape:path-effect effect="spiro" id="path-effect3149-6"/>
<inkscape:path-effect effect="spiro" id="path-effect3153-1"/>
<inkscape:path-effect effect="spiro" id="path-effect3157-8"/>
<inkscape:path-effect effect="spiro" id="path-effect3161-4"/>
<inkscape:path-effect effect="spiro" id="path-effect3165-8"/>
<inkscape:path-effect effect="spiro" id="path-effect3169-4"/>
<inkscape:path-effect effect="spiro" id="path-effect3173-0"/>
<inkscape:path-effect effect="spiro" id="path-effect3177-7"/>
<inkscape:path-effect effect="spiro" id="path-effect3181-6"/>
<inkscape:path-effect effect="spiro" id="path-effect3185-8"/>
<inkscape:path-effect effect="spiro" id="path-effect3189-9"/>
<inkscape:path-effect effect="spiro" id="path-effect3193-7"/>
<inkscape:path-effect effect="spiro" id="path-effect3197-3"/>
<inkscape:path-effect effect="spiro" id="path-effect3201-3"/>
</defs>
<path d="m 329.6885371631169,144.9454094414912 c 0,0 -9.3691648630806,-18.5615530306314 -37.6534361478519,-6.3639610390736" id="path2983" style="fill:none;stroke:#ff0000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;display:none"/>
<path d="m 326.8905349710195,144.9454094414912 c 0,0 -9.3691648630806,-18.5615530306314 -37.6534361478519,-6.3639610390736" id="path2983-8" style="fill:none;stroke:#ff0000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;display:none"/>
<path d="M 94.6324614631855,36.00250586938022 300.1705854663462,193.5309023590188 342.0166705927379,44.6173400524073 401.0934966535268,195.9922835541695 564.785535530295,54.46286483300981 476.1702964391128,237.8357638717294 616.4777583334849,232.9130014814282 525.4009848231031,347.3672270559314 647.2469385734796,426.1314253007506 502.0164078407082,428.5928064959011 630.0161976390828,582.4291311928135 446.6318834087184,497.5114799601184 426.9396080551219,662.4240200352077 337.0936017543393,529.5094354970756 211.5553463751634,700.5754285600419 223.863018471161,486.4352645819405 52.7863763367938,520.8946013140482 159.8631235719732,380.5958731904649 72.47865169038992,237.8357638717299 194.3246054407665,261.2188852256607 94.6324614631855,36.00250586938069 z" id="path3508" style="fill:#ff0000;stroke:none"/>
<path d="m 160.1985233083172,118.7982717399246 154.3242216264676,118.2770704473064 31.419302606586,-111.8087931572194 44.3566625034159,113.6568723829586 122.9049190198811,-106.2645554800019 -66.5349937551232,137.6819023175674 105.347073445612,-3.6961584514783 -68.3831880260988,85.9356839968712 91.4856164132948,59.1385352236531 -109.0434619875631,1.8480792257391 96.1061020907337,115.5049516086972 -137.6904731876862,-63.7587332880004 -14.7855541678056,123.8213081245232 -67.4590908906114,-99.7962781899145 -94.2579078197586,128.4415061888714 9.2409713548783,-160.7828926393062 -128.4495018328083,25.8731091603477 80.3964507874411,-105.3405158671315 -65.6108966196359,-107.1885950928715 91.4856164132951,17.5567526445221 -74.8518679745143,-169.0992491551333 z" id="path3512" style="fill:#ff8000;stroke:none"/>
<path d="m 226.2365903979516,204.2096633100054 99.1022747159463,75.9539014973134 20.1765110200129,-71.8001725091792 28.4844861459008,72.9869522200746 78.9257636959331,-68.2398333764925 -42.7267292188508,88.4150884617163 67.6506545965139,-2.373559421791 -43.9135828082631,55.1852565566419 58.7492526759201,37.9769507486567 -70.0243617753388,1.1867797108955 61.7163866494512,74.17373193097 -88.4205924112332,-40.9439000258953 -9.4948287153004,79.5142406299997 -43.3201560135574,-64.0861043883581 -60.529533060039,82.4811899072385 5.9342679470626,-103.2498348479099 -82.4863244641708,16.614915952537 51.6281311394449,-67.6464435210443 -42.1333024241446,-68.8332232319403 58.7492526759201,11.2744072535075 -48.0675703712075,-108.5903435469403 z" id="path3514" style="fill:#ffff00;stroke:none"/>
<path d="m -57.96064186096192,305.2593994140625 a 30.91234397888183,30.91234397888183 0 1 1 -61.82468795776368,0 30.91234397888183,30.91234397888183 0 1 1 61.82468795776368,0 z" transform="translate(435.3488372093023,54.09660107334526)" id="path3516" style="fill:#000000;fill-opacity:1;stroke:none"/>
<metadata>
<rdf:RDF>
<cc:Work>
<dc:format>image/svg+xml</dc:format>
<dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/>
<cc:license rdf:resource="http://creativecommons.org/licenses/publicdomain/"/>
<dc:publisher>
<cc:Agent rdf:about="http://openclipart.org/">
<dc:title>Open Clip Art Library</dc:title>
</cc:Agent>
</dc:publisher>
<dc:title>one eyed sun</dc:title>
<dc:date>2011-07-10T22:19:30</dc:date>
<dc:description>my mom came up with the name for this!</dc:description>
<dc:source>http://openclipart.org/detail/148927/one-eyed-sun-by-10binary</dc:source>
<dc:creator>
<cc:Agent>
<dc:title>10binary</dc:title>
</cc:Agent>
</dc:creator>
<dc:subject>
<rdf:Bag>
<rdf:li>clip art</rdf:li>
<rdf:li>clipart</rdf:li>
<rdf:li>eyed</rdf:li>
<rdf:li>one</rdf:li>
<rdf:li>sun</rdf:li>
</rdf:Bag>
</dc:subject>
</cc:Work>
<cc:License rdf:about="http://creativecommons.org/licenses/publicdomain/">
<cc:permits rdf:resource="http://creativecommons.org/ns#Reproduction"/>
<cc:permits rdf:resource="http://creativecommons.org/ns#Distribution"/>
<cc:permits rdf:resource="http://creativecommons.org/ns#DerivativeWorks"/>
</cc:License>
</rdf:RDF>
</metadata>
</svg>

After

Width:  |  Height:  |  Size: 6.9 KiB

View File

Before

Width:  |  Height:  |  Size: 7.1 KiB

After

Width:  |  Height:  |  Size: 7.1 KiB

View File

Before

Width:  |  Height:  |  Size: 509 B

After

Width:  |  Height:  |  Size: 509 B

View File

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

Before

Width:  |  Height:  |  Size: 1.9 KiB

After

Width:  |  Height:  |  Size: 1.9 KiB

View File

Before

Width:  |  Height:  |  Size: 981 B

After

Width:  |  Height:  |  Size: 981 B

View File

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@ -1,18 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 25.2.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" x="0px" y="0px"
viewBox="0 0 29.2 33" style="enable-background:new 0 0 29.2 33;" xml:space="preserve">
<style type="text/css">
.st0{fill:#F68D2E;}
</style>
<path class="st0" d="M27.2,18.5c-1.5-0.9-3.3-0.8-4.7,0.2c-0.3,0.2-0.6,0.2-0.9,0l-4.2-2.4c-0.1,0-0.1-0.1,0-0.1c0,0,0,0,0,0
l4.2-2.4c0.3-0.2,0.7-0.1,0.9,0.1c1.4,1,3.2,1.1,4.7,0.2c1.9-1.2,2.6-3.7,1.5-5.7c-1.1-2.1-3.7-2.8-5.8-1.7
c-1.5,0.8-2.4,2.4-2.2,4.1c0,0.3-0.1,0.7-0.4,0.8L16,13.9c-0.1,0-0.1,0-0.1,0c0,0,0,0,0-0.1V8.9c0-0.3,0.2-0.6,0.5-0.8
c2.1-1,3.1-3.5,2.1-5.7S15-0.6,12.8,0.4S9.7,3.9,10.7,6c0.4,0.9,1.2,1.7,2.1,2.1c0.3,0.1,0.5,0.4,0.5,0.8v4.9c0,0.1,0,0.1-0.1,0.1
c0,0,0,0-0.1,0l-4.2-2.4c-0.3-0.2-0.5-0.5-0.4-0.8C8.7,8.3,7,6.2,4.6,6S0.2,7.6,0,9.9s1.5,4.4,3.9,4.6c1,0.1,2-0.2,2.9-0.8
c0.3-0.2,0.6-0.2,0.9-0.1l4.2,2.4c0.1,0,0.1,0.1,0,0.1c0,0,0,0,0,0l-4.2,2.4c-0.3,0.2-0.7,0.1-0.9,0c-1.4-1-3.2-1-4.7-0.2
c-1.9,1.2-2.6,3.7-1.5,5.7c1.1,2.1,3.7,2.8,5.8,1.7c1.5-0.8,2.4-2.4,2.2-4.1c0-0.3,0.1-0.7,0.4-0.8l4.2-2.4c0.1,0,0.1,0,0.1,0
c0,0,0,0,0,0.1v4.9c0,0.3-0.2,0.6-0.5,0.8c-2.1,1-3.1,3.5-2.1,5.7s3.5,3.1,5.7,2.1c2.1-1,3.1-3.5,2.1-5.7c-0.4-0.9-1.2-1.7-2.1-2.1
c-0.3-0.1-0.5-0.4-0.5-0.8v-4.9c0-0.1,0-0.1,0.1-0.1c0,0,0,0,0.1,0l4.2,2.4c0.3,0.2,0.5,0.5,0.4,0.8c-0.2,2.3,1.5,4.4,3.9,4.6
c1.7,0.2,3.3-0.7,4.1-2.2C29.8,22.2,29.1,19.7,27.2,18.5L27.2,18.5z"/>
</svg>

Before

Width:  |  Height:  |  Size: 1.5 KiB

View File

@ -594,6 +594,9 @@
"confirm_delete_account": "Yes, delete account",
"delete_account_confirmation_message": "Are you sure you want to delete your Cal.com account? Anyone who you've shared your account link with will no longer be able to book using it and any preferences you have saved will be lost.",
"integrations": "Integrations",
"apps": "Apps",
"app_store": "App Store",
"app_store_description": "Connecting people, technology and the workplace.",
"settings": "Settings",
"event_type_moved_successfully": "Event type has been moved successfully",
"next_step": "Skip step",
@ -641,6 +644,24 @@
"import_from": "Import from",
"access_token": "Access token",
"visit_roadmap": "Roadmap",
"popular_categories": "Popular Categories",
"trending_apps": "Trending Apps",
"all_apps": "All Apps",
"installed_apps": "Installed Apps",
"manage_your_connected_apps": "Manage your connected apps",
"browse_apps": "Browse Apps",
"features": "Features",
"permissions": "Permissions",
"terms_and_privacy": "Terms and Privacy",
"build_by": "Build by {{author}}",
"subscribe": "Subscribe",
"buy": "Buy",
"install_app": "Install App",
"categories": "Categories",
"pricing": "Pricing",
"learn_more": "Learn more",
"privacy_policy": "Privacy Policy",
"terms_of_service": "Terms of Service",
"remove": "Remove",
"add": "Add",
"verify_wallet": "Verify Wallet",

View File

@ -5,9 +5,8 @@ import { z } from "zod";
import { checkPremiumUsername } from "@ee/lib/core/checkPremiumUsername";
import { ALL_APPS } from "@lib/apps/utils/AppUtils";
import { checkRegularUsername } from "@lib/core/checkRegularUsername";
import { getCalendarCredentials, getConnectedCalendars } from "@lib/integrations/calendar/CalendarManager";
import { ALL_INTEGRATIONS } from "@lib/integrations/getIntegrations";
import jackson from "@lib/jackson";
import {
isSAMLLoginEnabled,
@ -24,6 +23,10 @@ import { Schedule } from "@lib/types/schedule";
import { eventTypesRouter } from "@server/routers/viewer/eventTypes";
import { TRPCError } from "@trpc/server";
import {
getCalendarCredentials,
getConnectedCalendars,
} from "../../lib/apps/calendar/managers/CalendarManager";
import { createProtectedRouter, createRouter } from "../createRouter";
import { resizeBase64Image } from "../lib/resizeBase64Image";
import { viewerTeamsRouter } from "./viewer/teams";
@ -511,16 +514,16 @@ const loggedInViewerRouter = createProtectedRouter()
function countActive(items: { credentialIds: unknown[] }[]) {
return items.reduce((acc, item) => acc + item.credentialIds.length, 0);
}
const integrations = ALL_INTEGRATIONS.map((integration) => ({
...integration,
const apps = ALL_APPS.map((app) => ({
...app,
credentialIds: credentials
.filter((credential) => credential.type === integration.type)
.filter((credential) => credential.type === app.type)
.map((credential) => credential.id),
}));
// `flatMap()` these work like `.filter()` but infers the types correctly
const conferencing = integrations.flatMap((item) => (item.variant === "conferencing" ? [item] : []));
const payment = integrations.flatMap((item) => (item.variant === "payment" ? [item] : []));
const calendar = integrations.flatMap((item) => (item.variant === "calendar" ? [item] : []));
const conferencing = apps.flatMap((item) => (item.variant === "conferencing" ? [item] : []));
const payment = apps.flatMap((item) => (item.variant === "payment" ? [item] : []));
const calendar = apps.flatMap((item) => (item.variant === "calendar" ? [item] : []));
return {
conferencing: {

View File

@ -114,5 +114,5 @@
@font-face {
font-family: "Cal Sans";
src: url("/cal.ttf");
src: url("/CalSans-SemiBold.woff2");
}

View File

@ -2,6 +2,9 @@
@tailwind components;
@tailwind utilities;
@import "../node_modules/@glidejs/glide/dist/css/glide.core.min.css";
@import "../node_modules/@glidejs/glide/dist/css/glide.theme.min.css";
:root {
--brand-color: #292929;
--brand-text-color: #ffffff;

View File

@ -131,5 +131,5 @@ module.exports = {
}),
},
},
plugins: [require("@tailwindcss/forms")],
plugins: [require("@tailwindcss/forms"), require("@tailwindcss/typography")],
};

File diff suppressed because it is too large Load Diff

796
apps/web/yarn.lock.rej Normal file
View File

@ -0,0 +1,796 @@
diff a/apps/web/yarn.lock b/apps/web/yarn.lock (rejected hunks)
@@ -94,187 +73,132 @@
jsesc "^2.5.1"
source-map "^0.5.0"
-"@babel/generator@^7.13.0", "@babel/generator@^7.13.9", "@babel/generator@^7.16.0":
- version "7.16.0"
- resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.16.0.tgz#d40f3d1d5075e62d3500bccb67f3daa8a95265b2"
- integrity sha512-RR8hUCfRQn9j9RPKEVXo9LiwoxLPYn6hNZlvUOR8tSnaxlD0p0+la00ZP9/SnRt6HchKr+X0fO2r8vrETiJGew==
+"@babel/generator@^7.13.0", "@babel/generator@^7.13.9", "@babel/generator@^7.16.8":
+ version "7.16.8"
+ resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.16.8.tgz#359d44d966b8cd059d543250ce79596f792f2ebe"
+ integrity sha512-1ojZwE9+lOXzcWdWmO6TbUzDfqLD39CmEhN8+2cX9XkDo5yW1OpgfejfliysR2AWLpMamTiOiAp/mtroaymhpw==
dependencies:
- "@babel/types" "^7.16.0"
+ "@babel/types" "^7.16.8"
jsesc "^2.5.1"
source-map "^0.5.0"
-"@babel/generator@^7.16.5":
- version "7.16.5"
- resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.16.5.tgz#26e1192eb8f78e0a3acaf3eede3c6fc96d22bedf"
- integrity sha512-kIvCdjZqcdKqoDbVVdt5R99icaRtrtYhYK/xux5qiWCBmfdvEYMFZ68QCrpE5cbFM1JsuArUNs1ZkuKtTtUcZA==
- dependencies:
- "@babel/types" "^7.16.0"
- jsesc "^2.5.1"
- source-map "^0.5.0"
-
-"@babel/helper-annotate-as-pure@^7.16.0":
- version "7.16.0"
- resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.16.0.tgz#9a1f0ebcda53d9a2d00108c4ceace6a5d5f1f08d"
- integrity sha512-ItmYF9vR4zA8cByDocY05o0LGUkp1zhbTQOH1NFyl5xXEqlTJQCEJjieriw+aFpxo16swMxUnUiKS7a/r4vtHg==
- dependencies:
- "@babel/types" "^7.16.0"
-
-"@babel/helper-compilation-targets@^7.13.10", "@babel/helper-compilation-targets@^7.16.0":
- version "7.16.0"
- resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.16.0.tgz#01d615762e796c17952c29e3ede9d6de07d235a8"
- integrity sha512-S7iaOT1SYlqK0sQaCi21RX4+13hmdmnxIEAnQUB/eh7GeAnRjOUgTYpLkUOiRXzD+yog1JxP0qyAQZ7ZxVxLVg==
+"@babel/helper-annotate-as-pure@^7.16.7":
+ version "7.16.7"
+ resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.16.7.tgz#bb2339a7534a9c128e3102024c60760a3a7f3862"
+ integrity sha512-s6t2w/IPQVTAET1HitoowRGXooX8mCgtuP5195wD/QJPV6wYjpujCGF7JuMODVX2ZAJOf1GT6DT9MHEZvLOFSw==
dependencies:
- "@babel/compat-data" "^7.16.0"
- "@babel/helper-validator-option" "^7.14.5"
- browserslist "^4.16.6"
- semver "^6.3.0"
+ "@babel/types" "^7.16.7"
-"@babel/helper-compilation-targets@^7.16.3":
- version "7.16.3"
- resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.16.3.tgz#5b480cd13f68363df6ec4dc8ac8e2da11363cbf0"
- integrity sha512-vKsoSQAyBmxS35JUOOt+07cLc6Nk/2ljLIHwmq2/NM6hdioUaqEXq/S+nXvbvXbZkNDlWOymPanJGOc4CBjSJA==
+"@babel/helper-compilation-targets@^7.13.10", "@babel/helper-compilation-targets@^7.16.7":
+ version "7.16.7"
+ resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.16.7.tgz#06e66c5f299601e6c7da350049315e83209d551b"
+ integrity sha512-mGojBwIWcwGD6rfqgRXVlVYmPAv7eOpIemUG3dGnDdCY4Pae70ROij3XmfrH6Fa1h1aiDylpglbZyktfzyo/hA==
dependencies:
- "@babel/compat-data" "^7.16.0"
- "@babel/helper-validator-option" "^7.14.5"
+ "@babel/compat-data" "^7.16.4"
+ "@babel/helper-validator-option" "^7.16.7"
browserslist "^4.17.5"
semver "^6.3.0"
-"@babel/helper-create-class-features-plugin@^7.16.0", "@babel/helper-create-class-features-plugin@^7.16.5":
- version "7.16.5"
- resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.16.5.tgz#5d1bcd096792c1ebec6249eebc6358eec55d0cad"
- integrity sha512-NEohnYA7mkB8L5JhU7BLwcBdU3j83IziR9aseMueWGeAjblbul3zzb8UvJ3a1zuBiqCMObzCJHFqKIQE6hTVmg==
+"@babel/helper-create-class-features-plugin@^7.16.10", "@babel/helper-create-class-features-plugin@^7.16.7":
+ version "7.16.10"
+ resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.16.10.tgz#8a6959b9cc818a88815ba3c5474619e9c0f2c21c"
+ integrity sha512-wDeej0pu3WN/ffTxMNCPW5UCiOav8IcLRxSIyp/9+IF2xJUM9h/OYjg0IJLHaL6F8oU8kqMz9nc1vryXhMsgXg==
dependencies:
- "@babel/helper-annotate-as-pure" "^7.16.0"
- "@babel/helper-environment-visitor" "^7.16.5"
- "@babel/helper-function-name" "^7.16.0"
- "@babel/helper-member-expression-to-functions" "^7.16.5"
- "@babel/helper-optimise-call-expression" "^7.16.0"
- "@babel/helper-replace-supers" "^7.16.5"
- "@babel/helper-split-export-declaration" "^7.16.0"
+ "@babel/helper-annotate-as-pure" "^7.16.7"
+ "@babel/helper-environment-visitor" "^7.16.7"
+ "@babel/helper-function-name" "^7.16.7"
+ "@babel/helper-member-expression-to-functions" "^7.16.7"
+ "@babel/helper-optimise-call-expression" "^7.16.7"
+ "@babel/helper-replace-supers" "^7.16.7"
+ "@babel/helper-split-export-declaration" "^7.16.7"
-"@babel/helper-environment-visitor@^7.16.5":
- version "7.16.5"
- resolved "https://registry.yarnpkg.com/@babel/helper-environment-visitor/-/helper-environment-visitor-7.16.5.tgz#f6a7f38b3c6d8b07c88faea083c46c09ef5451b8"
- integrity sha512-ODQyc5AnxmZWm/R2W7fzhamOk1ey8gSguo5SGvF0zcB3uUzRpTRmM/jmLSm9bDMyPlvbyJ+PwPEK0BWIoZ9wjg==
- dependencies:
- "@babel/types" "^7.16.0"
-
-"@babel/helper-function-name@^7.12.13", "@babel/helper-function-name@^7.16.0":
- version "7.16.0"
- resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.16.0.tgz#b7dd0797d00bbfee4f07e9c4ea5b0e30c8bb1481"
- integrity sha512-BZh4mEk1xi2h4HFjWUXRQX5AEx4rvaZxHgax9gcjdLWdkjsY7MKt5p0otjsg5noXw+pB+clMCjw+aEVYADMjog==
+"@babel/helper-environment-visitor@^7.16.7":
+ version "7.16.7"
+ resolved "https://registry.yarnpkg.com/@babel/helper-environment-visitor/-/helper-environment-visitor-7.16.7.tgz#ff484094a839bde9d89cd63cba017d7aae80ecd7"
+ integrity sha512-SLLb0AAn6PkUeAfKJCCOl9e1R53pQlGAfc4y4XuMRZfqeMYLE0dM1LMhqbGAlGQY0lfw5/ohoYWAe9V1yibRag==
dependencies:
- "@babel/helper-get-function-arity" "^7.16.0"
- "@babel/template" "^7.16.0"
- "@babel/types" "^7.16.0"
+ "@babel/types" "^7.16.7"
-"@babel/helper-get-function-arity@^7.16.0":
- version "7.16.0"
- resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.16.0.tgz#0088c7486b29a9cb5d948b1a1de46db66e089cfa"
- integrity sha512-ASCquNcywC1NkYh/z7Cgp3w31YW8aojjYIlNg4VeJiHkqyP4AzIvr4qx7pYDb4/s8YcsZWqqOSxgkvjUz1kpDQ==
+"@babel/helper-function-name@^7.12.13", "@babel/helper-function-name@^7.16.7":
+ version "7.16.7"
+ resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.16.7.tgz#f1ec51551fb1c8956bc8dd95f38523b6cf375f8f"
+ integrity sha512-QfDfEnIUyyBSR3HtrtGECuZ6DAyCkYFp7GHl75vFtTnn6pjKeK0T1DB5lLkFvBea8MdaiUABx3osbgLyInoejA==
dependencies:
- "@babel/types" "^7.16.0"
+ "@babel/helper-get-function-arity" "^7.16.7"
+ "@babel/template" "^7.16.7"
+ "@babel/types" "^7.16.7"
-"@babel/helper-hoist-variables@^7.16.0":
- version "7.16.0"
- resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.16.0.tgz#4c9023c2f1def7e28ff46fc1dbcd36a39beaa81a"
- integrity sha512-1AZlpazjUR0EQZQv3sgRNfM9mEVWPK3M6vlalczA+EECcPz3XPh6VplbErL5UoMpChhSck5wAJHthlj1bYpcmg==
+"@babel/helper-get-function-arity@^7.16.7":
+ version "7.16.7"
+ resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.16.7.tgz#ea08ac753117a669f1508ba06ebcc49156387419"
+ integrity sha512-flc+RLSOBXzNzVhcLu6ujeHUrD6tANAOU5ojrRx/as+tbzf8+stUCj7+IfRRoAbEZqj/ahXEMsjhOhgeZsrnTw==
dependencies:
- "@babel/types" "^7.16.0"
+ "@babel/types" "^7.16.7"
-"@babel/helper-member-expression-to-functions@^7.16.0":
- version "7.16.0"
- resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.16.0.tgz#29287040efd197c77636ef75188e81da8bccd5a4"
- integrity sha512-bsjlBFPuWT6IWhl28EdrQ+gTvSvj5tqVP5Xeftp07SEuz5pLnsXZuDkDD3Rfcxy0IsHmbZ+7B2/9SHzxO0T+sQ==
+"@babel/helper-hoist-variables@^7.16.7":
+ version "7.16.7"
+ resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.16.7.tgz#86bcb19a77a509c7b77d0e22323ef588fa58c246"
+ integrity sha512-m04d/0Op34H5v7pbZw6pSKP7weA6lsMvfiIAMeIvkY/R4xQtBSMFEigu9QTZ2qB/9l22vsxtM8a+Q8CzD255fg==
dependencies:
- "@babel/types" "^7.16.0"
+ "@babel/types" "^7.16.7"
-"@babel/helper-member-expression-to-functions@^7.16.5":
- version "7.16.5"
- resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.16.5.tgz#1bc9f7e87354e86f8879c67b316cb03d3dc2caab"
- integrity sha512-7fecSXq7ZrLE+TWshbGT+HyCLkxloWNhTbU2QM1NTI/tDqyf0oZiMcEfYtDuUDCo528EOlt39G1rftea4bRZIw==
+"@babel/helper-member-expression-to-functions@^7.16.7":
+ version "7.16.7"
+ resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.16.7.tgz#42b9ca4b2b200123c3b7e726b0ae5153924905b0"
+ integrity sha512-VtJ/65tYiU/6AbMTDwyoXGPKHgTsfRarivm+YbB5uAzKUyuPjgZSgAFeG87FCigc7KNHu2Pegh1XIT3lXjvz3Q==
dependencies:
- "@babel/types" "^7.16.0"
+ "@babel/types" "^7.16.7"
-"@babel/helper-module-imports@^7.16.0":
- version "7.16.0"
- resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.16.0.tgz#90538e60b672ecf1b448f5f4f5433d37e79a3ec3"
- integrity sha512-kkH7sWzKPq0xt3H1n+ghb4xEMP8k0U7XV3kkB+ZGy69kDk2ySFW1qPi06sjKzFY3t1j6XbJSqr4mF9L7CYVyhg==
+"@babel/helper-module-imports@^7.16.7":
+ version "7.16.7"
+ resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.16.7.tgz#25612a8091a999704461c8a222d0efec5d091437"
+ integrity sha512-LVtS6TqjJHFc+nYeITRo6VLXve70xmq7wPhWTqDJusJEgGmkAACWwMiTNrvfoQo6hEhFwAIixNkvB0jPXDL8Wg==
dependencies:
- "@babel/types" "^7.16.0"
-
-"@babel/helper-module-transforms@^7.13.0", "@babel/helper-module-transforms@^7.16.0":
- version "7.16.0"
- resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.16.0.tgz#1c82a8dd4cb34577502ebd2909699b194c3e9bb5"
- integrity sha512-My4cr9ATcaBbmaEa8M0dZNA74cfI6gitvUAskgDtAFmAqyFKDSHQo5YstxPbN+lzHl2D9l/YOEFqb2mtUh4gfA==
- dependencies:
- "@babel/helper-module-imports" "^7.16.0"
- "@babel/helper-replace-supers" "^7.16.0"
- "@babel/helper-simple-access" "^7.16.0"
- "@babel/helper-split-export-declaration" "^7.16.0"
- "@babel/helper-validator-identifier" "^7.15.7"
- "@babel/template" "^7.16.0"
- "@babel/traverse" "^7.16.0"
- "@babel/types" "^7.16.0"
-
-"@babel/helper-module-transforms@^7.16.5":
- version "7.16.5"
- resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.16.5.tgz#530ebf6ea87b500f60840578515adda2af470a29"
- integrity sha512-CkvMxgV4ZyyioElFwcuWnDCcNIeyqTkCm9BxXZi73RR1ozqlpboqsbGUNvRTflgZtFbbJ1v5Emvm+lkjMYY/LQ==
- dependencies:
- "@babel/helper-environment-visitor" "^7.16.5"
- "@babel/helper-module-imports" "^7.16.0"
- "@babel/helper-simple-access" "^7.16.0"
- "@babel/helper-split-export-declaration" "^7.16.0"
- "@babel/helper-validator-identifier" "^7.15.7"
- "@babel/template" "^7.16.0"
- "@babel/traverse" "^7.16.5"
- "@babel/types" "^7.16.0"
+ "@babel/types" "^7.16.7"
-"@babel/helper-optimise-call-expression@^7.16.0":
- version "7.16.0"
- resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.16.0.tgz#cecdb145d70c54096b1564f8e9f10cd7d193b338"
- integrity sha512-SuI467Gi2V8fkofm2JPnZzB/SUuXoJA5zXe/xzyPP2M04686RzFKFHPK6HDVN6JvWBIEW8tt9hPR7fXdn2Lgpw==
+"@babel/helper-module-transforms@^7.13.0", "@babel/helper-module-transforms@^7.16.7":
+ version "7.16.7"
+ resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.16.7.tgz#7665faeb721a01ca5327ddc6bba15a5cb34b6a41"
+ integrity sha512-gaqtLDxJEFCeQbYp9aLAefjhkKdjKcdh6DB7jniIGU3Pz52WAmP268zK0VgPz9hUNkMSYeH976K2/Y6yPadpng==
+ dependencies:
+ "@babel/helper-environment-visitor" "^7.16.7"
+ "@babel/helper-module-imports" "^7.16.7"
+ "@babel/helper-simple-access" "^7.16.7"
+ "@babel/helper-split-export-declaration" "^7.16.7"
+ "@babel/helper-validator-identifier" "^7.16.7"
+ "@babel/template" "^7.16.7"
+ "@babel/traverse" "^7.16.7"
+ "@babel/types" "^7.16.7"
+
+"@babel/helper-optimise-call-expression@^7.16.7":
+ version "7.16.7"
+ resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.16.7.tgz#a34e3560605abbd31a18546bd2aad3e6d9a174f2"
+ integrity sha512-EtgBhg7rd/JcnpZFXpBy0ze1YRfdm7BnBX4uKMBd3ixa3RGAE002JZB66FJyNH7g0F38U05pXmA5P8cBh7z+1w==
dependencies:
- "@babel/types" "^7.16.0"
+ "@babel/types" "^7.16.7"
-"@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.12.13", "@babel/helper-plugin-utils@^7.14.5", "@babel/helper-plugin-utils@^7.8.0":
- version "7.14.5"
- resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.14.5.tgz#5ac822ce97eec46741ab70a517971e443a70c5a9"
- integrity sha512-/37qQCE3K0vvZKwoK4XU/irIJQdIfCJuhU5eKnNxpFDsOkgFaUAwbv+RYw6eYgsC0E4hS7r5KqGULUogqui0fQ==
-
-"@babel/helper-plugin-utils@^7.16.5", "@babel/helper-plugin-utils@^7.8.3":
- version "7.16.5"
- resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.16.5.tgz#afe37a45f39fce44a3d50a7958129ea5b1a5c074"
- integrity sha512-59KHWHXxVA9K4HNF4sbHCf+eJeFe0Te/ZFGqBT4OjXhrwvA04sGfaEGsVTdsjoszq0YTP49RC9UKe5g8uN2RwQ==
-
-"@babel/helper-replace-supers@^7.16.0":
- version "7.16.0"
- resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.16.0.tgz#73055e8d3cf9bcba8ddb55cad93fedc860f68f17"
- integrity sha512-TQxuQfSCdoha7cpRNJvfaYxxxzmbxXw/+6cS7V02eeDYyhxderSoMVALvwupA54/pZcOTtVeJ0xccp1nGWladA==
- dependencies:
- "@babel/helper-member-expression-to-functions" "^7.16.0"
- "@babel/helper-optimise-call-expression" "^7.16.0"
- "@babel/traverse" "^7.16.0"
- "@babel/types" "^7.16.0"
+"@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.12.13", "@babel/helper-plugin-utils@^7.14.5", "@babel/helper-plugin-utils@^7.16.7", "@babel/helper-plugin-utils@^7.8.0", "@babel/helper-plugin-utils@^7.8.3":
+ version "7.16.7"
+ resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.16.7.tgz#aa3a8ab4c3cceff8e65eb9e73d87dc4ff320b2f5"
+ integrity sha512-Qg3Nk7ZxpgMrsox6HreY1ZNKdBq7K72tDSliA6dCl5f007jR4ne8iD5UzuNnCJH2xBf2BEEVGr+/OL6Gdp7RxA==
-"@babel/helper-replace-supers@^7.16.5":
- version "7.16.5"
- resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.16.5.tgz#96d3988bd0ab0a2d22c88c6198c3d3234ca25326"
- integrity sha512-ao3seGVa/FZCMCCNDuBcqnBFSbdr8N2EW35mzojx3TwfIbdPmNK+JV6+2d5bR0Z71W5ocLnQp9en/cTF7pBJiQ==
+"@babel/helper-replace-supers@^7.16.7":
+ version "7.16.7"
+ resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.16.7.tgz#e9f5f5f32ac90429c1a4bdec0f231ef0c2838ab1"
+ integrity sha512-y9vsWilTNaVnVh6xiJfABzsNpgDPKev9HnAgz6Gb1p6UUwf9NepdlsV7VXGCftJM+jqD5f7JIEubcpLjZj5dBw==
dependencies:
- "@babel/helper-environment-visitor" "^7.16.5"
- "@babel/helper-member-expression-to-functions" "^7.16.5"
- "@babel/helper-optimise-call-expression" "^7.16.0"
- "@babel/traverse" "^7.16.5"
- "@babel/types" "^7.16.0"
+ "@babel/helper-environment-visitor" "^7.16.7"
+ "@babel/helper-member-expression-to-functions" "^7.16.7"
+ "@babel/helper-optimise-call-expression" "^7.16.7"
+ "@babel/traverse" "^7.16.7"
+ "@babel/types" "^7.16.7"
-"@babel/helper-simple-access@^7.16.0":
- version "7.16.0"
- resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.16.0.tgz#21d6a27620e383e37534cf6c10bba019a6f90517"
- integrity sha512-o1rjBT/gppAqKsYfUdfHq5Rk03lMQrkPHG1OWzHWpLgVXRH4HnMM9Et9CVdIqwkCQlobnGHEJMsgWP/jE1zUiw==
+"@babel/helper-simple-access@^7.16.7":
+ version "7.16.7"
+ resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.16.7.tgz#d656654b9ea08dbb9659b69d61063ccd343ff0f7"
+ integrity sha512-ZIzHVyoeLMvXMN/vok/a4LWRy8G2v205mNP0XOuf9XRLyX5/u9CnVulUtDgUTama3lT+bf/UqucuZjqiGuTS1g==
dependencies:
- "@babel/types" "^7.16.0"
+ "@babel/types" "^7.16.7"
"@babel/helper-skip-transparent-expression-wrappers@^7.16.0":
version "7.16.0"
@@ -283,47 +207,38 @@
dependencies:
"@babel/types" "^7.16.0"
-"@babel/helper-split-export-declaration@^7.12.13", "@babel/helper-split-export-declaration@^7.16.0":
- version "7.16.0"
- resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.16.0.tgz#29672f43663e936df370aaeb22beddb3baec7438"
- integrity sha512-0YMMRpuDFNGTHNRiiqJX19GjNXA4H0E8jZ2ibccfSxaCogbm3am5WN/2nQNj0YnQwGWM1J06GOcQ2qnh3+0paw==
+"@babel/helper-split-export-declaration@^7.12.13", "@babel/helper-split-export-declaration@^7.16.7":
+ version "7.16.7"
+ resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.16.7.tgz#0b648c0c42da9d3920d85ad585f2778620b8726b"
+ integrity sha512-xbWoy/PFoxSWazIToT9Sif+jJTlrMcndIsaOKvTA6u7QEo7ilkRZpjew18/W3c7nm8fXdUDXh02VXTbZ0pGDNw==
dependencies:
- "@babel/types" "^7.16.0"
-
-"@babel/helper-validator-identifier@^7.12.11", "@babel/helper-validator-identifier@^7.15.7":
- version "7.15.7"
- resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.15.7.tgz#220df993bfe904a4a6b02ab4f3385a5ebf6e2389"
- integrity sha512-K4JvCtQqad9OY2+yTU8w+E82ywk/fe+ELNlt1G8z3bVGlZfn/hOcQQsUhGhW/N+tb3fxK800wLtKOE/aM0m72w==
+ "@babel/types" "^7.16.7"
-"@babel/helper-validator-option@^7.14.5":
- version "7.14.5"
- resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.14.5.tgz#6e72a1fff18d5dfcb878e1e62f1a021c4b72d5a3"
- integrity sha512-OX8D5eeX4XwcroVW45NMvoYaIuFI+GQpA2a8Gi+X/U/cDUIRsV37qQfF905F0htTRCREQIB4KqPeaveRJUl3Ow==
+"@babel/helper-validator-identifier@^7.12.11", "@babel/helper-validator-identifier@^7.16.7":
+ version "7.16.7"
+ resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.16.7.tgz#e8c602438c4a8195751243da9031d1607d247cad"
+ integrity sha512-hsEnFemeiW4D08A5gUAZxLBTXpZ39P+a+DGDsHw1yxqyQ/jzFEnxf5uTEGp+3bzAbNOxU1paTgYS4ECU/IgfDw==
-"@babel/helpers@^7.13.10", "@babel/helpers@^7.16.0":
- version "7.16.0"
- resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.16.0.tgz#875519c979c232f41adfbd43a3b0398c2e388183"
- integrity sha512-dVRM0StFMdKlkt7cVcGgwD8UMaBfWJHl3A83Yfs8GQ3MO0LHIIIMvK7Fa0RGOGUQ10qikLaX6D7o5htcQWgTMQ==
- dependencies:
- "@babel/template" "^7.16.0"
- "@babel/traverse" "^7.16.0"
- "@babel/types" "^7.16.0"
+"@babel/helper-validator-option@^7.16.7":
+ version "7.16.7"
+ resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.16.7.tgz#b203ce62ce5fe153899b617c08957de860de4d23"
+ integrity sha512-TRtenOuRUVo9oIQGPC5G9DgK4743cdxvtOw0weQNpZXaS16SCBi5MNjZF8vba3ETURjZpTbVn7Vvcf2eAwFozQ==
-"@babel/helpers@^7.16.5":
- version "7.16.5"
- resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.16.5.tgz#29a052d4b827846dd76ece16f565b9634c554ebd"
- integrity sha512-TLgi6Lh71vvMZGEkFuIxzaPsyeYCHQ5jJOOX1f0xXn0uciFuE8cEk0wyBquMcCxBXZ5BJhE2aUB7pnWTD150Tw==
+"@babel/helpers@^7.13.10", "@babel/helpers@^7.16.7":
+ version "7.16.7"
+ resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.16.7.tgz#7e3504d708d50344112767c3542fc5e357fffefc"
+ integrity sha512-9ZDoqtfY7AuEOt3cxchfii6C7GDyyMBffktR5B2jvWv8u2+efwvpnVKXMWzNehqy68tKgAfSwfdw/lWpthS2bw==
dependencies:
- "@babel/template" "^7.16.0"
- "@babel/traverse" "^7.16.5"
- "@babel/types" "^7.16.0"
+ "@babel/template" "^7.16.7"
+ "@babel/traverse" "^7.16.7"
+ "@babel/types" "^7.16.7"
-"@babel/highlight@^7.10.4", "@babel/highlight@^7.16.0":
- version "7.16.0"
- resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.16.0.tgz#6ceb32b2ca4b8f5f361fb7fd821e3fddf4a1725a"
- integrity sha512-t8MH41kUQylBtu2+4IQA3atqevA2lRgqA2wyVB/YiWmsDSuylZZuXOUy9ric30hfzauEFfdsuk/eXTRrGrfd0g==
+"@babel/highlight@^7.10.4", "@babel/highlight@^7.16.7":
+ version "7.16.10"
+ resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.16.10.tgz#744f2eb81579d6eea753c227b0f570ad785aba88"
+ integrity sha512-5FnTQLSLswEj6IkgVw5KusNUUFY9ZGqe/TRFnP/BKYHYgfh7tc+C7mwiy95/yNP7Dh9x580Vv8r7u7ZfTBFxdw==
dependencies:
- "@babel/helper-validator-identifier" "^7.15.7"
+ "@babel/helper-validator-identifier" "^7.16.7"
chalk "^2.0.0"
js-tokens "^4.0.0"
@@ -466,6 +376,13 @@
dependencies:
"@babel/helper-plugin-utils" "^7.8.0"
+"@babel/plugin-syntax-jsx@^7.16.7":
+ version "7.16.7"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.16.7.tgz#50b6571d13f764266a113d77c82b4a6508bbe665"
+ integrity sha512-Esxmk7YjA8QysKeT3VhTXvF6y77f/a91SIs4pWb4H2eWGQkCKFgQaG6hdoEVZtGsrAcb2K5BW66XsOErD4WU3Q==
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.16.7"
+
"@babel/plugin-syntax-logical-assignment-operators@^7.10.4", "@babel/plugin-syntax-logical-assignment-operators@^7.8.3":
version "7.10.4"
resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz#ca91ef46303530448b906652bac2e9fe9941f699"
@@ -522,70 +439,67 @@
dependencies:
"@babel/helper-plugin-utils" "^7.14.5"
-"@babel/plugin-syntax-typescript@^7.16.0":
- version "7.16.5"
- resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.16.5.tgz#f47a33e4eee38554f00fb6b2f894fa1f5649b0b3"
- integrity sha512-/d4//lZ1Vqb4mZ5xTep3dDK888j7BGM/iKqBmndBaoYAFPlPKrGU608VVBz5JeyAb6YQDjRu1UKqj86UhwWVgw==
+"@babel/plugin-syntax-typescript@^7.16.7":
+ version "7.16.7"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.16.7.tgz#39c9b55ee153151990fb038651d58d3fd03f98f8"
+ integrity sha512-YhUIJHHGkqPgEcMYkPCKTyGUdoGKWtopIycQyjJH8OjvRgOYsXsaKehLVPScKJWAULPxMa4N1vCe6szREFlZ7A==
dependencies:
- "@babel/helper-plugin-utils" "^7.16.5"
+ "@babel/helper-plugin-utils" "^7.16.7"
"@babel/plugin-transform-modules-commonjs@^7.14.5":
- version "7.16.5"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.16.5.tgz#4ee03b089536f076b2773196529d27c32b9d7bde"
- integrity sha512-ABhUkxvoQyqhCWyb8xXtfwqNMJD7tx+irIRnUh6lmyFud7Jln1WzONXKlax1fg/ey178EXbs4bSGNd6PngO+SQ==
+ version "7.16.8"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.16.8.tgz#cdee19aae887b16b9d331009aa9a219af7c86afe"
+ integrity sha512-oflKPvsLT2+uKQopesJt3ApiaIS2HW+hzHFcwRNtyDGieAeC/dIHZX8buJQ2J2X1rxGPy4eRcUijm3qcSPjYcA==
dependencies:
- "@babel/helper-module-transforms" "^7.16.5"
- "@babel/helper-plugin-utils" "^7.16.5"
- "@babel/helper-simple-access" "^7.16.0"
+ "@babel/helper-module-transforms" "^7.16.7"
+ "@babel/helper-plugin-utils" "^7.16.7"
+ "@babel/helper-simple-access" "^7.16.7"
babel-plugin-dynamic-import-node "^2.3.3"
-"@babel/plugin-transform-typescript@^7.16.1":
- version "7.16.1"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.16.1.tgz#cc0670b2822b0338355bc1b3d2246a42b8166409"
- integrity sha512-NO4XoryBng06jjw/qWEU2LhcLJr1tWkhpMam/H4eas/CDKMX/b2/Ylb6EI256Y7+FVPCawwSM1rrJNOpDiz+Lg==
- dependencies:
- "@babel/helper-create-class-features-plugin" "^7.16.0"
- "@babel/helper-plugin-utils" "^7.14.5"
- "@babel/plugin-syntax-typescript" "^7.16.0"
-
-"@babel/preset-typescript@^7.14.5":
- version "7.16.5"
- resolved "https://registry.yarnpkg.com/@babel/preset-typescript/-/preset-typescript-7.16.5.tgz#b86a5b0ae739ba741347d2f58c52f52e63cf1ba1"
- integrity sha512-lmAWRoJ9iOSvs3DqOndQpj8XqXkzaiQs50VG/zESiI9D3eoZhGriU675xNCr0UwvsuXrhMAGvyk1w+EVWF3u8Q==
+"@babel/plugin-transform-react-jsx@^7.14.5":
+ version "7.16.7"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.16.7.tgz#86a6a220552afd0e4e1f0388a68a372be7add0d4"
+ integrity sha512-8D16ye66fxiE8m890w0BpPpngG9o9OVBBy0gH2E+2AR7qMR2ZpTYJEqLxAsoroenMId0p/wMW+Blc0meDgu0Ag==
dependencies:
- "@babel/helper-plugin-utils" "^7.16.5"
- "@babel/helper-validator-option" "^7.14.5"
- "@babel/plugin-transform-typescript" "^7.16.1"
+ "@babel/helper-annotate-as-pure" "^7.16.7"
+ "@babel/helper-module-imports" "^7.16.7"
+ "@babel/helper-plugin-utils" "^7.16.7"
+ "@babel/plugin-syntax-jsx" "^7.16.7"
+ "@babel/types" "^7.16.7"
-"@babel/runtime@^7.0.0":
- version "7.16.3"
- resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.16.3.tgz#b86f0db02a04187a3c17caa77de69840165d42d5"
- integrity sha512-WBwekcqacdY2e9AF/Q7WLFUWmdJGJTkbjqTjoMDgXkVZ3ZRUvOPsLb5KdwISoQVsbP+DQzVZW4Zhci0DvpbNTQ==
+"@babel/plugin-transform-typescript@^7.16.7":
+ version "7.16.8"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.16.8.tgz#591ce9b6b83504903fa9dd3652c357c2ba7a1ee0"
+ integrity sha512-bHdQ9k7YpBDO2d0NVfkj51DpQcvwIzIusJ7mEUaMlbZq3Kt/U47j24inXZHQ5MDiYpCs+oZiwnXyKedE8+q7AQ==
dependencies:
- regenerator-runtime "^0.13.4"
+ "@babel/helper-create-class-features-plugin" "^7.16.7"
+ "@babel/helper-plugin-utils" "^7.16.7"
+ "@babel/plugin-syntax-typescript" "^7.16.7"
-"@babel/runtime@^7.1.2", "@babel/runtime@^7.12.0", "@babel/runtime@^7.12.1", "@babel/runtime@^7.12.13", "@babel/runtime@^7.12.5", "@babel/runtime@^7.13.10", "@babel/runtime@^7.13.17", "@babel/runtime@^7.14.5", "@babel/runtime@^7.15.4", "@babel/runtime@^7.5.5", "@babel/runtime@^7.6.2", "@babel/runtime@^7.7.2", "@babel/runtime@^7.8.7", "@babel/runtime@^7.9.0":
- version "7.16.0"
- resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.16.0.tgz#e27b977f2e2088ba24748bf99b5e1dece64e4f0b"
- integrity sha512-Nht8L0O8YCktmsDV6FqFue7vQLRx3Hb0B37lS5y0jDRqRxlBG4wIJHnf9/bgSE2UyipKFA01YtS+npRdTWBUyw==
+"@babel/preset-typescript@^7.14.5":
+ version "7.16.7"
+ resolved "https://registry.yarnpkg.com/@babel/preset-typescript/-/preset-typescript-7.16.7.tgz#ab114d68bb2020afc069cd51b37ff98a046a70b9"
+ integrity sha512-WbVEmgXdIyvzB77AQjGBEyYPZx+8tTsO50XtfozQrkW8QB2rLJpH2lgx0TRw5EJrBxOZQ+wCcyPVQvS8tjEHpQ==
dependencies:
- regenerator-runtime "^0.13.4"
+ "@babel/helper-plugin-utils" "^7.16.7"
+ "@babel/helper-validator-option" "^7.16.7"
+ "@babel/plugin-transform-typescript" "^7.16.7"
-"@babel/runtime@^7.16.3":
+"@babel/runtime@^7.0.0", "@babel/runtime@^7.1.2", "@babel/runtime@^7.12.0", "@babel/runtime@^7.12.1", "@babel/runtime@^7.12.13", "@babel/runtime@^7.12.5", "@babel/runtime@^7.13.10", "@babel/runtime@^7.13.17", "@babel/runtime@^7.14.5", "@babel/runtime@^7.15.4", "@babel/runtime@^7.16.3", "@babel/runtime@^7.5.5", "@babel/runtime@^7.6.2", "@babel/runtime@^7.7.2", "@babel/runtime@^7.8.7", "@babel/runtime@^7.9.0":
version "7.16.7"
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.16.7.tgz#03ff99f64106588c9c403c6ecb8c3bafbbdff1fa"
integrity sha512-9E9FJowqAsytyOY6LG+1KuueckRL+aQW+mKvXRXnuFGyRAyepJPmEo9vgMfXUA6O9u3IeEdv9MAkppFcaQwogQ==
dependencies:
regenerator-runtime "^0.13.4"
-"@babel/template@^7.12.13", "@babel/template@^7.16.0", "@babel/template@^7.3.3":
- version "7.16.0"
- resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.16.0.tgz#d16a35ebf4cd74e202083356fab21dd89363ddd6"
- integrity sha512-MnZdpFD/ZdYhXwiunMqqgyZyucaYsbL0IrjoGjaVhGilz+x8YB++kRfygSOIj1yOtWKPlx7NBp+9I1RQSgsd5A==
+"@babel/template@^7.12.13", "@babel/template@^7.16.7", "@babel/template@^7.3.3":
+ version "7.16.7"
+ resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.16.7.tgz#8d126c8701fde4d66b264b3eba3d96f07666d155"
+ integrity sha512-I8j/x8kHUrbYRTUxXrrMbfCa7jxkE7tZre39x3kjr9hvI82cK1FfqLygotcWN5kdPGWcLdWMHpSBavse5tWw3w==
dependencies:
- "@babel/code-frame" "^7.16.0"
- "@babel/parser" "^7.16.0"
- "@babel/types" "^7.16.0"
+ "@babel/code-frame" "^7.16.7"
+ "@babel/parser" "^7.16.7"
+ "@babel/types" "^7.16.7"
"@babel/traverse@7.13.0":
version "7.13.0"
@@ -642,12 +541,12 @@
lodash "^4.17.19"
to-fast-properties "^2.0.0"
-"@babel/types@^7.0.0", "@babel/types@^7.13.0", "@babel/types@^7.16.0", "@babel/types@^7.3.0", "@babel/types@^7.3.3":
- version "7.16.0"
- resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.16.0.tgz#db3b313804f96aadd0b776c4823e127ad67289ba"
- integrity sha512-PJgg/k3SdLsGb3hhisFvtLOw5ts113klrpLuIPtCJIU+BB24fqq6lf8RWqKJEjzqXR9AEH1rIb5XTqwBHB+kQg==
+"@babel/types@^7.0.0", "@babel/types@^7.13.0", "@babel/types@^7.16.0", "@babel/types@^7.16.7", "@babel/types@^7.16.8", "@babel/types@^7.3.0", "@babel/types@^7.3.3":
+ version "7.16.8"
+ resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.16.8.tgz#0ba5da91dd71e0a4e7781a30f22770831062e3c1"
+ integrity sha512-smN2DQc5s4M7fntyjGtyIPbRJv6wW4rU/94fmYJ7PKQuZkC0qGMHXJbg6sNGt12JmVr4k5YaptI/XtiLJBnmIg==
dependencies:
- "@babel/helper-validator-identifier" "^7.15.7"
+ "@babel/helper-validator-identifier" "^7.16.7"
to-fast-properties "^2.0.0"
"@bcoe/v8-coverage@^0.2.3":
@@ -1958,9 +1851,9 @@
tsyringe "^4.6.0"
"@playwright/test@^1.17.1":
- version "1.17.1"
- resolved "https://registry.yarnpkg.com/@playwright/test/-/test-1.17.1.tgz#9e5aca496d2c90ce95ca19ac2c3a8867a4f606d3"
- integrity sha512-mMZS5OMTN/vUlqd1JZkFoAk2FsIZ4/E/00tw5it2c/VF4+3z/aWO+PPd8ShEGzYME7B16QGWNPjyFpDQI1t4RQ==
+ version "1.18.1"
+ resolved "https://registry.yarnpkg.com/@playwright/test/-/test-1.18.1.tgz#efaa3aa9c7f8aebeb75cd45fd9737529e9b30fbd"
+ integrity sha512-v6jAM2GpRvf4MUvSLkrAXg101XT9mLu2X2NbCnEoj7GHBXwavDlAJDMwh4Hn8oipDxB6MS6FTcr7opXsIMNwrA==
dependencies:
"@babel/code-frame" "^7.14.5"
"@babel/core" "^7.14.8"
@@ -1978,20 +1871,23 @@
"@babel/plugin-syntax-object-rest-spread" "^7.8.3"
"@babel/plugin-syntax-optional-catch-binding" "^7.8.3"
"@babel/plugin-transform-modules-commonjs" "^7.14.5"
+ "@babel/plugin-transform-react-jsx" "^7.14.5"
"@babel/preset-typescript" "^7.14.5"
- colors "^1.4.0"
+ babel-plugin-module-resolver "^4.1.0"
+ colors "1.4.0"
commander "^8.2.0"
debug "^4.1.1"
expect "=27.2.5"
jest-matcher-utils "=27.2.5"
jpeg-js "^0.4.2"
+ json5 "^2.2.0"
mime "^2.4.6"
minimatch "^3.0.3"
ms "^2.1.2"
open "^8.3.0"
pirates "^4.0.1"
pixelmatch "^5.2.1"
- playwright-core "=1.17.1"
+ playwright-core "=1.18.1"
pngjs "^5.0.0"
rimraf "^3.0.2"
source-map-support "^0.4.18"
@@ -3510,16 +3395,27 @@ babel-plugin-jest-hoist@^26.6.2:
"@types/babel__core" "^7.0.0"
"@types/babel__traverse" "^7.0.6"
-babel-plugin-jest-hoist@^27.2.0:
- version "27.2.0"
- resolved "https://registry.yarnpkg.com/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-27.2.0.tgz#79f37d43f7e5c4fdc4b2ca3e10cc6cf545626277"
- integrity sha512-TOux9khNKdi64mW+0OIhcmbAn75tTlzKhxmiNXevQaPbrBYK7YKjP1jl6NHTJ6XR5UgUrJbCnWlKVnJn29dfjw==
+babel-plugin-jest-hoist@^27.4.0:
+ version "27.4.0"
+ resolved "https://registry.yarnpkg.com/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-27.4.0.tgz#d7831fc0f93573788d80dee7e682482da4c730d6"
+ integrity sha512-Jcu7qS4OX5kTWBc45Hz7BMmgXuJqRnhatqpUhnzGC3OBYpOmf2tv6jFNwZpwM7wU7MUuv2r9IPS/ZlYOuburVw==
dependencies:
"@babel/template" "^7.3.3"
"@babel/types" "^7.3.3"
"@types/babel__core" "^7.0.0"
"@types/babel__traverse" "^7.0.6"
+babel-plugin-module-resolver@^4.1.0:
+ version "4.1.0"
+ resolved "https://registry.yarnpkg.com/babel-plugin-module-resolver/-/babel-plugin-module-resolver-4.1.0.tgz#22a4f32f7441727ec1fbf4967b863e1e3e9f33e2"
+ integrity sha512-MlX10UDheRr3lb3P0WcaIdtCSRlxdQsB1sBqL7W0raF070bGl1HQQq5K3T2vf2XAYie+ww+5AKC/WrkjRO2knA==
+ dependencies:
+ find-babel-config "^1.2.0"
+ glob "^7.1.6"
+ pkg-up "^3.1.0"
+ reselect "^4.0.0"
+ resolve "^1.13.1"
+
babel-preset-current-node-syntax@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz#b4399239b89b2a011f9ddbe3e4f401fc40cff73b"
@@ -4223,7 +4109,7 @@ colorette@^2.0.16:
resolved "https://registry.yarnpkg.com/colorette/-/colorette-2.0.16.tgz#713b9af84fdb000139f04546bd4a93f62a5085da"
integrity sha512-hUewv7oMjCp+wkBv5Rm0v87eJhq4woh5rSR+42YSQJKecCqgIqNkZ6lAlQms/BwHPJA5NKMRlpxPRv0n8HQW6g==
-colors@^1.4.0:
+colors@1.4.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/colors/-/colors-1.4.0.tgz#c50491479d4c1bdaed2c9ced32cf7c7dc2360f78"
integrity sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==
@@ -5597,6 +5471,14 @@ finalhandler@~1.1.2:
statuses "~1.5.0"
unpipe "~1.0.0"
+find-babel-config@^1.2.0:
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/find-babel-config/-/find-babel-config-1.2.0.tgz#a9b7b317eb5b9860cda9d54740a8c8337a2283a2"
+ integrity sha512-jB2CHJeqy6a820ssiqwrKMeyC6nNdmrcgkKWJWmpoxpE8RKciYJXCcXRq1h2AzCo5I5BJeN2tkGEO3hLTuePRA==
+ dependencies:
+ json5 "^0.5.1"
+ path-exists "^3.0.0"
+
find-up@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/find-up/-/find-up-2.1.0.tgz#45d1b7e506c717ddd482775a2b77920a3c0c57a7"
@@ -5604,6 +5486,13 @@ find-up@^2.1.0:
dependencies:
locate-path "^2.0.0"
+find-up@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/find-up/-/find-up-3.0.0.tgz#49169f1d7993430646da61ecc5ae355c21c97b73"
+ integrity sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==
+ dependencies:
+ locate-path "^3.0.0"
+
find-up@^4.0.0, find-up@^4.1.0:
version "4.1.0"
resolved "https://registry.yarnpkg.com/find-up/-/find-up-4.1.0.tgz#97afe7d6cdc0bc5928584b7c8d7b16e8a9aa5d19"
@@ -7526,13 +7382,18 @@ json-stringify-safe@~5.0.1:
resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb"
integrity sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=
-json5@2.x, json5@^2.1.2:
+json5@2.x, json5@^2.1.2, json5@^2.2.0:
version "2.2.0"
resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.0.tgz#2dfefe720c6ba525d9ebd909950f0515316c89a3"
integrity sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA==
dependencies:
minimist "^1.2.5"
+json5@^0.5.1:
+ version "0.5.1"
+ resolved "https://registry.yarnpkg.com/json5/-/json5-0.5.1.tgz#1eade7acc012034ad84e2396767ead9fa5495821"
+ integrity sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE=
+
jsonfile@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-4.0.0.tgz#8771aae0799b64076b76640fca058f9c10e33ecb"
@@ -7807,6 +7668,14 @@ locate-path@^2.0.0:
p-locate "^2.0.0"
path-exists "^3.0.0"
+locate-path@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-3.0.0.tgz#dbec3b3ab759758071b58fe59fc41871af21400e"
+ integrity sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==
+ dependencies:
+ p-locate "^3.0.0"
+ path-exists "^3.0.0"
+
locate-path@^5.0.0:
version "5.0.0"
resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-5.0.0.tgz#1afba396afd676a6d42504d0a67a3a7eb9f62aa0"
@@ -8824,7 +8684,7 @@ p-limit@^1.1.0:
dependencies:
p-try "^1.0.0"
-p-limit@^2.2.0:
+p-limit@^2.0.0, p-limit@^2.2.0:
version "2.3.0"
resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.3.0.tgz#3dd33c647a214fdfffd835933eb086da0dc21db1"
integrity sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==
@@ -8838,6 +8698,13 @@ p-locate@^2.0.0:
dependencies:
p-limit "^1.1.0"
+p-locate@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-3.0.0.tgz#322d69a05c0264b25997d9f40cd8a891ab0064a4"
+ integrity sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==
+ dependencies:
+ p-limit "^2.0.0"
+
p-locate@^4.1.0:
version "4.1.0"
resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-4.1.0.tgz#a3428bb7088b3a60292f66919278b7c297ad4f07"
@@ -9000,7 +8867,7 @@ path-key@^3.0.0, path-key@^3.1.0:
resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375"
integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==
-path-parse@^1.0.6:
+path-parse@^1.0.6, path-parse@^1.0.7:
version "1.0.7"
resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735"
integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==
@@ -9154,10 +9019,17 @@ pkg-dir@^4.2.0:
dependencies:
find-up "^4.0.0"
-playwright-core@=1.17.1:
- version "1.17.1"
- resolved "https://registry.yarnpkg.com/playwright-core/-/playwright-core-1.17.1.tgz#a16e0f89284a0ed8ae6d77e1c905c84b8a2ba022"
- integrity sha512-C3c8RpPiC3qr15fRDN6dx6WnUkPLFmST37gms2aoHPDRvp7EaGDPMMZPpqIm/QWB5J40xDrQCD4YYHz2nBTojQ==
+pkg-up@^3.1.0:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/pkg-up/-/pkg-up-3.1.0.tgz#100ec235cc150e4fd42519412596a28512a0def5"
+ integrity sha512-nDywThFk1i4BQK4twPQ6TA4RT8bDY96yeuCVBWL3ePARCiEKDRSrNGbFIgUJpLp+XeIR65v8ra7WuJOFUBtkMA==
+ dependencies:
+ find-up "^3.0.0"
+
+playwright-core@=1.18.1:
+ version "1.18.1"
+ resolved "https://registry.yarnpkg.com/playwright-core/-/playwright-core-1.18.1.tgz#a5cf3f212d10692382e2acd1f7bc8c9ff9bbb849"
+ integrity sha512-NALGl8R1GHzGLlhUApmpmfh6M1rrrPcDTygWvhTbprxwGB9qd/j9DRwyn4HTQcUB6o0/VOpo46fH9ez3+D/Rog==
dependencies:
commander "^8.2.0"
debug "^4.1.1"
@@ -9325,9 +9181,9 @@ prettier-linter-helpers@^1.0.0:
fast-diff "^1.1.2"
prettier@^2.3.2:
- version "2.4.1"
- resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.4.1.tgz#671e11c89c14a4cfc876ce564106c4a6726c9f5c"
- integrity sha512-9fbDAXSBcc6Bs1mZrDYb3XKzDLm4EXXL9sC1LqKP5rZkT6KRr/rf9amVUcODVXgguK/isJz0d0hP72WeaKWsvA==
+ version "2.5.1"
+ resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.5.1.tgz#fff75fa9d519c54cf0fce328c1017d94546bc56a"
+ integrity sha512-vBZcPRUR5MZJwoyi3ZoyQlc1rXeEck8KgeC9AwwOn+exuxLxq5toTRDTSaVrXHxelDMHy9zlicw8u66yxoSUFg==
pretty-format@^26.6.2:
version "26.6.2"
@@ -9594,32 +9439,16 @@ raw-body@2.4.2:
unpipe "1.0.0"
react-calendar@^3.3.1:
- version "3.5.0"
- resolved "https://registry.yarnpkg.com/react-calendar/-/react-calendar-3.5.0.tgz#ba7bc0b76e389ec91b385f34328f02457998678c"
- integrity sha512-WrDOON59188ciC7jw5YrlM/EgLTWM9TD9dflRWjgd9rlMxPScX8dNG4tJGE+z8d4xaEVccJmHbiYGCGsYdXdxQ==
+ version "3.6.0"
+ resolved "https://registry.yarnpkg.com/react-calendar/-/react-calendar-3.6.0.tgz#aec0a066439942972eb980b9f47730ba17f60eb3"
+ integrity sha512-hUNuPUPmiT6RGp7kZhes/yi/G9Kk1pitdzy8LShGW6wTC920HEF3hZkyZ8yT6HZNT3HPaav441i9E9pHQVrwEA==
dependencies:
"@wojtekmaj/date-utils" "^1.0.2"
get-user-locale "^1.2.0"
merge-class-names "^1.1.1"
prop-types "^15.6.0"
-react-date-picker@^8.3.3:
- version "8.3.5"
- resolved "https://registry.yarnpkg.com/react-date-picker/-/react-date-picker-8.3.5.tgz#3972db3fc1f37cfd6b09c09bf4988817b4d2be72"
- integrity sha512-s0Zo1xiK5xg8KGj+as84LeHS4guCdHKp/Ap6tkZMOr77A3REtezKrfLTiUeOM1xBScraBFajrZaQ/CFBNX09Cg==
- dependencies:
- "@types/react-calendar" "^3.0.0"
- "@wojtekmaj/date-utils" "^1.0.3"
- get-user-locale "^1.2.0"
- make-event-props "^1.1.0"
- merge-class-names "^1.1.1"
- merge-refs "^1.0.0"
- prop-types "^15.6.0"
- react-calendar "^3.3.1"
- react-fit "^1.0.3"
- update-input-width "^1.2.2"
-
-react-date-picker@^8.3.6:
+react-date-picker@^8.3.3, react-date-picker@^8.3.6:
version "8.3.6"
resolved "https://registry.yarnpkg.com/react-date-picker/-/react-date-picker-8.3.6.tgz#446142bee5691aea66a2bac53313357aca561cd4"
integrity sha512-c1rThf0jSKROoSGLpUEPtcC8VE+XoVgqxh+ng9aLYQvjDMGWQBgoat6Qrj8nRVzvCPpdXV4jqiCB3z2vVVuseA==
@@ -10055,6 +9873,11 @@ require-main-filename@^2.0.0:
resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-2.0.0.tgz#d0b329ecc7cc0f61649f62215be69af54aa8989b"
integrity sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==
+reselect@^4.0.0:
+ version "4.1.5"
+ resolved "https://registry.yarnpkg.com/reselect/-/reselect-4.1.5.tgz#852c361247198da6756d07d9296c2b51eddb79f6"
+ integrity sha512-uVdlz8J7OO+ASpBYoz1Zypgx0KasCY20H+N8JD13oUMtPvSHQuscrHop4KbXrbsBcdB9Ds7lVK7eRkBIfO43vQ==
+
resolve-cwd@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/resolve-cwd/-/resolve-cwd-3.0.0.tgz#0f0075f1bb2544766cf73ba6a6e2adfebcb13f2d"
@@ -10082,13 +9905,14 @@ resolve-url@^0.2.1:
resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a"
integrity sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=
-resolve@^1.10.0, resolve@^1.18.1, resolve@^1.20.0:
- version "1.20.0"
- resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.20.0.tgz#629a013fb3f70755d6f0b7935cc1c2c5378b1975"
- integrity sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==
+resolve@^1.10.0, resolve@^1.13.1, resolve@^1.18.1, resolve@^1.21.0:
+ version "1.22.0"
+ resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.0.tgz#5e0b8c67c15df57a89bdbabe603a002f21731198"
+ integrity sha512-Hhtrw0nLeSrFQ7phPp4OOcVjLPIeMnRlr5mcnVuMe7M/7eBn98A3hmFRLoFo3DLZkivSYwhRUJTyPyWAk56WLw==
dependencies:
- is-core-module "^2.2.0"
- path-parse "^1.0.6"
+ is-core-module "^2.8.1"
+ path-parse "^1.0.7"
+ supports-preserve-symlinks-flag "^1.0.0"
resolve@^2.0.0-next.3:
version "2.0.0-next.3"
@@ -10905,6 +10714,11 @@ supports-hyperlinks@^2.0.0:
has-flag "^4.0.0"
supports-color "^7.0.0"
+supports-preserve-symlinks-flag@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09"
+ integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==
+
swarm-js@^0.1.40:
version "0.1.40"
resolved "https://registry.yarnpkg.com/swarm-js/-/swarm-js-0.1.40.tgz#b1bc7b6dcc76061f6c772203e004c11997e06b99"