refactor: remove circular dependency between appstore and trpc (#23768)
* mv PaymentPage to web * mv 2 more components to web * refactor * update imports * mv * revert * fix * fix * update * migrate relevant test too * move setup components to web from appstore * move wipemycalother * mv * fix typechecks * mv more routing forms components * fix * fix * fix * fix: resolve type errors in SingleForm.tsx after migration - Updated SingleFormComponentProps type to include enriched form properties - Added proper typing for user, team, nonOrgUsername, nonOrgTeamslug, userOrigin, teamOrigin - Fixes type errors that occurred after migrating SingleForm.tsx from packages/app-store/routing-forms/components/ - Resolves both SingleForm.tsx and TestForm.tsx type errors Co-Authored-By: benny@cal.com <sldisek783@gmail.com> * delete * refactors * fix * fix * fix * remove usage of trpc client from OmniInstallAppButton.tsx * fix test * import only type * fix test * remove trpc package from appstore package.json * remove remaining trpc usage * update test * fix type checks * fix errors * fix * make it error * nit --------- Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
This commit is contained in:
+8
-3
@@ -23,10 +23,15 @@ module.exports = {
|
||||
files: ["packages/app-store/**/*.{ts,tsx,js,jsx}"],
|
||||
rules: {
|
||||
"no-restricted-imports": [
|
||||
"warn",
|
||||
"error",
|
||||
{
|
||||
paths: ["@calcom/trpc"],
|
||||
patterns: ["@calcom/trpc/*"],
|
||||
allowTypeImports: false,
|
||||
patterns: [
|
||||
{
|
||||
group: ["@calcom/trpc/*", "@trpc/*"],
|
||||
message: "tRPC imports are blocked in packages/app-store. Move UI to apps/web/components/apps or introduce an API boundary.",
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
+4
-4
@@ -6,6 +6,8 @@ import { Controller, useFieldArray, useWatch } from "react-hook-form";
|
||||
import { Toaster } from "sonner";
|
||||
import { v4 as uuidv4 } from "uuid";
|
||||
|
||||
import { FieldTypes } from "@calcom/app-store/routing-forms/lib/FieldTypes";
|
||||
import type { RoutingFormWithResponseCount } from "@calcom/app-store/routing-forms/types/types";
|
||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||
import classNames from "@calcom/ui/classNames";
|
||||
import { Button } from "@calcom/ui/components/button";
|
||||
@@ -19,13 +21,11 @@ import {
|
||||
} from "@calcom/ui/components/form";
|
||||
import { Icon } from "@calcom/ui/components/icon";
|
||||
import { Tooltip } from "@calcom/ui/components/tooltip";
|
||||
import type { getServerSidePropsForSingleFormView as getServerSideProps } from "@calcom/web/lib/apps/routing-forms/[...pages]/getServerSidePropsSingleForm";
|
||||
|
||||
import type { inferSSRProps } from "@lib/types/inferSSRProps";
|
||||
|
||||
import SingleForm from "../../components/SingleForm";
|
||||
import type { getServerSidePropsForSingleFormView as getServerSideProps } from "../../components/getServerSidePropsSingleForm";
|
||||
import { FieldTypes } from "../../lib/FieldTypes";
|
||||
import type { RoutingFormWithResponseCount } from "../../types/types";
|
||||
import SingleForm from "@components/apps/routing-forms/SingleForm";
|
||||
|
||||
type HookForm = UseFormReturn<RoutingFormWithResponseCount>;
|
||||
|
||||
+3
-3
@@ -3,6 +3,7 @@
|
||||
import { useState, useEffect } from "react";
|
||||
import type z from "zod";
|
||||
|
||||
import type { RoutingFormWithResponseCount } from "@calcom/app-store/routing-forms/types/types";
|
||||
import { WhenToWriteToRecord, SalesforceFieldType } from "@calcom/app-store/salesforce/lib/enums";
|
||||
import type { writeToRecordDataSchema as salesforceWriteToRecordDataSchema } from "@calcom/app-store/salesforce/zod";
|
||||
import { routingFormIncompleteBookingDataSchema as salesforceRoutingFormIncompleteBookingDataSchema } from "@calcom/app-store/salesforce/zod";
|
||||
@@ -17,10 +18,9 @@ import { Select } from "@calcom/ui/components/form";
|
||||
import { Label } from "@calcom/ui/components/form";
|
||||
import { Icon } from "@calcom/ui/components/icon";
|
||||
import { showToast } from "@calcom/ui/components/toast";
|
||||
import type { getServerSidePropsForSingleFormView as getServerSideProps } from "@calcom/web/lib/apps/routing-forms/[...pages]/getServerSidePropsSingleForm";
|
||||
|
||||
import SingleForm from "../../components/SingleForm";
|
||||
import type { getServerSidePropsForSingleFormView as getServerSideProps } from "../../components/getServerSidePropsSingleForm";
|
||||
import type { RoutingFormWithResponseCount } from "../../types/types";
|
||||
import SingleForm from "@components/apps/routing-forms/SingleForm";
|
||||
|
||||
function Page({ form }: { form: RoutingFormWithResponseCount }) {
|
||||
const { t } = useLocale();
|
||||
+32
-32
@@ -10,6 +10,36 @@ import type { UseFormReturn } from "react-hook-form";
|
||||
import { Toaster } from "sonner";
|
||||
import type { z } from "zod";
|
||||
|
||||
import { routingFormAppComponents } from "@calcom/app-store/routing-forms/appComponents";
|
||||
import DynamicAppComponent from "@calcom/app-store/routing-forms/components/DynamicAppComponent";
|
||||
import { EmptyState } from "@calcom/app-store/routing-forms/components/_components/EmptyState";
|
||||
import { RoutingSkeleton } from "@calcom/app-store/routing-forms/components/_components/RoutingSkeleton";
|
||||
import {
|
||||
withRaqbSettingsAndWidgets,
|
||||
ConfigFor,
|
||||
} from "@calcom/app-store/routing-forms/components/react-awesome-query-builder/config/uiConfig";
|
||||
import { RoutingPages } from "@calcom/app-store/routing-forms/lib/RoutingPages";
|
||||
import { createFallbackRoute } from "@calcom/app-store/routing-forms/lib/createFallbackRoute";
|
||||
import getEventTypeAppMetadata from "@calcom/app-store/routing-forms/lib/getEventTypeAppMetadata";
|
||||
import {
|
||||
getQueryBuilderConfigForFormFields,
|
||||
getQueryBuilderConfigForAttributes,
|
||||
type FormFieldsQueryBuilderConfigWithRaqbFields,
|
||||
type AttributesQueryBuilderConfigWithRaqbFields,
|
||||
isDynamicOperandField,
|
||||
} from "@calcom/app-store/routing-forms/lib/getQueryBuilderConfig";
|
||||
import isRouter from "@calcom/app-store/routing-forms/lib/isRouter";
|
||||
import type { RoutingFormWithResponseCount } from "@calcom/app-store/routing-forms/types/types";
|
||||
import type {
|
||||
GlobalRoute,
|
||||
LocalRoute,
|
||||
SerializableRoute,
|
||||
Attribute,
|
||||
EditFormRoute,
|
||||
AttributeRoutingConfig,
|
||||
} from "@calcom/app-store/routing-forms/types/types";
|
||||
import type { zodRoutes } from "@calcom/app-store/routing-forms/zod";
|
||||
import { RouteActionType } from "@calcom/app-store/routing-forms/zod";
|
||||
import { useOrgBranding } from "@calcom/features/ee/organizations/context/provider";
|
||||
import { areTheySiblingEntities } from "@calcom/lib/entityPermissionUtils.shared";
|
||||
import type { EventTypesByViewer } from "@calcom/lib/event-types/getEventTypesByViewer";
|
||||
@@ -29,39 +59,9 @@ import { SelectField } from "@calcom/ui/components/form";
|
||||
import { Switch } from "@calcom/ui/components/form";
|
||||
import type { IconName } from "@calcom/ui/components/icon";
|
||||
import { Icon } from "@calcom/ui/components/icon";
|
||||
import type { getServerSidePropsForSingleFormView as getServerSideProps } from "@calcom/web/lib/apps/routing-forms/[...pages]/getServerSidePropsSingleForm";
|
||||
|
||||
import { routingFormAppComponents } from "../../appComponents";
|
||||
import DynamicAppComponent from "../../components/DynamicAppComponent";
|
||||
import SingleForm from "../../components/SingleForm";
|
||||
import { EmptyState } from "../../components/_components/EmptyState";
|
||||
import { RoutingSkeleton } from "../../components/_components/RoutingSkeleton";
|
||||
import type { getServerSidePropsForSingleFormView as getServerSideProps } from "../../components/getServerSidePropsSingleForm";
|
||||
import {
|
||||
withRaqbSettingsAndWidgets,
|
||||
ConfigFor,
|
||||
} from "../../components/react-awesome-query-builder/config/uiConfig";
|
||||
import { RoutingPages } from "../../lib/RoutingPages";
|
||||
import { createFallbackRoute } from "../../lib/createFallbackRoute";
|
||||
import getEventTypeAppMetadata from "../../lib/getEventTypeAppMetadata";
|
||||
import {
|
||||
getQueryBuilderConfigForFormFields,
|
||||
getQueryBuilderConfigForAttributes,
|
||||
type FormFieldsQueryBuilderConfigWithRaqbFields,
|
||||
type AttributesQueryBuilderConfigWithRaqbFields,
|
||||
isDynamicOperandField,
|
||||
} from "../../lib/getQueryBuilderConfig";
|
||||
import isRouter from "../../lib/isRouter";
|
||||
import type { RoutingFormWithResponseCount } from "../../types/types";
|
||||
import type {
|
||||
GlobalRoute,
|
||||
LocalRoute,
|
||||
SerializableRoute,
|
||||
Attribute,
|
||||
EditFormRoute,
|
||||
AttributeRoutingConfig,
|
||||
} from "../../types/types";
|
||||
import type { zodRoutes } from "../../zod";
|
||||
import { RouteActionType } from "../../zod";
|
||||
import SingleForm from "@components/apps/routing-forms/SingleForm";
|
||||
|
||||
type Form = inferSSRProps<typeof getServerSideProps>["form"];
|
||||
|
||||
+9
-10
@@ -6,7 +6,15 @@ import { useEffect, useRef, useState } from "react";
|
||||
import { Toaster } from "sonner";
|
||||
import { v4 as uuidv4 } from "uuid";
|
||||
|
||||
import FormInputFields from "@calcom/app-store/routing-forms/components/FormInputFields";
|
||||
import { getAbsoluteEventTypeRedirectUrlWithEmbedSupport } from "@calcom/app-store/routing-forms/getEventTypeRedirectUrl";
|
||||
import getFieldIdentifier from "@calcom/app-store/routing-forms/lib/getFieldIdentifier";
|
||||
import { findMatchingRoute } from "@calcom/app-store/routing-forms/lib/processRoute";
|
||||
import { substituteVariables } from "@calcom/app-store/routing-forms/lib/substituteVariables";
|
||||
import { getFieldResponseForJsonLogic } from "@calcom/app-store/routing-forms/lib/transformResponse";
|
||||
import type { NonRouterRoute, FormResponse } from "@calcom/app-store/routing-forms/types/types";
|
||||
import { sdkActionManager, useIsEmbed } from "@calcom/embed-core/embed-iframe";
|
||||
import { getUrlSearchParamsToForward } from "@calcom/features/routing-forms/lib/getUrlSearchParamsToForward";
|
||||
import useGetBrandingColours from "@calcom/lib/getBrandColours";
|
||||
import { useCompatSearchParams } from "@calcom/lib/hooks/useCompatSearchParams";
|
||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||
@@ -18,16 +26,7 @@ import classNames from "@calcom/ui/classNames";
|
||||
import { Button } from "@calcom/ui/components/button";
|
||||
import { showToast } from "@calcom/ui/components/toast";
|
||||
import { useCalcomTheme } from "@calcom/ui/styles";
|
||||
|
||||
import FormInputFields from "../../components/FormInputFields";
|
||||
import { getAbsoluteEventTypeRedirectUrlWithEmbedSupport } from "../../getEventTypeRedirectUrl";
|
||||
import getFieldIdentifier from "../../lib/getFieldIdentifier";
|
||||
import { findMatchingRoute } from "../../lib/processRoute";
|
||||
import { substituteVariables } from "../../lib/substituteVariables";
|
||||
import { getFieldResponseForJsonLogic } from "../../lib/transformResponse";
|
||||
import type { NonRouterRoute, FormResponse } from "../../types/types";
|
||||
import type { getServerSideProps } from "./getServerSideProps";
|
||||
import { getUrlSearchParamsToForward } from "./getUrlSearchParamsToForward";
|
||||
import type { getServerSideProps } from "@calcom/web/lib/apps/routing-forms/[...pages]/getServerSidePropsRoutingLink";
|
||||
|
||||
type Props = inferSSRProps<typeof getServerSideProps>;
|
||||
const useBrandColors = ({
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
export const routingFormsComponents = {
|
||||
"form-edit": () => import("./FormEdit").then((mod) => mod.default),
|
||||
"route-builder": () => import("./RouteBuilder").then((mod) => mod.default),
|
||||
"routing-link": () => import("./RoutingLink").then((mod) => mod.default),
|
||||
"incomplete-booking": () => import("./IncompleteBooking").then((mod) => mod.default),
|
||||
};
|
||||
@@ -3,12 +3,12 @@ import type { PageProps as ServerPageProps } from "app/_types";
|
||||
import { _generateMetadata } from "app/_utils";
|
||||
import { cookies, headers } from "next/headers";
|
||||
|
||||
import { routingFormsComponents } from "@calcom/app-store/routing-forms/pages/app-routing.client-config";
|
||||
import type { routingServerSidePropsConfig } from "@calcom/app-store/routing-forms/pages/app-routing.server-config";
|
||||
|
||||
import type { routingServerSidePropsConfig } from "@lib/apps/routing-forms/[...pages]/app-routing.server-config";
|
||||
import { getServerSideProps } from "@lib/apps/routing-forms/[...pages]/getServerSideProps";
|
||||
import { buildLegacyCtx } from "@lib/buildLegacyCtx";
|
||||
|
||||
import { routingFormsComponents } from "./app-routing.client-config";
|
||||
|
||||
const normalizePages = (pages: string[] | string | undefined) => {
|
||||
const normalizedPages = Array.isArray(pages) ? pages : pages?.split("/") ?? [];
|
||||
return normalizedPages[0];
|
||||
|
||||
+11
-5
@@ -4,6 +4,8 @@ import { useAutoAnimate } from "@formkit/auto-animate/react";
|
||||
import { useEffect, useState } from "react";
|
||||
import { useFormContext } from "react-hook-form";
|
||||
|
||||
import { isFallbackRoute } from "@calcom/app-store/routing-forms/lib/isFallbackRoute";
|
||||
import type { RoutingFormWithResponseCount } from "@calcom/app-store/routing-forms/types/types";
|
||||
import LicenseRequired from "@calcom/features/ee/common/components/LicenseRequired";
|
||||
import SkeletonLoaderTeamList from "@calcom/features/ee/teams/components/SkeletonloaderTeamList";
|
||||
import { CreateButtonWithTeamsList } from "@calcom/features/ee/teams/components/createButton/CreateButtonWithTeamsList";
|
||||
@@ -25,11 +27,15 @@ import { EmptyScreen } from "@calcom/ui/components/empty-screen";
|
||||
import { Icon } from "@calcom/ui/components/icon";
|
||||
import { List, ListLinkItem } from "@calcom/ui/components/list";
|
||||
import { Tooltip } from "@calcom/ui/components/tooltip";
|
||||
|
||||
import type { SetNewFormDialogState, NewFormDialogState } from "../../components/FormActions";
|
||||
import { FormAction, FormActionsDropdown, FormActionsProvider } from "../../components/FormActions";
|
||||
import { isFallbackRoute } from "../../lib/isFallbackRoute";
|
||||
import type { RoutingFormWithResponseCount } from "../../types/types";
|
||||
import type {
|
||||
SetNewFormDialogState,
|
||||
NewFormDialogState,
|
||||
} from "@calcom/web/components/apps/routing-forms/FormActions";
|
||||
import {
|
||||
FormAction,
|
||||
FormActionsDropdown,
|
||||
FormActionsProvider,
|
||||
} from "@calcom/web/components/apps/routing-forms/FormActions";
|
||||
|
||||
function NewFormButton({ setNewFormDialogState }: { setNewFormDialogState: SetNewFormDialogState }) {
|
||||
const { t } = useLocale();
|
||||
@@ -1,6 +1,6 @@
|
||||
import { _generateMetadata } from "app/_utils";
|
||||
|
||||
import Forms from "@calcom/app-store/routing-forms/pages/forms/[...appPages]";
|
||||
import Forms from "./Forms";
|
||||
|
||||
export const generateMetadata = async ({ params }: { params: Promise<{ pages: string[] }> }) => {
|
||||
const pages = (await params).pages;
|
||||
|
||||
+6
-11
@@ -10,6 +10,7 @@ import dayjs from "@calcom/dayjs";
|
||||
import { sdkActionManager, useIsEmbed } from "@calcom/embed-core/embed-iframe";
|
||||
import { PayIcon } from "@calcom/features/bookings/components/event-meta/PayIcon";
|
||||
import { Price } from "@calcom/features/bookings/components/event-meta/Price";
|
||||
import type { PaymentPageProps } from "@calcom/features/ee/payments/pages/payment";
|
||||
import { APP_NAME, WEBSITE_URL } from "@calcom/lib/constants";
|
||||
import { getPaymentAppData } from "@calcom/lib/getPaymentAppData";
|
||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||
@@ -18,24 +19,20 @@ import { getIs24hClockFromLocalStorage, isBrowserLocale24h } from "@calcom/lib/t
|
||||
import { CURRENT_TIMEZONE } from "@calcom/lib/timezoneConstants";
|
||||
import { localStorage } from "@calcom/lib/webstorage";
|
||||
|
||||
import type { PaymentPageProps } from "../pages/payment";
|
||||
|
||||
const StripePaymentComponent = dynamic(() => import("./Payment"), {
|
||||
const StripePaymentComponent = dynamic(() => import("@calcom/features/ee/payments/components/Payment"), {
|
||||
ssr: false,
|
||||
});
|
||||
|
||||
const PaypalPaymentComponent = dynamic(
|
||||
() =>
|
||||
import("@calcom/app-store/paypal/components/PaypalPaymentComponent").then(
|
||||
(m) => m.PaypalPaymentComponent
|
||||
),
|
||||
import("@calcom/web/components/apps/paypal/PaypalPaymentComponent").then((m) => m.PaypalPaymentComponent),
|
||||
{
|
||||
ssr: false,
|
||||
}
|
||||
);
|
||||
|
||||
const AlbyPaymentComponent = dynamic(
|
||||
() => import("@calcom/app-store/alby/components/AlbyPaymentComponent").then((m) => m.AlbyPaymentComponent),
|
||||
() => import("@calcom/web/components/apps/alby/AlbyPaymentComponent").then((m) => m.AlbyPaymentComponent),
|
||||
{
|
||||
ssr: false,
|
||||
}
|
||||
@@ -43,9 +40,7 @@ const AlbyPaymentComponent = dynamic(
|
||||
|
||||
const HitpayPaymentComponent = dynamic(
|
||||
() =>
|
||||
import("@calcom/app-store/hitpay/components/HitpayPaymentComponent").then(
|
||||
(m) => m.HitpayPaymentComponent
|
||||
),
|
||||
import("@calcom/web/components/apps/hitpay/HitpayPaymentComponent").then((m) => m.HitpayPaymentComponent),
|
||||
{
|
||||
ssr: false,
|
||||
}
|
||||
@@ -53,7 +48,7 @@ const HitpayPaymentComponent = dynamic(
|
||||
|
||||
const BtcpayPaymentComponent = dynamic(
|
||||
() =>
|
||||
import("@calcom/app-store/btcpayserver/components/BtcpayPaymentComponent").then(
|
||||
import("@calcom/web/components/apps/btcpayserver/BtcpayPaymentComponent").then(
|
||||
(m) => m.BtcpayPaymentComponent
|
||||
),
|
||||
{
|
||||
@@ -3,12 +3,13 @@ import type { PageProps } from "app/_types";
|
||||
import { _generateMetadata } from "app/_utils";
|
||||
import { cookies, headers } from "next/headers";
|
||||
|
||||
import PaymentPage from "@calcom/features/ee/payments/components/PaymentPage";
|
||||
import { getServerSideProps, type PaymentPageProps } from "@calcom/features/ee/payments/pages/payment";
|
||||
import { APP_NAME } from "@calcom/lib/constants";
|
||||
|
||||
import { buildLegacyCtx } from "@lib/buildLegacyCtx";
|
||||
|
||||
import PaymentPage from "./PaymentPage";
|
||||
|
||||
export const generateMetadata = async ({ params, searchParams }: PageProps) => {
|
||||
const props = await getData(
|
||||
buildLegacyCtx(await headers(), await cookies(), await params, await searchParams)
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
import dynamic from "next/dynamic";
|
||||
|
||||
import { DynamicComponent } from "@calcom/app-store/_components/DynamicComponent";
|
||||
|
||||
export const AppSetupMap = {
|
||||
alby: dynamic(() => import("@calcom/web/components/apps/alby/Setup")),
|
||||
"apple-calendar": dynamic(() => import("@calcom/web/components/apps/applecalendar/Setup")),
|
||||
exchange: dynamic(() => import("@calcom/web/components/apps/exchangecalendar/Setup")),
|
||||
"exchange2013-calendar": dynamic(() => import("@calcom/web/components/apps/exchange2013calendar/Setup")),
|
||||
"exchange2016-calendar": dynamic(() => import("@calcom/web/components/apps/exchange2016calendar/Setup")),
|
||||
"caldav-calendar": dynamic(() => import("@calcom/web/components/apps/caldavcalendar/Setup")),
|
||||
"ics-feed": dynamic(() => import("@calcom/web/components/apps/ics-feedcalendar/Setup")),
|
||||
zapier: dynamic(() => import("@calcom/web/components/apps/zapier/Setup")),
|
||||
make: dynamic(() => import("@calcom/web/components/apps/make/Setup")),
|
||||
sendgrid: dynamic(() => import("@calcom/web/components/apps/sendgrid/Setup")),
|
||||
stripe: dynamic(() => import("@calcom/web/components/apps/stripepayment/Setup")),
|
||||
paypal: dynamic(() => import("@calcom/web/components/apps/paypal/Setup")),
|
||||
hitpay: dynamic(() => import("@calcom/web/components/apps/hitpay/Setup")),
|
||||
btcpayserver: dynamic(() => import("@calcom/web/components/apps/btcpayserver/Setup")),
|
||||
};
|
||||
|
||||
export const AppSetupPage = (props: { slug: string }) => {
|
||||
return <DynamicComponent<typeof AppSetupMap> componentMap={AppSetupMap} {...props} />;
|
||||
};
|
||||
|
||||
export default AppSetupPage;
|
||||
+3
-10
@@ -5,22 +5,15 @@ import { useState, useCallback, useEffect } from "react";
|
||||
import { Toaster } from "sonner";
|
||||
|
||||
import AppNotInstalledMessage from "@calcom/app-store/_components/AppNotInstalledMessage";
|
||||
import { albyCredentialKeysSchema } from "@calcom/app-store/alby/lib/albyCredentialKeysSchema";
|
||||
import type { IAlbySetupProps } from "@calcom/app-store/alby/pages/setup/_getServerSideProps";
|
||||
import { useCompatSearchParams } from "@calcom/lib/hooks/useCompatSearchParams";
|
||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||
import { trpc } from "@calcom/trpc";
|
||||
import { showToast } from "@calcom/ui/components/toast";
|
||||
import { Badge } from "@calcom/ui/components/badge";
|
||||
import { Button } from "@calcom/ui/components/button";
|
||||
import { Icon } from "@calcom/ui/components/icon";
|
||||
|
||||
import { albyCredentialKeysSchema } from "../../lib/albyCredentialKeysSchema";
|
||||
|
||||
export interface IAlbySetupProps {
|
||||
email: string | null;
|
||||
lightningAddress: string | null;
|
||||
clientId: string;
|
||||
clientSecret: string;
|
||||
}
|
||||
import { showToast } from "@calcom/ui/components/toast";
|
||||
|
||||
export default function AlbySetup(props: IAlbySetupProps) {
|
||||
const params = useCompatSearchParams();
|
||||
+2
-2
@@ -5,10 +5,10 @@ import { Toaster } from "sonner";
|
||||
|
||||
import { APP_NAME } from "@calcom/lib/constants";
|
||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||
import { PasswordField } from "@calcom/ui/components/form";
|
||||
import { TextField } from "@calcom/ui/components/form";
|
||||
import { Alert } from "@calcom/ui/components/alert";
|
||||
import { Button } from "@calcom/ui/components/button";
|
||||
import { PasswordField } from "@calcom/ui/components/form";
|
||||
import { TextField } from "@calcom/ui/components/form";
|
||||
import { Form } from "@calcom/ui/components/form";
|
||||
|
||||
export default function AppleCalendarSetup() {
|
||||
+352
-354
@@ -1,354 +1,352 @@
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import { useSession } from "next-auth/react";
|
||||
import Link from "next/link";
|
||||
import { useRouter } from "next/navigation";
|
||||
import { useState, useEffect } from "react";
|
||||
import { useForm } from "react-hook-form";
|
||||
import { Toaster } from "sonner";
|
||||
import { z } from "zod";
|
||||
|
||||
import AppNotInstalledMessage from "@calcom/app-store/_components/AppNotInstalledMessage";
|
||||
import { WEBAPP_URL } from "@calcom/lib/constants";
|
||||
import { useCompatSearchParams } from "@calcom/lib/hooks/useCompatSearchParams";
|
||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||
import { trpc } from "@calcom/trpc";
|
||||
import { Button } from "@calcom/ui/components/button";
|
||||
import { Icon } from "@calcom/ui/components/icon";
|
||||
import { showToast } from "@calcom/ui/components/toast";
|
||||
|
||||
import KeyField from "../../components/KeyInput";
|
||||
import { btcpayCredentialKeysSchema } from "../../lib/btcpayCredentialKeysSchema";
|
||||
|
||||
export type IBTCPaySetupProps = z.infer<typeof btcpayCredentialKeysSchema>;
|
||||
|
||||
export default function BTCPaySetup(props: IBTCPaySetupProps) {
|
||||
const params = useCompatSearchParams();
|
||||
if (params?.get("callback") === "true") {
|
||||
return <BTCPaySetupCallback />;
|
||||
}
|
||||
return <BTCPaySetupPage {...props} />;
|
||||
}
|
||||
|
||||
enum BTCPayOAuthError {
|
||||
Declined = "declined",
|
||||
Unknown = "unknown",
|
||||
}
|
||||
|
||||
function BTCPaySetupCallback() {
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
const searchParams = useCompatSearchParams();
|
||||
|
||||
useEffect(() => {
|
||||
if (!searchParams) {
|
||||
return;
|
||||
}
|
||||
if (!window.opener) {
|
||||
setError("Something went wrong. Opener not available. Please contact support");
|
||||
return;
|
||||
}
|
||||
const code = searchParams?.get("code");
|
||||
const error = searchParams?.get("error");
|
||||
|
||||
if (!code) {
|
||||
setError(BTCPayOAuthError.Declined);
|
||||
}
|
||||
if (error) {
|
||||
setError(error);
|
||||
return;
|
||||
}
|
||||
|
||||
window.opener.postMessage({
|
||||
type: "btcpayserver:oauth:success",
|
||||
payload: { code },
|
||||
});
|
||||
window.close();
|
||||
}, [searchParams]);
|
||||
|
||||
return (
|
||||
<div>
|
||||
{error && <p>Authorization failed: {error}</p>}
|
||||
{!error && <p>Connecting...</p>}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function BTCPaySetupPage(props: IBTCPaySetupProps) {
|
||||
const router = useRouter();
|
||||
const { t } = useLocale();
|
||||
const session = useSession();
|
||||
const [loading, setLoading] = useState<boolean>(false);
|
||||
const [validating, setValidating] = useState<boolean>(false);
|
||||
const [updatable, setUpdatable] = useState<boolean>(false);
|
||||
const [keyData, setKeyData] = useState<
|
||||
| {
|
||||
storeId: string;
|
||||
serverUrl: string;
|
||||
apiKey: string;
|
||||
webhookSecret: string;
|
||||
}
|
||||
| undefined
|
||||
>();
|
||||
const settingsSchema = z.object({
|
||||
storeId: z.string().trim(),
|
||||
serverUrl: z.string().trim(),
|
||||
apiKey: z.string().trim(),
|
||||
webhookSecret: z.string().optional(),
|
||||
});
|
||||
const integrations = trpc.viewer.apps.integrations.useQuery({ variant: "payment", appId: "btcpayserver" });
|
||||
const [btcPayPaymentAppCredentials] = integrations.data?.items || [];
|
||||
const [credentialId] = btcPayPaymentAppCredentials?.userCredentialIds || [-1];
|
||||
const showContent = !!integrations.data && integrations.isSuccess && !!credentialId;
|
||||
|
||||
const saveKeysMutation = trpc.viewer.apps.updateAppCredentials.useMutation({
|
||||
onSuccess: () => {
|
||||
showToast(t("keys_have_been_saved"), "success");
|
||||
router.push("/event-types");
|
||||
},
|
||||
onError: (error) => {
|
||||
showToast(error.message, "error");
|
||||
},
|
||||
});
|
||||
const deleteMutation = trpc.viewer.credentials.delete.useMutation({
|
||||
onSuccess: () => {
|
||||
router.push("/apps/btcpayserver");
|
||||
},
|
||||
onError: () => {
|
||||
showToast(t("error_removing_app"), "error");
|
||||
},
|
||||
});
|
||||
|
||||
const {
|
||||
register,
|
||||
handleSubmit,
|
||||
formState: { errors },
|
||||
watch,
|
||||
reset,
|
||||
} = useForm<z.infer<typeof settingsSchema>>({
|
||||
reValidateMode: "onChange",
|
||||
resolver: zodResolver(settingsSchema),
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
const _keyData = {
|
||||
storeId: props?.storeId || "",
|
||||
serverUrl: props?.serverUrl || "",
|
||||
apiKey: props?.apiKey || "",
|
||||
webhookSecret: props?.webhookSecret || "",
|
||||
};
|
||||
setKeyData(_keyData);
|
||||
}, [props]);
|
||||
|
||||
useEffect(() => {
|
||||
const subscription = watch((value) => {
|
||||
const { serverUrl, storeId, apiKey, webhookSecret } = value;
|
||||
if (
|
||||
serverUrl &&
|
||||
storeId &&
|
||||
apiKey &&
|
||||
(keyData?.serverUrl !== serverUrl || keyData?.storeId !== storeId || keyData?.apiKey !== apiKey)
|
||||
) {
|
||||
setUpdatable(true);
|
||||
} else {
|
||||
setUpdatable(false);
|
||||
}
|
||||
});
|
||||
return () => subscription.unsubscribe();
|
||||
}, [watch, keyData]);
|
||||
|
||||
const configureBTCPayWebhook = async (data: z.infer<typeof settingsSchema>) => {
|
||||
setValidating(true);
|
||||
const specificEvents = ["InvoiceSettled", "InvoiceProcessing"];
|
||||
const serverUrl = data.serverUrl.endsWith("/") ? data.serverUrl.slice(0, -1) : data.serverUrl;
|
||||
const endpoint = `${serverUrl}/api/v1/stores/${data.storeId}/webhooks`;
|
||||
const webhookUrl = `${WEBAPP_URL}/api/integrations/btcpayserver/webhook`;
|
||||
const requestBody = {
|
||||
enabled: true,
|
||||
automaticRedelivery: false,
|
||||
url: webhookUrl,
|
||||
authorizedEvents: {
|
||||
everything: false,
|
||||
specificEvents: specificEvents,
|
||||
},
|
||||
secret: null,
|
||||
};
|
||||
|
||||
try {
|
||||
const response = await fetch(endpoint, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
Authorization: `token ${data.apiKey}`,
|
||||
},
|
||||
body: JSON.stringify(requestBody),
|
||||
});
|
||||
if (!response.ok) {
|
||||
const errorBody = await response.text();
|
||||
showToast(`Failed to configure webhook: ${errorBody}`, "error");
|
||||
return false;
|
||||
}
|
||||
const webhookResponse = await response.json();
|
||||
saveKeysMutation.mutate({
|
||||
credentialId,
|
||||
key: btcpayCredentialKeysSchema.parse({
|
||||
...data,
|
||||
webhookSecret: webhookResponse.secret,
|
||||
}),
|
||||
});
|
||||
return true;
|
||||
} catch (error) {
|
||||
if (error instanceof Error) {
|
||||
showToast(error.message || "Failed to configure BTCPay webhook", "error");
|
||||
} else {
|
||||
showToast("An unknown error occurred while configuring BTCPay webhook", "error");
|
||||
}
|
||||
return false;
|
||||
} finally {
|
||||
setValidating(false);
|
||||
}
|
||||
};
|
||||
|
||||
const onSubmit = handleSubmit(async (data) => {
|
||||
if (loading) return;
|
||||
setLoading(true);
|
||||
|
||||
try {
|
||||
const isValid = await configureBTCPayWebhook(data);
|
||||
if (!isValid) {
|
||||
setLoading(false);
|
||||
return;
|
||||
}
|
||||
} catch (error: unknown) {
|
||||
let message = "";
|
||||
if (error instanceof Error) {
|
||||
message = error.message;
|
||||
}
|
||||
showToast(message, "error");
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
});
|
||||
|
||||
const onCancel = () => {
|
||||
deleteMutation.mutate({ id: credentialId });
|
||||
};
|
||||
|
||||
const btcpayIcon = (
|
||||
<>
|
||||
<img className="h-5 w-5" src="/app-store/btcpayserver/btcpay.svg" alt="BTCPay Server Icon" />
|
||||
</>
|
||||
);
|
||||
|
||||
if (session.status === "loading") return <></>;
|
||||
|
||||
if (integrations.isPending) {
|
||||
return <div className="absolute z-50 flex h-screen w-full items-center bg-gray-200" />;
|
||||
}
|
||||
|
||||
const isNewCredential = !props.serverUrl && !props.storeId && !props.webhookSecret && !props.apiKey;
|
||||
const webhookUri = `${WEBAPP_URL}/api/integrations/btcpayserver/webhook`;
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="bg-default flex h-screen items-center justify-center">
|
||||
{showContent ? (
|
||||
<div className="flex w-full w-full max-w-[43em] flex-col items-center justify-center space-y-4 p-4 lg:space-y-5">
|
||||
<form className="w-full space-y-4" onSubmit={onSubmit}>
|
||||
<div className="bg-default border-subtle overflow-auto rounded border">
|
||||
<div className="border-subtle flex items-center justify-between border-b-[1px] p-4 md:p-5">
|
||||
<h2 className="text-2xl font-semibold">BTCPay Server Information</h2>
|
||||
</div>
|
||||
<div className="w-full space-y-4 p-4 md:p-5">
|
||||
<div className="w-full">
|
||||
<KeyField
|
||||
{...register("serverUrl", { required: true })}
|
||||
id="serverUrl"
|
||||
name="serverUrl"
|
||||
containerClassName="w-full"
|
||||
label="BTCPay Server Url"
|
||||
autoComplete="off"
|
||||
autoCorrect="off"
|
||||
defaultValue={keyData?.serverUrl || ""}
|
||||
/>
|
||||
{errors.serverUrl && (
|
||||
<p data-testid="required" className="py-2 text-xs text-red-500">
|
||||
{errors.serverUrl?.message}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="w-full">
|
||||
<KeyField
|
||||
{...register("storeId", { required: true })}
|
||||
id="storeId"
|
||||
name="storeId"
|
||||
containerClassName="w-full"
|
||||
label="BTCPay Store Id"
|
||||
autoComplete="off"
|
||||
autoCorrect="off"
|
||||
defaultValue={keyData?.storeId || ""}
|
||||
/>
|
||||
{errors.storeId && (
|
||||
<p data-testid="required" className="py-2 text-xs text-red-500">
|
||||
{errors.storeId?.message}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="w-full">
|
||||
<KeyField
|
||||
{...register("apiKey", { required: true })}
|
||||
id="apiKey"
|
||||
name="apiKey"
|
||||
containerClassName="w-full"
|
||||
label="API Key"
|
||||
autoComplete="off"
|
||||
autoCorrect="off"
|
||||
defaultValue={keyData?.apiKey || ""}
|
||||
/>
|
||||
{errors.apiKey && (
|
||||
<p data-testid="required" className="py-2 text-xs text-red-500">
|
||||
{errors.apiKey?.message}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex justify-end gap-4">
|
||||
{isNewCredential ? (
|
||||
<>
|
||||
<Button color="secondary" className="h-10" onClick={onCancel}>
|
||||
Cancel
|
||||
</Button>
|
||||
<Button
|
||||
className="h-10"
|
||||
color="primary"
|
||||
type="submit"
|
||||
disabled={loading || validating || !updatable}>
|
||||
{loading ? (
|
||||
<>
|
||||
<Icon name="loader" className="mr-2 animate-spin" />
|
||||
{t("connecting")}
|
||||
</>
|
||||
) : (
|
||||
t("connect")
|
||||
)}
|
||||
</Button>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<Link href="/apps/btcpayserver" className="inline-block">
|
||||
<Button color="secondary">Go to App Store</Button>
|
||||
</Link>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
) : (
|
||||
<AppNotInstalledMessage appName="btcpayserver" />
|
||||
)}
|
||||
<Toaster position="bottom-right" />
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import { useSession } from "next-auth/react";
|
||||
import Link from "next/link";
|
||||
import { useRouter } from "next/navigation";
|
||||
import { useState, useEffect } from "react";
|
||||
import { useForm } from "react-hook-form";
|
||||
import { Toaster } from "sonner";
|
||||
import { z } from "zod";
|
||||
|
||||
import AppNotInstalledMessage from "@calcom/app-store/_components/AppNotInstalledMessage";
|
||||
import KeyField from "@calcom/app-store/btcpayserver/components/KeyInput";
|
||||
import { btcpayCredentialKeysSchema } from "@calcom/app-store/btcpayserver/lib/btcpayCredentialKeysSchema";
|
||||
import type { IBTCPaySetupProps } from "@calcom/app-store/btcpayserver/pages/setup/_getServerSideProps";
|
||||
import { WEBAPP_URL } from "@calcom/lib/constants";
|
||||
import { useCompatSearchParams } from "@calcom/lib/hooks/useCompatSearchParams";
|
||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||
import { trpc } from "@calcom/trpc";
|
||||
import { Button } from "@calcom/ui/components/button";
|
||||
import { Icon } from "@calcom/ui/components/icon";
|
||||
import { showToast } from "@calcom/ui/components/toast";
|
||||
|
||||
export default function BTCPaySetup(props: IBTCPaySetupProps) {
|
||||
const params = useCompatSearchParams();
|
||||
if (params?.get("callback") === "true") {
|
||||
return <BTCPaySetupCallback />;
|
||||
}
|
||||
return <BTCPaySetupPage {...props} />;
|
||||
}
|
||||
|
||||
enum BTCPayOAuthError {
|
||||
Declined = "declined",
|
||||
Unknown = "unknown",
|
||||
}
|
||||
|
||||
function BTCPaySetupCallback() {
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
const searchParams = useCompatSearchParams();
|
||||
|
||||
useEffect(() => {
|
||||
if (!searchParams) {
|
||||
return;
|
||||
}
|
||||
if (!window.opener) {
|
||||
setError("Something went wrong. Opener not available. Please contact support");
|
||||
return;
|
||||
}
|
||||
const code = searchParams?.get("code");
|
||||
const error = searchParams?.get("error");
|
||||
|
||||
if (!code) {
|
||||
setError(BTCPayOAuthError.Declined);
|
||||
}
|
||||
if (error) {
|
||||
setError(error);
|
||||
return;
|
||||
}
|
||||
|
||||
window.opener.postMessage({
|
||||
type: "btcpayserver:oauth:success",
|
||||
payload: { code },
|
||||
});
|
||||
window.close();
|
||||
}, [searchParams]);
|
||||
|
||||
return (
|
||||
<div>
|
||||
{error && <p>Authorization failed: {error}</p>}
|
||||
{!error && <p>Connecting...</p>}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function BTCPaySetupPage(props: IBTCPaySetupProps) {
|
||||
const router = useRouter();
|
||||
const { t } = useLocale();
|
||||
const session = useSession();
|
||||
const [loading, setLoading] = useState<boolean>(false);
|
||||
const [validating, setValidating] = useState<boolean>(false);
|
||||
const [updatable, setUpdatable] = useState<boolean>(false);
|
||||
const [keyData, setKeyData] = useState<
|
||||
| {
|
||||
storeId: string;
|
||||
serverUrl: string;
|
||||
apiKey: string;
|
||||
webhookSecret: string;
|
||||
}
|
||||
| undefined
|
||||
>();
|
||||
const settingsSchema = z.object({
|
||||
storeId: z.string().trim(),
|
||||
serverUrl: z.string().trim(),
|
||||
apiKey: z.string().trim(),
|
||||
webhookSecret: z.string().optional(),
|
||||
});
|
||||
const integrations = trpc.viewer.apps.integrations.useQuery({ variant: "payment", appId: "btcpayserver" });
|
||||
const [btcPayPaymentAppCredentials] = integrations.data?.items || [];
|
||||
const [credentialId] = btcPayPaymentAppCredentials?.userCredentialIds || [-1];
|
||||
const showContent = !!integrations.data && integrations.isSuccess && !!credentialId;
|
||||
|
||||
const saveKeysMutation = trpc.viewer.apps.updateAppCredentials.useMutation({
|
||||
onSuccess: () => {
|
||||
showToast(t("keys_have_been_saved"), "success");
|
||||
router.push("/event-types");
|
||||
},
|
||||
onError: (error) => {
|
||||
showToast(error.message, "error");
|
||||
},
|
||||
});
|
||||
const deleteMutation = trpc.viewer.credentials.delete.useMutation({
|
||||
onSuccess: () => {
|
||||
router.push("/apps/btcpayserver");
|
||||
},
|
||||
onError: () => {
|
||||
showToast(t("error_removing_app"), "error");
|
||||
},
|
||||
});
|
||||
|
||||
const {
|
||||
register,
|
||||
handleSubmit,
|
||||
formState: { errors },
|
||||
watch,
|
||||
reset,
|
||||
} = useForm<z.infer<typeof settingsSchema>>({
|
||||
reValidateMode: "onChange",
|
||||
resolver: zodResolver(settingsSchema),
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
const _keyData = {
|
||||
storeId: props?.storeId || "",
|
||||
serverUrl: props?.serverUrl || "",
|
||||
apiKey: props?.apiKey || "",
|
||||
webhookSecret: props?.webhookSecret || "",
|
||||
};
|
||||
setKeyData(_keyData);
|
||||
}, [props]);
|
||||
|
||||
useEffect(() => {
|
||||
const subscription = watch((value) => {
|
||||
const { serverUrl, storeId, apiKey, webhookSecret } = value;
|
||||
if (
|
||||
serverUrl &&
|
||||
storeId &&
|
||||
apiKey &&
|
||||
(keyData?.serverUrl !== serverUrl || keyData?.storeId !== storeId || keyData?.apiKey !== apiKey)
|
||||
) {
|
||||
setUpdatable(true);
|
||||
} else {
|
||||
setUpdatable(false);
|
||||
}
|
||||
});
|
||||
return () => subscription.unsubscribe();
|
||||
}, [watch, keyData]);
|
||||
|
||||
const configureBTCPayWebhook = async (data: z.infer<typeof settingsSchema>) => {
|
||||
setValidating(true);
|
||||
const specificEvents = ["InvoiceSettled", "InvoiceProcessing"];
|
||||
const serverUrl = data.serverUrl.endsWith("/") ? data.serverUrl.slice(0, -1) : data.serverUrl;
|
||||
const endpoint = `${serverUrl}/api/v1/stores/${data.storeId}/webhooks`;
|
||||
const webhookUrl = `${WEBAPP_URL}/api/integrations/btcpayserver/webhook`;
|
||||
const requestBody = {
|
||||
enabled: true,
|
||||
automaticRedelivery: false,
|
||||
url: webhookUrl,
|
||||
authorizedEvents: {
|
||||
everything: false,
|
||||
specificEvents: specificEvents,
|
||||
},
|
||||
secret: null,
|
||||
};
|
||||
|
||||
try {
|
||||
const response = await fetch(endpoint, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
Authorization: `token ${data.apiKey}`,
|
||||
},
|
||||
body: JSON.stringify(requestBody),
|
||||
});
|
||||
if (!response.ok) {
|
||||
const errorBody = await response.text();
|
||||
showToast(`Failed to configure webhook: ${errorBody}`, "error");
|
||||
return false;
|
||||
}
|
||||
const webhookResponse = await response.json();
|
||||
saveKeysMutation.mutate({
|
||||
credentialId,
|
||||
key: btcpayCredentialKeysSchema.parse({
|
||||
...data,
|
||||
webhookSecret: webhookResponse.secret,
|
||||
}),
|
||||
});
|
||||
return true;
|
||||
} catch (error) {
|
||||
if (error instanceof Error) {
|
||||
showToast(error.message || "Failed to configure BTCPay webhook", "error");
|
||||
} else {
|
||||
showToast("An unknown error occurred while configuring BTCPay webhook", "error");
|
||||
}
|
||||
return false;
|
||||
} finally {
|
||||
setValidating(false);
|
||||
}
|
||||
};
|
||||
|
||||
const onSubmit = handleSubmit(async (data) => {
|
||||
if (loading) return;
|
||||
setLoading(true);
|
||||
|
||||
try {
|
||||
const isValid = await configureBTCPayWebhook(data);
|
||||
if (!isValid) {
|
||||
setLoading(false);
|
||||
return;
|
||||
}
|
||||
} catch (error: unknown) {
|
||||
let message = "";
|
||||
if (error instanceof Error) {
|
||||
message = error.message;
|
||||
}
|
||||
showToast(message, "error");
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
});
|
||||
|
||||
const onCancel = () => {
|
||||
deleteMutation.mutate({ id: credentialId });
|
||||
};
|
||||
|
||||
const btcpayIcon = (
|
||||
<>
|
||||
<img className="h-5 w-5" src="/app-store/btcpayserver/btcpay.svg" alt="BTCPay Server Icon" />
|
||||
</>
|
||||
);
|
||||
|
||||
if (session.status === "loading") return <></>;
|
||||
|
||||
if (integrations.isPending) {
|
||||
return <div className="absolute z-50 flex h-screen w-full items-center bg-gray-200" />;
|
||||
}
|
||||
|
||||
const isNewCredential = !props.serverUrl && !props.storeId && !props.webhookSecret && !props.apiKey;
|
||||
const webhookUri = `${WEBAPP_URL}/api/integrations/btcpayserver/webhook`;
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="bg-default flex h-screen items-center justify-center">
|
||||
{showContent ? (
|
||||
<div className="flex w-full w-full max-w-[43em] flex-col items-center justify-center space-y-4 p-4 lg:space-y-5">
|
||||
<form className="w-full space-y-4" onSubmit={onSubmit}>
|
||||
<div className="bg-default border-subtle overflow-auto rounded border">
|
||||
<div className="border-subtle flex items-center justify-between border-b-[1px] p-4 md:p-5">
|
||||
<h2 className="text-2xl font-semibold">BTCPay Server Information</h2>
|
||||
</div>
|
||||
<div className="w-full space-y-4 p-4 md:p-5">
|
||||
<div className="w-full">
|
||||
<KeyField
|
||||
{...register("serverUrl", { required: true })}
|
||||
id="serverUrl"
|
||||
name="serverUrl"
|
||||
containerClassName="w-full"
|
||||
label="BTCPay Server Url"
|
||||
autoComplete="off"
|
||||
autoCorrect="off"
|
||||
defaultValue={keyData?.serverUrl || ""}
|
||||
/>
|
||||
{errors.serverUrl && (
|
||||
<p data-testid="required" className="py-2 text-xs text-red-500">
|
||||
{errors.serverUrl?.message}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="w-full">
|
||||
<KeyField
|
||||
{...register("storeId", { required: true })}
|
||||
id="storeId"
|
||||
name="storeId"
|
||||
containerClassName="w-full"
|
||||
label="BTCPay Store Id"
|
||||
autoComplete="off"
|
||||
autoCorrect="off"
|
||||
defaultValue={keyData?.storeId || ""}
|
||||
/>
|
||||
{errors.storeId && (
|
||||
<p data-testid="required" className="py-2 text-xs text-red-500">
|
||||
{errors.storeId?.message}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="w-full">
|
||||
<KeyField
|
||||
{...register("apiKey", { required: true })}
|
||||
id="apiKey"
|
||||
name="apiKey"
|
||||
containerClassName="w-full"
|
||||
label="API Key"
|
||||
autoComplete="off"
|
||||
autoCorrect="off"
|
||||
defaultValue={keyData?.apiKey || ""}
|
||||
/>
|
||||
{errors.apiKey && (
|
||||
<p data-testid="required" className="py-2 text-xs text-red-500">
|
||||
{errors.apiKey?.message}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex justify-end gap-4">
|
||||
{isNewCredential ? (
|
||||
<>
|
||||
<Button color="secondary" className="h-10" onClick={onCancel}>
|
||||
Cancel
|
||||
</Button>
|
||||
<Button
|
||||
className="h-10"
|
||||
color="primary"
|
||||
type="submit"
|
||||
disabled={loading || validating || !updatable}>
|
||||
{loading ? (
|
||||
<>
|
||||
<Icon name="loader" className="mr-2 animate-spin" />
|
||||
{t("connecting")}
|
||||
</>
|
||||
) : (
|
||||
t("connect")
|
||||
)}
|
||||
</Button>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<Link href="/apps/btcpayserver" className="inline-block">
|
||||
<Button color="secondary">Go to App Store</Button>
|
||||
</Link>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
) : (
|
||||
<AppNotInstalledMessage appName="btcpayserver" />
|
||||
)}
|
||||
<Toaster position="bottom-right" />
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
+2
-3
@@ -5,18 +5,17 @@ import { Controller, useForm } from "react-hook-form";
|
||||
import { Toaster } from "sonner";
|
||||
import z from "zod";
|
||||
|
||||
import { ExchangeAuthentication, ExchangeVersion } from "@calcom/app-store/exchangecalendar/enums";
|
||||
import { emailSchema } from "@calcom/lib/emailSchema";
|
||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||
import { EmailField } from "@calcom/ui/components/form";
|
||||
import { Alert } from "@calcom/ui/components/alert";
|
||||
import { Button } from "@calcom/ui/components/button";
|
||||
import { EmailField } from "@calcom/ui/components/form";
|
||||
import { Form } from "@calcom/ui/components/form";
|
||||
import { PasswordField } from "@calcom/ui/components/form";
|
||||
import { TextField } from "@calcom/ui/components/form";
|
||||
import { SelectField } from "@calcom/ui/components/form";
|
||||
|
||||
import { ExchangeAuthentication, ExchangeVersion } from "../../enums";
|
||||
|
||||
interface IFormData {
|
||||
url: string;
|
||||
username: string;
|
||||
+3
-1
@@ -1,9 +1,11 @@
|
||||
"use client";
|
||||
|
||||
import { useRouter } from "next/navigation";
|
||||
import qs from "qs";
|
||||
import { useEffect, useRef } from "react";
|
||||
import { z } from "zod";
|
||||
|
||||
import { useHitPayDropIn } from "./HitPayDropIn";
|
||||
import { useHitPayDropIn } from "@calcom/app-store/hitpay/components/HitPayDropIn";
|
||||
|
||||
const PaymentHitpayDataSchema = z.object({
|
||||
id: z.string(),
|
||||
+3
-5
@@ -8,6 +8,9 @@ import { Toaster } from "sonner";
|
||||
import { z } from "zod";
|
||||
|
||||
import AppNotInstalledMessage from "@calcom/app-store/_components/AppNotInstalledMessage";
|
||||
import KeyField from "@calcom/app-store/hitpay/components/KeyInput";
|
||||
import { hitpayCredentialKeysSchema } from "@calcom/app-store/hitpay/lib/hitpayCredentialKeysSchema";
|
||||
import type { IHitPaySetupProps } from "@calcom/app-store/hitpay/pages/setup/_getServerSideProps";
|
||||
import { useCompatSearchParams } from "@calcom/lib/hooks/useCompatSearchParams";
|
||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||
import { trpc } from "@calcom/trpc";
|
||||
@@ -16,11 +19,6 @@ import { Switch } from "@calcom/ui/components/form";
|
||||
import { Icon } from "@calcom/ui/components/icon";
|
||||
import { showToast } from "@calcom/ui/components/toast";
|
||||
|
||||
import KeyField from "../../components/KeyInput";
|
||||
import { hitpayCredentialKeysSchema } from "../../lib/hitpayCredentialKeysSchema";
|
||||
|
||||
export type IHitPaySetupProps = z.infer<typeof hitpayCredentialKeysSchema>;
|
||||
|
||||
export default function HitPaySetup(props: IHitPaySetupProps) {
|
||||
const params = useCompatSearchParams();
|
||||
if (params?.get("callback") === "true") {
|
||||
+1
-2
@@ -4,6 +4,7 @@ import { useState } from "react";
|
||||
import { Toaster } from "sonner";
|
||||
|
||||
import AppNotInstalledMessage from "@calcom/app-store/_components/AppNotInstalledMessage";
|
||||
import type { getServerSideProps } from "@calcom/app-store/make/pages/setup/_getServerSideProps";
|
||||
import ServerTrans from "@calcom/lib/components/ServerTrans";
|
||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||
import { trpc } from "@calcom/trpc/react";
|
||||
@@ -12,8 +13,6 @@ import { Icon } from "@calcom/ui/components/icon";
|
||||
import { showToast } from "@calcom/ui/components/toast";
|
||||
import { Tooltip } from "@calcom/ui/components/tooltip";
|
||||
|
||||
import type { getServerSideProps } from "./_getServerSideProps";
|
||||
|
||||
const MAKE = "make";
|
||||
|
||||
export default function MakeSetup({ inviteLink }: InferGetServerSidePropsType<typeof getServerSideProps>) {
|
||||
+2
@@ -1,3 +1,5 @@
|
||||
"use client";
|
||||
|
||||
import Link from "next/link";
|
||||
import z from "zod";
|
||||
|
||||
+1
-2
@@ -3,6 +3,7 @@ import { createContext, forwardRef, useContext, useState } from "react";
|
||||
import { useForm } from "react-hook-form";
|
||||
import { v4 as uuidv4 } from "uuid";
|
||||
|
||||
import getFieldIdentifier from "@calcom/app-store/routing-forms/lib/getFieldIdentifier";
|
||||
import { Dialog } from "@calcom/features/components/controlled-dialog";
|
||||
import { dataTableQueryParamsSerializer } from "@calcom/features/data-table/lib/serializers";
|
||||
import { ColumnFilterType } from "@calcom/features/data-table/lib/types";
|
||||
@@ -34,8 +35,6 @@ import { Form } from "@calcom/ui/components/form";
|
||||
import { Switch } from "@calcom/ui/components/form";
|
||||
import { showToast } from "@calcom/ui/components/toast";
|
||||
|
||||
import getFieldIdentifier from "../lib/getFieldIdentifier";
|
||||
|
||||
type FormField = {
|
||||
identifier?: string;
|
||||
id: string;
|
||||
+2
-3
@@ -5,6 +5,8 @@ import { useRef } from "react";
|
||||
import { Controller } from "react-hook-form";
|
||||
import type { UseFormReturn } from "react-hook-form";
|
||||
|
||||
import { TeamMemberSelect } from "@calcom/app-store/routing-forms/components/_components/TeamMemberSelect";
|
||||
import type { RoutingFormWithResponseCount } from "@calcom/app-store/routing-forms/types/types";
|
||||
import { IS_CALCOM } from "@calcom/lib/constants";
|
||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||
import useMeQuery from "@calcom/trpc/react/hooks/useMeQuery";
|
||||
@@ -13,9 +15,6 @@ import { Button } from "@calcom/ui/components/button";
|
||||
import { Switch, TextAreaField, TextField } from "@calcom/ui/components/form";
|
||||
import { Sheet, SheetContent, SheetHeader, SheetTitle, SheetFooter } from "@calcom/ui/components/sheet";
|
||||
|
||||
import type { RoutingFormWithResponseCount } from "../../types/types";
|
||||
import { TeamMemberSelect } from "./TeamMemberSelect";
|
||||
|
||||
type FormSettingsSlideoverProps = {
|
||||
form: RoutingFormWithResponseCount;
|
||||
hookForm: UseFormReturn<RoutingFormWithResponseCount>;
|
||||
+1
-1
@@ -12,7 +12,7 @@ import { ToggleGroup } from "@calcom/ui/components/form";
|
||||
import { Icon } from "@calcom/ui/components/icon";
|
||||
import { Tooltip } from "@calcom/ui/components/tooltip";
|
||||
|
||||
import { FormAction, FormActionsDropdown } from "../FormActions";
|
||||
import { FormAction, FormActionsDropdown } from "./FormActions";
|
||||
import { FormSettingsSlideover } from "./FormSettingsSlideover";
|
||||
|
||||
// Toggle group doesnt support HREF navigation, so we need to use this hook to handle navigation
|
||||
+23
-5
@@ -3,21 +3,39 @@
|
||||
import { AnimatePresence, motion } from "framer-motion";
|
||||
import { useEffect, useState } from "react";
|
||||
import { useFormContext } from "react-hook-form";
|
||||
import type { UseFormReturn } from "react-hook-form";
|
||||
|
||||
import { InfoLostWarningDialog } from "@calcom/app-store/routing-forms/components/InfoLostWarningDialog";
|
||||
import type { RoutingFormWithResponseCount } from "@calcom/app-store/routing-forms/types/types";
|
||||
import LicenseRequired from "@calcom/features/ee/common/components/LicenseRequired";
|
||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||
import { trpc } from "@calcom/trpc/react";
|
||||
import type { inferSSRProps } from "@calcom/types/inferSSRProps";
|
||||
import classNames from "@calcom/ui/classNames";
|
||||
import { Form } from "@calcom/ui/components/form";
|
||||
import { showToast } from "@calcom/ui/components/toast";
|
||||
|
||||
import type { SingleFormComponentProps } from "../types/shared";
|
||||
import type { RoutingFormWithResponseCount } from "../types/types";
|
||||
import type { getServerSidePropsForSingleFormView } from "@lib/apps/routing-forms/[...pages]/getServerSidePropsSingleForm";
|
||||
|
||||
import type { NewFormDialogState } from "./FormActions";
|
||||
import { FormActionsProvider } from "./FormActions";
|
||||
import { InfoLostWarningDialog } from "./InfoLostWarningDialog";
|
||||
import { Header } from "./_components/Header";
|
||||
import { TestFormRenderer, type UptoDateForm } from "./_components/TestForm";
|
||||
import { Header } from "./Header";
|
||||
import type { UptoDateForm } from "./TestForm";
|
||||
import { TestFormRenderer } from "./TestForm";
|
||||
|
||||
export type SingleFormComponentProps = {
|
||||
form: RoutingFormWithResponseCount;
|
||||
appUrl: string;
|
||||
Page: React.FC<{
|
||||
form: RoutingFormWithResponseCount;
|
||||
appUrl: string;
|
||||
hookForm: UseFormReturn<RoutingFormWithResponseCount>;
|
||||
}>;
|
||||
enrichedWithUserProfileForm: inferSSRProps<
|
||||
typeof getServerSidePropsForSingleFormView
|
||||
>["enrichedWithUserProfileForm"];
|
||||
permissions: inferSSRProps<typeof getServerSidePropsForSingleFormView>["permissions"];
|
||||
};
|
||||
|
||||
const BREAKPOINTS = {
|
||||
sm: 640,
|
||||
+11
-10
@@ -4,29 +4,30 @@ import { AnimatePresence, motion } from "framer-motion";
|
||||
import type { Dispatch, SetStateAction } from "react";
|
||||
import { useState, useMemo } from "react";
|
||||
|
||||
import FormInputFields from "@calcom/app-store/routing-forms/components/FormInputFields";
|
||||
import { ResultsView as Results } from "@calcom/app-store/routing-forms/components/_components/ResultSection";
|
||||
import { TeamMembersMatchResult } from "@calcom/app-store/routing-forms/components/_components/TeamMembersMatchResult";
|
||||
import type { MembersMatchResultType } from "@calcom/app-store/routing-forms/components/_components/TeamMembersMatchResult";
|
||||
import { findMatchingRoute } from "@calcom/app-store/routing-forms/lib/processRoute";
|
||||
import { substituteVariables } from "@calcom/app-store/routing-forms/lib/substituteVariables";
|
||||
import type { RoutingForm, FormResponse, NonRouterRoute } from "@calcom/app-store/routing-forms/types/types";
|
||||
import { useOrgBranding } from "@calcom/features/ee/organizations/context/provider";
|
||||
import { WEBSITE_URL } from "@calcom/lib/constants";
|
||||
import { useCompatSearchParams } from "@calcom/lib/hooks/useCompatSearchParams";
|
||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||
import { trpc } from "@calcom/trpc";
|
||||
import type { inferSSRProps } from "@calcom/types/inferSSRProps";
|
||||
import type { Brand } from "@calcom/types/utils";
|
||||
import { Button } from "@calcom/ui/components/button";
|
||||
import { Dialog, DialogContent, DialogHeader, DialogFooter } from "@calcom/ui/components/dialog";
|
||||
import { showToast } from "@calcom/ui/components/toast";
|
||||
|
||||
import type { getServerSidePropsForSingleFormView } from "@lib/apps/routing-forms/[...pages]/getServerSidePropsSingleForm";
|
||||
|
||||
import { TRPCClientError } from "@trpc/react-query";
|
||||
|
||||
import { findMatchingRoute } from "../../lib/processRoute";
|
||||
import { substituteVariables } from "../../lib/substituteVariables";
|
||||
import type { SingleFormComponentProps } from "../../types/shared";
|
||||
import type { RoutingForm, FormResponse, NonRouterRoute } from "../../types/types";
|
||||
import FormInputFields from "../FormInputFields";
|
||||
import { ResultsView as Results } from "./ResultSection";
|
||||
import type { MembersMatchResultType } from "./TeamMembersMatchResult";
|
||||
import { TeamMembersMatchResult } from "./TeamMembersMatchResult";
|
||||
|
||||
export type UptoDateForm = Brand<
|
||||
NonNullable<SingleFormComponentProps["enrichedWithUserProfileForm"]>,
|
||||
NonNullable<inferSSRProps<typeof getServerSidePropsForSingleFormView>["enrichedWithUserProfileForm"]>,
|
||||
"UptoDateForm"
|
||||
>;
|
||||
|
||||
+11
-7
@@ -2,8 +2,9 @@ import { render, screen, fireEvent } from "@testing-library/react";
|
||||
import type { Mock } from "vitest";
|
||||
import { vi } from "vitest";
|
||||
|
||||
import { TestFormRenderer } from "../components/_components/TestForm";
|
||||
import { findMatchingRoute } from "../lib/processRoute";
|
||||
import { findMatchingRoute } from "@calcom/app-store/routing-forms/lib/processRoute";
|
||||
|
||||
import { TestFormRenderer } from "./TestForm";
|
||||
|
||||
vi.mock("framer-motion", async () => {
|
||||
return {
|
||||
@@ -14,7 +15,7 @@ vi.mock("framer-motion", async () => {
|
||||
};
|
||||
});
|
||||
|
||||
vi.mock("../lib/processRoute", () => ({
|
||||
vi.mock("@calcom/app-store/routing-forms/lib/processRoute", () => ({
|
||||
findMatchingRoute: vi.fn(),
|
||||
}));
|
||||
|
||||
@@ -70,15 +71,18 @@ vi.mock("@calcom/lib/hooks/useApp", () => ({
|
||||
* Avoids the error due to Formbricks
|
||||
*/
|
||||
|
||||
vi.mock("../components/FormActions", () => ({
|
||||
vi.mock("./FormActions", () => ({
|
||||
FormAction: vi.fn(),
|
||||
FormActionsDropdown: vi.fn(),
|
||||
FormActionsProvider: vi.fn(),
|
||||
}));
|
||||
|
||||
vi.mock("../../components/react-awesome-query-builder/widgets", () => ({
|
||||
default: {},
|
||||
}));
|
||||
vi.mock(
|
||||
"@calcom/app-store/routing-forms/components/react-awesome-query-builder/widgets",
|
||||
async (importOriginal) => {
|
||||
return await importOriginal();
|
||||
}
|
||||
);
|
||||
|
||||
// Mock the necessary dependencies
|
||||
vi.mock("@calcom/lib/hooks/useLocale", () => ({
|
||||
@@ -12,12 +12,12 @@ import FormInputFields, {
|
||||
import { getAbsoluteEventTypeRedirectUrl } from "@calcom/app-store/routing-forms/getEventTypeRedirectUrl";
|
||||
import { findMatchingRoute } from "@calcom/app-store/routing-forms/lib/processRoute";
|
||||
import { substituteVariables } from "@calcom/app-store/routing-forms/lib/substituteVariables";
|
||||
import { getUrlSearchParamsToForwardForReroute } from "@calcom/app-store/routing-forms/pages/routing-link/getUrlSearchParamsToForward";
|
||||
import type { FormResponse, LocalRoute } from "@calcom/app-store/routing-forms/types/types";
|
||||
import { RouteActionType } from "@calcom/app-store/routing-forms/zod";
|
||||
import dayjs from "@calcom/dayjs";
|
||||
import { createBooking } from "@calcom/features/bookings/lib/create-booking";
|
||||
import { Dialog } from "@calcom/features/components/controlled-dialog";
|
||||
import { getUrlSearchParamsToForwardForReroute } from "@calcom/features/routing-forms/lib/getUrlSearchParamsToForward";
|
||||
import { useBookerUrl } from "@calcom/lib/hooks/useBookerUrl";
|
||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||
import type { EventType, User, Team, Attendee, Booking as PrismaBooking } from "@calcom/prisma/client";
|
||||
|
||||
+2
-2
@@ -2,8 +2,8 @@ import "server-only";
|
||||
|
||||
import type { AppGetServerSideProps } from "@calcom/types/AppGetServerSideProps";
|
||||
|
||||
import { getServerSidePropsForSingleFormView as getServerSidePropsSingleForm } from "../components/getServerSidePropsSingleForm";
|
||||
import { getServerSideProps as getServerSidePropsRoutingLink } from "./routing-link/getServerSideProps";
|
||||
import { getServerSideProps as getServerSidePropsRoutingLink } from "./getServerSidePropsRoutingLink";
|
||||
import { getServerSidePropsForSingleFormView as getServerSidePropsSingleForm } from "./getServerSidePropsSingleForm";
|
||||
|
||||
export const routingServerSidePropsConfig: Record<string, AppGetServerSideProps> = {
|
||||
"form-edit": getServerSidePropsSingleForm,
|
||||
@@ -1,11 +1,12 @@
|
||||
import type { GetServerSidePropsResult, GetServerSidePropsContext } from "next";
|
||||
import { z } from "zod";
|
||||
|
||||
import { routingServerSidePropsConfig } from "@calcom/app-store/routing-forms/pages/app-routing.server-config";
|
||||
import { getServerSession } from "@calcom/features/auth/lib/getServerSession";
|
||||
import prisma from "@calcom/prisma";
|
||||
import type { AppGetServerSidePropsContext } from "@calcom/types/AppGetServerSideProps";
|
||||
|
||||
import { routingServerSidePropsConfig } from "./app-routing.server-config";
|
||||
|
||||
const paramsSchema = z.object({
|
||||
pages: z.array(z.string()),
|
||||
});
|
||||
|
||||
+2
-3
@@ -1,10 +1,9 @@
|
||||
import { enrichFormWithMigrationData } from "@calcom/app-store/routing-forms/enrichFormWithMigrationData";
|
||||
import { getSerializableForm } from "@calcom/app-store/routing-forms/lib/getSerializableForm";
|
||||
import { orgDomainConfig } from "@calcom/features/ee/organizations/lib/orgDomains";
|
||||
import { isAuthorizedToViewFormOnOrgDomain } from "@calcom/features/routing-forms/lib/isAuthorizedToViewForm";
|
||||
import type { AppGetServerSidePropsContext, AppPrisma } from "@calcom/types/AppGetServerSideProps";
|
||||
|
||||
import { enrichFormWithMigrationData } from "../../enrichFormWithMigrationData";
|
||||
import { getSerializableForm } from "../../lib/getSerializableForm";
|
||||
|
||||
export const getServerSideProps = async function getServerSideProps(
|
||||
context: AppGetServerSidePropsContext,
|
||||
prisma: AppPrisma
|
||||
+2
-3
@@ -1,12 +1,11 @@
|
||||
import { enrichFormWithMigrationData } from "@calcom/app-store/routing-forms/enrichFormWithMigrationData";
|
||||
import { getSerializableForm } from "@calcom/app-store/routing-forms/lib/getSerializableForm";
|
||||
import { Resource } from "@calcom/features/pbac/domain/types/permission-registry";
|
||||
import { getResourcePermissions } from "@calcom/features/pbac/lib/resource-permissions";
|
||||
import { MembershipRepository } from "@calcom/lib/server/repository/membership";
|
||||
import { MembershipRole } from "@calcom/prisma/enums";
|
||||
import type { AppGetServerSidePropsContext, AppPrisma, AppUser } from "@calcom/types/AppGetServerSideProps";
|
||||
|
||||
import { enrichFormWithMigrationData } from "../enrichFormWithMigrationData";
|
||||
import { getSerializableForm } from "../lib/getSerializableForm";
|
||||
|
||||
export const getServerSidePropsForSingleFormView = async function getServerSidePropsForSingleFormView(
|
||||
context: AppGetServerSidePropsContext,
|
||||
prisma: AppPrisma,
|
||||
@@ -3,10 +3,10 @@
|
||||
import { useSession } from "next-auth/react";
|
||||
import { useRouter } from "next/navigation";
|
||||
|
||||
import { AppSetupPage } from "@calcom/app-store/_pages/setup";
|
||||
import type { getServerSideProps } from "@calcom/app-store/_pages/setup/_getServerSideProps";
|
||||
import { useCompatSearchParams } from "@calcom/lib/hooks/useCompatSearchParams";
|
||||
import type { inferSSRProps } from "@calcom/types/inferSSRProps";
|
||||
import { AppSetupPage } from "@calcom/web/components/apps/AppSetupPage";
|
||||
|
||||
export type PageProps = inferSSRProps<typeof getServerSideProps>;
|
||||
|
||||
|
||||
@@ -4,7 +4,6 @@ import { useReactTable, getCoreRowModel, getSortedRowModel, createColumnHelper }
|
||||
import { useSearchParams, usePathname } from "next/navigation";
|
||||
import { useMemo, useRef } from "react";
|
||||
|
||||
import { WipeMyCalActionButton } from "@calcom/app-store/wipemycalother/components";
|
||||
import dayjs from "@calcom/dayjs";
|
||||
import {
|
||||
useDataTable,
|
||||
@@ -29,6 +28,7 @@ import { EmptyScreen } from "@calcom/ui/components/empty-screen";
|
||||
import type { HorizontalTabItemProps } from "@calcom/ui/components/navigation";
|
||||
import { HorizontalTabs } from "@calcom/ui/components/navigation";
|
||||
import type { VerticalTabItemProps } from "@calcom/ui/components/navigation";
|
||||
import { WipeMyCalActionButton } from "@calcom/web/components/apps/wipemycalother/wipeMyCalActionButton";
|
||||
|
||||
import BookingListItem from "@components/booking/BookingListItem";
|
||||
import SkeletonLoader from "@components/booking/SkeletonLoader";
|
||||
|
||||
@@ -2,13 +2,14 @@
|
||||
|
||||
import { useState } from "react";
|
||||
|
||||
import { TestForm } from "@calcom/app-store/routing-forms/components/_components/TestForm";
|
||||
import type { RoutingForm } from "@calcom/app-store/routing-forms/types/types";
|
||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||
import { trpc } from "@calcom/trpc";
|
||||
import { Label } from "@calcom/ui/components/form";
|
||||
import { Select } from "@calcom/ui/components/form";
|
||||
|
||||
import { TestForm } from "../../components/apps/routing-forms/TestForm";
|
||||
|
||||
export default function InsightsVirtualQueuesPage() {
|
||||
const { t } = useLocale();
|
||||
const { data: routingForms, isLoading: isRoutingFormsLoading } =
|
||||
|
||||
@@ -25,8 +25,10 @@ export default function AppCard({
|
||||
switchTooltip,
|
||||
hideSettingsIcon = false,
|
||||
hideAppCardOptions = false,
|
||||
onAppInstallSuccess,
|
||||
}: {
|
||||
app: AppCardApp;
|
||||
onAppInstallSuccess: () => void;
|
||||
description?: React.ReactNode;
|
||||
switchChecked?: boolean;
|
||||
switchOnClick?: (e: boolean) => void;
|
||||
@@ -112,6 +114,7 @@ export default function AppCard({
|
||||
appId={app.slug}
|
||||
returnTo={returnTo}
|
||||
teamId={teamId}
|
||||
onAppInstallSuccess={onAppInstallSuccess}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
export function DynamicComponent<T extends Record<string, React.ComponentType<any>>>(props: {
|
||||
componentMap: T;
|
||||
slug: string;
|
||||
onAppInstallSuccess?: () => void;
|
||||
wrapperClassName?: string;
|
||||
}) {
|
||||
const { componentMap, slug, wrapperClassName, ...rest } = props;
|
||||
|
||||
@@ -16,12 +16,13 @@ export const EventTypeAppCard = (props: {
|
||||
eventType: EventTypeForAppCard;
|
||||
getAppData: GetAppData;
|
||||
setAppData: SetAppData;
|
||||
onAppInstallSuccess?: () => void;
|
||||
// For event type apps, get these props from shouldLockDisableProps
|
||||
LockedIcon?: JSX.Element | false;
|
||||
eventTypeFormMetadata: z.infer<typeof EventTypeMetaDataSchema>;
|
||||
disabled?: boolean;
|
||||
}) => {
|
||||
const { app, getAppData, setAppData, LockedIcon, disabled } = props;
|
||||
const { app, getAppData, setAppData, LockedIcon, disabled, onAppInstallSuccess } = props;
|
||||
return (
|
||||
<ErrorBoundary message={`There is some problem with ${app.name} App`}>
|
||||
<EventTypeAppContext.Provider value={{ getAppData, setAppData, LockedIcon, disabled }}>
|
||||
@@ -29,6 +30,7 @@ export const EventTypeAppCard = (props: {
|
||||
slug={app.slug === "stripe" ? "stripepayment" : app.slug}
|
||||
componentMap={EventTypeAddonMap}
|
||||
{...props}
|
||||
onAppInstallSuccess={onAppInstallSuccess}
|
||||
/>
|
||||
</EventTypeAppContext.Provider>
|
||||
</ErrorBoundary>
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import useApp from "@calcom/lib/hooks/useApp";
|
||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||
import { trpc } from "@calcom/trpc/react";
|
||||
import classNames from "@calcom/ui/classNames";
|
||||
import { Button } from "@calcom/ui/components/button";
|
||||
import { showToast } from "@calcom/ui/components/toast";
|
||||
@@ -17,24 +16,21 @@ export default function OmniInstallAppButton({
|
||||
className,
|
||||
returnTo,
|
||||
teamId,
|
||||
onAppInstallSuccess,
|
||||
}: {
|
||||
appId: string;
|
||||
className: string;
|
||||
onAppInstallSuccess: () => void;
|
||||
returnTo?: string;
|
||||
teamId?: number;
|
||||
}) {
|
||||
const { t } = useLocale();
|
||||
const { data: app } = useApp(appId);
|
||||
const utils = trpc.useUtils();
|
||||
|
||||
const mutation = useAddAppMutation(null, {
|
||||
returnTo,
|
||||
onSuccess: (data) => {
|
||||
utils.viewer.apps.appById.invalidate({ appId });
|
||||
utils.viewer.apps.integrations.invalidate({
|
||||
extendsFeature: "EventType",
|
||||
...(teamId && { teamId }),
|
||||
});
|
||||
onAppInstallSuccess();
|
||||
if (data?.setupPending) return;
|
||||
showToast(t("app_successfully_installed"), "success");
|
||||
},
|
||||
|
||||
@@ -30,6 +30,7 @@ const mockProps = {
|
||||
setAppData: setAppDataMock,
|
||||
LockedIcon: <div>MockedIcon</div>,
|
||||
disabled: false,
|
||||
onAppInstallSuccess: vi.fn(),
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
} as any;
|
||||
|
||||
|
||||
@@ -1,26 +0,0 @@
|
||||
import dynamic from "next/dynamic";
|
||||
|
||||
import { DynamicComponent } from "../../_components/DynamicComponent";
|
||||
|
||||
export const AppSetupMap = {
|
||||
alby: dynamic(() => import("../../alby/pages/setup")),
|
||||
"apple-calendar": dynamic(() => import("../../applecalendar/pages/setup")),
|
||||
exchange: dynamic(() => import("../../exchangecalendar/pages/setup")),
|
||||
"exchange2013-calendar": dynamic(() => import("../../exchange2013calendar/pages/setup")),
|
||||
"exchange2016-calendar": dynamic(() => import("../../exchange2016calendar/pages/setup")),
|
||||
"caldav-calendar": dynamic(() => import("../../caldavcalendar/pages/setup")),
|
||||
"ics-feed": dynamic(() => import("../../ics-feedcalendar/pages/setup")),
|
||||
zapier: dynamic(() => import("../../zapier/pages/setup")),
|
||||
make: dynamic(() => import("../../make/pages/setup")),
|
||||
sendgrid: dynamic(() => import("../../sendgrid/pages/setup")),
|
||||
stripe: dynamic(() => import("../../stripepayment/pages/setup")),
|
||||
paypal: dynamic(() => import("../../paypal/pages/setup")),
|
||||
hitpay: dynamic(() => import("../../hitpay/pages/setup")),
|
||||
btcpayserver: dynamic(() => import("../../btcpayserver/pages/setup")),
|
||||
};
|
||||
|
||||
export const AppSetupPage = (props: { slug: string }) => {
|
||||
return <DynamicComponent<typeof AppSetupMap> componentMap={AppSetupMap} {...props} />;
|
||||
};
|
||||
|
||||
export default AppSetupPage;
|
||||
@@ -15,6 +15,7 @@ const EventTypeAppCard: EventTypeAppCardComponent = function EventTypeAppCard({
|
||||
app,
|
||||
eventType,
|
||||
eventTypeFormMetadata,
|
||||
onAppInstallSuccess,
|
||||
}) {
|
||||
const searchParams = useSearchParams();
|
||||
const { t } = useLocale();
|
||||
@@ -32,6 +33,7 @@ const EventTypeAppCard: EventTypeAppCardComponent = function EventTypeAppCard({
|
||||
|
||||
return (
|
||||
<AppCard
|
||||
onAppInstallSuccess={onAppInstallSuccess}
|
||||
returnTo={WEBAPP_URL + asPath}
|
||||
app={app}
|
||||
switchChecked={requirePayment}
|
||||
|
||||
@@ -4,7 +4,13 @@ import { getServerSession } from "@calcom/features/auth/lib/getServerSession";
|
||||
import prisma from "@calcom/prisma";
|
||||
|
||||
import { getAlbyKeys } from "../../lib/getAlbyKeys";
|
||||
import type { IAlbySetupProps } from "./index";
|
||||
|
||||
export interface IAlbySetupProps {
|
||||
email: string | null;
|
||||
lightningAddress: string | null;
|
||||
clientId: string;
|
||||
clientSecret: string;
|
||||
}
|
||||
|
||||
export const getServerSideProps = async (ctx: GetServerSidePropsContext) => {
|
||||
const notFound = { notFound: true } as const;
|
||||
|
||||
@@ -6,12 +6,17 @@ import useIsAppEnabled from "../../_utils/useIsAppEnabled";
|
||||
import type { appDataSchema } from "../zod";
|
||||
import EventTypeAppSettingsInterface from "./EventTypeAppSettingsInterface";
|
||||
|
||||
const EventTypeAppCard: EventTypeAppCardComponent = function EventTypeAppCard({ app, eventType }) {
|
||||
const EventTypeAppCard: EventTypeAppCardComponent = function EventTypeAppCard({
|
||||
app,
|
||||
eventType,
|
||||
onAppInstallSuccess,
|
||||
}) {
|
||||
const { getAppData, setAppData, disabled } = useAppContextWithSchema<typeof appDataSchema>();
|
||||
const { enabled, updateEnabled } = useIsAppEnabled(app);
|
||||
|
||||
return (
|
||||
<AppCard
|
||||
onAppInstallSuccess={onAppInstallSuccess}
|
||||
app={app}
|
||||
switchOnClick={(e) => {
|
||||
updateEnabled(e);
|
||||
|
||||
@@ -17,6 +17,7 @@ const EventTypeAppCard: EventTypeAppCardComponent = function EventTypeAppCard({
|
||||
eventType,
|
||||
app,
|
||||
eventTypeFormMetadata,
|
||||
onAppInstallSuccess,
|
||||
}) {
|
||||
const { t } = useLocale();
|
||||
const pathname = usePathname();
|
||||
@@ -27,6 +28,7 @@ const EventTypeAppCard: EventTypeAppCardComponent = function EventTypeAppCard({
|
||||
|
||||
return (
|
||||
<AppCard
|
||||
onAppInstallSuccess={onAppInstallSuccess}
|
||||
returnTo={`${WEBAPP_URL}${pathname}?tabName=apps`}
|
||||
app={app}
|
||||
switchChecked={requirePayment}
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
import type { GetServerSidePropsContext } from "next";
|
||||
import { z } from "zod";
|
||||
|
||||
import { getServerSession } from "@calcom/features/auth/lib/getServerSession";
|
||||
import { CredentialRepository } from "@calcom/lib/server/repository/credential";
|
||||
|
||||
import { btcpayCredentialKeysSchema } from "../../lib/btcpayCredentialKeysSchema";
|
||||
import type { IBTCPaySetupProps } from "./index";
|
||||
|
||||
export type IBTCPaySetupProps = z.infer<typeof btcpayCredentialKeysSchema>;
|
||||
|
||||
export const getServerSideProps = async (ctx: GetServerSidePropsContext) => {
|
||||
try {
|
||||
|
||||
@@ -5,13 +5,18 @@ import useIsAppEnabled from "@calcom/app-store/_utils/useIsAppEnabled";
|
||||
import type { EventTypeAppCardComponent } from "@calcom/app-store/types";
|
||||
import { WEBAPP_URL } from "@calcom/lib/constants";
|
||||
|
||||
const EventTypeAppCard: EventTypeAppCardComponent = function EventTypeAppCard({ app, eventType }) {
|
||||
const EventTypeAppCard: EventTypeAppCardComponent = function EventTypeAppCard({
|
||||
app,
|
||||
eventType,
|
||||
onAppInstallSuccess,
|
||||
}) {
|
||||
const pathname = usePathname();
|
||||
|
||||
const { enabled, updateEnabled } = useIsAppEnabled(app);
|
||||
|
||||
return (
|
||||
<AppCard
|
||||
onAppInstallSuccess={onAppInstallSuccess}
|
||||
returnTo={`${WEBAPP_URL}${pathname}?tabName=apps`}
|
||||
app={app}
|
||||
teamId={eventType.team?.id || undefined}
|
||||
|
||||
@@ -6,12 +6,13 @@ import type { EventTypeAppCardComponent } from "@calcom/app-store/types";
|
||||
import type { appDataSchema } from "../zod";
|
||||
import EventTypeAppSettingsInterface from "./EventTypeAppSettingsInterface";
|
||||
|
||||
const EventTypeAppCard: EventTypeAppCardComponent = function EventTypeAppCard({ app, eventType }) {
|
||||
const EventTypeAppCard: EventTypeAppCardComponent = function EventTypeAppCard({ app, eventType, onAppInstallSuccess }) {
|
||||
const { getAppData, setAppData, disabled } = useAppContextWithSchema<typeof appDataSchema>();
|
||||
const { enabled, updateEnabled } = useIsAppEnabled(app);
|
||||
|
||||
return (
|
||||
<AppCard
|
||||
onAppInstallSuccess={onAppInstallSuccess}
|
||||
hideSettingsIcon
|
||||
app={app}
|
||||
switchOnClick={(e) => {
|
||||
|
||||
@@ -6,12 +6,17 @@ import type { EventTypeAppCardComponent } from "@calcom/app-store/types";
|
||||
import type { appDataSchema } from "../zod";
|
||||
import EventTypeAppSettingsInterface from "./EventTypeAppSettingsInterface";
|
||||
|
||||
const EventTypeAppCard: EventTypeAppCardComponent = function EventTypeAppCard({ app, eventType }) {
|
||||
const EventTypeAppCard: EventTypeAppCardComponent = function EventTypeAppCard({
|
||||
app,
|
||||
eventType,
|
||||
onAppInstallSuccess,
|
||||
}) {
|
||||
const { getAppData, setAppData, disabled } = useAppContextWithSchema<typeof appDataSchema>();
|
||||
const { enabled, updateEnabled } = useIsAppEnabled(app);
|
||||
|
||||
return (
|
||||
<AppCard
|
||||
onAppInstallSuccess={onAppInstallSuccess}
|
||||
hideSettingsIcon
|
||||
app={app}
|
||||
switchOnClick={(e) => {
|
||||
|
||||
@@ -7,7 +7,11 @@ import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||
import type { appDataSchema } from "../zod";
|
||||
import EventTypeAppSettingsInterface from "./EventTypeAppSettingsInterface";
|
||||
|
||||
const EventTypeAppCard: EventTypeAppCardComponent = function EventTypeAppCard({ app, eventType }) {
|
||||
const EventTypeAppCard: EventTypeAppCardComponent = function EventTypeAppCard({
|
||||
app,
|
||||
eventType,
|
||||
onAppInstallSuccess,
|
||||
}) {
|
||||
const { getAppData, setAppData, disabled } = useAppContextWithSchema<typeof appDataSchema>();
|
||||
const { enabled: showGifSelection, updateEnabled: setShowGifSelection } = useIsAppEnabled(app);
|
||||
|
||||
@@ -15,6 +19,7 @@ const EventTypeAppCard: EventTypeAppCardComponent = function EventTypeAppCard({
|
||||
|
||||
return (
|
||||
<AppCard
|
||||
onAppInstallSuccess={onAppInstallSuccess}
|
||||
app={app}
|
||||
description={t("confirmation_page_gif")}
|
||||
switchOnClick={(e) => {
|
||||
|
||||
@@ -6,12 +6,13 @@ import type { EventTypeAppCardComponent } from "@calcom/app-store/types";
|
||||
import type { appDataSchema } from "../zod";
|
||||
import EventTypeAppSettingsInterface from "./EventTypeAppSettingsInterface";
|
||||
|
||||
const EventTypeAppCard: EventTypeAppCardComponent = function EventTypeAppCard({ app, eventType }) {
|
||||
const EventTypeAppCard: EventTypeAppCardComponent = function EventTypeAppCard({ app, eventType, onAppInstallSuccess }) {
|
||||
const { getAppData, setAppData, disabled } = useAppContextWithSchema<typeof appDataSchema>();
|
||||
const { enabled, updateEnabled } = useIsAppEnabled(app);
|
||||
|
||||
return (
|
||||
<AppCard
|
||||
onAppInstallSuccess={onAppInstallSuccess}
|
||||
hideSettingsIcon
|
||||
app={app}
|
||||
switchOnClick={(e) => {
|
||||
|
||||
@@ -16,6 +16,7 @@ const EventTypeAppCard: EventTypeAppCardComponent = function EventTypeAppCard({
|
||||
app,
|
||||
eventType,
|
||||
eventTypeFormMetadata,
|
||||
onAppInstallSuccess,
|
||||
}) {
|
||||
const { t } = useLocale();
|
||||
const pathname = usePathname();
|
||||
@@ -27,6 +28,7 @@ const EventTypeAppCard: EventTypeAppCardComponent = function EventTypeAppCard({
|
||||
|
||||
return (
|
||||
<AppCard
|
||||
onAppInstallSuccess={onAppInstallSuccess}
|
||||
returnTo={`${WEBAPP_URL}${pathname}?tabName=apps`}
|
||||
app={app}
|
||||
switchChecked={enabled}
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
import type { GetServerSidePropsContext } from "next";
|
||||
import { z } from "zod";
|
||||
|
||||
import { getServerSession } from "@calcom/features/auth/lib/getServerSession";
|
||||
import prisma from "@calcom/prisma";
|
||||
|
||||
import { hitpayCredentialKeysSchema } from "../../lib/hitpayCredentialKeysSchema";
|
||||
import type { IHitPaySetupProps } from "./index";
|
||||
|
||||
export type IHitPaySetupProps = z.infer<typeof hitpayCredentialKeysSchema>;
|
||||
|
||||
export const getServerSideProps = async (ctx: GetServerSidePropsContext) => {
|
||||
const notFound = { notFound: true } as const;
|
||||
|
||||
@@ -5,13 +5,14 @@ import useIsAppEnabled from "@calcom/app-store/_utils/useIsAppEnabled";
|
||||
import type { EventTypeAppCardComponent } from "@calcom/app-store/types";
|
||||
import { WEBAPP_URL } from "@calcom/lib/constants";
|
||||
|
||||
const EventTypeAppCard: EventTypeAppCardComponent = function EventTypeAppCard({ app, eventType }) {
|
||||
const EventTypeAppCard: EventTypeAppCardComponent = function EventTypeAppCard({ app, eventType, onAppInstallSuccess }) {
|
||||
const pathname = usePathname();
|
||||
|
||||
const { enabled, updateEnabled } = useIsAppEnabled(app);
|
||||
|
||||
return (
|
||||
<AppCard
|
||||
onAppInstallSuccess={onAppInstallSuccess}
|
||||
returnTo={`${WEBAPP_URL}${pathname}?tabName=apps`}
|
||||
app={app}
|
||||
teamId={eventType.team?.id || undefined}
|
||||
|
||||
@@ -6,13 +6,14 @@ import { TextField } from "@calcom/ui/components/form";
|
||||
|
||||
import type { appDataSchema } from "../zod";
|
||||
|
||||
const EventTypeAppCard: EventTypeAppCardComponent = function EventTypeAppCard({ app, eventType }) {
|
||||
const EventTypeAppCard: EventTypeAppCardComponent = function EventTypeAppCard({ app, eventType, onAppInstallSuccess }) {
|
||||
const { getAppData, setAppData, disabled } = useAppContextWithSchema<typeof appDataSchema>();
|
||||
const siteId = getAppData("SITE_ID");
|
||||
const { enabled, updateEnabled } = useIsAppEnabled(app);
|
||||
|
||||
return (
|
||||
<AppCard
|
||||
onAppInstallSuccess={onAppInstallSuccess}
|
||||
app={app}
|
||||
switchOnClick={(e) => {
|
||||
updateEnabled(e);
|
||||
|
||||
@@ -6,7 +6,7 @@ import { TextField } from "@calcom/ui/components/form";
|
||||
|
||||
import type { appDataSchema } from "../zod";
|
||||
|
||||
const EventTypeAppCard: EventTypeAppCardComponent = function EventTypeAppCard({ app, eventType }) {
|
||||
const EventTypeAppCard: EventTypeAppCardComponent = function EventTypeAppCard({ app, eventType, onAppInstallSuccess }) {
|
||||
const { getAppData, setAppData, disabled } = useAppContextWithSchema<typeof appDataSchema>();
|
||||
const matomoUrl = getAppData("MATOMO_URL");
|
||||
const siteId = getAppData("SITE_ID");
|
||||
@@ -14,6 +14,7 @@ const EventTypeAppCard: EventTypeAppCardComponent = function EventTypeAppCard({
|
||||
|
||||
return (
|
||||
<AppCard
|
||||
onAppInstallSuccess={onAppInstallSuccess}
|
||||
hideSettingsIcon
|
||||
app={app}
|
||||
switchOnClick={(e) => {
|
||||
|
||||
@@ -6,12 +6,13 @@ import type { EventTypeAppCardComponent } from "@calcom/app-store/types";
|
||||
import type { appDataSchema } from "../zod";
|
||||
import EventTypeAppSettingsInterface from "./EventTypeAppSettingsInterface";
|
||||
|
||||
const EventTypeAppCard: EventTypeAppCardComponent = function EventTypeAppCard({ app, eventType }) {
|
||||
const EventTypeAppCard: EventTypeAppCardComponent = function EventTypeAppCard({ app, eventType, onAppInstallSuccess }) {
|
||||
const { getAppData, setAppData, disabled } = useAppContextWithSchema<typeof appDataSchema>();
|
||||
const { enabled, updateEnabled } = useIsAppEnabled(app);
|
||||
|
||||
return (
|
||||
<AppCard
|
||||
onAppInstallSuccess={onAppInstallSuccess}
|
||||
hideSettingsIcon
|
||||
app={app}
|
||||
switchOnClick={updateEnabled}
|
||||
|
||||
@@ -20,7 +20,7 @@ import { paymentOptions } from "../zod";
|
||||
|
||||
type Option = { value: string; label: string };
|
||||
|
||||
const EventTypeAppCard: EventTypeAppCardComponent = function EventTypeAppCard({ app, eventType }) {
|
||||
const EventTypeAppCard: EventTypeAppCardComponent = function EventTypeAppCard({ app, eventType, onAppInstallSuccess }) {
|
||||
const searchParams = useSearchParams();
|
||||
/** TODO "pathname" no longer contains square-bracket expressions. Rewrite the code relying on them if required. **/
|
||||
const pathname = usePathname();
|
||||
@@ -51,6 +51,7 @@ const EventTypeAppCard: EventTypeAppCardComponent = function EventTypeAppCard({
|
||||
|
||||
return (
|
||||
<AppCard
|
||||
onAppInstallSuccess={onAppInstallSuccess}
|
||||
returnTo={WEBAPP_URL + asPath}
|
||||
app={app}
|
||||
switchChecked={requirePayment}
|
||||
|
||||
@@ -20,7 +20,6 @@
|
||||
"@calcom/features": "*",
|
||||
"@calcom/lib": "*",
|
||||
"@calcom/office365video": "*",
|
||||
"@calcom/trpc": "*",
|
||||
"@calcom/ui": "*",
|
||||
"@calcom/zoomvideo": "*",
|
||||
"lodash": "^4.17.21",
|
||||
@@ -31,4 +30,4 @@
|
||||
"devDependencies": {
|
||||
"@calcom/types": "*"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -15,6 +15,7 @@ const EventTypeAppCard: EventTypeAppCardComponent = function EventTypeAppCard({
|
||||
app,
|
||||
eventType,
|
||||
eventTypeFormMetadata,
|
||||
onAppInstallSuccess,
|
||||
}) {
|
||||
const searchParams = useSearchParams();
|
||||
/** TODO "pathname" no longer contains square-bracket expressions. Rewrite the code relying on them if required. **/
|
||||
@@ -32,6 +33,7 @@ const EventTypeAppCard: EventTypeAppCardComponent = function EventTypeAppCard({
|
||||
|
||||
return (
|
||||
<AppCard
|
||||
onAppInstallSuccess={onAppInstallSuccess}
|
||||
returnTo={WEBAPP_URL + asPath}
|
||||
app={app}
|
||||
switchChecked={requirePayment}
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
import { z } from "zod";
|
||||
|
||||
import type { UpdateAppCredentialsOptions } from "@calcom/trpc/server/routers/viewer/apps/updateAppCredentials.handler";
|
||||
|
||||
import Paypal from "./Paypal";
|
||||
|
||||
const schema = z.object({
|
||||
@@ -12,7 +10,9 @@ const schema = z.object({
|
||||
}),
|
||||
});
|
||||
|
||||
const handlePaypalValidations = async ({ input }: UpdateAppCredentialsOptions) => {
|
||||
type TUpdateAppCredentialsInputSchema = { credentialId: number; key: { [k: string]: unknown } };
|
||||
|
||||
const handlePaypalValidations = async ({ input }: { input: TUpdateAppCredentialsInputSchema }) => {
|
||||
const validated = schema.safeParse(input);
|
||||
if (!validated.success) throw new Error("Invalid input");
|
||||
const { key } = validated.data;
|
||||
|
||||
@@ -5,13 +5,14 @@ import useIsAppEnabled from "@calcom/app-store/_utils/useIsAppEnabled";
|
||||
import type { EventTypeAppCardComponent } from "@calcom/app-store/types";
|
||||
import { WEBAPP_URL } from "@calcom/lib/constants";
|
||||
|
||||
const EventTypeAppCard: EventTypeAppCardComponent = function EventTypeAppCard({ app, eventType }) {
|
||||
const EventTypeAppCard: EventTypeAppCardComponent = function EventTypeAppCard({ app, eventType, onAppInstallSuccess }) {
|
||||
const pathname = usePathname();
|
||||
|
||||
const { enabled, updateEnabled } = useIsAppEnabled(app);
|
||||
|
||||
return (
|
||||
<AppCard
|
||||
onAppInstallSuccess={onAppInstallSuccess}
|
||||
returnTo={`${WEBAPP_URL}${pathname}?tabName=apps`}
|
||||
app={app}
|
||||
teamId={eventType.team?.id || undefined}
|
||||
|
||||
@@ -6,13 +6,14 @@ import type { EventTypeAppCardComponent } from "@calcom/app-store/types";
|
||||
import type { appDataSchema } from "../zod";
|
||||
import EventTypeAppSettingsInterface from "./EventTypeAppSettingsInterface";
|
||||
|
||||
const EventTypeAppCard: EventTypeAppCardComponent = function EventTypeAppCard({ app, eventType }) {
|
||||
const EventTypeAppCard: EventTypeAppCardComponent = function EventTypeAppCard({ app, eventType, onAppInstallSuccess }) {
|
||||
const { getAppData, setAppData, disabled } = useAppContextWithSchema<typeof appDataSchema>();
|
||||
|
||||
const { enabled, updateEnabled } = useIsAppEnabled(app);
|
||||
|
||||
return (
|
||||
<AppCard
|
||||
onAppInstallSuccess={onAppInstallSuccess}
|
||||
hideSettingsIcon
|
||||
app={app}
|
||||
switchOnClick={(e) => {
|
||||
|
||||
@@ -6,7 +6,11 @@ import { TextField } from "@calcom/ui/components/form";
|
||||
|
||||
import type { appDataSchema } from "../zod";
|
||||
|
||||
const EventTypeAppCard: EventTypeAppCardComponent = function EventTypeAppCard({ app, eventType }) {
|
||||
const EventTypeAppCard: EventTypeAppCardComponent = function EventTypeAppCard({
|
||||
app,
|
||||
eventType,
|
||||
onAppInstallSuccess,
|
||||
}) {
|
||||
const { getAppData, setAppData, disabled } = useAppContextWithSchema<typeof appDataSchema>();
|
||||
const trackingId = getAppData("TRACKING_ID");
|
||||
const apiHost = getAppData("API_HOST");
|
||||
@@ -14,6 +18,7 @@ const EventTypeAppCard: EventTypeAppCardComponent = function EventTypeAppCard({
|
||||
|
||||
return (
|
||||
<AppCard
|
||||
onAppInstallSuccess={onAppInstallSuccess}
|
||||
hideSettingsIcon
|
||||
app={app}
|
||||
switchOnClick={(e) => {
|
||||
|
||||
@@ -6,12 +6,13 @@ import type { EventTypeAppCardComponent } from "@calcom/app-store/types";
|
||||
import type { appDataSchema } from "../zod";
|
||||
import EventTypeAppSettingsInterface from "./EventTypeAppSettingsInterface";
|
||||
|
||||
const EventTypeAppCard: EventTypeAppCardComponent = function EventTypeAppCard({ eventType, app }) {
|
||||
const EventTypeAppCard: EventTypeAppCardComponent = function EventTypeAppCard({ eventType, app, onAppInstallSuccess }) {
|
||||
const { enabled, updateEnabled } = useIsAppEnabled(app);
|
||||
const { disabled, getAppData, setAppData } = useAppContextWithSchema<typeof appDataSchema>();
|
||||
|
||||
return (
|
||||
<AppCard
|
||||
onAppInstallSuccess={onAppInstallSuccess}
|
||||
app={app}
|
||||
switchOnClick={(e) => {
|
||||
updateEnabled(e);
|
||||
|
||||
@@ -1,20 +1,18 @@
|
||||
import { prisma } from "@calcom/prisma";
|
||||
import type { Prisma } from "@calcom/prisma/client";
|
||||
import type { App_RoutingForms_Form, User } from "@calcom/prisma/client";
|
||||
|
||||
import dayjs from "@calcom/dayjs";
|
||||
import type { Tasker } from "@calcom/features/tasker/tasker";
|
||||
import getWebhooks from "@calcom/features/webhooks/lib/getWebhooks";
|
||||
import { sendGenericWebhookPayload } from "@calcom/features/webhooks/lib/sendPayload";
|
||||
import getOrgIdFromMemberOrTeamId from "@calcom/lib/getOrgIdFromMemberOrTeamId";
|
||||
import { HttpError } from "@calcom/lib/http-error";
|
||||
import logger from "@calcom/lib/logger";
|
||||
import { withReporting } from "@calcom/lib/sentryWrapper";
|
||||
import { prisma } from "@calcom/prisma";
|
||||
import type { Prisma } from "@calcom/prisma/client";
|
||||
import type { App_RoutingForms_Form, User } from "@calcom/prisma/client";
|
||||
import { WebhookTriggerEvents } from "@calcom/prisma/enums";
|
||||
import { RoutingFormSettings } from "@calcom/prisma/zod-utils";
|
||||
import type { Ensure } from "@calcom/types/utils";
|
||||
|
||||
import { TRPCError } from "@trpc/server";
|
||||
|
||||
import type { FormResponse, SerializableForm, SerializableField, OrderedResponses } from "../types/types";
|
||||
|
||||
const moduleLogger = logger.getSubLogger({ prefix: ["routing-forms/lib/formSubmissionUtils"] });
|
||||
@@ -269,9 +267,7 @@ export const onSubmissionOfFormResponse = async ({
|
||||
}) => {
|
||||
if (!form.fields) {
|
||||
// There is no point in submitting a form that doesn't have fields defined
|
||||
throw new TRPCError({
|
||||
code: "BAD_REQUEST",
|
||||
});
|
||||
throw new HttpError({ statusCode: 400 });
|
||||
}
|
||||
const settings = RoutingFormSettings.parse(form.settings);
|
||||
let userWithEmails: string[] = [];
|
||||
|
||||
@@ -2,11 +2,9 @@ import "@calcom/lib/__mocks__/logger";
|
||||
import { prisma } from "@calcom/prisma/__mocks__/prisma";
|
||||
|
||||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import type { z } from "zod";
|
||||
|
||||
import { findTeamMembersMatchingAttributeLogic } from "@calcom/lib/raqb/findTeamMembersMatchingAttributeLogic";
|
||||
import { RoutingFormResponseRepository } from "@calcom/lib/server/repository/formResponse";
|
||||
import type { ZResponseInputSchema } from "@calcom/trpc/server/routers/viewer/routing-forms/response.schema";
|
||||
|
||||
import isRouter from "../lib/isRouter";
|
||||
import routerGetCrmContactOwnerEmail from "./crmRouting/routerGetCrmContactOwnerEmail";
|
||||
@@ -104,7 +102,14 @@ const mockForm: TargetRoutingFormForResponse = {
|
||||
updatedById: null,
|
||||
};
|
||||
|
||||
const mockResponse: z.infer<typeof ZResponseInputSchema>["response"] = {
|
||||
const mockResponse: Record<
|
||||
string,
|
||||
{
|
||||
value: (string | number | string[]) & (string | number | string[] | undefined);
|
||||
label: string;
|
||||
identifier?: string | undefined;
|
||||
}
|
||||
> = {
|
||||
name: { value: "John Doe", label: "Name" },
|
||||
email: { value: "john.doe@example.com", label: "Email" },
|
||||
};
|
||||
@@ -118,7 +123,7 @@ describe("handleResponse", () => {
|
||||
);
|
||||
});
|
||||
|
||||
it("should throw a TRPCError for missing required fields", async () => {
|
||||
it("should throw an Error for missing required fields", async () => {
|
||||
await expect(
|
||||
handleResponse({
|
||||
response: { email: { value: "test@test.com", label: "Email" } }, // Name is missing
|
||||
@@ -131,7 +136,7 @@ describe("handleResponse", () => {
|
||||
).rejects.toThrow(/Missing required fields Name/);
|
||||
});
|
||||
|
||||
it("should throw a TRPCError for invalid email", async () => {
|
||||
it("should throw an Error for invalid email", async () => {
|
||||
await expect(
|
||||
handleResponse({
|
||||
response: {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { z } from "zod";
|
||||
|
||||
import { emailSchema } from "@calcom/lib/emailSchema";
|
||||
import { HttpError } from "@calcom/lib/http-error";
|
||||
import logger from "@calcom/lib/logger";
|
||||
import { findTeamMembersMatchingAttributeLogic } from "@calcom/lib/raqb/findTeamMembersMatchingAttributeLogic";
|
||||
import { safeStringify } from "@calcom/lib/safeStringify";
|
||||
@@ -8,9 +9,6 @@ import { withReporting } from "@calcom/lib/sentryWrapper";
|
||||
import { RoutingFormResponseRepository } from "@calcom/lib/server/repository/formResponse";
|
||||
import { prisma } from "@calcom/prisma";
|
||||
import { Prisma } from "@calcom/prisma/client";
|
||||
import type { ZResponseInputSchema } from "@calcom/trpc/server/routers/viewer/routing-forms/response.schema";
|
||||
|
||||
import { TRPCError } from "@trpc/server";
|
||||
|
||||
import isRouter from "../lib/isRouter";
|
||||
import routerGetCrmContactOwnerEmail from "./crmRouting/routerGetCrmContactOwnerEmail";
|
||||
@@ -29,7 +27,14 @@ const _handleResponse = async ({
|
||||
queueFormResponse,
|
||||
fetchCrm,
|
||||
}: {
|
||||
response: z.infer<typeof ZResponseInputSchema>["response"];
|
||||
response: Record<
|
||||
string,
|
||||
{
|
||||
value: string | number | string[];
|
||||
label: string;
|
||||
identifier?: string;
|
||||
}
|
||||
>;
|
||||
identifierKeyedResponse: Record<string, string | string[]> | null;
|
||||
form: TargetRoutingFormForResponse;
|
||||
formFillerId: string;
|
||||
@@ -41,9 +46,7 @@ const _handleResponse = async ({
|
||||
try {
|
||||
if (!form.fields) {
|
||||
// There is no point in submitting a form that doesn't have fields defined
|
||||
throw new TRPCError({
|
||||
code: "BAD_REQUEST",
|
||||
});
|
||||
throw new HttpError({ statusCode: 400 });
|
||||
}
|
||||
|
||||
const formTeamId = form.teamId;
|
||||
@@ -58,8 +61,8 @@ const _handleResponse = async ({
|
||||
.map((f) => f.label);
|
||||
|
||||
if (missingFields.length) {
|
||||
throw new TRPCError({
|
||||
code: "BAD_REQUEST",
|
||||
throw new HttpError({
|
||||
statusCode: 400,
|
||||
message: `Missing required fields ${missingFields.join(", ")}`,
|
||||
});
|
||||
}
|
||||
@@ -83,8 +86,8 @@ const _handleResponse = async ({
|
||||
.map((f) => ({ label: f.label, type: f.type, value: response[f.id]?.value }));
|
||||
|
||||
if (invalidFields.length) {
|
||||
throw new TRPCError({
|
||||
code: "BAD_REQUEST",
|
||||
throw new HttpError({
|
||||
statusCode: 400,
|
||||
message: `Invalid value for fields ${invalidFields
|
||||
.map((f) => `'${f.label}' with value '${f.value}' should be valid ${f.type}`)
|
||||
.join(", ")}`,
|
||||
@@ -100,8 +103,8 @@ const _handleResponse = async ({
|
||||
let timeTaken: Record<string, number | null> = {};
|
||||
if (chosenRoute) {
|
||||
if (isRouter(chosenRoute)) {
|
||||
throw new TRPCError({
|
||||
code: "BAD_REQUEST",
|
||||
throw new HttpError({
|
||||
statusCode: 400,
|
||||
message: "Chosen route is a router",
|
||||
});
|
||||
}
|
||||
@@ -225,8 +228,9 @@ const _handleResponse = async ({
|
||||
} catch (e) {
|
||||
if (e instanceof Prisma.PrismaClientKnownRequestError) {
|
||||
if (e.code === "P2002") {
|
||||
throw new TRPCError({
|
||||
code: "CONFLICT",
|
||||
throw new HttpError({
|
||||
statusCode: 409,
|
||||
message: "Form response already exists",
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
export const routingFormsComponents = {
|
||||
"form-edit": () => import("./form-edit/[...appPages]").then((mod) => mod.default),
|
||||
"route-builder": () => import("./route-builder/[...appPages]").then((mod) => mod.default),
|
||||
"routing-link": () => import("./routing-link/[...appPages]").then((mod) => mod.default),
|
||||
"incomplete-booking": () => import("./incomplete-booking/[...appPages]").then((mod) => mod.default),
|
||||
};
|
||||
@@ -1,20 +0,0 @@
|
||||
import type { UseFormReturn } from "react-hook-form";
|
||||
|
||||
import type { inferSSRProps } from "@calcom/types/inferSSRProps";
|
||||
|
||||
import type { getServerSidePropsForSingleFormView } from "../components/getServerSidePropsSingleForm";
|
||||
import type { RoutingFormWithResponseCount } from "../types/types";
|
||||
|
||||
export type SingleFormComponentProps = {
|
||||
form: RoutingFormWithResponseCount;
|
||||
appUrl: string;
|
||||
Page: React.FC<{
|
||||
form: RoutingFormWithResponseCount;
|
||||
appUrl: string;
|
||||
hookForm: UseFormReturn<RoutingFormWithResponseCount>;
|
||||
}>;
|
||||
enrichedWithUserProfileForm: inferSSRProps<
|
||||
typeof getServerSidePropsForSingleFormView
|
||||
>["enrichedWithUserProfileForm"];
|
||||
permissions: inferSSRProps<typeof getServerSidePropsForSingleFormView>["permissions"];
|
||||
};
|
||||
@@ -20,7 +20,7 @@ import { SalesforceRecordEnum } from "../lib/enums";
|
||||
import type { appDataSchema } from "../zod";
|
||||
import WriteToObjectSettings, { BookingActionEnum } from "./components/WriteToObjectSettings";
|
||||
|
||||
const EventTypeAppCard: EventTypeAppCardComponent = function EventTypeAppCard({ app, eventType }) {
|
||||
const EventTypeAppCard: EventTypeAppCardComponent = function EventTypeAppCard({ app, eventType, onAppInstallSuccess }) {
|
||||
const pathname = usePathname();
|
||||
|
||||
const { getAppData, setAppData, disabled } = useAppContextWithSchema<typeof appDataSchema>();
|
||||
@@ -95,6 +95,7 @@ const EventTypeAppCard: EventTypeAppCardComponent = function EventTypeAppCard({
|
||||
|
||||
return (
|
||||
<AppCard
|
||||
onAppInstallSuccess={onAppInstallSuccess}
|
||||
returnTo={`${WEBAPP_URL}${pathname}?tabName=apps`}
|
||||
app={app}
|
||||
teamId={eventType.team?.id || undefined}
|
||||
|
||||
@@ -16,6 +16,7 @@ const EventTypeAppCard: EventTypeAppCardComponent = function EventTypeAppCard({
|
||||
app,
|
||||
eventType,
|
||||
eventTypeFormMetadata,
|
||||
onAppInstallSuccess,
|
||||
}) {
|
||||
const { t } = useLocale();
|
||||
const pathname = usePathname();
|
||||
@@ -27,6 +28,7 @@ const EventTypeAppCard: EventTypeAppCardComponent = function EventTypeAppCard({
|
||||
|
||||
return (
|
||||
<AppCard
|
||||
onAppInstallSuccess={onAppInstallSuccess}
|
||||
returnTo={`${WEBAPP_URL}${pathname}?tabName=apps`}
|
||||
app={app}
|
||||
switchChecked={enabled}
|
||||
|
||||
+2
-1
@@ -7,13 +7,14 @@ import { TextField } from "@calcom/ui/components/form";
|
||||
|
||||
import type { appDataSchema } from "../zod";
|
||||
|
||||
const EventTypeAppCard: EventTypeAppCardComponent = function EventTypeAppCard({ app, eventType }) {
|
||||
const EventTypeAppCard: EventTypeAppCardComponent = function EventTypeAppCard({ app, eventType, onAppInstallSuccess }) {
|
||||
const { getAppData, setAppData } = useAppContextWithSchema<typeof appDataSchema>();
|
||||
const trackingId = getAppData("trackingId");
|
||||
const [enabled, setEnabled] = useState(getAppData("enabled"));
|
||||
|
||||
return (
|
||||
<AppCard
|
||||
onAppInstallSuccess={onAppInstallSuccess}
|
||||
app={app}
|
||||
switchOnClick={(e) => {
|
||||
if (!e) {
|
||||
|
||||
+6
-1
@@ -6,13 +6,18 @@ import { Icon } from "@calcom/ui/components/icon";
|
||||
|
||||
import type { appDataSchema } from "../zod";
|
||||
|
||||
const EventTypeAppCard: EventTypeAppCardComponent = function EventTypeAppCard({ eventType, app }) {
|
||||
const EventTypeAppCard: EventTypeAppCardComponent = function EventTypeAppCard({
|
||||
eventType,
|
||||
app,
|
||||
onAppInstallSuccess,
|
||||
}) {
|
||||
const { getAppData, setAppData } = useAppContextWithSchema<typeof appDataSchema>();
|
||||
const isSunrise = getAppData("isSunrise");
|
||||
const { enabled, updateEnabled } = useIsAppEnabled(app);
|
||||
|
||||
return (
|
||||
<AppCard
|
||||
onAppInstallSuccess={onAppInstallSuccess}
|
||||
app={app}
|
||||
switchOnClick={(e) => {
|
||||
if (!e) {
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
// TODO: Generate this file automatically. This supposed to contain trpc-routes from all the apps automatically imported here and then exported.
|
||||
// Can't use this file right now as I am not able to figure out how to keep getting tRPC typesafety with merge calls done on already created router
|
||||
// Till that time import routers from each app directly to core.
|
||||
// import { Router } from "@trpc/server/dist/declarations/src/router";
|
||||
|
||||
export {};
|
||||
@@ -6,13 +6,14 @@ import { TextField } from "@calcom/ui/components/form";
|
||||
|
||||
import type { appDataSchema } from "../zod";
|
||||
|
||||
const EventTypeAppCard: EventTypeAppCardComponent = function EventTypeAppCard({ app, eventType }) {
|
||||
const EventTypeAppCard: EventTypeAppCardComponent = function EventTypeAppCard({ app, eventType, onAppInstallSuccess }) {
|
||||
const { getAppData, setAppData, disabled } = useAppContextWithSchema<typeof appDataSchema>();
|
||||
const siteId = getAppData("SITE_ID");
|
||||
const { enabled, updateEnabled } = useIsAppEnabled(app);
|
||||
|
||||
return (
|
||||
<AppCard
|
||||
onAppInstallSuccess={onAppInstallSuccess}
|
||||
app={app}
|
||||
switchOnClick={(e) => {
|
||||
updateEnabled(e);
|
||||
|
||||
Vendored
+1
@@ -65,6 +65,7 @@ export type EventTypeAppCardComponentProps = {
|
||||
URL: string;
|
||||
};
|
||||
app: EventTypeAppCardApp;
|
||||
onAppInstallSuccess: () => void;
|
||||
disabled?: boolean;
|
||||
LockedIcon?: JSX.Element | false;
|
||||
eventTypeFormMetadata?: z.infer<typeof EventTypeFormMetadataSchema>;
|
||||
|
||||
@@ -6,7 +6,11 @@ import { TextField } from "@calcom/ui/components/form";
|
||||
|
||||
import type { appDataSchema } from "../zod";
|
||||
|
||||
const EventTypeAppCard: EventTypeAppCardComponent = function EventTypeAppCard({ app, eventType }) {
|
||||
const EventTypeAppCard: EventTypeAppCardComponent = function EventTypeAppCard({
|
||||
app,
|
||||
eventType,
|
||||
onAppInstallSuccess,
|
||||
}) {
|
||||
const { getAppData, setAppData, disabled } = useAppContextWithSchema<typeof appDataSchema>();
|
||||
const siteId = getAppData("SITE_ID");
|
||||
const scriptURL = getAppData("SCRIPT_URL");
|
||||
@@ -14,6 +18,7 @@ const EventTypeAppCard: EventTypeAppCardComponent = function EventTypeAppCard({
|
||||
|
||||
return (
|
||||
<AppCard
|
||||
onAppInstallSuccess={onAppInstallSuccess}
|
||||
app={app}
|
||||
switchOnClick={(e) => {
|
||||
updateEnabled(e);
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
export { WipeMyCalActionButton } from "./wipeMyCalActionButton";
|
||||
@@ -5,13 +5,18 @@ import useIsAppEnabled from "@calcom/app-store/_utils/useIsAppEnabled";
|
||||
import type { EventTypeAppCardComponent } from "@calcom/app-store/types";
|
||||
import { WEBAPP_URL } from "@calcom/lib/constants";
|
||||
|
||||
const EventTypeAppCard: EventTypeAppCardComponent = function EventTypeAppCard({ app, eventType }) {
|
||||
const EventTypeAppCard: EventTypeAppCardComponent = function EventTypeAppCard({
|
||||
app,
|
||||
eventType,
|
||||
onAppInstallSuccess,
|
||||
}) {
|
||||
const pathname = usePathname();
|
||||
|
||||
const { enabled, updateEnabled } = useIsAppEnabled(app);
|
||||
|
||||
return (
|
||||
<AppCard
|
||||
onAppInstallSuccess={onAppInstallSuccess}
|
||||
returnTo={`${WEBAPP_URL}${pathname}?tabName=apps`}
|
||||
app={app}
|
||||
teamId={eventType.team?.id || undefined}
|
||||
|
||||
@@ -5,13 +5,18 @@ import useIsAppEnabled from "@calcom/app-store/_utils/useIsAppEnabled";
|
||||
import type { EventTypeAppCardComponent } from "@calcom/app-store/types";
|
||||
import { WEBAPP_URL } from "@calcom/lib/constants";
|
||||
|
||||
const EventTypeAppCard: EventTypeAppCardComponent = function EventTypeAppCard({ app, eventType }) {
|
||||
const EventTypeAppCard: EventTypeAppCardComponent = function EventTypeAppCard({
|
||||
app,
|
||||
eventType,
|
||||
onAppInstallSuccess,
|
||||
}) {
|
||||
const pathname = usePathname();
|
||||
|
||||
const { enabled, updateEnabled } = useIsAppEnabled(app);
|
||||
|
||||
return (
|
||||
<AppCard
|
||||
onAppInstallSuccess={onAppInstallSuccess}
|
||||
returnTo={`${WEBAPP_URL}${pathname}?tabName=apps`}
|
||||
app={app}
|
||||
teamId={eventType.team?.id || undefined}
|
||||
|
||||
@@ -25,6 +25,8 @@ export const EventAppsTab = ({ eventType }: { eventType: EventType }) => {
|
||||
teamId: eventType.team?.id || eventType.parent?.teamId,
|
||||
});
|
||||
|
||||
const utils = trpc.useUtils();
|
||||
|
||||
const formMethods = useFormContext<FormValues>();
|
||||
const installedApps =
|
||||
eventTypeApps?.items.filter((app) => app.userCredentialIds.length || app.teams.length) || [];
|
||||
@@ -41,6 +43,14 @@ export const EventAppsTab = ({ eventType }: { eventType: EventType }) => {
|
||||
const appsDisableProps = shouldLockDisableProps("apps", { simple: true });
|
||||
const lockedText = appsDisableProps.isLocked ? "locked" : "unlocked";
|
||||
|
||||
const handleAppInstallSuccess = (appId: string) => () => {
|
||||
utils.viewer.apps.appById.invalidate({ appId });
|
||||
utils.viewer.apps.integrations.invalidate({
|
||||
extendsFeature: "EventType",
|
||||
...(eventType.team?.id && { teamId: eventType.team.id }),
|
||||
});
|
||||
};
|
||||
|
||||
const appsWithTeamCredentials = eventTypeApps?.items.filter((app) => app.teams.length) || [];
|
||||
const cardsForAppsWithTeams = appsWithTeamCredentials.map((app) => {
|
||||
const appCards = [];
|
||||
@@ -58,6 +68,7 @@ export const EventAppsTab = ({ eventType }: { eventType: EventType }) => {
|
||||
app={app}
|
||||
eventType={eventType}
|
||||
eventTypeFormMetadata={eventTypeFormMetadata}
|
||||
onAppInstallSuccess={handleAppInstallSuccess(app.slug)}
|
||||
/>
|
||||
);
|
||||
}
|
||||
@@ -82,6 +93,7 @@ export const EventAppsTab = ({ eventType }: { eventType: EventType }) => {
|
||||
eventType={eventType}
|
||||
eventTypeFormMetadata={eventTypeFormMetadata}
|
||||
disabled={shouldLockDisableProps("apps").disabled}
|
||||
onAppInstallSuccess={handleAppInstallSuccess(app.slug)}
|
||||
/>
|
||||
);
|
||||
}
|
||||
@@ -147,6 +159,7 @@ export const EventAppsTab = ({ eventType }: { eventType: EventType }) => {
|
||||
app={app}
|
||||
eventType={eventType}
|
||||
eventTypeFormMetadata={eventTypeFormMetadata}
|
||||
onAppInstallSuccess={handleAppInstallSuccess(app.slug)}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
@@ -180,6 +193,7 @@ export const EventAppsTab = ({ eventType }: { eventType: EventType }) => {
|
||||
app={app}
|
||||
eventType={eventType}
|
||||
eventTypeFormMetadata={eventTypeFormMetadata}
|
||||
onAppInstallSuccess={handleAppInstallSuccess(app.slug)}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
|
||||
@@ -10,7 +10,6 @@ import { getSerializableForm } from "@calcom/app-store/routing-forms/lib/getSeri
|
||||
import { handleResponse } from "@calcom/app-store/routing-forms/lib/handleResponse";
|
||||
import { findMatchingRoute } from "@calcom/app-store/routing-forms/lib/processRoute";
|
||||
import { substituteVariables } from "@calcom/app-store/routing-forms/lib/substituteVariables";
|
||||
import { getUrlSearchParamsToForward } from "@calcom/app-store/routing-forms/pages/routing-link/getUrlSearchParamsToForward";
|
||||
import { orgDomainConfig } from "@calcom/features/ee/organizations/lib/orgDomains";
|
||||
import { isAuthorizedToViewFormOnOrgDomain } from "@calcom/features/routing-forms/lib/isAuthorizedToViewForm";
|
||||
import { checkRateLimitAndThrowError } from "@calcom/lib/checkRateLimitAndThrowError";
|
||||
@@ -18,8 +17,10 @@ import { PrismaRoutingFormRepository } from "@calcom/lib/server/repository/Prism
|
||||
import { UserRepository } from "@calcom/lib/server/repository/user";
|
||||
|
||||
import { getRoutedUrl } from "./getRoutedUrl";
|
||||
import { getUrlSearchParamsToForward } from "./getUrlSearchParamsToForward";
|
||||
|
||||
// Mock dependencies
|
||||
vi.mock("./getUrlSearchParamsToForward");
|
||||
vi.mock("@calcom/lib/checkRateLimitAndThrowError");
|
||||
vi.mock("@calcom/app-store/routing-forms/lib/handleResponse");
|
||||
vi.mock("@calcom/lib/server/repository/PrismaRoutingFormRepository");
|
||||
@@ -36,7 +37,6 @@ vi.mock("@calcom/app-store/routing-forms/lib/getSerializableForm");
|
||||
vi.mock("@calcom/app-store/routing-forms/lib/getResponseToStore");
|
||||
vi.mock("@calcom/app-store/routing-forms/lib/processRoute");
|
||||
vi.mock("@calcom/app-store/routing-forms/lib/substituteVariables");
|
||||
vi.mock("@calcom/app-store/routing-forms/pages/routing-link/getUrlSearchParamsToForward");
|
||||
vi.mock("@calcom/app-store/routing-forms/getEventTypeRedirectUrl");
|
||||
vi.mock("@calcom/app-store/routing-forms/enrichFormWithMigrationData", () => ({
|
||||
enrichFormWithMigrationData: vi.fn((form) => form),
|
||||
|
||||
@@ -13,7 +13,6 @@ import { getServerTimingHeader } from "@calcom/app-store/routing-forms/lib/getSe
|
||||
import { handleResponse } from "@calcom/app-store/routing-forms/lib/handleResponse";
|
||||
import { findMatchingRoute } from "@calcom/app-store/routing-forms/lib/processRoute";
|
||||
import { substituteVariables } from "@calcom/app-store/routing-forms/lib/substituteVariables";
|
||||
import { getUrlSearchParamsToForward } from "@calcom/app-store/routing-forms/pages/routing-link/getUrlSearchParamsToForward";
|
||||
import type { FormResponse } from "@calcom/app-store/routing-forms/types/types";
|
||||
import { orgDomainConfig } from "@calcom/features/ee/organizations/lib/orgDomains";
|
||||
import { isAuthorizedToViewFormOnOrgDomain } from "@calcom/features/routing-forms/lib/isAuthorizedToViewForm";
|
||||
@@ -27,6 +26,8 @@ import prisma from "@calcom/prisma";
|
||||
|
||||
import { TRPCError } from "@trpc/server";
|
||||
|
||||
import { getUrlSearchParamsToForward } from "./getUrlSearchParamsToForward";
|
||||
|
||||
const log = logger.getSubLogger({ prefix: ["[routing-forms]", "[router]"] });
|
||||
const querySchema = z
|
||||
.object({
|
||||
|
||||
+14
-11
@@ -1,12 +1,9 @@
|
||||
import type { inferSSRProps } from "@calcom/types/inferSSRProps";
|
||||
|
||||
import { ROUTING_FORM_RESPONSE_ID_QUERY_STRING } from "../../lib/constants";
|
||||
import getFieldIdentifier from "../../lib/getFieldIdentifier";
|
||||
import type { FormResponse, LocalRoute } from "../../types/types";
|
||||
import type { getServerSideProps } from "./getServerSideProps";
|
||||
import { ROUTING_FORM_RESPONSE_ID_QUERY_STRING } from "@calcom/app-store/routing-forms/lib/constants";
|
||||
import getFieldIdentifier from "@calcom/app-store/routing-forms/lib/getFieldIdentifier";
|
||||
import type { FormResponse, LocalRoute } from "@calcom/app-store/routing-forms/types/types";
|
||||
|
||||
type FormResponseValueOnly = { [key: string]: { value: FormResponse[keyof FormResponse]["value"] } };
|
||||
type Props = inferSSRProps<typeof getServerSideProps>;
|
||||
|
||||
type AttributeRoutingConfig = NonNullable<LocalRoute["attributeRoutingConfig"]>;
|
||||
type GetUrlSearchParamsToForwardOptions = {
|
||||
formResponse: Record<
|
||||
@@ -15,10 +12,16 @@ type GetUrlSearchParamsToForwardOptions = {
|
||||
value: number | string | string[];
|
||||
}
|
||||
>;
|
||||
fields: Pick<
|
||||
NonNullable<Props["form"]["fields"]>[number],
|
||||
"id" | "type" | "options" | "identifier" | "label"
|
||||
>[];
|
||||
fields: {
|
||||
id: string;
|
||||
type: string;
|
||||
label: string;
|
||||
options?: {
|
||||
id: string | null;
|
||||
label: string;
|
||||
}[];
|
||||
identifier?: string;
|
||||
}[];
|
||||
searchParams: URLSearchParams;
|
||||
formResponseId: number | null;
|
||||
queuedFormResponseId: string | null;
|
||||
@@ -18,7 +18,6 @@ const validators = {
|
||||
};
|
||||
|
||||
export const handleCustomValidations = async ({
|
||||
ctx,
|
||||
input,
|
||||
appId,
|
||||
}: UpdateAppCredentialsOptions & { appId: string }) => {
|
||||
@@ -28,7 +27,7 @@ export const handleCustomValidations = async ({
|
||||
if (!validatorGetter) return key;
|
||||
try {
|
||||
const validator = (await validatorGetter()).default;
|
||||
return await validator({ input, ctx });
|
||||
return await validator({ input });
|
||||
} catch (error) {
|
||||
throw new TRPCError({
|
||||
code: "BAD_REQUEST",
|
||||
|
||||
+1
-1
@@ -7,7 +7,7 @@ import type { ServerResponse } from "http";
|
||||
import type { NextApiResponse } from "next";
|
||||
|
||||
import { enrichFormWithMigrationData } from "@calcom/app-store/routing-forms/enrichFormWithMigrationData";
|
||||
import { getUrlSearchParamsToForwardForTestPreview } from "@calcom/app-store/routing-forms/pages/routing-link/getUrlSearchParamsToForward";
|
||||
import { getUrlSearchParamsToForwardForTestPreview } from "@calcom/features/routing-forms/lib/getUrlSearchParamsToForward";
|
||||
import { enrichHostsWithDelegationCredentials } from "@calcom/lib/delegationCredential/server";
|
||||
import { getLuckyUserService } from "@calcom/lib/di/containers/LuckyUser";
|
||||
import { entityPrismaWhereClause } from "@calcom/lib/entityPermissionUtils.server";
|
||||
|
||||
Reference in New Issue
Block a user