From 5071e6566fdebbfd379f834d9c217a9c70e1b03c Mon Sep 17 00:00:00 2001 From: Erik Date: Thu, 11 Apr 2024 17:06:17 -0300 Subject: [PATCH] Revert "feat: new App install flow (#11975)" (#14540) --- apps/api/v2/tsconfig.json | 4 +- apps/web/components/apps/AppPage.tsx | 4 - .../components/apps/InstallAppButtonChild.tsx | 38 -- .../apps/installation/AccountsStepCard.tsx | 97 ---- .../apps/installation/ConfigureStepCard.tsx | 206 -------- .../apps/installation/EventTypesStepCard.tsx | 110 ---- .../apps/installation/StepHeader.tsx | 19 - .../web/components/eventtype/EventAppsTab.tsx | 48 +- apps/web/lib/hooks/useAppsData.ts | 58 -- apps/web/pages/apps/[slug]/index.tsx | 1 - .../pages/apps/installation/[[...step]].tsx | 497 ------------------ apps/web/playwright/fixtures/apps.ts | 10 - apps/web/playwright/fixtures/users.ts | 17 +- .../web/playwright/integrations-stripe.e2e.ts | 19 +- apps/web/public/static/locales/en/common.json | 7 - packages/app-store-cli/src/build.ts | 8 - .../_components/DynamicComponent.tsx | 2 +- .../EventTypeAppSettingsInterface.tsx | 9 - .../_utils/oauth/decodeOAuthState.ts | 3 - .../components/EventTypeAppCardInterface.tsx | 110 +++- .../EventTypeAppSettingsInterface.tsx | 117 ----- packages/app-store/alby/config.json | 3 +- packages/app-store/amie/config.json | 3 +- packages/app-store/applecalendar/_metadata.ts | 1 - packages/app-store/apps.browser.generated.tsx | 13 - packages/app-store/around/config.json | 3 +- packages/app-store/basecamp3/api/callback.ts | 7 - .../components/EventTypeAppCardInterface.tsx | 73 ++- .../EventTypeAppSettingsInterface.tsx | 61 --- packages/app-store/basecamp3/config.json | 3 +- packages/app-store/cal-ai/config.json | 1 - .../app-store/caldavcalendar/_metadata.ts | 1 - packages/app-store/campfire/config.json | 3 +- packages/app-store/closecom/config.json | 3 +- packages/app-store/cron/config.json | 3 +- packages/app-store/dailyvideo/_metadata.ts | 1 - packages/app-store/discord/config.json | 3 +- packages/app-store/eightxeight/config.json | 3 +- packages/app-store/element-call/config.json | 3 +- .../exchange2013calendar/_metadata.ts | 1 - .../exchange2016calendar/_metadata.ts | 1 - .../app-store/exchangecalendar/config.json | 3 +- packages/app-store/facetime/config.json | 3 +- .../components/EventTypeAppCardInterface.tsx | 15 +- .../EventTypeAppSettingsInterface.tsx | 25 - packages/app-store/fathom/config.json | 3 +- .../components/EventTypeAppCardInterface.tsx | 15 +- .../EventTypeAppSettingsInterface.tsx | 23 - packages/app-store/ga4/config.json | 3 +- packages/app-store/giphy/_metadata.ts | 1 - .../components/EventTypeAppCardInterface.tsx | 19 +- .../EventTypeAppSettingsInterface.tsx | 23 - .../app-store/googlecalendar/_metadata.ts | 1 - packages/app-store/googlevideo/_metadata.ts | 1 - .../components/EventTypeAppCardInterface.tsx | 15 +- .../EventTypeAppSettingsInterface.tsx | 23 - packages/app-store/gtm/config.json | 3 +- packages/app-store/hubspot/_metadata.ts | 1 - packages/app-store/huddle01video/_metadata.ts | 1 - packages/app-store/intercom/api/callback.ts | 7 - packages/app-store/intercom/config.json | 3 +- packages/app-store/jitsivideo/_metadata.ts | 1 - packages/app-store/larkcalendar/_metadata.ts | 1 - packages/app-store/make/config.json | 3 +- .../components/EventTypeAppCardInterface.tsx | 15 +- .../EventTypeAppSettingsInterface.tsx | 23 - packages/app-store/metapixel/config.json | 3 +- packages/app-store/mirotalk/config.json | 3 +- packages/app-store/n8n/config.json | 3 +- .../app-store/office365calendar/_metadata.ts | 1 - .../app-store/office365video/api/callback.ts | 4 - packages/app-store/office365video/config.json | 3 +- .../components/EventTypeAppCardInterface.tsx | 125 ++++- .../EventTypeAppSettingsInterface.tsx | 131 ----- packages/app-store/paypal/config.json | 3 +- packages/app-store/ping/config.json | 3 +- packages/app-store/pipedream/config.json | 3 +- .../components/EventTypeAppCardInterface.tsx | 35 +- .../EventTypeAppSettingsInterface.tsx | 40 -- packages/app-store/plausible/config.json | 3 +- .../components/EventTypeAppCardInterface.tsx | 54 +- .../EventTypeAppSettingsInterface.tsx | 55 -- packages/app-store/qr_code/config.json | 3 +- packages/app-store/raycast/config.json | 3 +- packages/app-store/riverside/config.json | 3 +- packages/app-store/routing-forms/config.json | 3 +- packages/app-store/salesforce/api/callback.ts | 5 - packages/app-store/salesforce/config.json | 3 +- packages/app-store/sendgrid/config.json | 3 +- packages/app-store/signal/config.json | 3 +- packages/app-store/sirius_video/config.json | 3 +- packages/app-store/stripepayment/_metadata.ts | 1 - .../app-store/stripepayment/api/callback.ts | 4 - .../components/EventTypeAppCardInterface.tsx | 141 ++++- .../EventTypeAppSettingsInterface.tsx | 138 ----- packages/app-store/sylapsvideo/config.json | 3 +- packages/app-store/tandemvideo/_metadata.ts | 1 - packages/app-store/typeform/config.json | 3 +- packages/app-store/types.d.ts | 20 - packages/app-store/vimcal/config.json | 3 +- packages/app-store/vital/_metadata.ts | 1 - .../weather_in_your_calendar/config.json | 3 +- packages/app-store/webex/config.json | 3 +- packages/app-store/whatsapp/config.json | 3 +- packages/app-store/whereby/config.json | 3 +- .../app-store/wipemycalother/_metadata.ts | 1 - packages/app-store/wordpress/config.json | 3 +- packages/app-store/zapier/_metadata.ts | 1 - packages/app-store/zoho-bigin/api/callback.ts | 5 - packages/app-store/zoho-bigin/config.json | 3 +- packages/app-store/zohocalendar/config.json | 3 +- packages/app-store/zohocrm/api/callback.ts | 5 - packages/app-store/zohocrm/config.json | 3 +- packages/app-store/zoomvideo/_metadata.ts | 1 - .../playwright/tests/action-based.e2e.ts | 3 - packages/features/auth/SAMLLogin.tsx | 2 +- .../OverlayCalendarSettingsModal.tsx | 1 + .../components/heading/SchedulerHeading.tsx | 2 +- .../api-keys/components/ApiKeyDialogForm.tsx | 12 +- .../ee/dsync/components/DirectoryInfo.tsx | 1 + .../pages/components/MemberListItem.tsx | 8 +- .../settings/other-team-members-view.tsx | 1 + .../settings/other-team-profile-view.tsx | 10 +- .../organizations/pages/settings/profile.tsx | 1 + .../ee/teams/components/AddNewTeamMembers.tsx | 1 + .../ee/teams/pages/team-members-view.tsx | 1 + .../workflows/components/WorkflowListPage.tsx | 7 +- .../components/ChildrenEventTypeSelect.tsx | 2 +- .../insights/filters/Download/index.tsx | 2 +- .../schedules/components/DateOverrideList.tsx | 2 +- .../components/NewScheduleButton.tsx | 1 + .../schedules/components/Schedule.tsx | 1 + .../components/AvailabilityEditSheet.tsx | 6 +- .../components/AvailabilitySliderTable.tsx | 2 +- .../components/TroubleshooterHeader.tsx | 2 +- .../components/WebhookTestDisclosure.tsx | 2 +- packages/lib/apps/appOnboardingSteps.ts | 5 - .../lib/apps/getAppOnboardingRedirectUrl.ts | 8 - packages/lib/apps/getAppOnboardingUrl.ts | 27 - .../lib/apps/shouldRedirectToAppOnboarding.ts | 9 - .../availability/AvailabilitySettings.tsx | 11 +- .../viewer/eventTypes/update.handler.ts | 1 - packages/types/App.d.ts | 2 - packages/ui/components/apps/AppCard.tsx | 36 -- packages/ui/components/form/step/Steps.tsx | 23 +- .../components/scrollable/ScrollableArea.tsx | 2 +- 146 files changed, 698 insertions(+), 2151 deletions(-) delete mode 100644 apps/web/components/apps/installation/AccountsStepCard.tsx delete mode 100644 apps/web/components/apps/installation/ConfigureStepCard.tsx delete mode 100644 apps/web/components/apps/installation/EventTypesStepCard.tsx delete mode 100644 apps/web/components/apps/installation/StepHeader.tsx delete mode 100644 apps/web/lib/hooks/useAppsData.ts delete mode 100644 apps/web/pages/apps/installation/[[...step]].tsx delete mode 100644 packages/app-store/_components/EventTypeAppSettingsInterface.tsx delete mode 100644 packages/app-store/alby/components/EventTypeAppSettingsInterface.tsx delete mode 100644 packages/app-store/basecamp3/components/EventTypeAppSettingsInterface.tsx delete mode 100644 packages/app-store/fathom/components/EventTypeAppSettingsInterface.tsx delete mode 100644 packages/app-store/ga4/components/EventTypeAppSettingsInterface.tsx delete mode 100644 packages/app-store/giphy/components/EventTypeAppSettingsInterface.tsx delete mode 100644 packages/app-store/gtm/components/EventTypeAppSettingsInterface.tsx delete mode 100644 packages/app-store/metapixel/components/EventTypeAppSettingsInterface.tsx delete mode 100644 packages/app-store/paypal/components/EventTypeAppSettingsInterface.tsx delete mode 100644 packages/app-store/plausible/components/EventTypeAppSettingsInterface.tsx delete mode 100644 packages/app-store/qr_code/components/EventTypeAppSettingsInterface.tsx delete mode 100644 packages/app-store/stripepayment/components/EventTypeAppSettingsInterface.tsx delete mode 100644 packages/lib/apps/appOnboardingSteps.ts delete mode 100644 packages/lib/apps/getAppOnboardingRedirectUrl.ts delete mode 100644 packages/lib/apps/getAppOnboardingUrl.ts delete mode 100644 packages/lib/apps/shouldRedirectToAppOnboarding.ts diff --git a/apps/api/v2/tsconfig.json b/apps/api/v2/tsconfig.json index f56830b0ab..3e738f6261 100644 --- a/apps/api/v2/tsconfig.json +++ b/apps/api/v2/tsconfig.json @@ -23,6 +23,6 @@ "forceConsistentCasingInFileNames": false, "noFallthroughCasesInSwitch": false }, - "exclude": ["./dist"], - "include": ["./**/*.ts", "../../../packages/types/*.d.ts", "next-i18next.config.js"] + "exclude": ["./dist", "next-i18next.config.js"], + "include": ["./**/*.ts", "../../../packages/types/*.d.ts"] } diff --git a/apps/web/components/apps/AppPage.tsx b/apps/web/components/apps/AppPage.tsx index ae2313c733..4ff36ca97a 100644 --- a/apps/web/components/apps/AppPage.tsx +++ b/apps/web/components/apps/AppPage.tsx @@ -21,7 +21,6 @@ export type AppPageProps = { isGlobal?: AppType["isGlobal"]; logo: string; slug: string; - dirName: string | undefined; variant: string; body: React.ReactNode; categories: string[]; @@ -69,7 +68,6 @@ export const AppPage = ({ dependencies, concurrentMeetings, paid, - dirName, }: AppPageProps) => { const { t, i18n } = useLocale(); const hasDescriptionItems = descriptionItems && descriptionItems.length > 0; @@ -225,7 +223,6 @@ export const AppPage = ({ multiInstall concurrentMeetings={concurrentMeetings} paid={paid} - dirName={dirName} {...props} /> ); @@ -265,7 +262,6 @@ export const AppPage = ({ credentials={appDbQuery.data?.credentials} concurrentMeetings={concurrentMeetings} paid={paid} - dirName={dirName} {...props} /> ); diff --git a/apps/web/components/apps/InstallAppButtonChild.tsx b/apps/web/components/apps/InstallAppButtonChild.tsx index fd0a81113a..640a603160 100644 --- a/apps/web/components/apps/InstallAppButtonChild.tsx +++ b/apps/web/components/apps/InstallAppButtonChild.tsx @@ -1,14 +1,7 @@ -import { useRouter } from "next/navigation"; -import { useMemo } from "react"; - import useAddAppMutation from "@calcom/app-store/_utils/useAddAppMutation"; -import { appStoreMetadata } from "@calcom/app-store/appStoreMetaData"; import { doesAppSupportTeamInstall } from "@calcom/app-store/utils"; import { Spinner } from "@calcom/features/calendars/weeklyview/components/spinner/Spinner"; import type { UserAdminTeams } from "@calcom/features/ee/teams/lib/getUserAdminTeams"; -import { AppOnboardingSteps } from "@calcom/lib/apps/appOnboardingSteps"; -import { getAppOnboardingUrl } from "@calcom/lib/apps/getAppOnboardingUrl"; -import { shouldRedirectToAppOnboarding } from "@calcom/lib/apps/shouldRedirectToAppOnboarding"; import { WEBAPP_URL } from "@calcom/lib/constants"; import { useLocale } from "@calcom/lib/hooks/useLocale"; import type { RouterOutputs } from "@calcom/trpc/react"; @@ -33,9 +26,7 @@ export const InstallAppButtonChild = ({ multiInstall, credentials, concurrentMeetings, - dirName, paid, - onClick, ...props }: { userAdminTeams?: UserAdminTeams; @@ -45,10 +36,8 @@ export const InstallAppButtonChild = ({ credentials?: RouterOutputs["viewer"]["appCredentialsByType"]["credentials"]; concurrentMeetings?: boolean; paid?: AppFrontendPayload["paid"]; - dirName: string | undefined; } & ButtonProps) => { const { t } = useLocale(); - const router = useRouter(); const mutation = useAddAppMutation(null, { onSuccess: (data) => { @@ -60,18 +49,6 @@ export const InstallAppButtonChild = ({ }, }); const shouldDisableInstallation = !multiInstall ? !!(credentials && credentials.length) : false; - const appMetadata = appStoreMetadata[dirName as keyof typeof appStoreMetadata]; - const redirectToAppOnboarding = useMemo(() => shouldRedirectToAppOnboarding(appMetadata), [appMetadata]); - - const _onClick = (e: React.MouseEvent) => { - if (redirectToAppOnboarding) { - router.push( - getAppOnboardingUrl({ slug: addAppMutationInput.slug, step: AppOnboardingSteps.ACCOUNTS_STEP }) - ); - } else if (onClick) { - onClick(e); - } - }; // Paid apps don't support team installs at the moment // Also, cal.ai(the only paid app at the moment) doesn't support team install either @@ -79,7 +56,6 @@ export const InstallAppButtonChild = ({ return ( - ); - } return ( diff --git a/apps/web/components/apps/installation/AccountsStepCard.tsx b/apps/web/components/apps/installation/AccountsStepCard.tsx deleted file mode 100644 index 7ccb612bd7..0000000000 --- a/apps/web/components/apps/installation/AccountsStepCard.tsx +++ /dev/null @@ -1,97 +0,0 @@ -import type { FC } from "react"; -import React, { useState } from "react"; - -import { classNames } from "@calcom/lib"; -import { CAL_URL } from "@calcom/lib/constants"; -import { useLocale } from "@calcom/lib/hooks/useLocale"; -import type { Team, User } from "@calcom/prisma/client"; -import { Avatar, StepCard } from "@calcom/ui"; - -type AccountSelectorProps = { - avatar?: string; - name: string; - alreadyInstalled: boolean; - onClick?: () => void; - loading: boolean; - testId: string; -}; - -const AccountSelector: FC = ({ - avatar, - alreadyInstalled, - name, - onClick, - loading, - testId, -}) => { - const { t } = useLocale(); - const [selected, setSelected] = useState(false); - return ( -
{ - if (onClick) { - setSelected(true); - onClick(); - } - }}> - -
- {name} - {alreadyInstalled ? {t("already_installed")} : ""} -
-
- ); -}; - -export type PersonalAccountProps = Pick & { alreadyInstalled: boolean }; - -export type TeamsProp = (Pick & { - alreadyInstalled: boolean; -})[]; - -type AccountStepCardProps = { - teams: TeamsProp; - personalAccount: PersonalAccountProps; - onSelect: (id?: number) => void; - loading: boolean; -}; - -export const AccountsStepCard: FC = ({ teams, personalAccount, onSelect, loading }) => { - const { t } = useLocale(); - return ( - -
{t("install_app_on")}
-
- !personalAccount.alreadyInstalled && !loading && onSelect()} - loading={loading} - /> - {teams.map((team) => ( - !team.alreadyInstalled && !loading && onSelect(team.id)} - loading={loading} - /> - ))} -
-
- ); -}; diff --git a/apps/web/components/apps/installation/ConfigureStepCard.tsx b/apps/web/components/apps/installation/ConfigureStepCard.tsx deleted file mode 100644 index 9eb8b4bccb..0000000000 --- a/apps/web/components/apps/installation/ConfigureStepCard.tsx +++ /dev/null @@ -1,206 +0,0 @@ -import type { TEventType, TEventTypesForm } from "@pages/apps/installation/[[...step]]"; -import { X } from "lucide-react"; -import type { Dispatch, SetStateAction } from "react"; -import type { FC } from "react"; -import React, { forwardRef, useEffect, useRef, useState } from "react"; -import { createPortal } from "react-dom"; -import { useFieldArray, useFormContext } from "react-hook-form"; -import { useForm } from "react-hook-form"; -import type { z } from "zod"; - -import { EventTypeAppSettings } from "@calcom/app-store/_components/EventTypeAppSettingsInterface"; -import type { EventTypeAppsList } from "@calcom/app-store/utils"; -import { useLocale } from "@calcom/lib/hooks/useLocale"; -import type { AppCategories } from "@calcom/prisma/enums"; -import type { EventTypeMetaDataSchema } from "@calcom/prisma/zod-utils"; -import { Button, Form } from "@calcom/ui"; - -import useAppsData from "@lib/hooks/useAppsData"; - -type TFormType = { - metadata: z.infer; -}; - -type ConfigureStepCardProps = { - slug: string; - userName: string; - categories: AppCategories[]; - credentialId?: number; - loading?: boolean; - formPortalRef: React.RefObject; - eventTypes: TEventType[] | undefined; - setConfigureStep: Dispatch>; -}; - -type EventTypeAppSettingsFormProps = Pick< - ConfigureStepCardProps, - "slug" | "userName" | "categories" | "credentialId" | "loading" -> & { - eventType: TEventType; - handleDelete: () => void; - onSubmit: (values: z.infer) => void; -}; - -type EventTypeAppSettingsWrapperProps = Pick< - ConfigureStepCardProps, - "slug" | "userName" | "categories" | "credentialId" -> & { - eventType: TEventType; -}; - -const EventTypeAppSettingsWrapper: FC = ({ - slug, - eventType, - categories, - credentialId, -}) => { - const { getAppDataGetter, getAppDataSetter } = useAppsData(); - - useEffect(() => { - const appDataSetter = getAppDataSetter(slug as EventTypeAppsList, categories, credentialId); - appDataSetter("enabled", true); - }, []); - - return ( - - ); -}; - -const EventTypeAppSettingsForm = forwardRef( - function EventTypeAppSettingsForm(props, ref) { - const { handleDelete, onSubmit, eventType, loading } = props; - - const formMethods = useForm({ - defaultValues: { - metadata: eventType?.metadata, - }, - }); - - return ( -
{ - const data = formMethods.getValues("metadata"); - onSubmit(data); - }}> -
-
-
- {eventType.title}{" "} - - /{eventType.team ? eventType.team.slug : props.userName}/{eventType.slug} - -
- - !loading && handleDelete()} - /> - -
-
-
- ); - } -); - -export const ConfigureStepCard: FC = ({ - loading, - formPortalRef, - eventTypes, - setConfigureStep, - ...props -}) => { - const { t } = useLocale(); - const { control, getValues } = useFormContext(); - const { fields, update } = useFieldArray({ - control, - name: "eventTypes", - keyName: "fieldId", - }); - - const submitRefs = useRef>>([]); - submitRefs.current = fields.map( - (_ref, index) => (submitRefs.current[index] = React.createRef()) - ); - const mainForSubmitRef = useRef(null); - const [updatedEventTypesStatus, setUpdatedEventTypesStatus] = useState( - fields.filter((field) => field.selected).map((field) => ({ id: field.id, updated: false })) - ); - const [submit, setSubmit] = useState(false); - const allUpdated = updatedEventTypesStatus.every((item) => item.updated); - - useEffect(() => { - setUpdatedEventTypesStatus((prev) => - prev.filter((state) => fields.some((field) => field.id === state.id && field.selected)) - ); - if (!fields.some((field) => field.selected)) { - setConfigureStep(false); - } - }, [fields]); - - useEffect(() => { - if (submit && allUpdated && mainForSubmitRef.current) { - mainForSubmitRef.current?.click(); - setSubmit(false); - } - }, [submit, allUpdated, getValues, mainForSubmitRef]); - - return ( - formPortalRef?.current && - createPortal( -
-
- {fields.map((field, index) => { - return ( - field.selected && ( - { - const eventMetadataDb = eventTypes?.find( - (eventType) => eventType.id == field.id - )?.metadata; - update(index, { ...field, selected: false, metadata: eventMetadataDb }); - }} - onSubmit={(data) => { - update(index, { ...field, metadata: data }); - setUpdatedEventTypesStatus((prev) => - prev.map((item) => (item.id === field.id ? { ...item, updated: true } : item)) - ); - }} - ref={submitRefs.current[index]} - {...props} - /> - ) - ); - })} -
- - - -
, - formPortalRef?.current - ) - ); -}; diff --git a/apps/web/components/apps/installation/EventTypesStepCard.tsx b/apps/web/components/apps/installation/EventTypesStepCard.tsx deleted file mode 100644 index 4b5993f8a3..0000000000 --- a/apps/web/components/apps/installation/EventTypesStepCard.tsx +++ /dev/null @@ -1,110 +0,0 @@ -import type { TEventType, TEventTypesForm } from "@pages/apps/installation/[[...step]]"; -import type { Dispatch, SetStateAction } from "react"; -import type { FC } from "react"; -import React from "react"; -import { useFieldArray, useFormContext } from "react-hook-form"; - -import { useLocale } from "@calcom/lib/hooks/useLocale"; -import { EventTypeMetaDataSchema } from "@calcom/prisma/zod-utils"; -import { ScrollableArea, Badge, Button } from "@calcom/ui"; - -type EventTypesCardProps = { - userName: string; - setConfigureStep: Dispatch>; -}; - -export const EventTypesStepCard: FC = ({ setConfigureStep, userName }) => { - const { t } = useLocale(); - const { control } = useFormContext(); - const { fields, update } = useFieldArray({ - control, - name: "eventTypes", - keyName: "fieldId", - }); - - return ( - <> -
- -
    - {fields.map((field, index) => ( - update(index, { ...field, selected: !field.selected })} - userName={userName} - key={field.fieldId} - {...field} - /> - ))} -
-
-
- - - - ); -}; - -type EventTypeCardProps = TEventType & { userName: string; handleSelect: () => void }; - -const EventTypeCard: FC = ({ - title, - description, - id, - metadata, - length, - selected, - slug, - handleSelect, - team, - userName, -}) => { - const parsedMetaData = EventTypeMetaDataSchema.safeParse(metadata); - const durations = - parsedMetaData.success && - parsedMetaData.data?.multipleDuration && - Boolean(parsedMetaData.data?.multipleDuration.length) - ? [length, ...parsedMetaData.data?.multipleDuration?.filter((duration) => duration !== length)].sort() - : [length]; - return ( -
handleSelect()}> - - -
- ); -}; diff --git a/apps/web/components/apps/installation/StepHeader.tsx b/apps/web/components/apps/installation/StepHeader.tsx deleted file mode 100644 index e79dbc2ea6..0000000000 --- a/apps/web/components/apps/installation/StepHeader.tsx +++ /dev/null @@ -1,19 +0,0 @@ -import type { FC, ReactNode } from "react"; - -type StepHeaderProps = { - children?: ReactNode; - title: string; - subtitle: string; -}; -export const StepHeader: FC = ({ children, title, subtitle }) => { - return ( -
-
-

{title}

- -

{subtitle}

-
- {children} -
- ); -}; diff --git a/apps/web/components/eventtype/EventAppsTab.tsx b/apps/web/components/eventtype/EventAppsTab.tsx index 8515c5a074..8d56dd00b1 100644 --- a/apps/web/components/eventtype/EventAppsTab.tsx +++ b/apps/web/components/eventtype/EventAppsTab.tsx @@ -3,6 +3,7 @@ import Link from "next/link"; import type { EventTypeSetupProps } from "pages/event-types/[type]"; import { useFormContext } from "react-hook-form"; +import type { GetAppData, SetAppData } from "@calcom/app-store/EventTypeAppContext"; import { EventTypeAppCard } from "@calcom/app-store/_components/EventTypeAppCardInterface"; import type { EventTypeAppCardComponentProps } from "@calcom/app-store/types"; import type { EventTypeAppsList } from "@calcom/app-store/utils"; @@ -12,8 +13,6 @@ import { useLocale } from "@calcom/lib/hooks/useLocale"; import { trpc } from "@calcom/trpc/react"; import { Alert, Button, EmptyScreen } from "@calcom/ui"; -import useAppsData from "@lib/hooks/useAppsData"; - export type EventType = Pick["eventType"] & EventTypeAppCardComponentProps["eventType"]; @@ -29,8 +28,51 @@ export const EventAppsTab = ({ eventType }: { eventType: EventType }) => { eventTypeApps?.items.filter((app) => app.userCredentialIds.length || app.teams.length) || []; const notInstalledApps = eventTypeApps?.items.filter((app) => !app.userCredentialIds.length && !app.teams.length) || []; + const allAppsData = formMethods.watch("metadata")?.apps || {}; - const { getAppDataGetter, getAppDataSetter, eventTypeFormMetadata } = useAppsData(); + const setAllAppsData = (_allAppsData: typeof allAppsData) => { + formMethods.setValue( + "metadata", + { + ...formMethods.getValues("metadata"), + apps: _allAppsData, + }, + { shouldDirty: true } + ); + }; + + const getAppDataGetter = (appId: EventTypeAppsList): GetAppData => { + return function (key) { + const appData = allAppsData[appId as keyof typeof allAppsData] || {}; + if (key) { + return appData[key as keyof typeof appData]; + } + return appData; + }; + }; + + const eventTypeFormMetadata = formMethods.getValues("metadata"); + + const getAppDataSetter = ( + appId: EventTypeAppsList, + appCategories: string[], + credentialId?: number + ): SetAppData => { + return function (key, value) { + // Always get latest data available in Form because consequent calls to setData would update the Form but not allAppsData(it would update during next render) + const allAppsDataFromForm = formMethods.getValues("metadata")?.apps || {}; + const appData = allAppsDataFromForm[appId]; + setAllAppsData({ + ...allAppsDataFromForm, + [appId]: { + ...appData, + [key]: value, + credentialId, + appCategories, + }, + }); + }; + }; const { shouldLockDisableProps, isManagedEventType, isChildrenManagedEventType } = useLockedFieldsManager({ eventType, diff --git a/apps/web/lib/hooks/useAppsData.ts b/apps/web/lib/hooks/useAppsData.ts deleted file mode 100644 index b5496a867a..0000000000 --- a/apps/web/lib/hooks/useAppsData.ts +++ /dev/null @@ -1,58 +0,0 @@ -import type { FormValues } from "pages/event-types/[type]"; -import { useFormContext } from "react-hook-form"; - -import type { GetAppData, SetAppData } from "@calcom/app-store/EventTypeAppContext"; -import type { EventTypeAppsList } from "@calcom/app-store/utils"; - -const useAppsData = () => { - const formMethods = useFormContext(); - const allAppsData = formMethods.watch("metadata")?.apps || {}; - - const setAllAppsData = (_allAppsData: typeof allAppsData) => { - formMethods.setValue( - "metadata", - { - ...formMethods.getValues("metadata"), - apps: _allAppsData, - }, - { shouldDirty: true } - ); - }; - - const getAppDataGetter = (appId: EventTypeAppsList): GetAppData => { - return function (key) { - const appData = allAppsData[appId as keyof typeof allAppsData] || {}; - if (key) { - return appData[key as keyof typeof appData]; - } - return appData; - }; - }; - - const eventTypeFormMetadata = formMethods.getValues("metadata"); - - const getAppDataSetter = ( - appId: EventTypeAppsList, - appCategories: string[], - credentialId?: number - ): SetAppData => { - return function (key, value) { - // Always get latest data available in Form because consequent calls to setData would update the Form but not allAppsData(it would update during next render) - const allAppsDataFromForm = formMethods.getValues("metadata")?.apps || {}; - const appData = allAppsDataFromForm[appId]; - setAllAppsData({ - ...allAppsDataFromForm, - [appId]: { - ...appData, - [key]: value, - credentialId, - appCategories, - }, - }); - }; - }; - - return { getAppDataGetter, getAppDataSetter, eventTypeFormMetadata }; -}; - -export default useAppsData; diff --git a/apps/web/pages/apps/[slug]/index.tsx b/apps/web/pages/apps/[slug]/index.tsx index 1927fc8671..8eee52c3f5 100644 --- a/apps/web/pages/apps/[slug]/index.tsx +++ b/apps/web/pages/apps/[slug]/index.tsx @@ -53,7 +53,6 @@ function SingleAppPage(props: inferSSRProps) { slug={data.slug} variant={data.variant} type={data.type} - dirName={data.dirName} logo={data.logo} categories={data.categories ?? [data.category]} author={data.publisher} diff --git a/apps/web/pages/apps/installation/[[...step]].tsx b/apps/web/pages/apps/installation/[[...step]].tsx deleted file mode 100644 index a8f4040775..0000000000 --- a/apps/web/pages/apps/installation/[[...step]].tsx +++ /dev/null @@ -1,497 +0,0 @@ -import type { GetServerSidePropsContext } from "next"; -import { serverSideTranslations } from "next-i18next/serverSideTranslations"; -import Head from "next/head"; -import { usePathname, useRouter } from "next/navigation"; -import { useEffect, useMemo, useRef, useState } from "react"; -import { useForm } from "react-hook-form"; -import { Toaster } from "react-hot-toast"; -import { z } from "zod"; - -import checkForMultiplePaymentApps from "@calcom/app-store/_utils/payments/checkForMultiplePaymentApps"; -import { appStoreMetadata } from "@calcom/app-store/appStoreMetaData"; -import type { EventTypeAppSettingsComponentProps, EventTypeModel } from "@calcom/app-store/types"; -import { getLocale } from "@calcom/features/auth/lib/getLocale"; -import { getServerSession } from "@calcom/features/auth/lib/getServerSession"; -import { AppOnboardingSteps } from "@calcom/lib/apps/appOnboardingSteps"; -import { getAppOnboardingRedirectUrl } from "@calcom/lib/apps/getAppOnboardingRedirectUrl"; -import { getAppOnboardingUrl } from "@calcom/lib/apps/getAppOnboardingUrl"; -import { CAL_URL } from "@calcom/lib/constants"; -import { useLocale } from "@calcom/lib/hooks/useLocale"; -import prisma from "@calcom/prisma"; -import type { EventTypeMetaDataSchema } from "@calcom/prisma/zod-utils"; -import { trpc } from "@calcom/trpc/react"; -import type { AppMeta } from "@calcom/types/App"; -import { Form, Steps, showToast } from "@calcom/ui"; - -import { HttpError } from "@lib/core/http/error"; - -import PageWrapper from "@components/PageWrapper"; -import type { PersonalAccountProps, TeamsProp } from "@components/apps/installation/AccountsStepCard"; -import { AccountsStepCard } from "@components/apps/installation/AccountsStepCard"; -import { ConfigureStepCard } from "@components/apps/installation/ConfigureStepCard"; -import { EventTypesStepCard } from "@components/apps/installation/EventTypesStepCard"; -import { StepHeader } from "@components/apps/installation/StepHeader"; - -export type TEventType = EventTypeAppSettingsComponentProps["eventType"] & - Pick & { - selected: boolean; - }; - -export type TEventTypesForm = { - eventTypes: TEventType[]; -}; - -const STEPS = [ - AppOnboardingSteps.ACCOUNTS_STEP, - AppOnboardingSteps.EVENT_TYPES_STEP, - AppOnboardingSteps.CONFIGURE_STEP, -] as const; -const MAX_NUMBER_OF_STEPS = STEPS.length; - -type StepType = (typeof STEPS)[number]; - -type StepObj = Record< - StepType, - { - getTitle: (appName: string) => string; - getDescription: (appName: string) => string; - stepNumber: number; - } ->; - -type OnboardingPageProps = { - appMetadata: AppMeta; - step: StepType; - teams: TeamsProp; - personalAccount: PersonalAccountProps; - eventTypes?: TEventType[]; - userName: string; - credentialId?: number; -}; - -const OnboardingPage = ({ - step, - teams, - personalAccount, - appMetadata, - eventTypes, - userName, - credentialId, -}: OnboardingPageProps) => { - const { t } = useLocale(); - const pathname = usePathname(); - const router = useRouter(); - - const STEPS_MAP: StepObj = { - [AppOnboardingSteps.ACCOUNTS_STEP]: { - getTitle: () => `${t("select_account_header")}`, - getDescription: (appName) => `${t("select_account_description", { appName })}`, - stepNumber: 1, - }, - [AppOnboardingSteps.EVENT_TYPES_STEP]: { - getTitle: () => `${t("select_event_types_header")}`, - getDescription: (appName) => `${t("select_event_types_description", { appName })}`, - stepNumber: 2, - }, - [AppOnboardingSteps.CONFIGURE_STEP]: { - getTitle: (appName) => `${t("configure_app_header", { appName })}`, - getDescription: () => `${t("configure_app_description")}`, - stepNumber: 3, - }, - } as const; - const [configureStep, setConfigureStep] = useState(false); - const [isSelectingAccount, setIsSelectingAccount] = useState(false); - - const currentStep: AppOnboardingSteps = useMemo(() => { - if (step == AppOnboardingSteps.EVENT_TYPES_STEP && configureStep) { - return AppOnboardingSteps.CONFIGURE_STEP; - } - return step; - }, [step, configureStep]); - const stepObj = STEPS_MAP[currentStep]; - - const utils = trpc.useContext(); - - const formPortalRef = useRef(null); - - const formMethods = useForm({ - defaultValues: { - eventTypes, - }, - }); - - useEffect(() => { - eventTypes && formMethods.setValue("eventTypes", eventTypes); - }, [eventTypes]); - - const updateMutation = trpc.viewer.eventTypes.update.useMutation({ - onSuccess: async (data) => { - showToast(t("event_type_updated_successfully", { eventTypeTitle: data.eventType?.title }), "success"); - router.push("/event-types"); - }, - async onSettled() { - await utils.viewer.eventTypes.get.invalidate(); - }, - onError: (err) => { - let message = ""; - if (err instanceof HttpError) { - const message = `${err.statusCode}: ${err.message}`; - showToast(message, "error"); - } - - if (err.data?.code === "UNAUTHORIZED") { - message = `${err.data.code}: ${t("error_event_type_unauthorized_update")}`; - } - - if (err.data?.code === "PARSE_ERROR" || err.data?.code === "BAD_REQUEST") { - message = `${err.data.code}: ${t(err.message)}`; - } - - if (err.data?.code === "INTERNAL_SERVER_ERROR") { - message = t("unexpected_error_try_again"); - } - - showToast(message ? t(message) : t(err.message), "error"); - }, - }); - - const handleSelectAccount = async (teamId?: number) => { - try { - setIsSelectingAccount(true); - if (appMetadata.isOAuth) { - const state = JSON.stringify({ - appOnboardingRedirectUrl: getAppOnboardingRedirectUrl(appMetadata.slug, teamId), - teamId, - }); - - const res = await fetch( - `/api/integrations/${ - appMetadata.slug == "stripe" ? "stripepayment" : appMetadata.slug - }/add?state=${state}`, - { - method: "GET", - headers: { - "Content-Type": "application/json", - }, - } - ); - const oAuthUrl = (await res.json())?.url; - router.push(oAuthUrl); - return; - } else { - await fetch(`/api/integrations/${appMetadata.slug}/add${teamId ? `?teamId=${teamId}` : ""}`, { - method: "GET", - headers: { - "Content-Type": "application/json", - }, - }); - router.push( - getAppOnboardingUrl({ - slug: appMetadata.slug, - step: AppOnboardingSteps.EVENT_TYPES_STEP, - teamId, - }) - ); - } - } catch (error) { - setIsSelectingAccount(false); - router.push(`/apps`); - } - }; - - return ( -
- - - {t("install")} {appMetadata?.name ?? ""} - - - -
-
-
-
{ - const mutationPromises = values?.eventTypes - .filter((eventType) => eventType.selected) - .map((value: TEventType) => { - // Prevent two payment apps to be enabled - // Ok to cast type here because this metadata will be updated as the event type metadata - if ( - checkForMultiplePaymentApps(value.metadata as z.infer) - ) - throw new Error(t("event_setup_multiple_payment_apps_error")); - if (value.metadata?.apps?.stripe?.paymentOption === "HOLD" && value.seatsPerTimeSlot) { - throw new Error(t("seats_and_no_show_fee_error")); - } - return updateMutation.mutateAsync({ - id: value.id, - metadata: value.metadata, - }); - }); - await Promise.all(mutationPromises); - }}> - - - - {currentStep === AppOnboardingSteps.ACCOUNTS_STEP && ( - - )} - {currentStep === AppOnboardingSteps.EVENT_TYPES_STEP && - eventTypes && - Boolean(eventTypes?.length) && ( - - )} - {currentStep === AppOnboardingSteps.CONFIGURE_STEP && formPortalRef.current && ( - - )} - -
-
-
- -
- ); -}; - -// Redirect Error map to give context on edge cases, this is for the devs, never shown to users -const ERROR_MESSAGES = { - appNotFound: "App not found", - userNotAuthed: "User is not logged in", - userNotFound: "User from session not found", - appNotExtendsEventType: "App does not extend EventTypes", - userNotInTeam: "User is not in provided team", -} as const; - -const getUser = async (userId: number) => { - const user = await prisma.user.findUnique({ - where: { - id: userId, - }, - select: { - id: true, - avatar: true, - name: true, - username: true, - teams: { - where: { - accepted: true, - team: { - members: { - some: { - userId, - role: { - in: ["ADMIN", "OWNER"], - }, - }, - }, - }, - }, - select: { - team: { - select: { - id: true, - name: true, - logo: true, - }, - }, - }, - }, - }, - }); - - if (!user) { - throw new Error(ERROR_MESSAGES.userNotFound); - } - return user; -}; - -const getAppBySlug = async (appSlug: string) => { - const app = await prisma.app.findUnique({ - where: { slug: appSlug, enabled: true }, - select: { slug: true, keys: true, enabled: true, dirName: true }, - }); - if (!app) throw new Error(ERROR_MESSAGES.appNotFound); - return app; -}; - -const getEventTypes = async (userId: number, teamId?: number) => { - const eventTypes = ( - await prisma.eventType.findMany({ - select: { - id: true, - description: true, - durationLimits: true, - metadata: true, - length: true, - title: true, - position: true, - recurringEvent: true, - requiresConfirmation: true, - team: { select: { slug: true } }, - schedulingType: true, - teamId: true, - users: { select: { username: true } }, - seatsPerTimeSlot: true, - slug: true, - }, - where: teamId ? { teamId } : { userId }, - }) - ).sort((eventTypeA, eventTypeB) => { - return eventTypeB.position - eventTypeA.position; - }); - if (eventTypes.length === 0) { - return []; - } - return eventTypes.map((item) => ({ - ...item, - URL: `${CAL_URL}/${item.team ? `team/${item.team.slug}` : item?.users?.[0]?.username}/${item.slug}`, - selected: false, - })); -}; - -const getAppInstallsBySlug = async (appSlug: string, userId: number, teamIds?: number[]) => { - const appInstalls = await prisma.credential.findMany({ - where: { - OR: [ - { - appId: appSlug, - userId: userId, - }, - teamIds && Boolean(teamIds.length) - ? { - appId: appSlug, - teamId: { in: teamIds }, - } - : {}, - ], - }, - }); - return appInstalls; -}; - -export const getServerSideProps = async (context: GetServerSidePropsContext) => { - try { - let eventTypes: TEventType[] | null = null; - const { req, res, query, params } = context; - const stepsEnum = z.enum(STEPS); - const parsedAppSlug = z.coerce.string().parse(query?.slug); - const parsedStepParam = z.coerce.string().parse(params?.step); - const parsedTeamIdParam = z.coerce.number().optional().parse(query?.teamId); - const _ = stepsEnum.parse(parsedStepParam); - const session = await getServerSession({ req, res }); - const locale = await getLocale(context.req); - const app = await getAppBySlug(parsedAppSlug); - const appMetadata = appStoreMetadata[app.dirName as keyof typeof appStoreMetadata]; - const hasEventTypes = appMetadata?.extendsFeature === "EventType"; - - if (!session?.user?.id) throw new Error(ERROR_MESSAGES.userNotAuthed); - if (!hasEventTypes) { - throw new Error(ERROR_MESSAGES.appNotExtendsEventType); - } - - const user = await getUser(session.user.id); - - const userAcceptedTeams = user.teams.map((team) => ({ ...team.team })); - const hasTeams = Boolean(userAcceptedTeams.length); - - const appInstalls = await getAppInstallsBySlug( - parsedAppSlug, - user.id, - userAcceptedTeams.map(({ id }) => id) - ); - - if (parsedTeamIdParam) { - const isUserMemberOfTeam = userAcceptedTeams.some((team) => team.id === parsedTeamIdParam); - if (!isUserMemberOfTeam) { - throw new Error(ERROR_MESSAGES.userNotInTeam); - } - } - - if (parsedStepParam == AppOnboardingSteps.EVENT_TYPES_STEP) { - eventTypes = await getEventTypes(user.id, parsedTeamIdParam); - if (eventTypes.length === 0) { - return { - redirect: { permanent: false, destination: `/apps/installed/${appMetadata.categories[0]}` }, - }; - } - } - - const personalAccount = { - id: user.id, - name: user.name, - avatar: user.avatar, - alreadyInstalled: appInstalls.some((install) => !Boolean(install.teamId) && install.userId === user.id), - }; - - const teamsWithIsAppInstalled = hasTeams - ? userAcceptedTeams.map((team) => ({ - ...team, - alreadyInstalled: appInstalls.some( - (install) => Boolean(install.teamId) && install.teamId === team.id - ), - })) - : []; - let credentialId = null; - if (parsedTeamIdParam) { - credentialId = - appInstalls.find((item) => !!item.teamId && item.teamId == parsedTeamIdParam)?.id ?? null; - } else { - credentialId = appInstalls.find((item) => !!item.userId && item.userId == user.id)?.id ?? null; - } - return { - props: { - ...(await serverSideTranslations(locale, ["common"])), - app, - appMetadata, - step: parsedStepParam, - teams: teamsWithIsAppInstalled, - personalAccount, - eventTypes, - teamId: parsedTeamIdParam ?? null, - userName: user.username, - credentialId, - } as OnboardingPageProps, - }; - } catch (err) { - if (err instanceof z.ZodError) { - return { redirect: { permanent: false, destination: "/apps" } }; - } - - if (err instanceof Error) { - switch (err.message) { - case ERROR_MESSAGES.userNotAuthed: - return { redirect: { permanent: false, destination: "/auth/login" } }; - case ERROR_MESSAGES.userNotFound: - return { redirect: { permanent: false, destination: "/auth/login" } }; - default: - return { redirect: { permanent: false, destination: "/apps" } }; - } - } - } -}; - -OnboardingPage.PageWrapper = PageWrapper; - -export default OnboardingPage; diff --git a/apps/web/playwright/fixtures/apps.ts b/apps/web/playwright/fixtures/apps.ts index 6b0a294b6b..61c649684a 100644 --- a/apps/web/playwright/fixtures/apps.ts +++ b/apps/web/playwright/fixtures/apps.ts @@ -1,8 +1,5 @@ import { expect, type Page } from "@playwright/test"; -import { appStoreMetadata } from "@calcom/app-store/appStoreMetaData"; -import { shouldRedirectToAppOnboarding } from "@calcom/lib/apps/shouldRedirectToAppOnboarding"; - export function createAppsFixture(page: Page) { return { goToAppsCategory: async (category: string) => { @@ -12,13 +9,6 @@ export function createAppsFixture(page: Page) { installApp: async (app: string) => { await page.getByTestId(`app-store-app-card-${app}`).click(); await page.getByTestId("install-app-button").click(); - - const appMetadata = appStoreMetadata[app as keyof typeof appStoreMetadata]; - if (shouldRedirectToAppOnboarding(appMetadata)) { - await page.click('[data-testid="install-app-on-personal-account"]'); - await page.waitForURL(`apps/installation/event-types?slug=${app}`); - await page.goto(`/apps/installed/${appMetadata.categories[0]}?hl=${app}`); - } }, goBackToAppsPage: async () => { await page.getByTestId("add-apps").click(); diff --git a/apps/web/playwright/fixtures/users.ts b/apps/web/playwright/fixtures/users.ts index 679a19056e..4e7badbaa3 100644 --- a/apps/web/playwright/fixtures/users.ts +++ b/apps/web/playwright/fixtures/users.ts @@ -912,11 +912,14 @@ export async function getPaymentCredential(page: Page) { await page.goto("/apps/stripe"); /** We start the Stripe flow */ - await page.click('[data-testid="install-app-button"]'); - await page.click('[data-testid="install-app-on-personal-account"]'); - await page.waitForURL("https://connect.stripe.com/oauth/v2/authorize?*"); - /** We skip filling Stripe forms (testing mode only) */ - await page.click('[id="skip-account-app"]'); - await page.waitForURL("apps/installation/event-types?slug=stripe"); - await page.goto("/apps/installed/payment?hl=stripe"); + await Promise.all([ + page.waitForURL("https://connect.stripe.com/oauth/v2/authorize?*"), + page.click('[data-testid="install-app-button"]'), + ]); + + await Promise.all([ + page.waitForURL("/apps/installed/payment?hl=stripe"), + /** We skip filling Stripe forms (testing mode only) */ + page.click('[id="skip-account-app"]'), + ]); } diff --git a/apps/web/playwright/integrations-stripe.e2e.ts b/apps/web/playwright/integrations-stripe.e2e.ts index 31c00a35c9..19291b6345 100644 --- a/apps/web/playwright/integrations-stripe.e2e.ts +++ b/apps/web/playwright/integrations-stripe.e2e.ts @@ -92,13 +92,18 @@ test.describe("Stripe integration", () => { await page.goto("/apps/stripe"); /** We start the Stripe flow */ - await page.click('[data-testid="install-app-button"]'); - await page.click(`[data-testid="install-app-on-team-${team.id}"]`); - await page.waitForURL("https://connect.stripe.com/oauth/v2/authorize?*"); - await page.click('[id="skip-account-app"]'); - await page.waitForURL(`apps/installation/event-types?slug=stripe&teamId=${team.id}`); - await page.goto("/apps/installed/payment?hl=stripe"); - /** We skip filling Stripe forms (testing mode only) */ + await Promise.all([ + page.waitForURL("https://connect.stripe.com/oauth/v2/authorize?*"), + page.click('[data-testid="install-app-button"]'), + page.click('[data-testid="anything else"]'), + ]); + + await Promise.all([ + page.waitForURL("/apps/installed/payment?hl=stripe"), + /** We skip filling Stripe forms (testing mode only) */ + page.click('[id="skip-account-app"]'), + ]); + await owner.setupEventWithPrice(teamEvent, "stripe"); // Need to wait for the DB to be updated with the metadata diff --git a/apps/web/public/static/locales/en/common.json b/apps/web/public/static/locales/en/common.json index 2a3018379e..fa2278ffcd 100644 --- a/apps/web/public/static/locales/en/common.json +++ b/apps/web/public/static/locales/en/common.json @@ -2371,13 +2371,6 @@ "disconnect_account_hint": "Disconnecting your connected account will change the way you log in. You will only be able to login to your account using email + password", "cookie_consent_checkbox": "I consent to our privacy policy and cookie usage", "make_a_call": "Make a Call", - "select_account_header": "Select Account", - "select_account_description": "Install {{appName}} on your personal account or on a team account.", - "select_event_types_header": "Select Event Types", - "select_event_types_description": "On which event type do you want to install {{appName}}?", - "configure_app_header": "Configure {{appName}}", - "configure_app_description": "Finalise the App setup. You can change these settings later.", - "already_installed": "already installed", "ooo_reasons_unspecified": "Unspecified", "ooo_reasons_vacation": "Vacation", "ooo_reasons_travel": "Travel", diff --git a/packages/app-store-cli/src/build.ts b/packages/app-store-cli/src/build.ts index 91c461b548..68702b7710 100644 --- a/packages/app-store-cli/src/build.ts +++ b/packages/app-store-cli/src/build.ts @@ -328,14 +328,6 @@ function generateFiles() { lazyImport: true, }) ); - browserOutput.push( - ...getExportedObject("EventTypeSettingsMap", { - importConfig: { - fileToBeImported: "components/EventTypeAppSettingsInterface.tsx", - }, - lazyImport: true, - }) - ); const banner = `/** This file is autogenerated using the command \`yarn app-store:build --watch\`. diff --git a/packages/app-store/_components/DynamicComponent.tsx b/packages/app-store/_components/DynamicComponent.tsx index e13a5a4292..30e00222f8 100644 --- a/packages/app-store/_components/DynamicComponent.tsx +++ b/packages/app-store/_components/DynamicComponent.tsx @@ -8,7 +8,7 @@ export function DynamicComponent { - const { slug, ...rest } = props; - return ; -}; diff --git a/packages/app-store/_utils/oauth/decodeOAuthState.ts b/packages/app-store/_utils/oauth/decodeOAuthState.ts index 2a432997ef..c300a808c6 100644 --- a/packages/app-store/_utils/oauth/decodeOAuthState.ts +++ b/packages/app-store/_utils/oauth/decodeOAuthState.ts @@ -7,9 +7,6 @@ export function decodeOAuthState(req: NextApiRequest) { return undefined; } const state: IntegrationOAuthCallbackState = JSON.parse(req.query.state); - if (state.appOnboardingRedirectUrl) { - state.appOnboardingRedirectUrl = decodeURIComponent(state.appOnboardingRedirectUrl); - } return state; } diff --git a/packages/app-store/alby/components/EventTypeAppCardInterface.tsx b/packages/app-store/alby/components/EventTypeAppCardInterface.tsx index 70b497522e..3bc5e0e3fb 100644 --- a/packages/app-store/alby/components/EventTypeAppCardInterface.tsx +++ b/packages/app-store/alby/components/EventTypeAppCardInterface.tsx @@ -1,15 +1,20 @@ import { usePathname, useSearchParams } from "next/navigation"; -import { useState, useMemo } from "react"; +import { useState, useEffect, useMemo } from "react"; import { useAppContextWithSchema } from "@calcom/app-store/EventTypeAppContext"; import AppCard from "@calcom/app-store/_components/AppCard"; +import { currencyOptions } from "@calcom/app-store/alby/lib/currencyOptions"; import type { EventTypeAppCardComponent } from "@calcom/app-store/types"; import { WEBAPP_URL } from "@calcom/lib/constants"; import { useLocale } from "@calcom/lib/hooks/useLocale"; +import { Alert, Select, TextField } from "@calcom/ui"; +import { SatSymbol } from "@calcom/ui/components/icon/SatSymbol"; import checkForMultiplePaymentApps from "../../_utils/payments/checkForMultiplePaymentApps"; import type { appDataSchema } from "../zod"; -import EventTypeAppSettingsInterface from "./EventTypeAppSettingsInterface"; +import { PaypalPaymentOptions as paymentOptions } from "../zod"; + +type Option = { value: string; label: string }; const EventTypeAppCard: EventTypeAppCardComponent = function EventTypeAppCard({ app, @@ -17,19 +22,38 @@ const EventTypeAppCard: EventTypeAppCardComponent = function EventTypeAppCard({ eventTypeFormMetadata, }) { const searchParams = useSearchParams(); - const { t } = useLocale(); /** TODO "pathname" no longer contains square-bracket expressions. Rewrite the code relying on them if required. **/ const pathname = usePathname(); const asPath = useMemo( () => `${pathname}${searchParams ? `?${searchParams.toString()}` : ""}`, [pathname, searchParams] ); - const { getAppData, setAppData, disabled } = useAppContextWithSchema(); + const { getAppData, setAppData } = useAppContextWithSchema(); + const price = getAppData("price"); + const currency = getAppData("currency"); + const [selectedCurrency, setSelectedCurrency] = useState( + currencyOptions.find((c) => c.value === currency) || currencyOptions[0] + ); + const paymentOption = getAppData("paymentOption"); + const paymentOptionSelectValue = paymentOptions?.find((option) => paymentOption === option.value) || { + label: paymentOptions[0].label, + value: paymentOptions[0].value, + }; + const seatsEnabled = !!eventType.seatsPerTimeSlot; const [requirePayment, setRequirePayment] = useState(getAppData("enabled")); + const { t } = useLocale(); + const recurringEventDefined = eventType.recurringEvent?.count !== undefined; const otherPaymentAppEnabled = checkForMultiplePaymentApps(eventTypeFormMetadata); const shouldDisableSwitch = !requirePayment && otherPaymentAppEnabled; + // make sure a currency is selected + useEffect(() => { + if (!currency && requirePayment) { + setAppData("currency", selectedCurrency.value); + } + }, [currency, selectedCurrency, setAppData, requirePayment]); + return ( Add bitcoin lightning payments to your events} disableSwitch={shouldDisableSwitch} switchTooltip={shouldDisableSwitch ? t("other_payment_app_enabled") : undefined}> - + <> + {recurringEventDefined ? ( + + ) : ( + requirePayment && ( + <> +
+ } + addOnSuffix={selectedCurrency.unit || selectedCurrency.value} + type="number" + required + className="block w-full rounded-sm border-gray-300 pl-2 pr-12 text-sm" + placeholder="Price" + onChange={(e) => { + setAppData("price", Number(e.target.value)); + if (currency) { + setAppData("currency", currency); + } + }} + value={price && price > 0 ? price : undefined} + /> +
+
+ + { - if (e) { - setSelectedCurrency(e); - setAppData("currency", e.value); - } - }} - /> -
- -
- - - defaultValue={ - paymentOptionSelectValue - ? { ...paymentOptionSelectValue, label: t(paymentOptionSelectValue.label) } - : { ...paymentOptions[0], label: t(paymentOptions[0].label) } - } - options={paymentOptions.map((option) => { - return { ...option, label: t(option.label) || option.label }; - })} - onChange={(input) => { - if (input) setAppData("paymentOption", input.value); - }} - className="mb-1 h-[38px] w-full" - isDisabled={seatsEnabled} - /> -
- {seatsEnabled && paymentOption === "HOLD" && ( - - )} - - ) - )} - - ); -}; - -export default EventTypeAppSettingsInterface; diff --git a/packages/app-store/alby/config.json b/packages/app-store/alby/config.json index 318d26addf..632ef31447 100644 --- a/packages/app-store/alby/config.json +++ b/packages/app-store/alby/config.json @@ -14,6 +14,5 @@ "isTemplate": false, "__createdUsingCli": true, "__template": "event-type-app-card", - "dirName": "alby", - "isOAuth": false + "dirName": "alby" } diff --git a/packages/app-store/amie/config.json b/packages/app-store/amie/config.json index ac87eed277..74a9210dc5 100644 --- a/packages/app-store/amie/config.json +++ b/packages/app-store/amie/config.json @@ -12,6 +12,5 @@ "description": "The joyful productivity app\r\r", "__createdUsingCli": true, "dependencies": ["google-calendar"], - "dirName": "amie", - "isOAuth": false + "dirName": "amie" } diff --git a/packages/app-store/applecalendar/_metadata.ts b/packages/app-store/applecalendar/_metadata.ts index b5947fad57..1b468204a3 100644 --- a/packages/app-store/applecalendar/_metadata.ts +++ b/packages/app-store/applecalendar/_metadata.ts @@ -17,7 +17,6 @@ export const metadata = { url: "https://cal.com/", email: "help@cal.com", dirName: "applecalendar", - isOAuth: false, } as AppMeta; export default metadata; diff --git a/packages/app-store/apps.browser.generated.tsx b/packages/app-store/apps.browser.generated.tsx index 96f1633ca6..19142d4eb5 100644 --- a/packages/app-store/apps.browser.generated.tsx +++ b/packages/app-store/apps.browser.generated.tsx @@ -41,16 +41,3 @@ export const EventTypeAddonMap = { import("./templates/event-type-app-card/components/EventTypeAppCardInterface") ), }; -export const EventTypeSettingsMap = { - alby: dynamic(() => import("./alby/components/EventTypeAppSettingsInterface")), - basecamp3: dynamic(() => import("./basecamp3/components/EventTypeAppSettingsInterface")), - fathom: dynamic(() => import("./fathom/components/EventTypeAppSettingsInterface")), - ga4: dynamic(() => import("./ga4/components/EventTypeAppSettingsInterface")), - giphy: dynamic(() => import("./giphy/components/EventTypeAppSettingsInterface")), - gtm: dynamic(() => import("./gtm/components/EventTypeAppSettingsInterface")), - metapixel: dynamic(() => import("./metapixel/components/EventTypeAppSettingsInterface")), - paypal: dynamic(() => import("./paypal/components/EventTypeAppSettingsInterface")), - plausible: dynamic(() => import("./plausible/components/EventTypeAppSettingsInterface")), - qr_code: dynamic(() => import("./qr_code/components/EventTypeAppSettingsInterface")), - stripepayment: dynamic(() => import("./stripepayment/components/EventTypeAppSettingsInterface")), -}; diff --git a/packages/app-store/around/config.json b/packages/app-store/around/config.json index 186802b882..0cc2358e49 100644 --- a/packages/app-store/around/config.json +++ b/packages/app-store/around/config.json @@ -20,6 +20,5 @@ "urlRegExp": "^http(s)?:\\/\\/(www\\.)?around.co\\/[a-zA-Z0-9]*", "organizerInputPlaceholder": "https://www.around.co/rick" } - }, - "isOAuth": false + } } diff --git a/packages/app-store/basecamp3/api/callback.ts b/packages/app-store/basecamp3/api/callback.ts index fb121835f5..c2dbb9fad1 100644 --- a/packages/app-store/basecamp3/api/callback.ts +++ b/packages/app-store/basecamp3/api/callback.ts @@ -5,7 +5,6 @@ import prisma from "@calcom/prisma"; import getAppKeysFromSlug from "../../_utils/getAppKeysFromSlug"; import getInstalledAppPath from "../../_utils/getInstalledAppPath"; -import { decodeOAuthState } from "../../_utils/oauth/decodeOAuthState"; import appConfig from "../config.json"; export default async function handler(req: NextApiRequest, res: NextApiResponse) { @@ -87,11 +86,5 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse) }, }); - const state = decodeOAuthState(req); - - if (state?.appOnboardingRedirectUrl && state.appOnboardingRedirectUrl !== "") { - return res.redirect(state.appOnboardingRedirectUrl); - } - res.redirect(getInstalledAppPath({ variant: appConfig.variant, slug: appConfig.slug })); } diff --git a/packages/app-store/basecamp3/components/EventTypeAppCardInterface.tsx b/packages/app-store/basecamp3/components/EventTypeAppCardInterface.tsx index d359812bea..98a5518ab8 100644 --- a/packages/app-store/basecamp3/components/EventTypeAppCardInterface.tsx +++ b/packages/app-store/basecamp3/components/EventTypeAppCardInterface.tsx @@ -1,29 +1,76 @@ +import { useState, useEffect } from "react"; + import { useAppContextWithSchema } from "@calcom/app-store/EventTypeAppContext"; import AppCard from "@calcom/app-store/_components/AppCard"; import type { EventTypeAppCardComponent } from "@calcom/app-store/types"; +import { trpc } from "@calcom/trpc/react"; +import { Select } from "@calcom/ui"; -import useIsAppEnabled from "../../_utils/useIsAppEnabled"; import type { appDataSchema } from "../zod"; -import EventTypeAppSettingsInterface from "./EventTypeAppSettingsInterface"; -const EventTypeAppCard: EventTypeAppCardComponent = function EventTypeAppCard({ app, eventType }) { - const { getAppData, setAppData, disabled } = useAppContextWithSchema(); - const { enabled, updateEnabled } = useIsAppEnabled(app); +const EventTypeAppCard: EventTypeAppCardComponent = function EventTypeAppCard({ app }) { + const { getAppData } = useAppContextWithSchema(); + const [enabled, setEnabled] = useState(getAppData("enabled")); + const [projects, setProjects] = useState(); + const [selectedProject, setSelectedProject] = useState(); + const { data } = trpc.viewer.appBasecamp3.projects.useQuery(); + const setProject = trpc.viewer.appBasecamp3.projectMutation.useMutation(); + + useEffect( + function refactorMeWithoutEffect() { + setSelectedProject({ + value: data?.projects.currentProject, + // eslint-disable-next-line @typescript-eslint/no-explicit-any + label: data?.projects?.find((project: any) => project.id === data?.currentProject)?.name, + }); + setProjects( + // eslint-disable-next-line @typescript-eslint/no-explicit-any + data?.projects?.map((project: any) => { + return { + value: project.id, + label: project.name, + }; + }) + ); + }, + [data] + ); return ( { - updateEnabled(e); + if (!e) { + setEnabled(false); + } else { + setEnabled(true); + } }} switchChecked={enabled}> - +
+
+
+

Link a Basecamp project to this event:

+
+ { - if (project) { - setProject.mutate({ projectId: project?.value.toString() }); - setSelectedProject(project); - } - }} - value={selectedProject} - /> -
-
- Please note that as of now you can only link one of your projects to - cal.com -
-
- ); -}; - -export default EventTypeAppSettingsInterface; diff --git a/packages/app-store/basecamp3/config.json b/packages/app-store/basecamp3/config.json index af9d241373..a0cad118dc 100644 --- a/packages/app-store/basecamp3/config.json +++ b/packages/app-store/basecamp3/config.json @@ -13,6 +13,5 @@ "isTemplate": false, "__createdUsingCli": true, "__template": "event-type-app-card", - "dirName": "basecamp3", - "isOAuth": true + "dirName": "basecamp3" } diff --git a/packages/app-store/cal-ai/config.json b/packages/app-store/cal-ai/config.json index c13c045312..6ec6551057 100644 --- a/packages/app-store/cal-ai/config.json +++ b/packages/app-store/cal-ai/config.json @@ -14,7 +14,6 @@ "__createdUsingCli": true, "__template": "basic", "dirName": "cal-ai", - "isOAuth": false, "paid": { "priceInUsd": 8, "priceId": "price_1O1ziDH8UDiwIftkDHp3MCTP", diff --git a/packages/app-store/caldavcalendar/_metadata.ts b/packages/app-store/caldavcalendar/_metadata.ts index 1ea69be584..e342f74fb2 100644 --- a/packages/app-store/caldavcalendar/_metadata.ts +++ b/packages/app-store/caldavcalendar/_metadata.ts @@ -17,7 +17,6 @@ export const metadata = { url: "https://cal.com/", email: "ali@cal.com", dirName: "caldavcalendar", - isOAuth: false, } as AppMeta; export default metadata; diff --git a/packages/app-store/campfire/config.json b/packages/app-store/campfire/config.json index 2fb381f1ff..7f8e670066 100644 --- a/packages/app-store/campfire/config.json +++ b/packages/app-store/campfire/config.json @@ -19,6 +19,5 @@ "organizerInputPlaceholder": "https://party.campfire.to/your-team", "urlRegExp": "^http(s)?:\\/\\/(www\\.)?party.campfire.to\\/[a-zA-Z0-9]*" } - }, - "isOAuth": false + } } diff --git a/packages/app-store/closecom/config.json b/packages/app-store/closecom/config.json index 5224a8ab02..58a46a86e9 100644 --- a/packages/app-store/closecom/config.json +++ b/packages/app-store/closecom/config.json @@ -11,6 +11,5 @@ "publisher": "Cal.com, Inc.", "email": "help@cal.com", "description": "Close is the inside sales CRM of choice for startups and SMBs. Make more calls, send more emails and close more deals starting today.", - "__createdUsingCli": true, - "isOAuth": false + "__createdUsingCli": true } diff --git a/packages/app-store/cron/config.json b/packages/app-store/cron/config.json index d5c8dae388..8e0b71952b 100644 --- a/packages/app-store/cron/config.json +++ b/packages/app-store/cron/config.json @@ -13,6 +13,5 @@ "isTemplate": false, "__createdUsingCli": true, "__template": "link-as-an-app", - "dependencies": ["google-calendar"], - "isOAuth": false + "dependencies": ["google-calendar"] } diff --git a/packages/app-store/dailyvideo/_metadata.ts b/packages/app-store/dailyvideo/_metadata.ts index 38c6b5df78..b416739784 100644 --- a/packages/app-store/dailyvideo/_metadata.ts +++ b/packages/app-store/dailyvideo/_metadata.ts @@ -26,7 +26,6 @@ export const metadata = { }, key: { apikey: process.env.DAILY_API_KEY }, dirName: "dailyvideo", - isOAuth: false, } as AppMeta; export default metadata; diff --git a/packages/app-store/discord/config.json b/packages/app-store/discord/config.json index 1449a0169c..34682ccce9 100644 --- a/packages/app-store/discord/config.json +++ b/packages/app-store/discord/config.json @@ -21,6 +21,5 @@ "description": "Copy your server invite link and start scheduling calls in Discord! Discord is a VoIP and instant messaging social platform. Users have the ability to communicate with voice calls, video calls, text messaging, media and files in private chats or as part of communities.", "isTemplate": false, "__createdUsingCli": true, - "__template": "event-type-location-video-static", - "isOAuth": false + "__template": "event-type-location-video-static" } diff --git a/packages/app-store/eightxeight/config.json b/packages/app-store/eightxeight/config.json index c0baba41f8..a809d0ff54 100644 --- a/packages/app-store/eightxeight/config.json +++ b/packages/app-store/eightxeight/config.json @@ -22,6 +22,5 @@ "isTemplate": false, "__createdUsingCli": true, "__template": "event-type-location-video-static", - "dirName": "eightxeight", - "isOAuth": false + "dirName": "eightxeight" } diff --git a/packages/app-store/element-call/config.json b/packages/app-store/element-call/config.json index 7de9af060a..e27a228af1 100644 --- a/packages/app-store/element-call/config.json +++ b/packages/app-store/element-call/config.json @@ -22,6 +22,5 @@ "isTemplate": false, "__createdUsingCli": true, "__template": "event-type-location-video-static", - "dirName": "element-call", - "isOAuth": false + "dirName": "element-call" } diff --git a/packages/app-store/exchange2013calendar/_metadata.ts b/packages/app-store/exchange2013calendar/_metadata.ts index 8859f4fdf2..3d7c0734af 100644 --- a/packages/app-store/exchange2013calendar/_metadata.ts +++ b/packages/app-store/exchange2013calendar/_metadata.ts @@ -18,7 +18,6 @@ export const metadata = { url: "https://cal.com/", email: "help@cal.com", dirName: "exchange2013calendar", - isOAuth: false, } as AppMeta; export default metadata; diff --git a/packages/app-store/exchange2016calendar/_metadata.ts b/packages/app-store/exchange2016calendar/_metadata.ts index a851408161..138b5e5442 100644 --- a/packages/app-store/exchange2016calendar/_metadata.ts +++ b/packages/app-store/exchange2016calendar/_metadata.ts @@ -18,7 +18,6 @@ export const metadata = { url: "https://cal.com/", email: "help@cal.com", dirName: "exchange2016calendar", - isOAuth: false, } as AppMeta; export default metadata; diff --git a/packages/app-store/exchangecalendar/config.json b/packages/app-store/exchangecalendar/config.json index c55b9bd13a..113fef68a6 100644 --- a/packages/app-store/exchangecalendar/config.json +++ b/packages/app-store/exchangecalendar/config.json @@ -12,6 +12,5 @@ "publisher": "Cal.com", "email": "help@cal.com", "description": "Fetch Microsoft Exchange calendars and availabilities using Exchange Web Services (EWS).", - "__createdUsingCli": true, - "isOAuth": false + "__createdUsingCli": true } diff --git a/packages/app-store/facetime/config.json b/packages/app-store/facetime/config.json index ca7c28ad3c..874468fbf6 100644 --- a/packages/app-store/facetime/config.json +++ b/packages/app-store/facetime/config.json @@ -21,6 +21,5 @@ "urlRegExp": "^https?:\\/\\/facetime\\.apple\\.com\\/join.+$" } }, - "isTemplate": false, - "isOAuth": false + "isTemplate": false } diff --git a/packages/app-store/fathom/components/EventTypeAppCardInterface.tsx b/packages/app-store/fathom/components/EventTypeAppCardInterface.tsx index 10e0a0f8a6..09899e57f7 100644 --- a/packages/app-store/fathom/components/EventTypeAppCardInterface.tsx +++ b/packages/app-store/fathom/components/EventTypeAppCardInterface.tsx @@ -2,12 +2,13 @@ import { useAppContextWithSchema } from "@calcom/app-store/EventTypeAppContext"; import AppCard from "@calcom/app-store/_components/AppCard"; import useIsAppEnabled from "@calcom/app-store/_utils/useIsAppEnabled"; import type { EventTypeAppCardComponent } from "@calcom/app-store/types"; +import { TextField } from "@calcom/ui"; import type { appDataSchema } from "../zod"; -import EventTypeAppSettingsInterface from "./EventTypeAppSettingsInterface"; const EventTypeAppCard: EventTypeAppCardComponent = function EventTypeAppCard({ app, eventType }) { const { getAppData, setAppData, disabled } = useAppContextWithSchema(); + const trackingId = getAppData("trackingId"); const { enabled, updateEnabled } = useIsAppEnabled(app); return ( @@ -19,12 +20,14 @@ const EventTypeAppCard: EventTypeAppCardComponent = function EventTypeAppCard({ }} switchChecked={enabled} teamId={eventType.team?.id || undefined}> - { + setAppData("trackingId", e.target.value); + }} />
); diff --git a/packages/app-store/fathom/components/EventTypeAppSettingsInterface.tsx b/packages/app-store/fathom/components/EventTypeAppSettingsInterface.tsx deleted file mode 100644 index ea2a79002c..0000000000 --- a/packages/app-store/fathom/components/EventTypeAppSettingsInterface.tsx +++ /dev/null @@ -1,25 +0,0 @@ -import type { EventTypeAppSettingsComponent } from "@calcom/app-store/types"; -import { TextField } from "@calcom/ui"; - -const EventTypeAppSettingsInterface: EventTypeAppSettingsComponent = ({ - getAppData, - setAppData, - disabled, - slug, -}) => { - const trackingId = getAppData("trackingId"); - - return ( - { - setAppData("trackingId", e.target.value); - }} - /> - ); -}; - -export default EventTypeAppSettingsInterface; diff --git a/packages/app-store/fathom/config.json b/packages/app-store/fathom/config.json index 029bbaf649..b491e51160 100644 --- a/packages/app-store/fathom/config.json +++ b/packages/app-store/fathom/config.json @@ -23,6 +23,5 @@ } }, "description": "Fathom Analytics provides simple, privacy-focused website analytics. We're a GDPR-compliant, Google Analytics alternative.", - "__createdUsingCli": true, - "isOAuth": false + "__createdUsingCli": true } diff --git a/packages/app-store/ga4/components/EventTypeAppCardInterface.tsx b/packages/app-store/ga4/components/EventTypeAppCardInterface.tsx index 10e0a0f8a6..09899e57f7 100644 --- a/packages/app-store/ga4/components/EventTypeAppCardInterface.tsx +++ b/packages/app-store/ga4/components/EventTypeAppCardInterface.tsx @@ -2,12 +2,13 @@ import { useAppContextWithSchema } from "@calcom/app-store/EventTypeAppContext"; import AppCard from "@calcom/app-store/_components/AppCard"; import useIsAppEnabled from "@calcom/app-store/_utils/useIsAppEnabled"; import type { EventTypeAppCardComponent } from "@calcom/app-store/types"; +import { TextField } from "@calcom/ui"; import type { appDataSchema } from "../zod"; -import EventTypeAppSettingsInterface from "./EventTypeAppSettingsInterface"; const EventTypeAppCard: EventTypeAppCardComponent = function EventTypeAppCard({ app, eventType }) { const { getAppData, setAppData, disabled } = useAppContextWithSchema(); + const trackingId = getAppData("trackingId"); const { enabled, updateEnabled } = useIsAppEnabled(app); return ( @@ -19,12 +20,14 @@ const EventTypeAppCard: EventTypeAppCardComponent = function EventTypeAppCard({ }} switchChecked={enabled} teamId={eventType.team?.id || undefined}> - { + setAppData("trackingId", e.target.value); + }} />
); diff --git a/packages/app-store/ga4/components/EventTypeAppSettingsInterface.tsx b/packages/app-store/ga4/components/EventTypeAppSettingsInterface.tsx deleted file mode 100644 index 0ad1148d49..0000000000 --- a/packages/app-store/ga4/components/EventTypeAppSettingsInterface.tsx +++ /dev/null @@ -1,23 +0,0 @@ -import type { EventTypeAppSettingsComponent } from "@calcom/app-store/types"; -import { TextField } from "@calcom/ui"; - -const EventTypeAppSettingsInterface: EventTypeAppSettingsComponent = ({ - getAppData, - setAppData, - disabled, -}) => { - const trackingId = getAppData("trackingId"); - - return ( - { - setAppData("trackingId", e.target.value); - }} - /> - ); -}; - -export default EventTypeAppSettingsInterface; diff --git a/packages/app-store/ga4/config.json b/packages/app-store/ga4/config.json index 30d6e8eb06..b0bdb496d5 100644 --- a/packages/app-store/ga4/config.json +++ b/packages/app-store/ga4/config.json @@ -24,6 +24,5 @@ ] } }, - "__createdUsingCli": true, - "isOAuth": false + "__createdUsingCli": true } diff --git a/packages/app-store/giphy/_metadata.ts b/packages/app-store/giphy/_metadata.ts index 5be513f2a7..050f4ab234 100644 --- a/packages/app-store/giphy/_metadata.ts +++ b/packages/app-store/giphy/_metadata.ts @@ -17,7 +17,6 @@ export const metadata = { extendsFeature: "EventType", email: "help@cal.com", dirName: "giphy", - isOAuth: false, } as AppMeta; export default metadata; diff --git a/packages/app-store/giphy/components/EventTypeAppCardInterface.tsx b/packages/app-store/giphy/components/EventTypeAppCardInterface.tsx index b48ce29e34..b285eeedef 100644 --- a/packages/app-store/giphy/components/EventTypeAppCardInterface.tsx +++ b/packages/app-store/giphy/components/EventTypeAppCardInterface.tsx @@ -1,14 +1,15 @@ import { useAppContextWithSchema } from "@calcom/app-store/EventTypeAppContext"; import AppCard from "@calcom/app-store/_components/AppCard"; import useIsAppEnabled from "@calcom/app-store/_utils/useIsAppEnabled"; +import { SelectGifInput } from "@calcom/app-store/giphy/components"; import type { EventTypeAppCardComponent } from "@calcom/app-store/types"; import { useLocale } from "@calcom/lib/hooks/useLocale"; import type { appDataSchema } from "../zod"; -import EventTypeAppSettingsInterface from "./EventTypeAppSettingsInterface"; const EventTypeAppCard: EventTypeAppCardComponent = function EventTypeAppCard({ app, eventType }) { const { getAppData, setAppData, disabled } = useAppContextWithSchema(); + const thankYouPage = getAppData("thankYouPage"); const { enabled: showGifSelection, updateEnabled: setShowGifSelection } = useIsAppEnabled(app); const { t } = useLocale(); @@ -22,13 +23,15 @@ const EventTypeAppCard: EventTypeAppCardComponent = function EventTypeAppCard({ }} switchChecked={showGifSelection} teamId={eventType.team?.id || undefined}> - + {showGifSelection && ( + { + setAppData("thankYouPage", url); + }} + /> + )} ); }; diff --git a/packages/app-store/giphy/components/EventTypeAppSettingsInterface.tsx b/packages/app-store/giphy/components/EventTypeAppSettingsInterface.tsx deleted file mode 100644 index 0cb8017443..0000000000 --- a/packages/app-store/giphy/components/EventTypeAppSettingsInterface.tsx +++ /dev/null @@ -1,23 +0,0 @@ -import type { EventTypeAppSettingsComponent } from "@calcom/app-store/types"; - -import SelectGifInput from "./SelectGifInput"; - -const EventTypeAppSettingsInterface: EventTypeAppSettingsComponent = ({ - getAppData, - setAppData, - disabled, -}) => { - const thankYouPage = getAppData("thankYouPage"); - - return ( - { - setAppData("thankYouPage", url); - }} - /> - ); -}; - -export default EventTypeAppSettingsInterface; diff --git a/packages/app-store/googlecalendar/_metadata.ts b/packages/app-store/googlecalendar/_metadata.ts index 4701bde435..dbdb831035 100644 --- a/packages/app-store/googlecalendar/_metadata.ts +++ b/packages/app-store/googlecalendar/_metadata.ts @@ -18,7 +18,6 @@ export const metadata = { url: "https://cal.com/", email: "help@cal.com", dirName: "googlecalendar", - isOAuth: true, } as AppMeta; export default metadata; diff --git a/packages/app-store/googlevideo/_metadata.ts b/packages/app-store/googlevideo/_metadata.ts index c835c79d22..1fc1bbc03d 100644 --- a/packages/app-store/googlevideo/_metadata.ts +++ b/packages/app-store/googlevideo/_metadata.ts @@ -27,7 +27,6 @@ export const metadata = { }, dirName: "googlevideo", dependencies: ["google-calendar"], - isOAuth: false, } as AppMeta; export default metadata; diff --git a/packages/app-store/gtm/components/EventTypeAppCardInterface.tsx b/packages/app-store/gtm/components/EventTypeAppCardInterface.tsx index 10e0a0f8a6..09899e57f7 100644 --- a/packages/app-store/gtm/components/EventTypeAppCardInterface.tsx +++ b/packages/app-store/gtm/components/EventTypeAppCardInterface.tsx @@ -2,12 +2,13 @@ import { useAppContextWithSchema } from "@calcom/app-store/EventTypeAppContext"; import AppCard from "@calcom/app-store/_components/AppCard"; import useIsAppEnabled from "@calcom/app-store/_utils/useIsAppEnabled"; import type { EventTypeAppCardComponent } from "@calcom/app-store/types"; +import { TextField } from "@calcom/ui"; import type { appDataSchema } from "../zod"; -import EventTypeAppSettingsInterface from "./EventTypeAppSettingsInterface"; const EventTypeAppCard: EventTypeAppCardComponent = function EventTypeAppCard({ app, eventType }) { const { getAppData, setAppData, disabled } = useAppContextWithSchema(); + const trackingId = getAppData("trackingId"); const { enabled, updateEnabled } = useIsAppEnabled(app); return ( @@ -19,12 +20,14 @@ const EventTypeAppCard: EventTypeAppCardComponent = function EventTypeAppCard({ }} switchChecked={enabled} teamId={eventType.team?.id || undefined}> - { + setAppData("trackingId", e.target.value); + }} /> ); diff --git a/packages/app-store/gtm/components/EventTypeAppSettingsInterface.tsx b/packages/app-store/gtm/components/EventTypeAppSettingsInterface.tsx deleted file mode 100644 index 0ad1148d49..0000000000 --- a/packages/app-store/gtm/components/EventTypeAppSettingsInterface.tsx +++ /dev/null @@ -1,23 +0,0 @@ -import type { EventTypeAppSettingsComponent } from "@calcom/app-store/types"; -import { TextField } from "@calcom/ui"; - -const EventTypeAppSettingsInterface: EventTypeAppSettingsComponent = ({ - getAppData, - setAppData, - disabled, -}) => { - const trackingId = getAppData("trackingId"); - - return ( - { - setAppData("trackingId", e.target.value); - }} - /> - ); -}; - -export default EventTypeAppSettingsInterface; diff --git a/packages/app-store/gtm/config.json b/packages/app-store/gtm/config.json index f535c680e8..b2faf7243d 100644 --- a/packages/app-store/gtm/config.json +++ b/packages/app-store/gtm/config.json @@ -21,6 +21,5 @@ }, "isTemplate": false, "__createdUsingCli": true, - "__template": "booking-pages-tag", - "isOAuth": false + "__template": "booking-pages-tag" } diff --git a/packages/app-store/hubspot/_metadata.ts b/packages/app-store/hubspot/_metadata.ts index 7212d9635d..ea5379a233 100644 --- a/packages/app-store/hubspot/_metadata.ts +++ b/packages/app-store/hubspot/_metadata.ts @@ -17,7 +17,6 @@ export const metadata = { title: "HubSpot CRM", email: "help@cal.com", dirName: "hubspot", - isOAuth: true, } as AppMeta; export default metadata; diff --git a/packages/app-store/huddle01video/_metadata.ts b/packages/app-store/huddle01video/_metadata.ts index 65f90fd31a..9a0f3d6003 100644 --- a/packages/app-store/huddle01video/_metadata.ts +++ b/packages/app-store/huddle01video/_metadata.ts @@ -28,7 +28,6 @@ export const metadata = { key: { apikey: randomString(12) }, dirName: "huddle01video", concurrentMeetings: true, - isOAuth: false, } as AppMeta; export default metadata; diff --git a/packages/app-store/intercom/api/callback.ts b/packages/app-store/intercom/api/callback.ts index 64c05ceb5d..6665aba5b6 100644 --- a/packages/app-store/intercom/api/callback.ts +++ b/packages/app-store/intercom/api/callback.ts @@ -8,7 +8,6 @@ import prisma from "@calcom/prisma"; import getAppKeysFromSlug from "../../_utils/getAppKeysFromSlug"; import getInstalledAppPath from "../../_utils/getInstalledAppPath"; import createOAuthAppCredential from "../../_utils/oauth/createOAuthAppCredential"; -import { decodeOAuthState } from "../../_utils/oauth/decodeOAuthState"; const log = logger.getSubLogger({ prefix: [`[[intercom/api/callback]`] }); @@ -86,12 +85,6 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse) req ); - const state = decodeOAuthState(req); - - if (state?.appOnboardingRedirectUrl && state.appOnboardingRedirectUrl !== "") { - return res.redirect(state.appOnboardingRedirectUrl); - } - res.redirect( getSafeRedirectUrl(`${WEBAPP_URL}/apps/installed/automation?hl=intercom`) ?? getInstalledAppPath({ variant: "automation", slug: "intercom" }) diff --git a/packages/app-store/intercom/config.json b/packages/app-store/intercom/config.json index ef9a2955c2..37c6831818 100644 --- a/packages/app-store/intercom/config.json +++ b/packages/app-store/intercom/config.json @@ -13,6 +13,5 @@ "isTemplate": false, "__createdUsingCli": true, "__template": "basic", - "dirName": "intercom", - "isOAuth": true + "dirName": "intercom" } diff --git a/packages/app-store/jitsivideo/_metadata.ts b/packages/app-store/jitsivideo/_metadata.ts index 2a5b71700e..6f6b042431 100644 --- a/packages/app-store/jitsivideo/_metadata.ts +++ b/packages/app-store/jitsivideo/_metadata.ts @@ -25,7 +25,6 @@ export const metadata = { }, dirName: "jitsivideo", concurrentMeetings: true, - isOAuth: false, } as AppMeta; export default metadata; diff --git a/packages/app-store/larkcalendar/_metadata.ts b/packages/app-store/larkcalendar/_metadata.ts index ea00f1cde6..050e2ed7d8 100644 --- a/packages/app-store/larkcalendar/_metadata.ts +++ b/packages/app-store/larkcalendar/_metadata.ts @@ -16,7 +16,6 @@ export const metadata = { url: "https://larksuite.com/", email: "alan@larksuite.com", dirName: "larkcalendar", - isOAuth: true, } as AppMeta; export default metadata; diff --git a/packages/app-store/make/config.json b/packages/app-store/make/config.json index 9d51eab49c..bc2a1349da 100644 --- a/packages/app-store/make/config.json +++ b/packages/app-store/make/config.json @@ -14,6 +14,5 @@ "__createdUsingCli": true, "__template": "basic", "imageSrc": "icon.svg", - "dirName": "make", - "isOAuth": false + "dirName": "make" } diff --git a/packages/app-store/metapixel/components/EventTypeAppCardInterface.tsx b/packages/app-store/metapixel/components/EventTypeAppCardInterface.tsx index 8bab69cac9..38ee45f214 100644 --- a/packages/app-store/metapixel/components/EventTypeAppCardInterface.tsx +++ b/packages/app-store/metapixel/components/EventTypeAppCardInterface.tsx @@ -2,12 +2,13 @@ import { useAppContextWithSchema } from "@calcom/app-store/EventTypeAppContext"; import AppCard from "@calcom/app-store/_components/AppCard"; import useIsAppEnabled from "@calcom/app-store/_utils/useIsAppEnabled"; import type { EventTypeAppCardComponent } from "@calcom/app-store/types"; +import { TextField } from "@calcom/ui"; import type { appDataSchema } from "../zod"; -import EventTypeAppSettingsInterface from "./EventTypeAppSettingsInterface"; const EventTypeAppCard: EventTypeAppCardComponent = function EventTypeAppCard({ app, eventType }) { const { getAppData, setAppData, disabled } = useAppContextWithSchema(); + const trackingId = getAppData("trackingId"); const { enabled, updateEnabled } = useIsAppEnabled(app); return ( @@ -17,12 +18,14 @@ const EventTypeAppCard: EventTypeAppCardComponent = function EventTypeAppCard({ switchOnClick={updateEnabled} switchChecked={enabled} teamId={eventType.team?.id || undefined}> - { + setAppData("trackingId", e.target.value); + }} /> ); diff --git a/packages/app-store/metapixel/components/EventTypeAppSettingsInterface.tsx b/packages/app-store/metapixel/components/EventTypeAppSettingsInterface.tsx deleted file mode 100644 index 14b3103673..0000000000 --- a/packages/app-store/metapixel/components/EventTypeAppSettingsInterface.tsx +++ /dev/null @@ -1,23 +0,0 @@ -import type { EventTypeAppSettingsComponent } from "@calcom/app-store/types"; -import { TextField } from "@calcom/ui"; - -const EventTypeAppSettingsInterface: EventTypeAppSettingsComponent = ({ - getAppData, - setAppData, - disabled, -}) => { - const trackingId = getAppData("trackingId"); - - return ( - { - setAppData("trackingId", e.target.value); - }} - /> - ); -}; - -export default EventTypeAppSettingsInterface; diff --git a/packages/app-store/metapixel/config.json b/packages/app-store/metapixel/config.json index a56804c0e8..7d055c3b49 100644 --- a/packages/app-store/metapixel/config.json +++ b/packages/app-store/metapixel/config.json @@ -21,6 +21,5 @@ } ] } - }, - "isOAuth": false + } } diff --git a/packages/app-store/mirotalk/config.json b/packages/app-store/mirotalk/config.json index d1dbcf09fa..c0cea23d8e 100644 --- a/packages/app-store/mirotalk/config.json +++ b/packages/app-store/mirotalk/config.json @@ -22,6 +22,5 @@ "isTemplate": false, "__createdUsingCli": true, "__template": "event-type-location-video-static", - "dirName": "mirotalk", - "isOAuth": false + "dirName": "mirotalk" } diff --git a/packages/app-store/n8n/config.json b/packages/app-store/n8n/config.json index 2770acacc5..1b6cec2091 100644 --- a/packages/app-store/n8n/config.json +++ b/packages/app-store/n8n/config.json @@ -10,6 +10,5 @@ "publisher": "Cal.com, Inc.", "email": "help@cal.com", "description": "Automate without limits. The workflow automation platform that doesn't box you in, that you never outgrow", - "__createdUsingCli": true, - "isOAuth": false + "__createdUsingCli": true } diff --git a/packages/app-store/office365calendar/_metadata.ts b/packages/app-store/office365calendar/_metadata.ts index 98ded5de73..6389322c54 100644 --- a/packages/app-store/office365calendar/_metadata.ts +++ b/packages/app-store/office365calendar/_metadata.ts @@ -16,7 +16,6 @@ export const metadata = { dirName: "office365calendar", url: "https://cal.com/", email: "help@cal.com", - isOAuth: true, } as AppMeta; export default metadata; diff --git a/packages/app-store/office365video/api/callback.ts b/packages/app-store/office365video/api/callback.ts index cfadcde47b..fd2db4ae66 100644 --- a/packages/app-store/office365video/api/callback.ts +++ b/packages/app-store/office365video/api/callback.ts @@ -104,10 +104,6 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse) await createOAuthAppCredential({ appId: "msteams", type: "office365_video" }, responseBody, req); - if (state?.appOnboardingRedirectUrl && state.appOnboardingRedirectUrl !== "") { - return res.redirect(state.appOnboardingRedirectUrl); - } - return res.redirect( getSafeRedirectUrl(state?.returnTo) ?? getInstalledAppPath({ variant: "conferencing", slug: "msteams" }) ); diff --git a/packages/app-store/office365video/config.json b/packages/app-store/office365video/config.json index 9b663ad63d..4880ce02e6 100644 --- a/packages/app-store/office365video/config.json +++ b/packages/app-store/office365video/config.json @@ -22,6 +22,5 @@ } }, "dirName": "office365video", - "concurrentMeetings": true, - "isOAuth": true + "concurrentMeetings": true } diff --git a/packages/app-store/paypal/components/EventTypeAppCardInterface.tsx b/packages/app-store/paypal/components/EventTypeAppCardInterface.tsx index 3dc6efbfe6..02fcb22c5b 100644 --- a/packages/app-store/paypal/components/EventTypeAppCardInterface.tsx +++ b/packages/app-store/paypal/components/EventTypeAppCardInterface.tsx @@ -1,15 +1,23 @@ import { usePathname, useSearchParams } from "next/navigation"; -import { useState, useMemo } from "react"; +import { useState, useEffect, useMemo } from "react"; import { useAppContextWithSchema } from "@calcom/app-store/EventTypeAppContext"; import AppCard from "@calcom/app-store/_components/AppCard"; +import { + currencyOptions, + currencySymbols, + isAcceptedCurrencyCode, +} from "@calcom/app-store/paypal/lib/currencyOptions"; import type { EventTypeAppCardComponent } from "@calcom/app-store/types"; import { WEBAPP_URL } from "@calcom/lib/constants"; import { useLocale } from "@calcom/lib/hooks/useLocale"; +import { Alert, Select, TextField } from "@calcom/ui"; import checkForMultiplePaymentApps from "../../_utils/payments/checkForMultiplePaymentApps"; import type { appDataSchema } from "../zod"; -import EventTypeAppSettingsInterface from "./EventTypeAppSettingsInterface"; +import { PaypalPaymentOptions as paymentOptions } from "../zod"; + +type Option = { value: string; label: string }; const EventTypeAppCard: EventTypeAppCardComponent = function EventTypeAppCard({ app, @@ -23,13 +31,40 @@ const EventTypeAppCard: EventTypeAppCardComponent = function EventTypeAppCard({ () => `${pathname}${searchParams ? `?${searchParams.toString()}` : ""}`, [pathname, searchParams] ); - const { getAppData, setAppData, disabled } = useAppContextWithSchema(); + const { getAppData, setAppData } = useAppContextWithSchema(); + const price = getAppData("price"); + + const currency = getAppData("currency"); + const [selectedCurrency, setSelectedCurrency] = useState(currencyOptions.find((c) => c.value === currency)); + const [currencySymbol, setCurrencySymbol] = useState( + isAcceptedCurrencyCode(currency) ? currencySymbols[currency] : "" + ); + + const paymentOption = getAppData("paymentOption"); + const paymentOptionSelectValue = paymentOptions?.find((option) => paymentOption === option.value) || { + label: paymentOptions[0].label, + value: paymentOptions[0].value, + }; + const seatsEnabled = !!eventType.seatsPerTimeSlot; const [requirePayment, setRequirePayment] = useState(getAppData("enabled")); - const otherPaymentAppEnabled = checkForMultiplePaymentApps(eventTypeFormMetadata); const { t } = useLocale(); + const recurringEventDefined = eventType.recurringEvent?.count !== undefined; + const otherPaymentAppEnabled = checkForMultiplePaymentApps(eventTypeFormMetadata); const shouldDisableSwitch = !requirePayment && otherPaymentAppEnabled; + useEffect(() => { + if (requirePayment) { + if (!getAppData("currency")) { + setAppData("currency", currencyOptions[0].value); + } + if (!getAppData("paymentOption")) { + setAppData("paymentOption", paymentOptions[0].value); + } + } + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); + return ( <> - + {recurringEventDefined ? ( + + ) : ( + requirePayment && ( + <> +
+ { + setAppData("price", Number(e.target.value) * 100); + if (selectedCurrency) { + setAppData("currency", selectedCurrency.value); + } + }} + value={price > 0 ? price / 100 : undefined} + /> +
+
+ + { - if (e) { - setSelectedCurrency(e); - setCurrencySymbol(currencySymbols[e.value]); - setAppData("currency", e.value); - } - }} - /> -
- -
- - - data-testid="paypal-payment-option-select" - defaultValue={ - paymentOptionSelectValue - ? { ...paymentOptionSelectValue, label: t(paymentOptionSelectValue.label) } - : { ...paymentOptions[0], label: t(paymentOptions[0].label) } - } - options={paymentOptions.map((option) => { - return { ...option, label: t(option.label) || option.label }; - })} - onChange={(input) => { - if (input) setAppData("paymentOption", input.value); - }} - className="mb-1 h-[38px] w-full" - isDisabled={seatsEnabled} - /> -
- {seatsEnabled && paymentOption === "HOLD" && ( - - )} - - ); -}; - -export default EventTypeAppSettingsInterface; diff --git a/packages/app-store/paypal/config.json b/packages/app-store/paypal/config.json index 86558342a0..5624fd3f39 100644 --- a/packages/app-store/paypal/config.json +++ b/packages/app-store/paypal/config.json @@ -14,6 +14,5 @@ "__createdUsingCli": true, "imageSrc": "icon.svg", "__template": "event-type-app-card", - "dirName": "paypal", - "isOAuth": true + "dirName": "paypal" } diff --git a/packages/app-store/ping/config.json b/packages/app-store/ping/config.json index dadb6e2ba2..2559c47fb1 100644 --- a/packages/app-store/ping/config.json +++ b/packages/app-store/ping/config.json @@ -20,6 +20,5 @@ "organizerInputPlaceholder": "https://www.ping.gg/call/theo", "urlRegExp": "^http(s)?:\\/\\/(www\\.)?ping.gg\\/call\\/[a-zA-Z0-9]*" } - }, - "isOAuth": false + } } diff --git a/packages/app-store/pipedream/config.json b/packages/app-store/pipedream/config.json index 7812bad8df..37fa14a103 100644 --- a/packages/app-store/pipedream/config.json +++ b/packages/app-store/pipedream/config.json @@ -10,6 +10,5 @@ "publisher": "Pipedream, Inc.", "email": "support@pipedream.com", "description": "Connect APIs, remarkably fast. Stop writing boilerplate code, struggling with authentication and managing infrastructure. Start connecting APIs with code-level control when you need it — and no code when you don't", - "__createdUsingCli": true, - "isOAuth": false + "__createdUsingCli": true } diff --git a/packages/app-store/plausible/components/EventTypeAppCardInterface.tsx b/packages/app-store/plausible/components/EventTypeAppCardInterface.tsx index 440f307ff8..306d0be058 100644 --- a/packages/app-store/plausible/components/EventTypeAppCardInterface.tsx +++ b/packages/app-store/plausible/components/EventTypeAppCardInterface.tsx @@ -2,13 +2,14 @@ import { useAppContextWithSchema } from "@calcom/app-store/EventTypeAppContext"; import AppCard from "@calcom/app-store/_components/AppCard"; import useIsAppEnabled from "@calcom/app-store/_utils/useIsAppEnabled"; import type { EventTypeAppCardComponent } from "@calcom/app-store/types"; +import { TextField } from "@calcom/ui"; import type { appDataSchema } from "../zod"; -import EventTypeAppSettingsInterface from "./EventTypeAppSettingsInterface"; const EventTypeAppCard: EventTypeAppCardComponent = function EventTypeAppCard({ app, eventType }) { const { getAppData, setAppData, disabled } = useAppContextWithSchema(); - + const plausibleUrl = getAppData("PLAUSIBLE_URL"); + const trackingId = getAppData("trackingId"); const { enabled, updateEnabled } = useIsAppEnabled(app); return ( @@ -20,13 +21,29 @@ const EventTypeAppCard: EventTypeAppCardComponent = function EventTypeAppCard({ }} switchChecked={enabled} teamId={eventType.team?.id || undefined}> - +
+ { + setAppData("PLAUSIBLE_URL", e.target.value); + }} + /> + { + setAppData("trackingId", e.target.value); + }} + /> +
); }; diff --git a/packages/app-store/plausible/components/EventTypeAppSettingsInterface.tsx b/packages/app-store/plausible/components/EventTypeAppSettingsInterface.tsx deleted file mode 100644 index bafa35679f..0000000000 --- a/packages/app-store/plausible/components/EventTypeAppSettingsInterface.tsx +++ /dev/null @@ -1,40 +0,0 @@ -import type { EventTypeAppSettingsComponent } from "@calcom/app-store/types"; -import { TextField } from "@calcom/ui"; - -const EventTypeAppSettingsInterface: EventTypeAppSettingsComponent = ({ - getAppData, - setAppData, - disabled, - slug, -}) => { - const plausibleUrl = getAppData("PLAUSIBLE_URL"); - const trackingId = getAppData("trackingId"); - - return ( -
- { - setAppData("PLAUSIBLE_URL", e.target.value); - }} - /> - { - setAppData("trackingId", e.target.value); - }} - /> -
- ); -}; - -export default EventTypeAppSettingsInterface; diff --git a/packages/app-store/plausible/config.json b/packages/app-store/plausible/config.json index 8d157e8814..2fa2baee89 100644 --- a/packages/app-store/plausible/config.json +++ b/packages/app-store/plausible/config.json @@ -23,6 +23,5 @@ } }, "description": "Simple, privacy-friendly Google Analytics alternative.", - "__createdUsingCli": true, - "isOAuth": false + "__createdUsingCli": true } diff --git a/packages/app-store/qr_code/components/EventTypeAppCardInterface.tsx b/packages/app-store/qr_code/components/EventTypeAppCardInterface.tsx index 53df00b922..acab0974a2 100644 --- a/packages/app-store/qr_code/components/EventTypeAppCardInterface.tsx +++ b/packages/app-store/qr_code/components/EventTypeAppCardInterface.tsx @@ -1,14 +1,39 @@ +import { useState } from "react"; + import { useAppContextWithSchema } from "@calcom/app-store/EventTypeAppContext"; import AppCard from "@calcom/app-store/_components/AppCard"; import useIsAppEnabled from "@calcom/app-store/_utils/useIsAppEnabled"; import type { EventTypeAppCardComponent } from "@calcom/app-store/types"; +import { useLocale } from "@calcom/lib/hooks/useLocale"; +import { Tooltip, TextField } from "@calcom/ui"; import type { appDataSchema } from "../zod"; -import EventTypeAppSettingsInterface from "./EventTypeAppSettingsInterface"; const EventTypeAppCard: EventTypeAppCardComponent = function EventTypeAppCard({ eventType, app }) { + const { t } = useLocale(); + const { disabled } = useAppContextWithSchema(); + const [additionalParameters, setAdditionalParameters] = useState(""); const { enabled, updateEnabled } = useIsAppEnabled(app); - const { disabled, getAppData, setAppData } = useAppContextWithSchema(); + + const query = additionalParameters !== "" ? `?${additionalParameters}` : ""; + const eventTypeURL = eventType.URL + query; + + function QRCode({ size, data }: { size: number; data: string }) { + const QR_URL = `https://api.qrserver.com/v1/create-qr-code/?size=${size}&data=${data}`; + return ( + + + {eventTypeURL} + + + ); + } return ( - +
+
+ setAdditionalParameters(e.target.value)} + label={t("additional_url_parameters")} + containerClassName="w-full" + /> +
+ +
+ + + +
+
); }; diff --git a/packages/app-store/qr_code/components/EventTypeAppSettingsInterface.tsx b/packages/app-store/qr_code/components/EventTypeAppSettingsInterface.tsx deleted file mode 100644 index cc069d32eb..0000000000 --- a/packages/app-store/qr_code/components/EventTypeAppSettingsInterface.tsx +++ /dev/null @@ -1,55 +0,0 @@ -import { useState } from "react"; - -import type { EventTypeAppSettingsComponent } from "@calcom/app-store/types"; -import { classNames } from "@calcom/lib"; -import { useLocale } from "@calcom/lib/hooks/useLocale"; -import { TextField, Tooltip } from "@calcom/ui"; - -const EventTypeAppSettingsInterface: EventTypeAppSettingsComponent = ({ eventType, disabled }) => { - const { t } = useLocale(); - const [additionalParameters, setAdditionalParameters] = useState(""); - const query = additionalParameters !== "" ? `?${additionalParameters}` : ""; - const eventTypeURL = eventType.URL + query; - - function QRCode({ size, data }: { size: number; data: string }) { - const QR_URL = `https://api.qrserver.com/v1/create-qr-code/?size=${size}&data=${data}`; - return ( - - - = 256 && "min-h-32" - )} - style={{ padding: size / 16, borderRadius: size / 20 }} - width={size} - src={QR_URL} - alt={eventTypeURL} - /> - - - ); - } - return ( -
-
- setAdditionalParameters(e.target.value)} - label={t("additional_url_parameters")} - containerClassName="w-full" - /> -
- -
- - - -
-
- ); -}; - -export default EventTypeAppSettingsInterface; diff --git a/packages/app-store/qr_code/config.json b/packages/app-store/qr_code/config.json index 25763202ba..3597091bbd 100644 --- a/packages/app-store/qr_code/config.json +++ b/packages/app-store/qr_code/config.json @@ -11,6 +11,5 @@ "publisher": "Cal.com, Inc.", "email": "support@cal.com", "description": "Easily generate a QR code for your links to print, share, or embed.", - "__createdUsingCli": true, - "isOAuth": false + "__createdUsingCli": true } diff --git a/packages/app-store/raycast/config.json b/packages/app-store/raycast/config.json index aac51930e6..12680a74c3 100644 --- a/packages/app-store/raycast/config.json +++ b/packages/app-store/raycast/config.json @@ -10,6 +10,5 @@ "publisher": "Eric Luce", "email": "info@restlessmindstech.com", "description": "Quickly share your Cal.com meeting links with Raycast", - "__createdUsingCli": true, - "isOAuth": false + "__createdUsingCli": true } diff --git a/packages/app-store/riverside/config.json b/packages/app-store/riverside/config.json index 947d2c3ecc..45788adfe7 100644 --- a/packages/app-store/riverside/config.json +++ b/packages/app-store/riverside/config.json @@ -18,6 +18,5 @@ "type": "integrations:riverside_video", "linkType": "static" } - }, - "isOAuth": false + } } diff --git a/packages/app-store/routing-forms/config.json b/packages/app-store/routing-forms/config.json index 22eacf8097..55ad690527 100644 --- a/packages/app-store/routing-forms/config.json +++ b/packages/app-store/routing-forms/config.json @@ -17,6 +17,5 @@ "upgradeUrl": "/routing-forms/forms" }, "description": "It would allow a booker to connect with the right person or choose the right event, faster. It would work by taking inputs from the booker and using that data to route to the correct booker/event as configured by Cal user", - "__createdUsingCli": true, - "isOAuth": false + "__createdUsingCli": true } diff --git a/packages/app-store/salesforce/api/callback.ts b/packages/app-store/salesforce/api/callback.ts index a764389404..aad019a560 100644 --- a/packages/app-store/salesforce/api/callback.ts +++ b/packages/app-store/salesforce/api/callback.ts @@ -42,11 +42,6 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse) await createOAuthAppCredential({ appId: appConfig.slug, type: appConfig.type }, salesforceTokenInfo, req); const state = decodeOAuthState(req); - - if (state?.appOnboardingRedirectUrl && state.appOnboardingRedirectUrl !== "") { - return res.redirect(state.appOnboardingRedirectUrl); - } - res.redirect( getSafeRedirectUrl(state?.returnTo) ?? getInstalledAppPath({ variant: "other", slug: "salesforce" }) ); diff --git a/packages/app-store/salesforce/config.json b/packages/app-store/salesforce/config.json index d159830f94..3f95a3c9b0 100644 --- a/packages/app-store/salesforce/config.json +++ b/packages/app-store/salesforce/config.json @@ -10,6 +10,5 @@ "publisher": "Cal.com, Inc.", "email": "help@cal.com", "description": "Salesforce (Sales Cloud) is a cloud-based application designed to help your salespeople sell smarter and faster by centralizing customer information, logging their interactions with your company, and automating many of the tasks salespeople do every day.", - "__createdUsingCli": true, - "isOAuth": true + "__createdUsingCli": true } diff --git a/packages/app-store/sendgrid/config.json b/packages/app-store/sendgrid/config.json index d98cf3af04..3f15a92402 100644 --- a/packages/app-store/sendgrid/config.json +++ b/packages/app-store/sendgrid/config.json @@ -10,6 +10,5 @@ "publisher": "Cal.com, Inc.", "email": "help@cal.com", "description": "SendGrid delivers your transactional and marketing emails through the world's largest cloud-based email delivery platform.", - "__createdUsingCli": true, - "isOAuth": false + "__createdUsingCli": true } diff --git a/packages/app-store/signal/config.json b/packages/app-store/signal/config.json index fe3bf5bd2f..bb0e8f5a93 100644 --- a/packages/app-store/signal/config.json +++ b/packages/app-store/signal/config.json @@ -19,6 +19,5 @@ "organizerInputPlaceholder": "https://signal.me/#p/+11234567890", "urlRegExp": "^http(s)?:\\/\\/(www\\.)?signal.me\\/[a-zA-Z0-9]*" } - }, - "isOAuth": false + } } diff --git a/packages/app-store/sirius_video/config.json b/packages/app-store/sirius_video/config.json index d8c02a2f65..b44436beba 100644 --- a/packages/app-store/sirius_video/config.json +++ b/packages/app-store/sirius_video/config.json @@ -19,6 +19,5 @@ "organizerInputPlaceholder": "https://sirius.video/sebastian", "urlRegExp": "^http(s)?:\\/\\/(www\\.)?sirius.video\\/[a-zA-Z0-9]*" } - }, - "isOAuth": false + } } diff --git a/packages/app-store/stripepayment/_metadata.ts b/packages/app-store/stripepayment/_metadata.ts index 54f87d7210..26bd34023d 100644 --- a/packages/app-store/stripepayment/_metadata.ts +++ b/packages/app-store/stripepayment/_metadata.ts @@ -23,7 +23,6 @@ export const metadata = { extendsFeature: "EventType", email: "help@cal.com", dirName: "stripepayment", - isOAuth: true, } as AppMeta; export default metadata; diff --git a/packages/app-store/stripepayment/api/callback.ts b/packages/app-store/stripepayment/api/callback.ts index 61d16f7506..98e3b4ca87 100644 --- a/packages/app-store/stripepayment/api/callback.ts +++ b/packages/app-store/stripepayment/api/callback.ts @@ -53,10 +53,6 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse) req ); - if (state?.appOnboardingRedirectUrl && state.appOnboardingRedirectUrl !== "") { - return res.redirect(state.appOnboardingRedirectUrl); - } - const returnTo = getReturnToValueFromQueryState(req); res.redirect(returnTo || getInstalledAppPath({ variant: "payment", slug: "stripe" })); } diff --git a/packages/app-store/stripepayment/components/EventTypeAppCardInterface.tsx b/packages/app-store/stripepayment/components/EventTypeAppCardInterface.tsx index 24f406e14c..886f626913 100644 --- a/packages/app-store/stripepayment/components/EventTypeAppCardInterface.tsx +++ b/packages/app-store/stripepayment/components/EventTypeAppCardInterface.tsx @@ -1,48 +1,157 @@ import { usePathname } from "next/navigation"; -import { useState } from "react"; +import { useState, useEffect } from "react"; import { useAppContextWithSchema } from "@calcom/app-store/EventTypeAppContext"; import AppCard from "@calcom/app-store/_components/AppCard"; import type { EventTypeAppCardComponent } from "@calcom/app-store/types"; import { WEBAPP_URL } from "@calcom/lib/constants"; import { useLocale } from "@calcom/lib/hooks/useLocale"; +import { Alert, Select, TextField } from "@calcom/ui"; import checkForMultiplePaymentApps from "../../_utils/payments/checkForMultiplePaymentApps"; -import useIsAppEnabled from "../../_utils/useIsAppEnabled"; +import { paymentOptions } from "../lib/constants"; +import { + convertToSmallestCurrencyUnit, + convertFromSmallestToPresentableCurrencyUnit, +} from "../lib/currencyConversions"; +import { currencyOptions } from "../lib/currencyOptions"; import type { appDataSchema } from "../zod"; -import EventTypeAppSettingsInterface from "./EventTypeAppSettingsInterface"; + +type Option = { value: string; label: string }; const EventTypeAppCard: EventTypeAppCardComponent = function EventTypeAppCard({ app, eventType, eventTypeFormMetadata, }) { - const { t } = useLocale(); const pathname = usePathname(); const { getAppData, setAppData, disabled } = useAppContextWithSchema(); - const { enabled, updateEnabled } = useIsAppEnabled(app); - const otherPaymentAppEnabled = checkForMultiplePaymentApps(eventTypeFormMetadata); + const price = getAppData("price"); + const currency = getAppData("currency") || currencyOptions[0].value; + const [selectedCurrency, setSelectedCurrency] = useState( + currencyOptions.find((c) => c.value === currency) || { + label: currencyOptions[0].label, + value: currencyOptions[0].value, + } + ); + const paymentOption = getAppData("paymentOption"); + const paymentOptionSelectValue = paymentOptions.find((option) => paymentOption === option.value); const [requirePayment, setRequirePayment] = useState(getAppData("enabled")); + const otherPaymentAppEnabled = checkForMultiplePaymentApps(eventTypeFormMetadata); + const shouldDisableSwitch = !requirePayment && otherPaymentAppEnabled; + const { t } = useLocale(); + const recurringEventDefined = eventType.recurringEvent?.count !== undefined; + const seatsEnabled = !!eventType.seatsPerTimeSlot; + const getCurrencySymbol = (locale: string, currency: string) => + (0) + .toLocaleString(locale, { + style: "currency", + currency, + minimumFractionDigits: 0, + maximumFractionDigits: 0, + }) + .replace(/\d/g, "") + .trim(); + + useEffect(() => { + if (requirePayment) { + if (!getAppData("currency")) { + setAppData("currency", currencyOptions[0].value); + } + if (!getAppData("paymentOption")) { + setAppData("paymentOption", paymentOptions[0].value); + } + } + }, [requirePayment, getAppData, setAppData]); + return ( { - updateEnabled(e); + switchChecked={requirePayment} + switchOnClick={(enabled) => { + setRequirePayment(enabled); }} teamId={eventType.team?.id || undefined} disableSwitch={shouldDisableSwitch} switchTooltip={shouldDisableSwitch ? t("other_payment_app_enabled") : undefined}> - + <> + {recurringEventDefined && ( + + )} + {!recurringEventDefined && requirePayment && ( + <> +
+ {selectedCurrency.value ? getCurrencySymbol("en", selectedCurrency.value) : ""} + } + addOnSuffix={currency.toUpperCase()} + addOnClassname="h-[38px]" + step="0.01" + min="0.5" + type="number" + required + placeholder="Price" + disabled={disabled} + onChange={(e) => { + setAppData("price", convertToSmallestCurrencyUnit(Number(e.target.value), currency)); + }} + value={price > 0 ? convertFromSmallestToPresentableCurrencyUnit(price, currency) : undefined} + /> +
+
+ + { - if (e) { - setSelectedCurrency(e); - setAppData("currency", e.value); - } - }} - /> -
-
- - - data-testid="stripe-payment-option-select" - defaultValue={ - paymentOptionSelectValue - ? { ...paymentOptionSelectValue, label: t(paymentOptionSelectValue.label) } - : { ...paymentOptions[0], label: t(paymentOptions[0].label) } - } - options={paymentOptions.map((option) => { - return { ...option, label: t(option.label) || option.label }; - })} - onChange={(input) => { - if (input) setAppData("paymentOption", input.value); - }} - className="mb-1 h-[38px] w-full" - isDisabled={seatsEnabled || disabled} - /> -
- - {seatsEnabled && paymentOption === "HOLD" && ( - - )} - - )} - - ); -}; - -export default EventTypeAppSettingsInterface; diff --git a/packages/app-store/sylapsvideo/config.json b/packages/app-store/sylapsvideo/config.json index 6ab5fe68ff..424ba6ce6c 100644 --- a/packages/app-store/sylapsvideo/config.json +++ b/packages/app-store/sylapsvideo/config.json @@ -18,6 +18,5 @@ "type": "integrations:sylaps_video", "label": "Sylaps" } - }, - "isOAuth": false + } } diff --git a/packages/app-store/tandemvideo/_metadata.ts b/packages/app-store/tandemvideo/_metadata.ts index 6deef75e2d..28f9477129 100644 --- a/packages/app-store/tandemvideo/_metadata.ts +++ b/packages/app-store/tandemvideo/_metadata.ts @@ -24,7 +24,6 @@ export const metadata = { }, }, dirName: "tandemvideo", - isOAuth: true, } as AppMeta; export default metadata; diff --git a/packages/app-store/typeform/config.json b/packages/app-store/typeform/config.json index ff0a14c376..daf11d5a7d 100644 --- a/packages/app-store/typeform/config.json +++ b/packages/app-store/typeform/config.json @@ -10,6 +10,5 @@ "publisher": "Cal.com, Inc.", "email": "help@cal.com", "description": "Adds a link to copy Typeform Redirect URL", - "__createdUsingCli": true, - "isOAuth": false + "__createdUsingCli": true } diff --git a/packages/app-store/types.d.ts b/packages/app-store/types.d.ts index da1fb01df9..dfb22ab85b 100644 --- a/packages/app-store/types.d.ts +++ b/packages/app-store/types.d.ts @@ -10,7 +10,6 @@ export type IntegrationOAuthCallbackState = { onErrorReturnTo: string; fromApp: boolean; installGoogleVideo?: boolean; - appOnboardingRedirectUrl?: string; teamId?: number; }; @@ -57,23 +56,4 @@ export type EventTypeAppCardComponentProps = { LockedIcon?: JSX.Element | false; eventTypeFormMetadata?: z.infer; }; - -export type EventTypeAppSettingsComponentProps = { - // Limit what data should be accessible to apps\ - eventType: Pick< - z.infer, - "id" | "title" | "description" | "teamId" | "length" | "recurringEvent" | "seatsPerTimeSlot" | "team" - > & { - URL: string; - }; - getAppData: GetAppData; - setAppData: SetAppData; - disabled?: boolean; - slug: string; -}; - export type EventTypeAppCardComponent = React.FC; - -export type EventTypeAppSettingsComponent = React.FC; - -export type EventTypeModel = z.infer; diff --git a/packages/app-store/vimcal/config.json b/packages/app-store/vimcal/config.json index 4baeb62de9..f38f25ad8f 100644 --- a/packages/app-store/vimcal/config.json +++ b/packages/app-store/vimcal/config.json @@ -11,6 +11,5 @@ "email": "support@cal.com", "description": "The world's fastest calendar, beautifully designed for a remote world\r", "__createdUsingCli": true, - "dependencies": ["google-calendar"], - "isOAuth": false + "dependencies": ["google-calendar"] } diff --git a/packages/app-store/vital/_metadata.ts b/packages/app-store/vital/_metadata.ts index 19d47d1527..f0359e0b04 100644 --- a/packages/app-store/vital/_metadata.ts +++ b/packages/app-store/vital/_metadata.ts @@ -18,7 +18,6 @@ export const metadata = { variant: "other", email: "support@tryvital.io", dirName: "vital", - isOAuth: true, } as AppMeta; export default metadata; diff --git a/packages/app-store/weather_in_your_calendar/config.json b/packages/app-store/weather_in_your_calendar/config.json index 6193d26c1c..e7769ebd57 100644 --- a/packages/app-store/weather_in_your_calendar/config.json +++ b/packages/app-store/weather_in_your_calendar/config.json @@ -10,6 +10,5 @@ "publisher": "Andreas Vejnø Andersen", "email": "info@vejnoe.dk", "description": "Get the local weather forecast with icons in your calendar\r\r", - "__createdUsingCli": true, - "isOAuth": false + "__createdUsingCli": true } diff --git a/packages/app-store/webex/config.json b/packages/app-store/webex/config.json index f37f9b5ac2..587fc561f5 100644 --- a/packages/app-store/webex/config.json +++ b/packages/app-store/webex/config.json @@ -22,6 +22,5 @@ "isTemplate": false, "__createdUsingCli": true, "__template": "basic", - "concurrentMeetings": true, - "isAuth": true + "concurrentMeetings": true } diff --git a/packages/app-store/whatsapp/config.json b/packages/app-store/whatsapp/config.json index af42fc8ce5..dde161c6ae 100644 --- a/packages/app-store/whatsapp/config.json +++ b/packages/app-store/whatsapp/config.json @@ -19,6 +19,5 @@ "organizerInputPlaceholder": "https://wa.me/send?phone=1234567890", "urlRegExp": "^http(s)?:\\/\\/(www\\.)?wa.me\\/[a-zA-Z0-9]*" } - }, - "isAuth": false + } } diff --git a/packages/app-store/whereby/config.json b/packages/app-store/whereby/config.json index 5bf0dcd9d6..3844faa3f2 100644 --- a/packages/app-store/whereby/config.json +++ b/packages/app-store/whereby/config.json @@ -20,6 +20,5 @@ "organizerInputPlaceholder": "https://www.whereby.com/cal", "urlRegExp": "^(?:https?://)?(?:(?!.*-\\.)(?:\\w+(-\\w+)*\\.))*whereby\\.com(/[\\w\\-._~:?#\\[\\]@!$&'()*+,;%=]+)*$" } - }, - "isAuth": false + } } diff --git a/packages/app-store/wipemycalother/_metadata.ts b/packages/app-store/wipemycalother/_metadata.ts index d7819dea08..7b1c1d9c4e 100644 --- a/packages/app-store/wipemycalother/_metadata.ts +++ b/packages/app-store/wipemycalother/_metadata.ts @@ -18,7 +18,6 @@ export const metadata = { variant: "other", email: "help@cal.com", dirName: "wipemycalother", - isOAuth: false, } as AppMeta; export default metadata; diff --git a/packages/app-store/wordpress/config.json b/packages/app-store/wordpress/config.json index c29179fedf..260e7411a0 100644 --- a/packages/app-store/wordpress/config.json +++ b/packages/app-store/wordpress/config.json @@ -10,6 +10,5 @@ "publisher": "Cal.com, Inc.", "email": "support@cal.com", "description": "Embedded booking pages right into your wordpress page", - "__createdUsingCli": true, - "isAuth": false + "__createdUsingCli": true } diff --git a/packages/app-store/zapier/_metadata.ts b/packages/app-store/zapier/_metadata.ts index b8be473f70..26b50fb9d2 100644 --- a/packages/app-store/zapier/_metadata.ts +++ b/packages/app-store/zapier/_metadata.ts @@ -17,7 +17,6 @@ export const metadata = { variant: "automation", email: "help@cal.com", dirName: "zapier", - isOAuth: false, } as AppMeta; export default metadata; diff --git a/packages/app-store/zoho-bigin/api/callback.ts b/packages/app-store/zoho-bigin/api/callback.ts index 96a3ad3a05..f1ab94a2a8 100644 --- a/packages/app-store/zoho-bigin/api/callback.ts +++ b/packages/app-store/zoho-bigin/api/callback.ts @@ -55,11 +55,6 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse) await createOAuthAppCredential({ appId: appConfig.slug, type: appConfig.type }, tokenInfo.data, req); const state = decodeOAuthState(req); - - if (state?.appOnboardingRedirectUrl && state.appOnboardingRedirectUrl !== "") { - return res.redirect(state.appOnboardingRedirectUrl); - } - res.redirect( getSafeRedirectUrl(state?.returnTo) ?? getInstalledAppPath({ variant: appConfig.variant, slug: appConfig.slug }) diff --git a/packages/app-store/zoho-bigin/config.json b/packages/app-store/zoho-bigin/config.json index d4a2851271..aea58ef2c7 100644 --- a/packages/app-store/zoho-bigin/config.json +++ b/packages/app-store/zoho-bigin/config.json @@ -13,6 +13,5 @@ "isTemplate": false, "__createdUsingCli": true, "__template": "basic", - "scope": "ZohoBigin.modules.events.ALL,ZohoBigin.modules.contacts.ALL", - "isOAuth": true + "scope": "ZohoBigin.modules.events.ALL,ZohoBigin.modules.contacts.ALL" } diff --git a/packages/app-store/zohocalendar/config.json b/packages/app-store/zohocalendar/config.json index 5bdbb60829..6d43249f52 100644 --- a/packages/app-store/zohocalendar/config.json +++ b/packages/app-store/zohocalendar/config.json @@ -10,6 +10,5 @@ "logo": "icon.svg", "publisher": "Cal.com", "url": "https://cal.com/", - "email": "help@cal.com", - "isAuth": true + "email": "help@cal.com" } diff --git a/packages/app-store/zohocrm/api/callback.ts b/packages/app-store/zohocrm/api/callback.ts index bcbed269fa..9f02f28201 100644 --- a/packages/app-store/zohocrm/api/callback.ts +++ b/packages/app-store/zohocrm/api/callback.ts @@ -55,11 +55,6 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse) await createOAuthAppCredential({ appId: appConfig.slug, type: appConfig.type }, zohoCrmTokenInfo.data, req); const state = decodeOAuthState(req); - - if (state?.appOnboardingRedirectUrl && state.appOnboardingRedirectUrl !== "") { - return res.redirect(state.appOnboardingRedirectUrl); - } - res.redirect( getSafeRedirectUrl(state?.returnTo) ?? getInstalledAppPath({ variant: "other", slug: "zohocrm" }) ); diff --git a/packages/app-store/zohocrm/config.json b/packages/app-store/zohocrm/config.json index 2a0cf837ca..daea3c1162 100644 --- a/packages/app-store/zohocrm/config.json +++ b/packages/app-store/zohocrm/config.json @@ -12,6 +12,5 @@ "description": "Zoho CRM is a cloud-based application designed to help your salespeople sell smarter and faster by centralizing customer information, logging their interactions with your company, and automating many of the tasks salespeople do every day", "isTemplate": false, "__createdUsingCli": true, - "__template": "basic", - "isOAuth": true + "__template": "basic" } diff --git a/packages/app-store/zoomvideo/_metadata.ts b/packages/app-store/zoomvideo/_metadata.ts index 4a65fe8480..665efb8446 100644 --- a/packages/app-store/zoomvideo/_metadata.ts +++ b/packages/app-store/zoomvideo/_metadata.ts @@ -25,7 +25,6 @@ export const metadata = { }, }, dirName: "zoomvideo", - isOAuth: true, } as AppMeta; export default metadata; diff --git a/packages/embeds/embed-core/playwright/tests/action-based.e2e.ts b/packages/embeds/embed-core/playwright/tests/action-based.e2e.ts index e84bf3187e..1d6106a1ab 100644 --- a/packages/embeds/embed-core/playwright/tests/action-based.e2e.ts +++ b/packages/embeds/embed-core/playwright/tests/action-based.e2e.ts @@ -1,11 +1,8 @@ import type { Page } from "@playwright/test"; import { expect } from "@playwright/test"; -// eslint-disable-next-line no-restricted-imports import { test } from "@calcom/web/playwright/lib/fixtures"; -// eslint-disable-next-line no-restricted-imports import type { Fixtures } from "@calcom/web/playwright/lib/fixtures"; -// eslint-disable-next-line no-restricted-imports import { selectFirstAvailableTimeSlotNextMonth } from "@calcom/web/playwright/lib/testUtils"; import { diff --git a/packages/features/auth/SAMLLogin.tsx b/packages/features/auth/SAMLLogin.tsx index 2c74571f4f..b0d9973d5f 100644 --- a/packages/features/auth/SAMLLogin.tsx +++ b/packages/features/auth/SAMLLogin.tsx @@ -6,7 +6,7 @@ import z from "zod"; import { HOSTED_CAL_FEATURES } from "@calcom/lib/constants"; import { useLocale } from "@calcom/lib/hooks/useLocale"; import { trpc } from "@calcom/trpc/react"; -import { Button } from "@calcom/ui"; +import { Button, Icon } from "@calcom/ui"; interface Props { samlTenantID: string; diff --git a/packages/features/bookings/Booker/components/OverlayCalendar/OverlayCalendarSettingsModal.tsx b/packages/features/bookings/Booker/components/OverlayCalendar/OverlayCalendarSettingsModal.tsx index 642af0dac3..ab4eeaef6f 100644 --- a/packages/features/bookings/Booker/components/OverlayCalendar/OverlayCalendarSettingsModal.tsx +++ b/packages/features/bookings/Booker/components/OverlayCalendar/OverlayCalendarSettingsModal.tsx @@ -9,6 +9,7 @@ import { DialogClose, DialogContent, EmptyScreen, + Icon, ListItem, ListItemText, ListItemTitle, diff --git a/packages/features/calendars/weeklyview/components/heading/SchedulerHeading.tsx b/packages/features/calendars/weeklyview/components/heading/SchedulerHeading.tsx index 17832275cc..4ff86c79fe 100644 --- a/packages/features/calendars/weeklyview/components/heading/SchedulerHeading.tsx +++ b/packages/features/calendars/weeklyview/components/heading/SchedulerHeading.tsx @@ -1,5 +1,5 @@ import dayjs from "@calcom/dayjs"; -import { Button, ButtonGroup } from "@calcom/ui"; +import { Button, ButtonGroup, Icon } from "@calcom/ui"; import { useCalendarStore } from "../../state/store"; diff --git a/packages/features/ee/api-keys/components/ApiKeyDialogForm.tsx b/packages/features/ee/api-keys/components/ApiKeyDialogForm.tsx index 3230a003b7..c2ab1b305f 100644 --- a/packages/features/ee/api-keys/components/ApiKeyDialogForm.tsx +++ b/packages/features/ee/api-keys/components/ApiKeyDialogForm.tsx @@ -6,7 +6,17 @@ import type { TApiKeys } from "@calcom/ee/api-keys/components/ApiKeyListItem"; import LicenseRequired from "@calcom/ee/common/components/LicenseRequired"; import { useLocale } from "@calcom/lib/hooks/useLocale"; import { trpc } from "@calcom/trpc/react"; -import { Button, DialogFooter, Form, SelectField, showToast, Switch, TextField, Tooltip } from "@calcom/ui"; +import { + Button, + DialogFooter, + Form, + Icon, + SelectField, + showToast, + Switch, + TextField, + Tooltip, +} from "@calcom/ui"; export default function ApiKeyDialogForm({ defaultValues, diff --git a/packages/features/ee/dsync/components/DirectoryInfo.tsx b/packages/features/ee/dsync/components/DirectoryInfo.tsx index 005cbc412b..43f47653a3 100644 --- a/packages/features/ee/dsync/components/DirectoryInfo.tsx +++ b/packages/features/ee/dsync/components/DirectoryInfo.tsx @@ -2,6 +2,7 @@ import type { Directory } from "@boxyhq/saml-jackson"; import { useLocale } from "@calcom/lib/hooks/useLocale"; import { Button, showToast, Label, Tooltip } from "@calcom/ui"; +import { Icon } from "@calcom/ui"; const DirectoryInfo = ({ directory }: { directory: Directory }) => { const { t } = useLocale(); diff --git a/packages/features/ee/organizations/pages/components/MemberListItem.tsx b/packages/features/ee/organizations/pages/components/MemberListItem.tsx index 94158465be..f48e62fa64 100644 --- a/packages/features/ee/organizations/pages/components/MemberListItem.tsx +++ b/packages/features/ee/organizations/pages/components/MemberListItem.tsx @@ -11,6 +11,7 @@ import { DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger, + Icon, Tooltip, UserAvatar, } from "@calcom/ui"; @@ -81,7 +82,12 @@ export default function MemberListItem(props: Props) {
-
- {t("preview")} + + {t("preview")} + { - diff --git a/packages/features/ee/organizations/pages/settings/profile.tsx b/packages/features/ee/organizations/pages/settings/profile.tsx index 9dfe272be3..bce21646ac 100644 --- a/packages/features/ee/organizations/pages/settings/profile.tsx +++ b/packages/features/ee/organizations/pages/settings/profile.tsx @@ -22,6 +22,7 @@ import { Button, Editor, Form, + Icon, ImageUploader, Label, LinkIconButton, diff --git a/packages/features/ee/teams/components/AddNewTeamMembers.tsx b/packages/features/ee/teams/components/AddNewTeamMembers.tsx index 26603456ab..7b7eac226e 100644 --- a/packages/features/ee/teams/components/AddNewTeamMembers.tsx +++ b/packages/features/ee/teams/components/AddNewTeamMembers.tsx @@ -16,6 +16,7 @@ import { trpc } from "@calcom/trpc/react"; import { Badge, Button, + Icon, showToast, SkeletonButton, SkeletonContainer, diff --git a/packages/features/ee/teams/pages/team-members-view.tsx b/packages/features/ee/teams/pages/team-members-view.tsx index 576fcf2981..d534118eb2 100644 --- a/packages/features/ee/teams/pages/team-members-view.tsx +++ b/packages/features/ee/teams/pages/team-members-view.tsx @@ -11,6 +11,7 @@ import { MembershipRole } from "@calcom/prisma/enums"; import type { RouterOutputs } from "@calcom/trpc/react"; import { trpc } from "@calcom/trpc/react"; import { Button, Meta, showToast, TextField } from "@calcom/ui"; +import { Icon } from "@calcom/ui"; import { getLayout } from "../../../settings/layouts/SettingsLayout"; import DisableTeamImpersonation from "../components/DisableTeamImpersonation"; diff --git a/packages/features/ee/workflows/components/WorkflowListPage.tsx b/packages/features/ee/workflows/components/WorkflowListPage.tsx index 0299b8ba2e..5f67d3e343 100644 --- a/packages/features/ee/workflows/components/WorkflowListPage.tsx +++ b/packages/features/ee/workflows/components/WorkflowListPage.tsx @@ -252,7 +252,12 @@ export default function WorkflowListPage({ workflows }: Props) {
- } diff --git a/packages/features/timezone-buddy/components/AvailabilitySliderTable.tsx b/packages/features/timezone-buddy/components/AvailabilitySliderTable.tsx index 2e5b04e6bd..97bf068eac 100644 --- a/packages/features/timezone-buddy/components/AvailabilitySliderTable.tsx +++ b/packages/features/timezone-buddy/components/AvailabilitySliderTable.tsx @@ -9,7 +9,7 @@ import { useLocale } from "@calcom/lib/hooks/useLocale"; import type { MembershipRole } from "@calcom/prisma/enums"; import { trpc } from "@calcom/trpc"; import type { UserProfile } from "@calcom/types/UserProfile"; -import { Button, ButtonGroup, DataTable, UserAvatar } from "@calcom/ui"; +import { Button, ButtonGroup, DataTable, Icon, UserAvatar } from "@calcom/ui"; import { UpgradeTip } from "../../tips/UpgradeTip"; import { createTimezoneBuddyStore, TBContext } from "../store"; diff --git a/packages/features/troubleshooter/components/TroubleshooterHeader.tsx b/packages/features/troubleshooter/components/TroubleshooterHeader.tsx index a781f0495e..063f74cbe9 100644 --- a/packages/features/troubleshooter/components/TroubleshooterHeader.tsx +++ b/packages/features/troubleshooter/components/TroubleshooterHeader.tsx @@ -2,7 +2,7 @@ import { useMemo } from "react"; import dayjs from "@calcom/dayjs"; import { useLocale } from "@calcom/lib/hooks/useLocale"; -import { Button, ButtonGroup } from "@calcom/ui"; +import { Button, ButtonGroup, Icon } from "@calcom/ui"; import { useTroubleshooterStore } from "../store"; diff --git a/packages/features/webhooks/components/WebhookTestDisclosure.tsx b/packages/features/webhooks/components/WebhookTestDisclosure.tsx index 5bf6d048d0..e8b448a969 100644 --- a/packages/features/webhooks/components/WebhookTestDisclosure.tsx +++ b/packages/features/webhooks/components/WebhookTestDisclosure.tsx @@ -4,7 +4,7 @@ import { ZodError } from "zod"; import { useLocale } from "@calcom/lib/hooks/useLocale"; import { trpc } from "@calcom/trpc/react"; import { ZTestTriggerInputSchema } from "@calcom/trpc/server/routers/viewer/webhook/testTrigger.schema"; -import { Badge, Button, showToast } from "@calcom/ui"; +import { Badge, Button, Icon, showToast } from "@calcom/ui"; export default function WebhookTestDisclosure() { const [subscriberUrl, webhookSecret]: [string, string] = useWatch({ name: ["subscriberUrl", "secret"] }); diff --git a/packages/lib/apps/appOnboardingSteps.ts b/packages/lib/apps/appOnboardingSteps.ts deleted file mode 100644 index e6117b9296..0000000000 --- a/packages/lib/apps/appOnboardingSteps.ts +++ /dev/null @@ -1,5 +0,0 @@ -export enum AppOnboardingSteps { - ACCOUNTS_STEP = "accounts", - EVENT_TYPES_STEP = "event-types", - CONFIGURE_STEP = "configure", -} diff --git a/packages/lib/apps/getAppOnboardingRedirectUrl.ts b/packages/lib/apps/getAppOnboardingRedirectUrl.ts deleted file mode 100644 index 8a7bb37630..0000000000 --- a/packages/lib/apps/getAppOnboardingRedirectUrl.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { AppOnboardingSteps } from "@calcom/lib/apps/appOnboardingSteps"; - -import { getAppOnboardingUrl } from "./getAppOnboardingUrl"; - -export const getAppOnboardingRedirectUrl = (slug: string, teamId?: number) => { - const url = getAppOnboardingUrl({ slug, teamId, step: AppOnboardingSteps.EVENT_TYPES_STEP }); - return encodeURIComponent(url); -}; diff --git a/packages/lib/apps/getAppOnboardingUrl.ts b/packages/lib/apps/getAppOnboardingUrl.ts deleted file mode 100644 index fda259dfe7..0000000000 --- a/packages/lib/apps/getAppOnboardingUrl.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { stringify } from "querystring"; - -import type { AppOnboardingSteps } from "@calcom/lib/apps/appOnboardingSteps"; - -export const getAppOnboardingUrl = ({ - slug, - step, - teamId, - eventTypeIds, -}: { - slug: string; - step: AppOnboardingSteps; - teamId?: number; - eventTypeIds?: number[]; -}) => { - const params: { [key: string]: string | number | number[] } = { slug }; - if (!!eventTypeIds && eventTypeIds.length > 0) { - params.eventTypeIds = eventTypeIds.join(","); - } - - if (!!teamId) { - params.teamId = teamId; - } - const query = stringify(params); - - return `/apps/installation/${step}?${query}`; -}; diff --git a/packages/lib/apps/shouldRedirectToAppOnboarding.ts b/packages/lib/apps/shouldRedirectToAppOnboarding.ts deleted file mode 100644 index 868167e877..0000000000 --- a/packages/lib/apps/shouldRedirectToAppOnboarding.ts +++ /dev/null @@ -1,9 +0,0 @@ -import type { AppMeta } from "@calcom/types/App"; - -export const shouldRedirectToAppOnboarding = (appMetadata: AppMeta) => { - // const appMetadata = appStoreMetadata[dirName as keyof typeof appStoreMetadata]; - const hasEventTypes = appMetadata?.extendsFeature == "EventType"; - const isOAuth = appMetadata?.isOAuth; - const isCalendar = appMetadata?.category === "calendar"; - return !isCalendar && (hasEventTypes || isOAuth); -}; diff --git a/packages/platform/atoms/availability/AvailabilitySettings.tsx b/packages/platform/atoms/availability/AvailabilitySettings.tsx index 1e12d68464..ceba69d268 100644 --- a/packages/platform/atoms/availability/AvailabilitySettings.tsx +++ b/packages/platform/atoms/availability/AvailabilitySettings.tsx @@ -178,7 +178,10 @@ const DateOverride = ({ onChange={(ranges) => ranges.forEach((range) => append({ ranges: [range] }))} userTimeFormat={userTimeFormat} Trigger={ - } @@ -321,7 +324,11 @@ export function AvailabilitySettings({ openSidebar ? "translate-x-0 opacity-100" : "translate-x-full opacity-0" )}>
- - ); - } return ( diff --git a/packages/ui/components/form/step/Steps.tsx b/packages/ui/components/form/step/Steps.tsx index fb042d69a1..3c52946628 100644 --- a/packages/ui/components/form/step/Steps.tsx +++ b/packages/ui/components/form/step/Steps.tsx @@ -1,30 +1,17 @@ import classNames from "@calcom/lib/classNames"; -type StepWithNav = { +interface ISteps { maxSteps: number; currentStep: number; navigateToStep: (step: number) => void; - disableNavigation?: false; stepLabel?: (currentStep: number, maxSteps: number) => string; -}; +} -type StepWithoutNav = { - maxSteps: number; - currentStep: number; - navigateToStep?: undefined; - disableNavigation: true; - stepLabel?: (currentStep: number, maxSteps: number) => string; -}; - -// Discriminative union on disableNavigation prop -type StepsProps = StepWithNav | StepWithoutNav; - -const Steps = (props: StepsProps) => { +const Steps = (props: ISteps) => { const { maxSteps, currentStep, navigateToStep, - disableNavigation = false, stepLabel = (currentStep, totalSteps) => `Step ${currentStep} of ${totalSteps}`, } = props; return ( @@ -35,10 +22,10 @@ const Steps = (props: StepsProps) => { return index <= currentStep - 1 ? (
navigateToStep?.(index)} + onClick={() => navigateToStep(index)} className={classNames( "bg-inverted h-1 w-full rounded-[1px]", - index < currentStep - 1 && !disableNavigation ? "cursor-pointer" : "" + index < currentStep - 1 ? "cursor-pointer" : "" )} data-testid={`step-indicator-${index}`} /> diff --git a/packages/ui/components/scrollable/ScrollableArea.tsx b/packages/ui/components/scrollable/ScrollableArea.tsx index 1583c046f5..1e1306e2bb 100644 --- a/packages/ui/components/scrollable/ScrollableArea.tsx +++ b/packages/ui/components/scrollable/ScrollableArea.tsx @@ -35,7 +35,7 @@ const ScrollableArea = ({ children, className }: PropsWithChildren<{ className?: className // Pass in your max-w / max-h )}> {children} - {isOverflowingY &&
} + {isOverflowingY &&
}
); };