diff --git a/.vscode/settings.json b/.vscode/settings.json index 4bb9b69736..404259b470 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -5,5 +5,9 @@ "editor.codeActionsOnSave": { "source.fixAll.eslint": true }, - "eslint.run": "onSave" + "eslint.run": "onSave", + "workbench.colorCustomizations": { + "titleBar.activeBackground": "#888888", + "titleBar.inactiveBackground": "#292929" + } } diff --git a/components/ClientSuspense.tsx b/components/ClientSuspense.tsx new file mode 100644 index 0000000000..f0723d2ebd --- /dev/null +++ b/components/ClientSuspense.tsx @@ -0,0 +1,9 @@ +import { Suspense, SuspenseProps } from "react"; + +/** + * Wrapper around `` which will render the `fallback` when on server + * Can be simply replaced by `` once React 18 is ready. + */ +export const ClientSuspense = (props: SuspenseProps) => { + return <>{typeof window !== "undefined" ? : props.fallback}; +}; diff --git a/components/integrations/CalendarListContainer.tsx b/components/integrations/CalendarListContainer.tsx new file mode 100644 index 0000000000..14244690de --- /dev/null +++ b/components/integrations/CalendarListContainer.tsx @@ -0,0 +1,220 @@ +import React, { Fragment } from "react"; +import { useMutation } from "react-query"; + +import { QueryCell } from "@lib/QueryCell"; +import showToast from "@lib/notification"; +import { trpc } from "@lib/trpc"; + +import { List } from "@components/List"; +import { ShellSubHeading } from "@components/Shell"; +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"; + +type Props = { + onChanged: () => unknown | Promise; +}; + +function CalendarSwitch(props: { + type: string; + externalId: string; + title: string; + defaultSelected: boolean; +}) { + const utils = trpc.useContext(); + + const mutation = useMutation< + unknown, + unknown, + { + isOn: boolean; + } + >( + async ({ isOn }) => { + const body = { + integration: props.type, + externalId: props.externalId, + }; + if (isOn) { + const res = await fetch("/api/availability/calendar", { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify(body), + }); + if (!res.ok) { + throw new Error("Something went wrong"); + } + } else { + const res = await fetch("/api/availability/calendar", { + method: "DELETE", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify(body), + }); + + if (!res.ok) { + throw new Error("Something went wrong"); + } + } + }, + { + async onSettled() { + await utils.invalidateQueries(["viewer.integrations"]); + }, + onError() { + showToast(`Something went wrong when toggling "${props.title}""`, "error"); + }, + } + ); + return ( +
+ { + mutation.mutate({ isOn }); + }} + /> +
+ ); +} + +function ConnectedCalendarsList(props: Props) { + const query = trpc.useQuery(["viewer.connectedCalendars"], { suspense: true }); + + return ( + null} + success={({ data }) => ( + + {data.map((item) => ( + + {item.calendars ? ( + ( + + )} + onOpenChange={props.onChanged} + /> + }> +
    + {item.calendars.map((cal) => ( + + ))} +
+
+ ) : ( + ( + + )} + onOpenChange={() => props.onChanged()} + /> + } + /> + )} +
+ ))} +
+ )} + /> + ); +} + +function CalendarList(props: Props) { + const query = trpc.useQuery(["viewer.integrations"]); + + return ( + ( + + {data.calendar.items.map((item) => ( + ( + + )} + onOpenChange={() => props.onChanged()} + /> + } + /> + ))} + + )} + /> + ); +} +export function CalendarListContainer(props: { heading?: false }) { + const { heading = true } = props; + const utils = trpc.useContext(); + const onChanged = () => + Promise.allSettled([ + utils.invalidateQueries(["viewer.integrations"]), + utils.invalidateQueries(["viewer.connectedCalendars"]), + ]); + const query = trpc.useQuery(["viewer.connectedCalendars"]); + return ( + <> + {heading && ( + } + subtitle={ + <> + Configure how your links integrate with your calendars. +
+ You can override these settings on a per event basis. + + } + /> + )} + + {!!query.data?.length && ( + } + /> + )} + + + ); +} diff --git a/components/integrations/CalendarSwitch.tsx b/components/integrations/CalendarSwitch.tsx deleted file mode 100644 index 9e4330d9b2..0000000000 --- a/components/integrations/CalendarSwitch.tsx +++ /dev/null @@ -1,75 +0,0 @@ -import { useMutation } from "react-query"; - -import showToast from "@lib/notification"; -import { trpc } from "@lib/trpc"; - -import Switch from "@components/ui/Switch"; - -export default function CalendarSwitch(props: { - type: string; - externalId: string; - title: string; - defaultSelected: boolean; -}) { - const utils = trpc.useContext(); - - const mutation = useMutation< - unknown, - unknown, - { - isOn: boolean; - } - >( - async ({ isOn }) => { - const body = { - integration: props.type, - externalId: props.externalId, - }; - if (isOn) { - const res = await fetch("/api/availability/calendar", { - method: "POST", - headers: { - "Content-Type": "application/json", - }, - body: JSON.stringify(body), - }); - if (!res.ok) { - throw new Error("Something went wrong"); - } - } else { - const res = await fetch("/api/availability/calendar", { - method: "DELETE", - headers: { - "Content-Type": "application/json", - }, - body: JSON.stringify(body), - }); - - if (!res.ok) { - throw new Error("Something went wrong"); - } - } - }, - { - async onSettled() { - await utils.invalidateQueries(["viewer.integrations"]); - }, - onError() { - showToast(`Something went wrong when toggling "${props.title}""`, "error"); - }, - } - ); - return ( -
- { - mutation.mutate({ isOn }); - }} - /> -
- ); -} diff --git a/components/integrations/CalendarsList.tsx b/components/integrations/CalendarsList.tsx deleted file mode 100644 index c845dad3f6..0000000000 --- a/components/integrations/CalendarsList.tsx +++ /dev/null @@ -1,45 +0,0 @@ -import React, { ReactNode } from "react"; - -import { List } from "@components/List"; -import Button from "@components/ui/Button"; - -import ConnectIntegration from "./ConnectIntegrations"; -import IntegrationListItem from "./IntegrationListItem"; - -interface Props { - calendars: { - children?: ReactNode; - description: string; - imageSrc: string; - title: string; - type: string; - }[]; - onChanged: () => void | Promise; -} - -const CalendarsList = (props: Props): JSX.Element => { - const { calendars, onChanged } = props; - return ( - - {calendars.map((item) => ( - ( - - )} - onOpenChange={onChanged} - /> - } - /> - ))} - - ); -}; - -export default CalendarsList; diff --git a/components/integrations/ConnectIntegrations.tsx b/components/integrations/ConnectIntegrations.tsx index 40b10d90f7..3e96f7e7aa 100644 --- a/components/integrations/ConnectIntegrations.tsx +++ b/components/integrations/ConnectIntegrations.tsx @@ -9,7 +9,7 @@ import { ButtonBaseProps } from "@components/ui/Button"; export default function ConnectIntegration(props: { type: string; render: (renderProps: ButtonBaseProps) => JSX.Element; - onOpenChange: (isOpen: boolean) => void | Promise; + onOpenChange: (isOpen: boolean) => unknown | Promise; }) { const { type } = props; const [isLoading, setIsLoading] = useState(false); diff --git a/components/integrations/ConnectedCalendarsList.tsx b/components/integrations/ConnectedCalendarsList.tsx deleted file mode 100644 index 5c1c185a67..0000000000 --- a/components/integrations/ConnectedCalendarsList.tsx +++ /dev/null @@ -1,98 +0,0 @@ -import React, { Fragment, ReactNode } from "react"; - -import { List } from "@components/List"; -import { Alert } from "@components/ui/Alert"; -import Button from "@components/ui/Button"; - -import CalendarSwitch from "./CalendarSwitch"; -import DisconnectIntegration from "./DisconnectIntegration"; -import IntegrationListItem from "./IntegrationListItem"; - -type CalIntersection = - | { - calendars: { - externalId: string; - name: string; - isSelected: boolean; - }[]; - error?: never; - } - | { - calendars?: never; - error: { - message: string; - }; - }; - -type Props = { - onChanged: (isOpen: boolean) => void | Promise; - connectedCalendars: (CalIntersection & { - credentialId: number; - integration: { - type: string; - imageSrc: string; - title: string; - children?: ReactNode; - }; - primary?: { externalId: string } | undefined | null; - })[]; -}; - -const ConnectedCalendarsList = (props: Props): JSX.Element => { - const { connectedCalendars, onChanged } = props; - return ( - - {connectedCalendars.map((item) => ( - - {item.calendars ? ( - ( - - )} - onOpenChange={onChanged} - /> - }> -
    - {item.calendars.map((cal) => ( - - ))} -
-
- ) : ( - ( - - )} - onOpenChange={onChanged} - /> - } - /> - )} -
- ))} -
- ); -}; - -export default ConnectedCalendarsList; diff --git a/components/integrations/DisconnectIntegration.tsx b/components/integrations/DisconnectIntegration.tsx index d3ce8e6793..9b3e3db25b 100644 --- a/components/integrations/DisconnectIntegration.tsx +++ b/components/integrations/DisconnectIntegration.tsx @@ -9,7 +9,7 @@ export default function DisconnectIntegration(props: { /** Integration credential id */ id: number; render: (renderProps: ButtonBaseProps) => JSX.Element; - onOpenChange: (isOpen: boolean) => void | Promise; + onOpenChange: (isOpen: boolean) => unknown | Promise; }) { const [modalOpen, setModalOpen] = useState(false); const mutation = useMutation( diff --git a/lib/QueryCell.tsx b/lib/QueryCell.tsx index 84a7a45ba7..733c64dfc4 100644 --- a/lib/QueryCell.tsx +++ b/lib/QueryCell.tsx @@ -13,36 +13,37 @@ import { Alert } from "@components/ui/Alert"; type ErrorLike = { message: string; }; +type JSXElementOrNull = JSX.Element | null; interface QueryCellOptionsBase { query: UseQueryResult; error?: ( query: QueryObserverLoadingErrorResult | QueryObserverRefetchErrorResult - ) => JSX.Element; - loading?: (query: QueryObserverLoadingResult) => JSX.Element; - idle?: (query: QueryObserverIdleResult) => JSX.Element; + ) => JSXElementOrNull; + loading?: (query: QueryObserverLoadingResult) => JSXElementOrNull; + idle?: (query: QueryObserverIdleResult) => JSXElementOrNull; } interface QueryCellOptionsNoEmpty extends QueryCellOptionsBase { - success: (query: QueryObserverSuccessResult) => JSX.Element; + success: (query: QueryObserverSuccessResult) => JSXElementOrNull; } interface QueryCellOptionsWithEmpty extends QueryCellOptionsBase { - success: (query: QueryObserverSuccessResult, TError>) => JSX.Element; + success: (query: QueryObserverSuccessResult, TError>) => JSXElementOrNull; /** * If there's no data (`null`, `undefined`, or `[]`), render this component */ - empty: (query: QueryObserverSuccessResult) => JSX.Element; + empty: (query: QueryObserverSuccessResult) => JSXElementOrNull; } export function QueryCell( opts: QueryCellOptionsWithEmpty -): JSX.Element; +): JSXElementOrNull; export function QueryCell( opts: QueryCellOptionsNoEmpty -): JSX.Element; +): JSXElementOrNull; export function QueryCell( opts: QueryCellOptionsNoEmpty | QueryCellOptionsWithEmpty ) { diff --git a/lib/webhooks/constants.ts b/lib/webhooks/constants.ts index b774d51d28..ddd5a44507 100644 --- a/lib/webhooks/constants.ts +++ b/lib/webhooks/constants.ts @@ -5,4 +5,4 @@ export const WEBHOOK_TRIGGER_EVENTS = [ WebhookTriggerEvents.BOOKING_CANCELLED, WebhookTriggerEvents.BOOKING_CREATED, WebhookTriggerEvents.BOOKING_RESCHEDULED, -] as const; +] as ["BOOKING_CANCELLED", "BOOKING_CREATED", "BOOKING_RESCHEDULED"]; diff --git a/package.json b/package.json index d691f7235f..b5ee1fd172 100644 --- a/package.json +++ b/package.json @@ -36,8 +36,8 @@ "@heroicons/react": "^1.0.4", "@hookform/resolvers": "^2.8.1", "@jitsu/sdk-js": "^2.2.4", - "@prisma/client": "^2.30.2", "@next/bundle-analyzer": "11.1.2", + "@prisma/client": "^2.30.2", "@radix-ui/react-avatar": "^0.1.0", "@radix-ui/react-collapsible": "^0.1.0", "@radix-ui/react-dialog": "^0.1.0", @@ -75,8 +75,8 @@ "nodemailer": "^6.6.3", "otplib": "^12.0.1", "qrcode": "^1.4.4", - "react": "17.0.2", - "react-dom": "17.0.2", + "react": "^17.0.2", + "react-dom": "^17.0.2", "react-easy-crop": "^3.5.2", "react-hook-form": "^7.17.5", "react-hot-toast": "^2.1.0", diff --git a/pages/getting-started.tsx b/pages/getting-started.tsx index 9a2f1b38c1..0c73963e10 100644 --- a/pages/getting-started.tsx +++ b/pages/getting-started.tsx @@ -19,11 +19,9 @@ import getIntegrations from "@lib/integrations/getIntegrations"; import prisma from "@lib/prisma"; import { inferSSRProps } from "@lib/types/inferSSRProps"; +import { ClientSuspense } from "@components/ClientSuspense"; import Loader from "@components/Loader"; -import { ShellSubHeading } from "@components/Shell"; -import CalendarsList from "@components/integrations/CalendarsList"; -import ConnectedCalendarsList from "@components/integrations/ConnectedCalendarsList"; -import SubHeadingTitleWithConnections from "@components/integrations/SubHeadingTitleWithConnections"; +import { CalendarListContainer } from "@components/integrations/CalendarListContainer"; import { Alert } from "@components/ui/Alert"; import Button from "@components/ui/Button"; import SchedulerForm, { SCHEDULE_FORM_ID } from "@components/ui/Schedule/Schedule"; @@ -41,10 +39,6 @@ export default function Onboarding(props: inferSSRProps { - router.replace(router.asPath); - }; - const DEFAULT_EVENT_TYPES = [ { title: t("15min_meeting"), @@ -123,12 +117,9 @@ export default function Onboarding(props: inferSSRProps(null); /** End Name */ /** TimeZone */ - const [selectedTimeZone, setSelectedTimeZone] = useState({ - value: props.user.timeZone ?? dayjs.tz.guess(), - label: null, - }); + const [selectedTimeZone, setSelectedTimeZone] = useState(props.user.timeZone ?? dayjs.tz.guess()); const currentTime = React.useMemo(() => { - return dayjs().tz(selectedTimeZone.value).format("H:mm A"); + return dayjs().tz(selectedTimeZone).format("H:mm A"); }, [selectedTimeZone]); /** End TimeZone */ @@ -269,7 +260,9 @@ export default function Onboarding(props: inferSSRProps { + setSelectedTimeZone(value); + }} className="block w-full mt-1 border-gray-300 rounded-md shadow-sm focus:ring-blue-500 focus:border-blue-500 sm:text-sm" /> @@ -285,7 +278,7 @@ export default function Onboarding(props: inferSSRProps - {props.connectedCalendars.length > 0 && ( - <> - { - refreshData(); - }} - /> - } - /> - - )} - { - refreshData(); - }} - /> - + }> + + ), hideConfirm: true, confirmText: t("continue"), diff --git a/pages/integrations/index.tsx b/pages/integrations/index.tsx index f825e3c0ca..0cb1192787 100644 --- a/pages/integrations/index.tsx +++ b/pages/integrations/index.tsx @@ -19,15 +19,16 @@ import showToast from "@lib/notification"; import { inferQueryOutput, trpc } from "@lib/trpc"; import { WEBHOOK_TRIGGER_EVENTS } from "@lib/webhooks/constants"; +import { ClientSuspense } from "@components/ClientSuspense"; import { Dialog, DialogContent, DialogFooter, DialogTrigger } from "@components/Dialog"; import { List, ListItem, ListItemText, ListItemTitle } from "@components/List"; +import Loader from "@components/Loader"; import Shell, { ShellSubHeading } from "@components/Shell"; import { Tooltip } from "@components/Tooltip"; import ConfirmationDialogContent from "@components/dialog/ConfirmationDialogContent"; import { FieldsetLegend, Form, InputGroupBox, TextField } from "@components/form/fields"; -import CalendarsList from "@components/integrations/CalendarsList"; +import { CalendarListContainer } from "@components/integrations/CalendarListContainer"; import ConnectIntegration from "@components/integrations/ConnectIntegrations"; -import ConnectedCalendarsList from "@components/integrations/ConnectedCalendarsList"; import DisconnectIntegration from "@components/integrations/DisconnectIntegration"; import IntegrationListItem from "@components/integrations/IntegrationListItem"; import SubHeadingTitleWithConnections from "@components/integrations/SubHeadingTitleWithConnections"; @@ -35,15 +36,14 @@ import { Alert } from "@components/ui/Alert"; import Button from "@components/ui/Button"; import Switch from "@components/ui/Switch"; -type TIntegrations = inferQueryOutput<"viewer.integrations">; -type TWebhook = TIntegrations["webhooks"][number]; +type TWebhook = inferQueryOutput<"viewer.webhook.list">[number]; function WebhookListItem(props: { webhook: TWebhook; onEditWebhook: () => void }) { const { t } = useLocale(); const utils = trpc.useContext(); const deleteWebhook = trpc.useMutation("viewer.webhook.delete", { async onSuccess() { - await utils.invalidateQueries(["viewer.integrations"]); + await utils.invalidateQueries(["viewer.webhhook.list"]); }, }); @@ -195,11 +195,11 @@ function WebhookDialogForm(props: { .handleSubmit(async (values) => { if (values.id) { await utils.client.mutation("viewer.webhook.edit", values); - await utils.invalidateQueries(["viewer.integrations"]); + await utils.invalidateQueries(["viewer.webhook.list"]); showToast(t("webhook_updated_successfully"), "success"); } else { await utils.client.mutation("viewer.webhook.create", values); - await utils.invalidateQueries(["viewer.integrations"]); + await utils.invalidateQueries(["viewer.webhook.list"]); showToast(t("webhook_created_successfully"), "success"); } @@ -269,8 +269,81 @@ function WebhookDialogForm(props: { ); } -function WebhookEmbed(props: { webhooks: TWebhook[] }) { +function WebhookListContainer() { const { t } = useLocale(); + const query = trpc.useQuery(["viewer.webhook.list"], { suspense: true }); + + const [newWebhookModal, setNewWebhookModal] = useState(false); + const [editModalOpen, setEditModalOpen] = useState(false); + const [editing, setEditing] = useState(null); + return ( + ( + <> + + + +
+ Webhooks +
+ Webhooks + Automation +
+
+ +
+
+
+
+ + {data.length ? ( + + {data.map((item) => ( + { + setEditing(item); + setEditModalOpen(true); + }} + /> + ))} + + ) : null} + + {/* New webhook dialog */} + !isOpen && setNewWebhookModal(false)}> + + setNewWebhookModal(false)} /> + + + {/* Edit webhook dialog */} + !isOpen && setEditModalOpen(false)}> + + {editing && ( + setEditModalOpen(false)} + defaultValues={editing} + /> + )} + + + + )} + /> + ); +} + +function IframeEmbedContainer() { + const { t } = useLocale(); + // doesn't need suspense as it should already be loaded const user = trpc.useQuery(["viewer.me"]).data; const iframeTemplate = ``; @@ -278,57 +351,9 @@ function WebhookEmbed(props: { webhooks: TWebhook[] }) { "schedule_a_meeting" )}${iframeTemplate}`; - const [newWebhookModal, setNewWebhookModal] = useState(false); - const [editModalOpen, setEditModalOpen] = useState(false); - const [editing, setEditing] = useState(null); return ( <> - - - -
- Webhooks -
- Webhooks - Automation -
-
- -
-
-
-
- - {props.webhooks.length ? ( - - {props.webhooks.map((item) => ( - { - setEditing(item); - setEditModalOpen(true); - }} - /> - ))} - - ) : null} -
-
-
- {/* {!!props.webhooks.length && ( - {}} - onEditWebhook={editWebhook}> - )} */} -
-
-
- - +
@@ -398,25 +423,6 @@ function WebhookEmbed(props: { webhooks: TWebhook[] }) { {t("browse_api_documentation")}
- - {/* New webhook dialog */} - !isOpen && setNewWebhookModal(false)}> - - setNewWebhookModal(false)} /> - - - {/* Edit webhook dialog */} - !isOpen && setEditModalOpen(false)}> - - {editing && ( - setEditModalOpen(false)} - defaultValues={editing} - /> - )} - - ); } @@ -474,89 +480,59 @@ function ConnectOrDisconnectIntegrationButton(props: { ); } -export default function IntegrationsPage() { - const query = trpc.useQuery(["viewer.integrations"]); - const utils = trpc.useContext(); - const handleOpenChange = () => { - utils.invalidateQueries(["viewer.integrations"]); - }; +function IntegrationsContainer() { + const query = trpc.useQuery(["viewer.integrations"], { suspense: true }); + return ( + ( + <> + + } + /> + + {data.conferencing.items.map((item) => ( + } + /> + ))} + + + } + /> + + {data.payment.items.map((item) => ( + } + /> + ))} + + + )}> + ); +} + +export default function IntegrationsPage() { return ( - { - return ( - <> - - } - /> - - {data.conferencing.items.map((item) => ( - } - /> - ))} - - - - } - /> - - {data.payment.items.map((item) => ( - } - /> - ))} - - - - } - subtitle={ - <> - Configure how your links integrate with your calendars. -
- You can override these settings on a per event basis. - - } - /> - - {data.connectedCalendars.length > 0 && ( - <> - - } - /> - - )} - - - - ); - }} - /> + }> + + + + +
); } diff --git a/server/routers/viewer.tsx b/server/routers/viewer.tsx index 24c946a1db..89244d5512 100644 --- a/server/routers/viewer.tsx +++ b/server/routers/viewer.tsx @@ -313,6 +313,18 @@ const loggedInViewerRouter = createProtectedRouter() }; }, }) + .query("connectedCalendars", { + async resolve({ ctx }) { + const { user } = ctx; + // get user's credentials + their connected integrations + const calendarCredentials = getCalendarCredentials(user.credentials, user.id); + + // get all the connected integrations' calendars (from third party) + const connectedCalendars = await getConnectedCalendars(calendarCredentials, user.selectedCalendars); + + return connectedCalendars; + }, + }) .query("integrations", { async resolve({ ctx }) { const { user } = ctx; @@ -338,11 +350,6 @@ const loggedInViewerRouter = createProtectedRouter() // get all the connected integrations' calendars (from third party) const connectedCalendars = await getConnectedCalendars(calendarCredentials, user.selectedCalendars); - const webhooks = await ctx.prisma.webhook.findMany({ - where: { - userId: user.id, - }, - }); return { conferencing: { items: conferencing, @@ -357,7 +364,6 @@ const loggedInViewerRouter = createProtectedRouter() numActive: countActive(payment), }, connectedCalendars, - webhooks, }; }, }) diff --git a/tsconfig.json b/tsconfig.json index da9366290b..84a7cd0884 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -38,7 +38,8 @@ "jest-playwright-preset", "expect-playwright" ], - "allowJs": false + "allowJs": false, + "incremental": true }, "include": [ "next-env.d.ts", diff --git a/yarn.lock b/yarn.lock index c404d5d745..a12c894aaa 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2611,11 +2611,6 @@ bowser@^2.8.1: resolved "https://registry.yarnpkg.com/bowser/-/bowser-2.11.0.tgz#5ca3c35757a7aa5771500c70a73a9f91ef420a8f" integrity sha512-AlcaJBi/pqqJBIQ8U9Mcpc9i8Aqxn88Skv5d+xBX006BY5u8N3mGLHa5Lgppa7L/HfwgwLgZ6NYs+Ag6uUmJRA== -bowser@^2.8.1: - version "2.11.0" - resolved "https://registry.yarnpkg.com/bowser/-/bowser-2.11.0.tgz#5ca3c35757a7aa5771500c70a73a9f91ef420a8f" - integrity sha512-AlcaJBi/pqqJBIQ8U9Mcpc9i8Aqxn88Skv5d+xBX006BY5u8N3mGLHa5Lgppa7L/HfwgwLgZ6NYs+Ag6uUmJRA== - brace-expansion@^1.1.7: version "1.1.11" resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" @@ -3818,11 +3813,6 @@ fast-equals@^1.6.3: resolved "https://registry.yarnpkg.com/fast-equals/-/fast-equals-1.6.3.tgz#84839a1ce20627c463e1892f2ae316380c81b459" integrity sha512-4WKW0AL5+WEqO0zWavAfYGY1qwLsBgE//DN4TTcVEN2UlINgkv9b3vm2iHicoenWKSX9mKWmGOsU/iI5IST7pQ== -fast-equals@^1.6.3: - version "1.6.3" - resolved "https://registry.yarnpkg.com/fast-equals/-/fast-equals-1.6.3.tgz#84839a1ce20627c463e1892f2ae316380c81b459" - integrity sha512-4WKW0AL5+WEqO0zWavAfYGY1qwLsBgE//DN4TTcVEN2UlINgkv9b3vm2iHicoenWKSX9mKWmGOsU/iI5IST7pQ== - fast-glob@^3.1.1, fast-glob@^3.2.7: version "3.2.7" resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.2.7.tgz#fd6cb7a2d7e9aa7a7846111e85a196d6b2f766a1" @@ -4348,18 +4338,6 @@ history@^4.9.0: tiny-warning "^1.0.0" value-equal "^1.0.1" -history@^4.9.0: - version "4.10.1" - resolved "https://registry.yarnpkg.com/history/-/history-4.10.1.tgz#33371a65e3a83b267434e2b3f3b1b4c58aad4cf3" - integrity sha512-36nwAD620w12kuzPAsyINPWJqlNbij+hpK1k9XRloDtym8mxzGYl2c17LnV6IAGB2Dmg4tEa7G7DlawS0+qjew== - dependencies: - "@babel/runtime" "^7.1.2" - loose-envify "^1.2.0" - resolve-pathname "^3.0.0" - tiny-invariant "^1.0.2" - tiny-warning "^1.0.0" - value-equal "^1.0.1" - hmac-drbg@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/hmac-drbg/-/hmac-drbg-1.0.1.tgz#d2745701025a6c775a6c545793ed502fc0c649a1" @@ -6556,13 +6534,6 @@ path-to-regexp@^1.7.0: dependencies: isarray "0.0.1" -path-to-regexp@^1.7.0: - version "1.8.0" - resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-1.8.0.tgz#887b3ba9d84393e87a0a0b9f4cb756198b53548a" - integrity sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA== - dependencies: - isarray "0.0.1" - path-type@^3.0.0: version "3.0.0" resolved "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz#cef31dc8e0a1a3bb0d105c0cd97cf3bf47f4e36f" @@ -6998,9 +6969,10 @@ react-date-picker@^8.3.3: react-fit "^1.0.3" update-input-width "^1.2.2" -react-dom@17.0.2: +react-dom@^17.0.2: version "17.0.2" - resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-17.0.2.tgz#ecffb6845e3ad8dbfcdc498f0d0a939736502c23" + resolved "https://registry.npmjs.org/react-dom/-/react-dom-17.0.2.tgz#ecffb6845e3ad8dbfcdc498f0d0a939736502c23" + integrity sha512-s4h96KtLDUQlsENhMn1ar8t2bEa+q/YAtj8pPPdIjPDGBDIVNsrD9aXNWqspUe6AzKCIG0C1HZZLqLV7qpOBGA== dependencies: loose-envify "^1.1.0" object-assign "^4.1.1" @@ -7197,9 +7169,10 @@ react-use-intercom@1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/react-use-intercom/-/react-use-intercom-1.4.0.tgz#796527728c131ebf132186385bf78f69dbcd84cc" -react@17.0.2: +react@^17.0.2: version "17.0.2" - resolved "https://registry.yarnpkg.com/react/-/react-17.0.2.tgz#d0b5cc516d29eb3eee383f75b62864cfb6800037" + resolved "https://registry.npmjs.org/react/-/react-17.0.2.tgz#d0b5cc516d29eb3eee383f75b62864cfb6800037" + integrity sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA== dependencies: loose-envify "^1.1.0" object-assign "^4.1.1" @@ -7332,11 +7305,6 @@ resolve-pathname@^3.0.0: resolved "https://registry.yarnpkg.com/resolve-pathname/-/resolve-pathname-3.0.0.tgz#99d02224d3cf263689becbb393bc560313025dcd" integrity sha512-C7rARubxI8bXFNB/hqcp/4iUeIXJhJZvFPFPiSPRnhU5UPxzMFIl+2E6yY6c4k9giDJAhtV+enfA+G89N6Csng== -resolve-pathname@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/resolve-pathname/-/resolve-pathname-3.0.0.tgz#99d02224d3cf263689becbb393bc560313025dcd" - integrity sha512-C7rARubxI8bXFNB/hqcp/4iUeIXJhJZvFPFPiSPRnhU5UPxzMFIl+2E6yY6c4k9giDJAhtV+enfA+G89N6Csng== - resolve@^1.10.0, resolve@^1.20.0: version "1.20.0" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.20.0.tgz#629a013fb3f70755d6f0b7935cc1c2c5378b1975" @@ -7431,7 +7399,8 @@ saxes@^5.0.1: scheduler@^0.20.2: version "0.20.2" - resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.20.2.tgz#4baee39436e34aa93b4874bddcbf0fe8b8b50e91" + resolved "https://registry.npmjs.org/scheduler/-/scheduler-0.20.2.tgz#4baee39436e34aa93b4874bddcbf0fe8b8b50e91" + integrity sha512-2eWfGgAqqWFGqtdMmcL5zCMK1U8KlXv8SQFGglL3CEtd0aDVDWgeF/YoCmvln55m5zSk3J/20hTaSBeSObsQDQ== dependencies: loose-envify "^1.1.0" object-assign "^4.1.1"