diff --git a/packages/app-store/apps.browser.generated.tsx b/packages/app-store/apps.browser.generated.tsx index 0da82056e8..dd1eae9805 100644 --- a/packages/app-store/apps.browser.generated.tsx +++ b/packages/app-store/apps.browser.generated.tsx @@ -19,6 +19,7 @@ export const InstallAppButtonMap = { larkcalendar: dynamic(() => import("./larkcalendar/components/InstallAppButton")), office365calendar: dynamic(() => import("./office365calendar/components/InstallAppButton")), office365video: dynamic(() => import("./office365video/components/InstallAppButton")), + plausible: dynamic(() => import("./plausible/components/InstallAppButton")), riverside: dynamic(() => import("./riverside/components/InstallAppButton")), tandemvideo: dynamic(() => import("./tandemvideo/components/InstallAppButton")), vital: dynamic(() => import("./vital/components/InstallAppButton")), @@ -35,6 +36,7 @@ export const EventTypeAddonMap = { fathom: dynamic(() => import("./fathom/extensions/EventTypeAppCard")), ga4: dynamic(() => import("./ga4/extensions/EventTypeAppCard")), giphy: dynamic(() => import("./giphy/extensions/EventTypeAppCard")), + plausible: dynamic(() => import("./plausible/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 7d8bb53464..1cc1b00518 100644 --- a/packages/app-store/apps.metadata.generated.ts +++ b/packages/app-store/apps.metadata.generated.ts @@ -26,6 +26,7 @@ import { metadata as office365calendar_meta } from "./office365calendar/_metadat import { metadata as office365video_meta } from "./office365video/_metadata"; import { metadata as ping_meta } from "./ping/_metadata"; import { metadata as pipedream_meta } from "./pipedream/_metadata"; +import { metadata as plausible_meta } from "./plausible/_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"; @@ -72,6 +73,7 @@ export const appStoreMetadata = { office365video: office365video_meta, ping: ping_meta, pipedream: pipedream_meta, + plausible: plausible_meta, qr_code: qr_code_meta, rainbow: rainbow_meta, raycast: raycast_meta, diff --git a/packages/app-store/apps.schemas.generated.ts b/packages/app-store/apps.schemas.generated.ts index 8052328221..e0d145f1b6 100644 --- a/packages/app-store/apps.schemas.generated.ts +++ b/packages/app-store/apps.schemas.generated.ts @@ -6,6 +6,7 @@ import { appDataSchema as routing_forms_schema } from "./ee/routing-forms/zod"; import { appDataSchema as fathom_schema } from "./fathom/zod"; import { appDataSchema as ga4_schema } from "./ga4/zod"; import { appDataSchema as giphy_schema } from "./giphy/zod"; +import { appDataSchema as plausible_schema } from "./plausible/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"; @@ -16,6 +17,7 @@ export const appDataSchemas = { fathom: fathom_schema, ga4: ga4_schema, giphy: giphy_schema, + plausible: plausible_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 7a9c2d08c3..1bd44d031f 100644 --- a/packages/app-store/apps.server.generated.ts +++ b/packages/app-store/apps.server.generated.ts @@ -25,6 +25,7 @@ export const apiHandlers = { office365video: import("./office365video/api"), ping: import("./ping/api"), pipedream: import("./pipedream/api"), + plausible: import("./plausible/api"), qr_code: import("./qr_code/api"), rainbow: import("./rainbow/api"), raycast: import("./raycast/api"), diff --git a/packages/app-store/eventTypeAnalytics.ts b/packages/app-store/eventTypeAnalytics.ts index d76be86d8e..58ff75b599 100644 --- a/packages/app-store/eventTypeAnalytics.ts +++ b/packages/app-store/eventTypeAnalytics.ts @@ -21,6 +21,17 @@ export const trackingApps: Partial< }, ], }, + plausible: { + scripts: [ + { + src: "https://plausible.io/js/script.js", + content: undefined, + attrs: { + "data-domain": "{TRACKED_DOMAIN}", + }, + }, + ], + }, ga4: { scripts: [ { diff --git a/packages/app-store/index.ts b/packages/app-store/index.ts index 6c678cd4f9..0d8277a07c 100644 --- a/packages/app-store/index.ts +++ b/packages/app-store/index.ts @@ -15,6 +15,7 @@ import * as jitsivideo from "./jitsivideo"; import * as larkcalendar from "./larkcalendar"; import * as office365calendar from "./office365calendar"; import * as office365video from "./office365video"; +import * as plausible from "./plausible"; import * as salesforce from "./salesforce"; import * as sendgrid from "./sendgrid"; import * as stripepayment from "./stripepayment"; @@ -38,6 +39,7 @@ const appStore = { larkcalendar, office365calendar, office365video, + plausible, salesforce, sendgrid, stripepayment, diff --git a/packages/app-store/plausible/README.mdx b/packages/app-store/plausible/README.mdx new file mode 100644 index 0000000000..b69e4ce790 --- /dev/null +++ b/packages/app-store/plausible/README.mdx @@ -0,0 +1,8 @@ +--- +items: + - /api/app-store/plausible/1.jpg +--- + +Simple, privacy-friendly Google Analytics alternative. + +Use the Plausible app to track analytics of your bookings. diff --git a/packages/app-store/plausible/_metadata.ts b/packages/app-store/plausible/_metadata.ts new file mode 100644 index 0000000000..f8e160d47d --- /dev/null +++ b/packages/app-store/plausible/_metadata.ts @@ -0,0 +1,10 @@ +import type { AppMeta } from "@calcom/types/App"; + +import config from "./config.json"; + +export const metadata = { + category: "analytics", + ...config, +} as AppMeta; + +export default metadata; diff --git a/packages/app-store/plausible/api/add.ts b/packages/app-store/plausible/api/add.ts new file mode 100644 index 0000000000..45c6741f36 --- /dev/null +++ b/packages/app-store/plausible/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/plausible/api/index.ts b/packages/app-store/plausible/api/index.ts new file mode 100644 index 0000000000..4c0d2ead01 --- /dev/null +++ b/packages/app-store/plausible/api/index.ts @@ -0,0 +1 @@ +export { default as add } from "./add"; diff --git a/packages/app-store/plausible/components/.gitkeep b/packages/app-store/plausible/components/.gitkeep new file mode 100644 index 0000000000..e69de29bb2 diff --git a/packages/app-store/plausible/components/InstallAppButton.tsx b/packages/app-store/plausible/components/InstallAppButton.tsx new file mode 100644 index 0000000000..f31f3988e0 --- /dev/null +++ b/packages/app-store/plausible/components/InstallAppButton.tsx @@ -0,0 +1,18 @@ +import type { InstallAppButtonProps } from "@calcom/app-store/types"; + +import useAddAppMutation from "../../_utils/useAddAppMutation"; + +export default function InstallAppButton(props: InstallAppButtonProps) { + const mutation = useAddAppMutation("plausible_analytics"); + + return ( + <> + {props.render({ + onClick() { + mutation.mutate(""); + }, + loading: mutation.isLoading, + })} + + ); +} diff --git a/packages/app-store/plausible/components/index.ts b/packages/app-store/plausible/components/index.ts new file mode 100644 index 0000000000..0d6008d4ca --- /dev/null +++ b/packages/app-store/plausible/components/index.ts @@ -0,0 +1 @@ +export { default as InstallAppButton } from "./InstallAppButton"; diff --git a/packages/app-store/plausible/config.json b/packages/app-store/plausible/config.json new file mode 100644 index 0000000000..f514b7172c --- /dev/null +++ b/packages/app-store/plausible/config.json @@ -0,0 +1,16 @@ +{ + "/*": "Don't modify slug - If required, do it using cli edit command", + "name": "Plausible", + "slug": "plausible", + "type": "plausible_analytics", + "imageSrc": "/api/app-store/plausible/icon.svg", + "logo": "/api/app-store/plausible/icon.svg", + "url": "https://cal.com/apps/plausible", + "variant": "analytics", + "categories": ["analytics"], + "publisher": "Cal.com, Inc.", + "email": "help@cal.com", + "extendsFeature": "EventType", + "description": "Simple, privacy-friendly Google Analytics alternative.", + "__createdUsingCli": true +} diff --git a/packages/app-store/plausible/extensions/EventTypeAppCard.tsx b/packages/app-store/plausible/extensions/EventTypeAppCard.tsx new file mode 100644 index 0000000000..38f09c5f86 --- /dev/null +++ b/packages/app-store/plausible/extensions/EventTypeAppCard.tsx @@ -0,0 +1,38 @@ +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 { TextField } from "@calcom/ui"; + +import { appDataSchema } from "../zod"; + +const EventTypeAppCard: EventTypeAppCardComponent = function EventTypeAppCard({ app }) { + const [getAppData, setAppData] = useAppContextWithSchema(); + const trackedDomain = getAppData("trackedDomain"); + const [enabled, setEnabled] = useState(getAppData("enabled")); + + return ( + { + if (!e) { + setEnabled(false); + } else { + setEnabled(true); + } + }} + switchChecked={enabled}> + { + setAppData("trackedDomain", e.target.value); + }} + /> + + ); +}; + +export default EventTypeAppCard; diff --git a/packages/app-store/plausible/index.ts b/packages/app-store/plausible/index.ts new file mode 100644 index 0000000000..5d372ceda3 --- /dev/null +++ b/packages/app-store/plausible/index.ts @@ -0,0 +1,2 @@ +export * as api from "./api"; +export { metadata } from "./_metadata"; diff --git a/packages/app-store/plausible/package.json b/packages/app-store/plausible/package.json new file mode 100644 index 0000000000..2f57f2fd12 --- /dev/null +++ b/packages/app-store/plausible/package.json @@ -0,0 +1,14 @@ +{ + "$schema": "https://json.schemastore.org/package.json", + "private": true, + "name": "@calcom/plausible", + "version": "0.0.0", + "main": "./index.ts", + "description": "Simple, privacy-friendly Google Analytics alternative.", + "dependencies": { + "@calcom/lib": "*" + }, + "devDependencies": { + "@calcom/types": "*" + } +} diff --git a/packages/app-store/plausible/static/1.jpg b/packages/app-store/plausible/static/1.jpg new file mode 100644 index 0000000000..859baf341d Binary files /dev/null and b/packages/app-store/plausible/static/1.jpg differ diff --git a/packages/app-store/plausible/static/icon.svg b/packages/app-store/plausible/static/icon.svg new file mode 100644 index 0000000000..05eac3f650 --- /dev/null +++ b/packages/app-store/plausible/static/icon.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/packages/app-store/plausible/zod.ts b/packages/app-store/plausible/zod.ts new file mode 100644 index 0000000000..5d99948edc --- /dev/null +++ b/packages/app-store/plausible/zod.ts @@ -0,0 +1,9 @@ +import { z } from "zod"; + +import { eventTypeAppCardZod } from "../eventTypeAppCardZod"; + +export const appDataSchema = eventTypeAppCardZod.merge( + z.object({ + trackedDomain: z.string(), + }) +); diff --git a/packages/prisma/seed-app-store.config.json b/packages/prisma/seed-app-store.config.json index 9abb2a0bee..2d9e156f39 100644 --- a/packages/prisma/seed-app-store.config.json +++ b/packages/prisma/seed-app-store.config.json @@ -84,6 +84,12 @@ "slug": "fathom", "type": "fathom_analytics" }, + { + "dirName": "plausible", + "categories": ["analytics"], + "slug": "plausible", + "type": "plausible_analytics" + }, { "dirName": "wordpress", "categories": ["other"],