diff --git a/apps/web/components/v2/eventtype/EventAppsTab.tsx b/apps/web/components/v2/eventtype/EventAppsTab.tsx index eea8a134da..f1bed4a23f 100644 --- a/apps/web/components/v2/eventtype/EventAppsTab.tsx +++ b/apps/web/components/v2/eventtype/EventAppsTab.tsx @@ -4,6 +4,7 @@ import { useFormContext } from "react-hook-form"; import EventTypeAppContext, { GetAppData, SetAppData } from "@calcom/app-store/EventTypeAppContext"; import { EventTypeAddonMap } from "@calcom/app-store/apps.browser.generated"; +import { EventTypeAppCardComponentProps } from "@calcom/app-store/types"; import { EventTypeAppsList } from "@calcom/app-store/utils"; import { useLocale } from "@calcom/lib/hooks/useLocale"; import { inferQueryOutput, trpc } from "@calcom/trpc/react"; @@ -11,7 +12,9 @@ import { Icon } from "@calcom/ui"; import ErrorBoundary from "@calcom/ui/ErrorBoundary"; import { Button, EmptyScreen } from "@calcom/ui/v2"; -type EventType = Pick["eventType"]; +type EventType = Pick["eventType"] & + EventTypeAppCardComponentProps["eventType"]; + function AppCardWrapper({ app, eventType, diff --git a/apps/web/pages/event-types/[type]/index.tsx b/apps/web/pages/event-types/[type]/index.tsx index 31a87a9966..810bd62a74 100644 --- a/apps/web/pages/event-types/[type]/index.tsx +++ b/apps/web/pages/event-types/[type]/index.tsx @@ -178,6 +178,10 @@ const EventTypePage = (props: inferSSRProps) => { ).length; } + const permalink = `${CAL_URL}/${team ? `team/${team.slug}` : eventType.users[0].username}/${ + eventType.slug + }`; + const tabMap = { setup: ( ) => { limits: , advanced: , recurring: , - apps: , + apps: , workflows: ( ; }) { + const animationRef = useRef(null); + + useEffect(() => { + animationRef.current && autoAnimate(animationRef.current); + }, [animationRef]); + return ( -
+
{/* Don't know why but w-[42px] isn't working, started happening when I started using next/dynamic */} diff --git a/packages/app-store/apps.browser.generated.tsx b/packages/app-store/apps.browser.generated.tsx index 9dc13e45f4..da2438ae1b 100644 --- a/packages/app-store/apps.browser.generated.tsx +++ b/packages/app-store/apps.browser.generated.tsx @@ -36,6 +36,7 @@ export const AppSettingsComponentsMap = { export const EventTypeAddonMap = { fathom: dynamic(() => import("./fathom/extensions/EventTypeAppCard")), giphy: dynamic(() => import("./giphy/extensions/EventTypeAppCard")), + qr_code: dynamic(() => import("./qr_code/extensions/EventTypeAppCard")), rainbow: dynamic(() => import("./rainbow/extensions/EventTypeAppCard")), stripepayment: dynamic(() => import("./stripepayment/extensions/EventTypeAppCard")), }; diff --git a/packages/app-store/apps.metadata.generated.ts b/packages/app-store/apps.metadata.generated.ts index 5b0f9f52e6..e2163cb2ed 100644 --- a/packages/app-store/apps.metadata.generated.ts +++ b/packages/app-store/apps.metadata.generated.ts @@ -24,6 +24,7 @@ import { metadata as n8n_meta } from "./n8n/_metadata"; import { metadata as office365calendar_meta } from "./office365calendar/_metadata"; import { metadata as office365video_meta } from "./office365video/_metadata"; import { metadata as ping_meta } from "./ping/_metadata"; +import { metadata as qr_code_meta } from "./qr_code/_metadata"; import { metadata as rainbow_meta } from "./rainbow/_metadata"; import { metadata as raycast_meta } from "./raycast/_metadata"; import { metadata as riverside_meta } from "./riverside/_metadata"; @@ -61,6 +62,7 @@ export const appStoreMetadata = { office365calendar: office365calendar_meta, office365video: office365video_meta, ping: ping_meta, + qr_code: qr_code_meta, rainbow: rainbow_meta, raycast: raycast_meta, riverside: riverside_meta, diff --git a/packages/app-store/apps.schemas.generated.ts b/packages/app-store/apps.schemas.generated.ts index f447ee4d48..87aa18b16c 100644 --- a/packages/app-store/apps.schemas.generated.ts +++ b/packages/app-store/apps.schemas.generated.ts @@ -5,6 +5,7 @@ import { appDataSchema as routing_forms_schema } from "./ee/routing-forms/zod"; import { appDataSchema as fathom_schema } from "./fathom/zod"; import { appDataSchema as giphy_schema } from "./giphy/zod"; +import { appDataSchema as qr_code_schema } from "./qr_code/zod"; import { appDataSchema as rainbow_schema } from "./rainbow/zod"; import { appDataSchema as stripepayment_schema } from "./stripepayment/zod"; @@ -12,6 +13,7 @@ export const appDataSchemas = { "routing-forms": routing_forms_schema, fathom: fathom_schema, giphy: giphy_schema, + qr_code: qr_code_schema, rainbow: rainbow_schema, stripe: stripepayment_schema, }; diff --git a/packages/app-store/apps.server.generated.ts b/packages/app-store/apps.server.generated.ts index 5185c648d5..519c8884d0 100644 --- a/packages/app-store/apps.server.generated.ts +++ b/packages/app-store/apps.server.generated.ts @@ -23,6 +23,7 @@ export const apiHandlers = { office365calendar: import("./office365calendar/api"), office365video: import("./office365video/api"), ping: import("./ping/api"), + qr_code: import("./qr_code/api"), rainbow: import("./rainbow/api"), raycast: import("./raycast/api"), riverside: import("./riverside/api"), diff --git a/packages/app-store/qr_code/README.mdx b/packages/app-store/qr_code/README.mdx new file mode 100644 index 0000000000..36e9b75060 --- /dev/null +++ b/packages/app-store/qr_code/README.mdx @@ -0,0 +1,5 @@ +--- +description: Easily generate a QR code for your links to print, share, or embed. +--- + +{description} diff --git a/packages/app-store/qr_code/_metadata.ts b/packages/app-store/qr_code/_metadata.ts new file mode 100644 index 0000000000..9c7f2aa320 --- /dev/null +++ b/packages/app-store/qr_code/_metadata.ts @@ -0,0 +1,10 @@ +import type { AppMeta } from "@calcom/types/App"; + +import config from "./config.json"; + +export const metadata = { + category: "other", + ...config, +} as AppMeta; + +export default metadata; diff --git a/packages/app-store/qr_code/api/add.ts b/packages/app-store/qr_code/api/add.ts new file mode 100644 index 0000000000..45c6741f36 --- /dev/null +++ b/packages/app-store/qr_code/api/add.ts @@ -0,0 +1,17 @@ +import { AppDeclarativeHandler } from "@calcom/types/AppHandler"; + +import { createDefaultInstallation } from "../../_utils/installation"; +import appConfig from "../config.json"; + +const handler: AppDeclarativeHandler = { + // Instead of passing appType and slug from here, api/integrations/[..args] should be able to derive and pass these directly to createCredential + appType: appConfig.type, + variant: appConfig.variant, + slug: appConfig.slug, + supportsMultipleInstalls: false, + handlerType: "add", + createCredential: ({ appType, user, slug }) => + createDefaultInstallation({ appType, userId: user.id, slug, key: {} }), +}; + +export default handler; diff --git a/packages/app-store/qr_code/api/index.ts b/packages/app-store/qr_code/api/index.ts new file mode 100644 index 0000000000..4c0d2ead01 --- /dev/null +++ b/packages/app-store/qr_code/api/index.ts @@ -0,0 +1 @@ +export { default as add } from "./add"; diff --git a/packages/app-store/qr_code/components/.gitkeep b/packages/app-store/qr_code/components/.gitkeep new file mode 100644 index 0000000000..e69de29bb2 diff --git a/packages/app-store/qr_code/config.json b/packages/app-store/qr_code/config.json new file mode 100644 index 0000000000..1237f6e180 --- /dev/null +++ b/packages/app-store/qr_code/config.json @@ -0,0 +1,16 @@ +{ + "/*": "Don't modify slug - If required, do it using cli edit command", + "name": "QR Code", + "slug": "qr_code", + "type": "qr_code_other", + "imageSrc": "/api/app-store/qr_code/icon.svg", + "logo": "/api/app-store/qr_code/icon.svg", + "url": "https://cal.com/apps/qr_code", + "variant": "other", + "categories": ["other"], + "extendsFeature": "EventType", + "publisher": "Cal.com, Inc.", + "email": "support@cal.com", + "description": "Easily generate a QR code for your links to print, share, or embed.", + "__createdUsingCli": true +} diff --git a/packages/app-store/qr_code/extensions/EventTypeAppCard.tsx b/packages/app-store/qr_code/extensions/EventTypeAppCard.tsx new file mode 100644 index 0000000000..81bbb6fdea --- /dev/null +++ b/packages/app-store/qr_code/extensions/EventTypeAppCard.tsx @@ -0,0 +1,54 @@ +import { useState } from "react"; + +import { useAppContextWithSchema } from "@calcom/app-store/EventTypeAppContext"; +import AppCard from "@calcom/app-store/_components/AppCard"; +import type { EventTypeAppCardComponent } from "@calcom/app-store/types"; +import { Tooltip } from "@calcom/ui/v2"; + +import { appDataSchema } from "../zod"; + +const EventTypeAppCard: EventTypeAppCardComponent = function EventTypeAppCard({ eventType, app }) { + const [getAppData, setAppData] = useAppContextWithSchema(); + const [enabled, setEnabled] = useState(getAppData("enabled")); + + const eventTypeURL = eventType.URL; + + function QRCode({ size, data }: { size: number; data: string }) { + const QR_URL = "https://api.qrserver.com/v1/create-qr-code/?size=" + size + "&data=" + data; + return ( + + + {eventTypeURL} + + + ); + } + + return ( + { + if (!e) { + setEnabled(false); + } else { + setEnabled(true); + } + }} + switchChecked={enabled}> +
+ + + +
+
+ ); +}; + +export default EventTypeAppCard; diff --git a/packages/app-store/qr_code/index.ts b/packages/app-store/qr_code/index.ts new file mode 100644 index 0000000000..5d372ceda3 --- /dev/null +++ b/packages/app-store/qr_code/index.ts @@ -0,0 +1,2 @@ +export * as api from "./api"; +export { metadata } from "./_metadata"; diff --git a/packages/app-store/qr_code/package.json b/packages/app-store/qr_code/package.json new file mode 100644 index 0000000000..d2a6d7f37d --- /dev/null +++ b/packages/app-store/qr_code/package.json @@ -0,0 +1,14 @@ +{ + "$schema": "https://json.schemastore.org/package.json", + "private": true, + "name": "@calcom/qr_code", + "version": "0.0.0", + "main": "./index.ts", + "description": "Easily generate a QR code of your links", + "dependencies": { + "@calcom/lib": "*" + }, + "devDependencies": { + "@calcom/types": "*" + } +} diff --git a/packages/app-store/qr_code/static/icon.svg b/packages/app-store/qr_code/static/icon.svg new file mode 100644 index 0000000000..5471edbac1 --- /dev/null +++ b/packages/app-store/qr_code/static/icon.svg @@ -0,0 +1,244 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/packages/app-store/qr_code/zod.ts b/packages/app-store/qr_code/zod.ts new file mode 100644 index 0000000000..48f9750401 --- /dev/null +++ b/packages/app-store/qr_code/zod.ts @@ -0,0 +1,3 @@ +import { eventTypeAppCardZod } from "../eventTypeAppCardZod"; + +export const appDataSchema = eventTypeAppCardZod; diff --git a/packages/app-store/types.d.ts b/packages/app-store/types.d.ts index 779de6d52b..ba281b498a 100644 --- a/packages/app-store/types.d.ts +++ b/packages/app-store/types.d.ts @@ -22,9 +22,14 @@ export interface InstallAppButtonProps { ) => JSX.Element; onChanged?: () => unknown; } - -export type EventTypeAppCardComponent = React.FC<{ +export type EventTypeAppCardComponentProps = { // Limit what data should be accessible to apps - eventType: Pick, "id", "title" | "description" | "teamId" | "length">; + eventType: Pick< + z.infer, + "id" | "title" | "description" | "teamId" | "length" | "recurringEvent" + > & { + URL: string; + }; app: inferQueryOutput<"viewer.apps">[number]; -}>; +}; +export type EventTypeAppCardComponent = React.FC; diff --git a/packages/prisma/seed-app-store.config.json b/packages/prisma/seed-app-store.config.json index 8cfd8ee8b3..11f30ee3e1 100644 --- a/packages/prisma/seed-app-store.config.json +++ b/packages/prisma/seed-app-store.config.json @@ -88,6 +88,12 @@ "slug": "exchange", "type": "exchange_calendar" }, + { + "dirName": "qr_code", + "categories": ["other"], + "slug": "qr_code", + "type": "qr_code_other" + }, { "dirName": "weather_in_your_calendar", "categories": ["other"], diff --git a/packages/prisma/zod/webhook.ts b/packages/prisma/zod/webhook.ts index 82ad655492..5341972772 100755 --- a/packages/prisma/zod/webhook.ts +++ b/packages/prisma/zod/webhook.ts @@ -7,7 +7,7 @@ export const _WebhookModel = z.object({ id: z.string(), userId: z.number().int().nullish(), eventTypeId: z.number().int().nullish(), - subscriberUrl: z.string(), + subscriberUrl: z.string().url(), payloadTemplate: z.string().nullish(), createdAt: z.date(), active: z.boolean(),