feat: Implement Dub.co for conversion tracking (#16165)

* FEAT: Implement Dub.co for conversion tracking

* add link creation, @vercel/functions

* use refer.cal.com/:username instead of go.cal.com/r/:username

* sale conversion tracking

* add copy referral link

* limit to IS_CALCOM only

* Update yarn.lock

* fix DubAnalytics

* use workaround for isNewUser

* pass req to getOptions

* Update next-auth-options.ts

* fix ts errors

* only show DubAnalytics outside EU

* add Dub Analytics to /signup

* use WEBSITE_URL instead

* on-demand generate links

* add migration

* add check for existing link + change fetch method to poast

* remove refer.cal.com from PoweredByCal

* limit DubAnalytics to /signup only

* simplify generate-referral-link

* restore yarn.lock

* add yarn with dub sdk in

* add yarn with dub sdk in

* yarn

* Update yarn.lock

---------

Co-authored-by: sean <sean@brydon.io>
Co-authored-by: Peer Richelsen <peer@cal.com>
This commit is contained in:
authored and GitHub committed 2024-09-12 12:33:10 -07:00
1 parent f4bc7d2ea4
commit cf16cd3ed2
49 files changed
+1548 -120

No files matched your search

+1
View File
@@ -215,6 +215,7 @@ const generateTeamCheckoutSession = async ({
metadata: {
pendingPaymentTeamId,
ownerId,
dubCustomerId: ownerId, // pass the userId during checkout creation for sales conversion tracking: https://d.to/conversions/stripe
},
});
@@ -1,10 +1,9 @@
import type { PageProps } from "app/_types";
import { _generateMetadata } from "app/_utils";
import { WithLayout } from "app/layoutHOC";
import { getServerSession } from "next-auth";
import { notFound } from "next/navigation";
import { AUTH_OPTIONS } from "@calcom/features/auth/lib/next-auth-options";
import { getServerSessionForAppDir } from "@calcom/feature-auth/lib/get-server-session-for-app-dir";
import { ScheduleRepository } from "@calcom/lib/server/repository/schedule";
import { TravelScheduleRepository } from "@calcom/lib/server/repository/travelSchedule";
import { UserRepository } from "@calcom/lib/server/repository/user";
@@ -34,7 +33,7 @@ const Page = async ({ params }: PageProps) => {
}
const scheduleId = Number(params.schedule);
const session = await getServerSession(AUTH_OPTIONS);
const session = await getServerSessionForAppDir();
const userId = session?.user?.id;
if (!userId) {
notFound();
+2 -3
View File
@@ -1,9 +1,8 @@
import { _generateMetadata } from "app/_utils";
import { WithLayout } from "app/layoutHOC";
import { getServerSession } from "next-auth";
import { notFound } from "next/navigation";
import { AUTH_OPTIONS } from "@calcom/features/auth/lib/next-auth-options";
import { getServerSessionForAppDir } from "@calcom/feature-auth/lib/get-server-session-for-app-dir";
import { OrganizationRepository } from "@calcom/lib/server/repository/organization";
import AvailabilityPage from "~/availability/availability-view";
@@ -16,7 +15,7 @@ export const generateMetadata = async () => {
};
const Page = async () => {
const session = await getServerSession(AUTH_OPTIONS);
const session = await getServerSessionForAppDir();
const userId = session?.user?.id;
const orgId = session?.user?.org?.id;
if (!userId || !orgId) {
@@ -1,8 +1,7 @@
import { _generateMetadata } from "app/_utils";
import { getFixedT } from "app/_utils";
import { getServerSession } from "next-auth";
import { AUTH_OPTIONS } from "@calcom/feature-auth/lib/next-auth-options";
import { getServerSessionForAppDir } from "@calcom/feature-auth/lib/get-server-session-for-app-dir";
import AdminAppsList from "@calcom/features/apps/AdminAppsList";
import SettingsHeader from "@calcom/features/settings/appDir/SettingsHeader";
@@ -13,7 +12,7 @@ export const generateMetadata = async () =>
);
const Page = async () => {
const session = await getServerSession(AUTH_OPTIONS);
const session = await getServerSessionForAppDir();
const t = await getFixedT(session?.user.locale || "en");
@@ -1,8 +1,7 @@
import { _generateMetadata } from "app/_utils";
import { getFixedT } from "app/_utils";
import { getServerSession } from "next-auth";
import { AUTH_OPTIONS } from "@calcom/feature-auth/lib/next-auth-options";
import { getServerSessionForAppDir } from "@calcom/feature-auth/lib/get-server-session-for-app-dir";
import SettingsHeader from "@calcom/features/settings/appDir/SettingsHeader";
import ImpersonationView from "~/settings/admin/impersonation-view";
@@ -14,7 +13,7 @@ export const generateMetadata = async () =>
);
const Page = async () => {
const session = await getServerSession(AUTH_OPTIONS);
const session = await getServerSessionForAppDir();
const t = await getFixedT(session?.user.locale || "en");
return (
@@ -1,8 +1,7 @@
import { _generateMetadata } from "app/_utils";
import { getFixedT } from "app/_utils";
import { getServerSession } from "next-auth";
import { AUTH_OPTIONS } from "@calcom/feature-auth/lib/next-auth-options";
import { getServerSessionForAppDir } from "@calcom/feature-auth/lib/get-server-session-for-app-dir";
import LicenseRequired from "@calcom/features/ee/common/components/LicenseRequired";
import AdminOrgTable from "@calcom/features/ee/organizations/pages/settings/admin/AdminOrgPage";
import SettingsHeader from "@calcom/features/settings/appDir/SettingsHeader";
@@ -14,7 +13,7 @@ export const generateMetadata = async () =>
);
const Page = async () => {
const session = await getServerSession(AUTH_OPTIONS);
const session = await getServerSessionForAppDir();
const t = await getFixedT(session?.user.locale || "en");
return (
@@ -1,8 +1,7 @@
import { _generateMetadata } from "app/_utils";
import { getFixedT } from "app/_utils";
import { getServerSession } from "next-auth";
import { AUTH_OPTIONS } from "@calcom/feature-auth/lib/next-auth-options";
import { getServerSessionForAppDir } from "@calcom/feature-auth/lib/get-server-session-for-app-dir";
import SettingsHeader from "@calcom/features/settings/appDir/SettingsHeader";
import BillingView from "~/settings/billing/billing-view";
@@ -14,7 +13,8 @@ export const generateMetadata = async () =>
);
const Page = async () => {
const session = await getServerSession(AUTH_OPTIONS);
// FIXME: Refactor me once next-auth endpoint is migrated to App Router
const session = await getServerSessionForAppDir();
const t = await getFixedT(session?.user.locale || "en");
@@ -1,7 +1,6 @@
import { getFixedT, _generateMetadata } from "app/_utils";
import { getServerSession } from "next-auth";
import { AUTH_OPTIONS } from "@calcom/feature-auth/lib/next-auth-options";
import { getServerSessionForAppDir } from "@calcom/feature-auth/lib/get-server-session-for-app-dir";
import SettingsHeader from "@calcom/features/settings/appDir/SettingsHeader";
import { APP_NAME } from "@calcom/lib/constants";
@@ -15,7 +14,8 @@ export const generateMetadata = async () =>
);
const Page = async () => {
const session = await getServerSession(AUTH_OPTIONS);
// FIXME: Refactor me once next-auth endpoint is migrated to App Router
const session = await getServerSessionForAppDir();
const t = await getFixedT(session?.user.locale || "en");
@@ -1,8 +1,7 @@
import type { PageProps } from "app/_types";
import { getFixedT, _generateMetadata } from "app/_utils";
import { getServerSession } from "next-auth";
import { AUTH_OPTIONS } from "@calcom/feature-auth/lib/next-auth-options";
import { getServerSessionForAppDir } from "@calcom/feature-auth/lib/get-server-session-for-app-dir";
import SettingsHeader from "@calcom/features/settings/appDir/SettingsHeader";
import { EditWebhookView } from "@calcom/features/webhooks/pages/webhook-edit-view";
import { APP_NAME } from "@calcom/lib/constants";
@@ -15,7 +14,7 @@ export const generateMetadata = async () =>
);
const Page = async ({ params }: PageProps) => {
const session = await getServerSession(AUTH_OPTIONS);
const session = await getServerSessionForAppDir();
const t = await getFixedT(session?.user.locale || "en");
const id = typeof params?.id === "string" ? params.id : undefined;
@@ -1,7 +1,6 @@
import { getFixedT, _generateMetadata } from "app/_utils";
import { getServerSession } from "next-auth";
import { AUTH_OPTIONS } from "@calcom/feature-auth/lib/next-auth-options";
import { getServerSessionForAppDir } from "@calcom/feature-auth/lib/get-server-session-for-app-dir";
import SettingsHeader from "@calcom/features/settings/appDir/SettingsHeader";
import { NewWebhookView } from "@calcom/features/webhooks/pages/webhook-new-view";
import { APP_NAME } from "@calcom/lib/constants";
@@ -13,7 +12,7 @@ export const generateMetadata = async () =>
);
const Page = async () => {
const session = await getServerSession(AUTH_OPTIONS);
const session = await getServerSessionForAppDir();
const t = await getFixedT(session?.user.locale || "en");
@@ -1,8 +1,7 @@
import { _generateMetadata } from "app/_utils";
import { getFixedT } from "app/_utils";
import { getServerSession } from "next-auth";
import { AUTH_OPTIONS } from "@calcom/feature-auth/lib/next-auth-options";
import { getServerSessionForAppDir } from "@calcom/feature-auth/lib/get-server-session-for-app-dir";
import SettingsHeader from "@calcom/features/settings/appDir/SettingsHeader";
import AppearancePage from "~/settings/my-account/appearance-view";
@@ -14,7 +13,7 @@ export const generateMetadata = async () =>
);
const Page = async () => {
const session = await getServerSession(AUTH_OPTIONS);
const session = await getServerSessionForAppDir();
const t = await getFixedT(session?.user.locale || "en");
return (
@@ -1,8 +1,7 @@
import { _generateMetadata } from "app/_utils";
import { getFixedT } from "app/_utils";
import { getServerSession } from "next-auth";
import { AUTH_OPTIONS } from "@calcom/feature-auth/lib/next-auth-options";
import { getServerSessionForAppDir } from "@calcom/feature-auth/lib/get-server-session-for-app-dir";
import SettingsHeader from "@calcom/features/settings/appDir/SettingsHeader";
import { Button } from "@calcom/ui";
@@ -15,7 +14,7 @@ export const generateMetadata = async () =>
);
const Page = async () => {
const session = await getServerSession(AUTH_OPTIONS);
const session = await getServerSessionForAppDir();
const t = await getFixedT(session?.user.locale || "en");
const AddCalendarButton = () => {
@@ -1,8 +1,7 @@
import { _generateMetadata } from "app/_utils";
import { getFixedT } from "app/_utils";
import { getServerSession } from "next-auth";
import { AUTH_OPTIONS } from "@calcom/feature-auth/lib/next-auth-options";
import { getServerSessionForAppDir } from "@calcom/feature-auth/lib/get-server-session-for-app-dir";
import SettingsHeader from "@calcom/features/settings/appDir/SettingsHeader";
import { Button } from "@calcom/ui";
@@ -15,7 +14,7 @@ export const generateMetadata = async () =>
);
const Page = async () => {
const session = await getServerSession(AUTH_OPTIONS);
const session = await getServerSessionForAppDir();
const t = await getFixedT(session?.user.locale || "en");
const AddConferencingButton = () => {
@@ -1,8 +1,7 @@
import { _generateMetadata } from "app/_utils";
import { getFixedT } from "app/_utils";
import { getServerSession } from "next-auth";
import { AUTH_OPTIONS } from "@calcom/feature-auth/lib/next-auth-options";
import { getServerSessionForAppDir } from "@calcom/feature-auth/lib/get-server-session-for-app-dir";
import SettingsHeader from "@calcom/features/settings/appDir/SettingsHeader";
import GeneralQueryView from "~/settings/my-account/general-view";
@@ -14,7 +13,7 @@ export const generateMetadata = async () =>
);
const Page = async () => {
const session = await getServerSession(AUTH_OPTIONS);
const session = await getServerSessionForAppDir();
const t = await getFixedT(session?.user.locale || "en");
return (
@@ -1,8 +1,7 @@
import { _generateMetadata } from "app/_utils";
import { getFixedT } from "app/_utils";
import { getServerSession } from "next-auth";
import { AUTH_OPTIONS } from "@calcom/feature-auth/lib/next-auth-options";
import { getServerSessionForAppDir } from "@calcom/feature-auth/lib/get-server-session-for-app-dir";
import SettingsHeader from "@calcom/features/settings/appDir/SettingsHeader";
import CreateNewOutOfOfficeEntryButton from "@calcom/features/settings/outOfOffice/CreateNewOutOfOfficeEntryButton";
import { OutOfOfficeEntriesList } from "@calcom/features/settings/outOfOffice/OutOfOfficeEntriesList";
@@ -14,7 +13,7 @@ export const generateMetadata = async () =>
);
const Page = async () => {
const session = await getServerSession(AUTH_OPTIONS);
const session = await getServerSessionForAppDir();
const t = await getFixedT(session?.user.locale || "en");
@@ -1,8 +1,7 @@
import { _generateMetadata } from "app/_utils";
import { getFixedT } from "app/_utils";
import { getServerSession } from "next-auth";
import { AUTH_OPTIONS } from "@calcom/feature-auth/lib/next-auth-options";
import { getServerSessionForAppDir } from "@calcom/feature-auth/lib/get-server-session-for-app-dir";
import SettingsHeader from "@calcom/features/settings/appDir/SettingsHeader";
import { APP_NAME } from "@calcom/lib/constants";
@@ -15,7 +14,7 @@ export const generateMetadata = async () =>
);
const Page = async () => {
const session = await getServerSession(AUTH_OPTIONS);
const session = await getServerSessionForAppDir();
const t = await getFixedT(session?.user.locale || "en");
return (
@@ -1,7 +1,6 @@
import { getFixedT, _generateMetadata } from "app/_utils";
import { getServerSession } from "next-auth";
import { AUTH_OPTIONS } from "@calcom/feature-auth/lib/next-auth-options";
import { getServerSessionForAppDir } from "@calcom/feature-auth/lib/get-server-session-for-app-dir";
import { AdminAPIView } from "@calcom/features/ee/organizations/pages/settings/admin-api";
import SettingsHeader from "@calcom/features/settings/appDir/SettingsHeader";
@@ -12,7 +11,7 @@ export const generateMetadata = async () =>
);
const Page = async () => {
const session = await getServerSession(AUTH_OPTIONS);
const session = await getServerSessionForAppDir();
const t = await getFixedT(session?.user.locale || "en");
@@ -1,7 +1,6 @@
import { _generateMetadata, getFixedT } from "app/_utils";
import { getServerSession } from "next-auth";
import { AUTH_OPTIONS } from "@calcom/features/auth/lib/next-auth-options";
import { getServerSessionForAppDir } from "@calcom/feature-auth/lib/get-server-session-for-app-dir";
import DirectorySyncTeamView from "@calcom/features/ee/dsync/page/team-dsync-view";
import SettingsHeader from "@calcom/features/settings/appDir/SettingsHeader";
@@ -12,7 +11,7 @@ export const generateMetadata = async () =>
);
const Page = async () => {
const session = await getServerSession(AUTH_OPTIONS);
const session = await getServerSessionForAppDir();
const t = await getFixedT(session?.user.locale || "en");
return (
@@ -1,7 +1,6 @@
import { _generateMetadata, getFixedT } from "app/_utils";
import { getServerSession } from "next-auth";
import { AUTH_OPTIONS } from "@calcom/features/auth/lib/next-auth-options";
import { getServerSessionForAppDir } from "@calcom/feature-auth/lib/get-server-session-for-app-dir";
import PrivacyView from "@calcom/features/ee/organizations/pages/settings/privacy";
import SettingsHeader from "@calcom/features/settings/appDir/SettingsHeader";
@@ -12,7 +11,7 @@ export const generateMetadata = async () =>
);
const Page = async () => {
const session = await getServerSession(AUTH_OPTIONS);
const session = await getServerSessionForAppDir();
const t = await getFixedT(session?.user.locale || "en");
return (
@@ -1,8 +1,7 @@
import { _generateMetadata } from "app/_utils";
import { getFixedT } from "app/_utils";
import { getServerSession } from "next-auth";
import { AUTH_OPTIONS } from "@calcom/feature-auth/lib/next-auth-options";
import { getServerSessionForAppDir } from "@calcom/feature-auth/lib/get-server-session-for-app-dir";
import SettingsHeader from "@calcom/features/settings/appDir/SettingsHeader";
import ProfileImpersonationViewWrapper from "~/settings/security/impersonation-view";
@@ -14,7 +13,7 @@ export const generateMetadata = async () =>
);
const Page = async () => {
const session = await getServerSession(AUTH_OPTIONS);
const session = await getServerSessionForAppDir();
const t = await getFixedT(session?.user.locale || "en");
@@ -1,8 +1,7 @@
import { _generateMetadata } from "app/_utils";
import { getFixedT } from "app/_utils";
import { getServerSession } from "next-auth";
import { AUTH_OPTIONS } from "@calcom/feature-auth/lib/next-auth-options";
import { getServerSessionForAppDir } from "@calcom/feature-auth/lib/get-server-session-for-app-dir";
import SettingsHeader from "@calcom/features/settings/appDir/SettingsHeader";
import PasswordViewWrapper from "~/settings/security/password-view";
@@ -14,7 +13,7 @@ export const generateMetadata = async () =>
);
const Page = async () => {
const session = await getServerSession(AUTH_OPTIONS);
const session = await getServerSessionForAppDir();
const t = await getFixedT(session?.user.locale || "en");
@@ -1,8 +1,7 @@
import { _generateMetadata } from "app/_utils";
import { getFixedT } from "app/_utils";
import { getServerSession } from "next-auth";
import { AUTH_OPTIONS } from "@calcom/feature-auth/lib/next-auth-options";
import { getServerSessionForAppDir } from "@calcom/feature-auth/lib/get-server-session-for-app-dir";
import SAMLSSO from "@calcom/features/ee/sso/page/user-sso-view";
import SettingsHeader from "@calcom/features/settings/appDir/SettingsHeader";
@@ -13,7 +12,7 @@ export const generateMetadata = async () =>
);
const Page = async () => {
const session = await getServerSession(AUTH_OPTIONS);
const session = await getServerSessionForAppDir();
const t = await getFixedT(session?.user.locale || "en");
@@ -1,8 +1,7 @@
import { _generateMetadata } from "app/_utils";
import { getFixedT } from "app/_utils";
import { getServerSession } from "next-auth";
import { AUTH_OPTIONS } from "@calcom/feature-auth/lib/next-auth-options";
import { getServerSessionForAppDir } from "@calcom/feature-auth/lib/get-server-session-for-app-dir";
import SettingsHeader from "@calcom/features/settings/appDir/SettingsHeader";
import TwoFactorAuthView from "~/settings/security/two-factor-auth-view";
@@ -13,7 +12,7 @@ export const generateMetadata = async () =>
(t) => t("add_an_extra_layer_of_security")
);
const Page = async () => {
const session = await getServerSession(AUTH_OPTIONS);
const session = await getServerSessionForAppDir();
const t = await getFixedT(session?.user.locale || "en");
@@ -1,11 +1,10 @@
import type { PageProps } from "app/_types";
import { _generateMetadata } from "app/_utils";
import { WithLayout } from "app/layoutHOC";
import { getServerSession } from "next-auth";
import { notFound } from "next/navigation";
import { z } from "zod";
import { AUTH_OPTIONS } from "@calcom/features/auth/lib/next-auth-options";
import { getServerSessionForAppDir } from "@calcom/feature-auth/lib/get-server-session-for-app-dir";
import LegacyPage from "@calcom/features/ee/workflows/pages/workflow";
import { WorkflowRepository } from "@calcom/lib/server/repository/workflow";
@@ -30,7 +29,8 @@ export const generateMetadata = async ({ params, searchParams }: PageProps) => {
export const generateStaticParams = () => [];
const Page = async ({ params, searchParams }: PageProps) => {
const session = await getServerSession(AUTH_OPTIONS);
// FIXME: Refactor me once next-auth endpoint is migrated to App Router
const session = await getServerSessionForAppDir();
const user = session?.user;
const parsed = querySchema.safeParse({ ...params, ...searchParams });
if (!parsed.success) {
+3 -3
View File
@@ -1,9 +1,8 @@
import type { PageProps } from "app/_types";
import { _generateMetadata } from "app/_utils";
import { WithLayout } from "app/layoutHOC";
import { getServerSession } from "next-auth";
import { AUTH_OPTIONS } from "@calcom/features/auth/lib/next-auth-options";
import { getServerSessionForAppDir } from "@calcom/feature-auth/lib/get-server-session-for-app-dir";
import LegacyPage from "@calcom/features/ee/workflows/pages/index";
import { getTeamsFiltersFromQuery } from "@calcom/features/filters/lib/getTeamsFiltersFromQuery";
import { WorkflowRepository } from "@calcom/lib/server/repository/workflow";
@@ -15,7 +14,8 @@ export const generateMetadata = async () =>
);
const Page = async ({ params, searchParams }: PageProps) => {
const session = await getServerSession(AUTH_OPTIONS);
// FIXME: Refactor me once next-auth endpoint is migrated to App Router
const session = await getServerSessionForAppDir();
const user = session?.user;
const filters = getTeamsFiltersFromQuery({ ...searchParams, ...params });
@@ -1,8 +1,7 @@
import { getServerSession } from "next-auth";
import dynamic from "next/dynamic";
import React from "react";
import { AUTH_OPTIONS } from "@calcom/features/auth/lib/next-auth-options";
import { getServerSessionForAppDir } from "@calcom/feature-auth/lib/get-server-session-for-app-dir";
import SettingsLayoutAppDir from "@calcom/features/settings/appDir/SettingsLayoutAppDir";
import type { AdminLayoutProps } from "./AdminLayoutAppDirClient";
@@ -14,7 +13,8 @@ const AdminLayoutAppDirClient = dynamic(() => import("./AdminLayoutAppDirClient"
type AdminLayoutAppDirProps = Omit<AdminLayoutProps, "userRole">;
export default async function AdminLayoutAppDir(props: AdminLayoutAppDirProps) {
const session = await getServerSession(AUTH_OPTIONS);
// FIXME: Refactor me once next-auth endpoint is migrated to App Router
const session = await getServerSessionForAppDir();
const userRole = session?.user?.role;
return await SettingsLayoutAppDir({ children: <AdminLayoutAppDirClient {...props} userRole={userRole} /> });
@@ -1,12 +1,13 @@
import type { GetServerSidePropsContext } from "next";
import { getServerSession } from "@calcom/feature-auth/lib/getServerSession";
import { AUTH_OPTIONS } from "@calcom/feature-auth/lib/next-auth-options";
import { getOptions } from "@calcom/feature-auth/lib/next-auth-options";
export const getServerSideProps = async (context: GetServerSidePropsContext) => {
const session = await getServerSession({
req: context.req,
authOptions: AUTH_OPTIONS,
res: context.res,
authOptions: getOptions({ getDclid: () => context.req.cookies.dclid }),
});
// Disable this check if we ever make this self serve.
if (session?.user.role !== "ADMIN") {
+1
View File
@@ -44,6 +44,7 @@
"@calcom/ui": "*",
"@daily-co/daily-js": "^0.59.0",
"@daily-co/daily-react": "^0.17.2",
"@dub/analytics": "^0.0.15",
"@formkit/auto-animate": "1.0.0-beta.5",
"@glidejs/glide": "^3.5.2",
"@hookform/error-message": "^2.0.0",
+7 -2
View File
@@ -1,5 +1,10 @@
import type { NextApiRequest, NextApiResponse } from "next";
import NextAuth from "next-auth";
import { AUTH_OPTIONS } from "@calcom/features/auth/lib/next-auth-options";
import { getOptions } from "@calcom/features/auth/lib/next-auth-options";
export default NextAuth(AUTH_OPTIONS);
// pass req to NextAuth: https://github.com/nextauthjs/next-auth/discussions/469
const handler = (req: NextApiRequest, res: NextApiResponse) =>
NextAuth(req, res, getOptions({ getDclid: () => req.cookies.dclid }));
export default handler;
@@ -0,0 +1,49 @@
import type { NextApiRequest, NextApiResponse } from "next";
import { dub } from "@calcom/features/auth/lib/dub";
import { getServerSession } from "@calcom/features/auth/lib/getServerSession";
import prisma from "@calcom/prisma";
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
if (req.method !== "POST") {
return res.status(405).json({ message: "Method not allowed" });
}
const session = await getServerSession({ req, res });
if (!session?.user?.username) {
return res.status(401).json({ message: "Unauthorized" });
}
try {
return await dub.links.get({
externalId: `ext_${session.user.id.toString()}`,
});
} catch (error) {
console.log("Referral link not found, creating...");
}
const { id: referralLinkId, shortLink } = await dub.links.create({
domain: "refer.cal.com",
key: session.user.username,
url: "https://cal.com",
externalId: session.user.id.toString(), // @see https://d.to/externalId
trackConversion: true, // enable conversion tracking @see https://d.to/conversions
});
/*
Even though we are relying in externalId for retrieving the referral link,
we still save the referralLinkId in the database for future reference.
E.g. we can use this to tell how many users created a referral link.
*/
await prisma.user.update({
where: {
id: session.user.id,
},
data: {
referralLinkId,
},
});
return res.status(200).json({ shortLink });
}
+8
View File
@@ -1,5 +1,6 @@
"use client";
import { Analytics as DubAnalytics } from "@dub/analytics/react";
import { zodResolver } from "@hookform/resolvers/zod";
import { signIn } from "next-auth/react";
import { Trans } from "next-i18next";
@@ -26,7 +27,9 @@ import {
CLOUDFLARE_SITE_ID,
WEBSITE_PRIVACY_POLICY_URL,
WEBSITE_TERMS_URL,
WEBSITE_URL,
} from "@calcom/lib/constants";
import { isENVDev } from "@calcom/lib/env";
import { fetchUsername } from "@calcom/lib/fetchUsername";
import { pushGTMEvent } from "@calcom/lib/gtm";
import { useCompatSearchParams } from "@calcom/lib/hooks/useCompatSearchParams";
@@ -309,6 +312,11 @@ export default function Signup({
__html: `<iframe src="https://www.googletagmanager.com/ns.html?id=${process.env.NEXT_PUBLIC_GTM_ID}" height="0" width="0" style="display:none;visibility:hidden"></iframe>`,
}}
/>
<DubAnalytics
cookieOptions={{
domain: isENVDev ? undefined : `.${new URL(WEBSITE_URL).hostname}`,
}}
/>
</>
) : null}
<div
@@ -34,7 +34,10 @@ export function createWorkflowPageFixture(page: Page) {
};
const saveWorkflow = async () => {
const submitPromise = page.waitForResponse("/api/trpc/workflows/update?batch=1");
await page.getByTestId("save-workflow").click();
const response = await submitPromise;
expect(response.status()).toBe(200);
};
const assertListCount = async (count: number) => {
+1 -1
View File
@@ -26,7 +26,7 @@ test.describe("Workflow Tab - Event Type", () => {
await fillNameInput("Edited Workflow");
await saveWorkflow();
await page.getByTestId("go-back-button").click();
await page.waitForLoadState("networkidle");
page.getByTestId("workflow-list").waitFor();
await hasWorkflowInList("Edited Workflow");
});
@@ -213,6 +213,7 @@
"view_notifications": "View notifications",
"view_public_page": "View public page",
"copy_public_page_link": "Copy public page link",
"copy_referral_link": "Copy referral link",
"sign_out": "Sign out",
"add_another": "Add another",
"install_another": "Install another",
@@ -37,6 +37,7 @@ export const getServerSideProps = async (context: GetServerSidePropsContext) =>
const availability = await checkUsername(usernameParam, currentOrgDomain);
if (availability.available && availability.premium && IS_PREMIUM_USERNAME_ENABLED) {
const stripePremiumUrl = await getStripePremiumUsernameUrl({
userId: session.user.id.toString(),
userEmail: session.user.email,
username: usernameParam,
successDestination,
@@ -104,12 +105,14 @@ export const getServerSideProps = async (context: GetServerSidePropsContext) =>
};
type GetStripePremiumUsernameUrl = {
userId: string;
userEmail: string;
username: string;
successDestination: string;
};
const getStripePremiumUsernameUrl = async ({
userId,
userEmail,
username,
successDestination,
@@ -136,6 +139,9 @@ const getStripePremiumUsernameUrl = async ({
success_url: `${process.env.NEXT_PUBLIC_WEBAPP_URL}${successDestination}&session_id={CHECKOUT_SESSION_ID}`,
cancel_url: process.env.NEXT_PUBLIC_WEBAPP_URL || "https://app.cal.com",
allow_promotion_codes: true,
metadata: {
dubCustomerId: userId, // pass the userId during checkout creation for sales conversion tracking: https://d.to/conversions/stripe
},
});
return checkoutSession.url;