diff --git a/apps/api/v1/pages/api/teams/_post.ts b/apps/api/v1/pages/api/teams/_post.ts index 9b01ffe83a..12fef369d4 100644 --- a/apps/api/v1/pages/api/teams/_post.ts +++ b/apps/api/v1/pages/api/teams/_post.ts @@ -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 }, }); diff --git a/apps/web/app/future/availability/[schedule]/page.tsx b/apps/web/app/future/availability/[schedule]/page.tsx index 8955baa8c7..2c4fb1382e 100644 --- a/apps/web/app/future/availability/[schedule]/page.tsx +++ b/apps/web/app/future/availability/[schedule]/page.tsx @@ -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(); diff --git a/apps/web/app/future/availability/page.tsx b/apps/web/app/future/availability/page.tsx index c75021f80a..09d33577b0 100644 --- a/apps/web/app/future/availability/page.tsx +++ b/apps/web/app/future/availability/page.tsx @@ -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) { diff --git a/apps/web/app/future/settings/(admin)/admin/apps/[category]/page.tsx b/apps/web/app/future/settings/(admin)/admin/apps/[category]/page.tsx index 90c04a5c3a..cd70a918fa 100644 --- a/apps/web/app/future/settings/(admin)/admin/apps/[category]/page.tsx +++ b/apps/web/app/future/settings/(admin)/admin/apps/[category]/page.tsx @@ -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"); diff --git a/apps/web/app/future/settings/(admin)/admin/impersonation/page.tsx b/apps/web/app/future/settings/(admin)/admin/impersonation/page.tsx index d3c29d61ad..8b932d1dcc 100644 --- a/apps/web/app/future/settings/(admin)/admin/impersonation/page.tsx +++ b/apps/web/app/future/settings/(admin)/admin/impersonation/page.tsx @@ -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 ( diff --git a/apps/web/app/future/settings/(admin)/admin/organizations/page.tsx b/apps/web/app/future/settings/(admin)/admin/organizations/page.tsx index 672632f91a..2b20b5d393 100644 --- a/apps/web/app/future/settings/(admin)/admin/organizations/page.tsx +++ b/apps/web/app/future/settings/(admin)/admin/organizations/page.tsx @@ -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 ( diff --git a/apps/web/app/future/settings/(settings)/billing/page.tsx b/apps/web/app/future/settings/(settings)/billing/page.tsx index 656487851d..0822b347cc 100644 --- a/apps/web/app/future/settings/(settings)/billing/page.tsx +++ b/apps/web/app/future/settings/(settings)/billing/page.tsx @@ -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"); diff --git a/apps/web/app/future/settings/(settings)/developer/api-keys/page.tsx b/apps/web/app/future/settings/(settings)/developer/api-keys/page.tsx index 31f740e36d..d64087b672 100644 --- a/apps/web/app/future/settings/(settings)/developer/api-keys/page.tsx +++ b/apps/web/app/future/settings/(settings)/developer/api-keys/page.tsx @@ -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"); diff --git a/apps/web/app/future/settings/(settings)/developer/webhooks/[id]/page.tsx b/apps/web/app/future/settings/(settings)/developer/webhooks/[id]/page.tsx index 709d2e0fff..718fd1faf4 100644 --- a/apps/web/app/future/settings/(settings)/developer/webhooks/[id]/page.tsx +++ b/apps/web/app/future/settings/(settings)/developer/webhooks/[id]/page.tsx @@ -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; diff --git a/apps/web/app/future/settings/(settings)/developer/webhooks/new/page.tsx b/apps/web/app/future/settings/(settings)/developer/webhooks/new/page.tsx index 4c60a8989f..f871693059 100644 --- a/apps/web/app/future/settings/(settings)/developer/webhooks/new/page.tsx +++ b/apps/web/app/future/settings/(settings)/developer/webhooks/new/page.tsx @@ -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"); diff --git a/apps/web/app/future/settings/(settings)/my-account/appearance/page.tsx b/apps/web/app/future/settings/(settings)/my-account/appearance/page.tsx index b32f763a79..9a3c085aab 100644 --- a/apps/web/app/future/settings/(settings)/my-account/appearance/page.tsx +++ b/apps/web/app/future/settings/(settings)/my-account/appearance/page.tsx @@ -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 ( diff --git a/apps/web/app/future/settings/(settings)/my-account/calendars/page.tsx b/apps/web/app/future/settings/(settings)/my-account/calendars/page.tsx index 4b5b25885a..7802d51a91 100644 --- a/apps/web/app/future/settings/(settings)/my-account/calendars/page.tsx +++ b/apps/web/app/future/settings/(settings)/my-account/calendars/page.tsx @@ -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 = () => { diff --git a/apps/web/app/future/settings/(settings)/my-account/conferencing/page.tsx b/apps/web/app/future/settings/(settings)/my-account/conferencing/page.tsx index add5f7dd58..dbfe964287 100644 --- a/apps/web/app/future/settings/(settings)/my-account/conferencing/page.tsx +++ b/apps/web/app/future/settings/(settings)/my-account/conferencing/page.tsx @@ -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 = () => { diff --git a/apps/web/app/future/settings/(settings)/my-account/general/page.tsx b/apps/web/app/future/settings/(settings)/my-account/general/page.tsx index 773337ae07..c6ef48a09b 100644 --- a/apps/web/app/future/settings/(settings)/my-account/general/page.tsx +++ b/apps/web/app/future/settings/(settings)/my-account/general/page.tsx @@ -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 ( diff --git a/apps/web/app/future/settings/(settings)/my-account/out-of-office/page.tsx b/apps/web/app/future/settings/(settings)/my-account/out-of-office/page.tsx index 993615b0a6..47c1466719 100644 --- a/apps/web/app/future/settings/(settings)/my-account/out-of-office/page.tsx +++ b/apps/web/app/future/settings/(settings)/my-account/out-of-office/page.tsx @@ -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"); diff --git a/apps/web/app/future/settings/(settings)/my-account/profile/page.tsx b/apps/web/app/future/settings/(settings)/my-account/profile/page.tsx index 3504f51af9..a1981539d1 100644 --- a/apps/web/app/future/settings/(settings)/my-account/profile/page.tsx +++ b/apps/web/app/future/settings/(settings)/my-account/profile/page.tsx @@ -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 ( diff --git a/apps/web/app/future/settings/(settings)/organizations/admin-api/page.tsx b/apps/web/app/future/settings/(settings)/organizations/admin-api/page.tsx index 8f5b2ddea0..254d6b4c2e 100644 --- a/apps/web/app/future/settings/(settings)/organizations/admin-api/page.tsx +++ b/apps/web/app/future/settings/(settings)/organizations/admin-api/page.tsx @@ -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"); diff --git a/apps/web/app/future/settings/(settings)/organizations/dsync/page.tsx b/apps/web/app/future/settings/(settings)/organizations/dsync/page.tsx index 78a01b931a..6a963583fb 100644 --- a/apps/web/app/future/settings/(settings)/organizations/dsync/page.tsx +++ b/apps/web/app/future/settings/(settings)/organizations/dsync/page.tsx @@ -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 ( diff --git a/apps/web/app/future/settings/(settings)/organizations/privacy/page.tsx b/apps/web/app/future/settings/(settings)/organizations/privacy/page.tsx index bf9ade6a03..d95eed66a0 100644 --- a/apps/web/app/future/settings/(settings)/organizations/privacy/page.tsx +++ b/apps/web/app/future/settings/(settings)/organizations/privacy/page.tsx @@ -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 ( diff --git a/apps/web/app/future/settings/(settings)/security/impersonation/page.tsx b/apps/web/app/future/settings/(settings)/security/impersonation/page.tsx index 4e20939393..1d4edc82be 100644 --- a/apps/web/app/future/settings/(settings)/security/impersonation/page.tsx +++ b/apps/web/app/future/settings/(settings)/security/impersonation/page.tsx @@ -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"); diff --git a/apps/web/app/future/settings/(settings)/security/password/page.tsx b/apps/web/app/future/settings/(settings)/security/password/page.tsx index 09a6d0e68f..df37858d99 100644 --- a/apps/web/app/future/settings/(settings)/security/password/page.tsx +++ b/apps/web/app/future/settings/(settings)/security/password/page.tsx @@ -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"); diff --git a/apps/web/app/future/settings/(settings)/security/sso/page.tsx b/apps/web/app/future/settings/(settings)/security/sso/page.tsx index b5f311b369..4579dd6abd 100644 --- a/apps/web/app/future/settings/(settings)/security/sso/page.tsx +++ b/apps/web/app/future/settings/(settings)/security/sso/page.tsx @@ -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"); diff --git a/apps/web/app/future/settings/(settings)/security/two-factor-auth/page.tsx b/apps/web/app/future/settings/(settings)/security/two-factor-auth/page.tsx index dbfed4e9ab..b60a01617c 100644 --- a/apps/web/app/future/settings/(settings)/security/two-factor-auth/page.tsx +++ b/apps/web/app/future/settings/(settings)/security/two-factor-auth/page.tsx @@ -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"); diff --git a/apps/web/app/future/workflows/[workflow]/page.tsx b/apps/web/app/future/workflows/[workflow]/page.tsx index c66b415071..e09a9562f9 100644 --- a/apps/web/app/future/workflows/[workflow]/page.tsx +++ b/apps/web/app/future/workflows/[workflow]/page.tsx @@ -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) { diff --git a/apps/web/app/future/workflows/page.tsx b/apps/web/app/future/workflows/page.tsx index 416ec0f6e4..7c869e031d 100644 --- a/apps/web/app/future/workflows/page.tsx +++ b/apps/web/app/future/workflows/page.tsx @@ -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 }); diff --git a/apps/web/components/auth/layouts/AdminLayoutAppDir.tsx b/apps/web/components/auth/layouts/AdminLayoutAppDir.tsx index 8404786384..44ac10743a 100644 --- a/apps/web/components/auth/layouts/AdminLayoutAppDir.tsx +++ b/apps/web/components/auth/layouts/AdminLayoutAppDir.tsx @@ -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; 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: }); diff --git a/apps/web/lib/settings/license-key/new/getServerSideProps.tsx b/apps/web/lib/settings/license-key/new/getServerSideProps.tsx index 31e018e8e4..8b8be211d1 100644 --- a/apps/web/lib/settings/license-key/new/getServerSideProps.tsx +++ b/apps/web/lib/settings/license-key/new/getServerSideProps.tsx @@ -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") { diff --git a/apps/web/package.json b/apps/web/package.json index 251062f49e..b0ce626a51 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -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", diff --git a/apps/web/pages/api/auth/[...nextauth].tsx b/apps/web/pages/api/auth/[...nextauth].tsx index dcc7a822d2..ccb457fad9 100644 --- a/apps/web/pages/api/auth/[...nextauth].tsx +++ b/apps/web/pages/api/auth/[...nextauth].tsx @@ -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; diff --git a/apps/web/pages/api/generate-referral-link.ts b/apps/web/pages/api/generate-referral-link.ts new file mode 100644 index 0000000000..a28c252664 --- /dev/null +++ b/apps/web/pages/api/generate-referral-link.ts @@ -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 }); +} diff --git a/apps/web/pages/signup.tsx b/apps/web/pages/signup.tsx index 2620efd175..233a13cc05 100644 --- a/apps/web/pages/signup.tsx +++ b/apps/web/pages/signup.tsx @@ -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: ``, }} /> + ) : null}
{ + 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) => { diff --git a/apps/web/playwright/workflow.e2e.ts b/apps/web/playwright/workflow.e2e.ts index 60df8c7814..96a0595d56 100644 --- a/apps/web/playwright/workflow.e2e.ts +++ b/apps/web/playwright/workflow.e2e.ts @@ -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"); }); diff --git a/apps/web/public/static/locales/en/common.json b/apps/web/public/static/locales/en/common.json index b8028e7790..8b26870690 100644 --- a/apps/web/public/static/locales/en/common.json +++ b/apps/web/public/static/locales/en/common.json @@ -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", diff --git a/apps/web/server/lib/auth/sso/[provider]/getServerSideProps.tsx b/apps/web/server/lib/auth/sso/[provider]/getServerSideProps.tsx index 338bdd934b..88166626f1 100644 --- a/apps/web/server/lib/auth/sso/[provider]/getServerSideProps.tsx +++ b/apps/web/server/lib/auth/sso/[provider]/getServerSideProps.tsx @@ -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; diff --git a/packages/features/auth/lib/dub.ts b/packages/features/auth/lib/dub.ts new file mode 100644 index 0000000000..59acf19b97 --- /dev/null +++ b/packages/features/auth/lib/dub.ts @@ -0,0 +1,5 @@ +import { Dub } from "dub"; + +export const dub = new Dub({ + token: process.env.DUB_API_KEY, +}); diff --git a/packages/features/auth/lib/get-server-session-for-app-dir.ts b/packages/features/auth/lib/get-server-session-for-app-dir.ts new file mode 100644 index 0000000000..37d83b87b7 --- /dev/null +++ b/packages/features/auth/lib/get-server-session-for-app-dir.ts @@ -0,0 +1,8 @@ +import { getServerSession } from "next-auth"; +import { cookies } from "next/headers"; + +import { getOptions } from "./next-auth-options"; + +export async function getServerSessionForAppDir() { + return await getServerSession(getOptions({ getDclid: () => cookies().get("dclid")?.value })); +} diff --git a/packages/features/auth/lib/next-auth-options.ts b/packages/features/auth/lib/next-auth-options.ts index 2e645671ca..b75a98a13c 100644 --- a/packages/features/auth/lib/next-auth-options.ts +++ b/packages/features/auth/lib/next-auth-options.ts @@ -1,5 +1,6 @@ import type { Membership, Team, UserPermissionRole } from "@prisma/client"; -import type { AuthOptions, Session } from "next-auth"; +import { waitUntil } from "@vercel/functions"; +import type { AuthOptions, Session, User } from "next-auth"; import type { JWT } from "next-auth/jwt"; import { encode } from "next-auth/jwt"; import type { Provider } from "next-auth/providers"; @@ -13,7 +14,7 @@ import ImpersonationProvider from "@calcom/features/ee/impersonation/lib/Imperso import { getOrgFullOrigin, subdomainSuffix } from "@calcom/features/ee/organizations/lib/orgDomains"; import { clientSecretVerifier, hostedCal, isSAMLLoginEnabled } from "@calcom/features/ee/sso/lib/saml"; import { checkRateLimitAndThrowError } from "@calcom/lib/checkRateLimitAndThrowError"; -import { HOSTED_CAL_FEATURES } from "@calcom/lib/constants"; +import { HOSTED_CAL_FEATURES, IS_CALCOM } from "@calcom/lib/constants"; import { ENABLE_PROFILE_SWITCHER, IS_TEAM_BILLING_ENABLED, WEBAPP_URL } from "@calcom/lib/constants"; import { symmetricDecrypt, symmetricEncrypt } from "@calcom/lib/crypto"; import { defaultCookies } from "@calcom/lib/default-cookies"; @@ -29,6 +30,7 @@ import { IdentityProvider, MembershipRole } from "@calcom/prisma/enums"; import { teamMetadataSchema, userMetadata } from "@calcom/prisma/zod-utils"; import { ErrorCode } from "./ErrorCode"; +import { dub } from "./dub"; import { isPasswordValid } from "./isPasswordValid"; import CalComAdapter from "./next-auth-custom-adapter"; import { verifyPassword } from "./verifyPassword"; @@ -235,6 +237,7 @@ const providers: Provider[] = [ belongsToActiveTeam: hasActiveTeams, locale: user.locale, profile: user.allProfiles[0], + createdAt: user.createdDate, }; }, }), @@ -404,7 +407,12 @@ const mapIdentityProvider = (providerName: string) => { } }; -export const AUTH_OPTIONS: AuthOptions = { +export const getOptions = ({ + getDclid, +}: { + /** so we can extract the Dub cookie in both pages and app routers */ + getDclid: () => string | undefined; +}): AuthOptions => ({ // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore adapter: calcomAdapter, @@ -924,7 +932,43 @@ export const AUTH_OPTIONS: AuthOptions = { return baseUrl; }, }, -}; + events: { + async signIn(message) { + /* only run this code if: + - it's a hosted cal account + - DUB_API_KEY is configured + - it's a new user + */ + const user = message.user as User & { + username: string; + createdAt: string; + }; + // check if the user was created in the last 10 minutes + // this is a workaround – in the future once we move to use the Account model in the DB + // we should use NextAuth's isNewUser flag instead: https://next-auth.js.org/configuration/events#signin + const isNewUser = new Date(user.createdAt) > new Date(Date.now() - 10 * 60 * 1000); + if ((isENVDev || IS_CALCOM) && process.env.DUB_API_KEY && isNewUser) { + const dclid = getDclid(); + // check if there's a dclid cookie set by @dub/analytics + if (dclid) { + // here we use waitUntil – meaning this code will run async to not block the main thread + waitUntil( + // if so, send a lead event to Dub + // @see https://d.to/conversions/next-auth + dub.track.lead({ + clickId: dclid, + eventName: "Sign Up", + customerId: user.id.toString(), + customerName: user.name, + customerEmail: user.email, + customerAvatar: user.image, + }) + ); + } + } + }, + }, +}); /** * Identifies the profile the user should be logged into. diff --git a/packages/features/auth/package.json b/packages/features/auth/package.json index 9f451d5709..ba50422204 100644 --- a/packages/features/auth/package.json +++ b/packages/features/auth/package.json @@ -13,6 +13,7 @@ "@calcom/trpc": "*", "@calcom/ui": "*", "bcryptjs": "^2.4.3", + "dub": "^0.35.0", "handlebars": "^4.7.7", "jose": "^4.13.1", "lru-cache": "^9.0.3", diff --git a/packages/features/ee/teams/lib/payments.ts b/packages/features/ee/teams/lib/payments.ts index 487f4de388..fb1512bc4c 100644 --- a/packages/features/ee/teams/lib/payments.ts +++ b/packages/features/ee/teams/lib/payments.ts @@ -79,6 +79,7 @@ export const generateTeamCheckoutSession = async ({ teamName, teamSlug, userId, + dubCustomerId: userId, // pass the userId during checkout creation for sales conversion tracking: https://d.to/conversions/stripe }, }); return session; @@ -173,6 +174,7 @@ export const purchaseTeamOrOrgSubscription = async (input: { subscription_data: { metadata: { teamId, + dubCustomerId: userId, }, }, }); diff --git a/packages/features/package.json b/packages/features/package.json index 31de0ab73d..7f3d5d6592 100644 --- a/packages/features/package.json +++ b/packages/features/package.json @@ -13,6 +13,7 @@ "@calcom/ui": "*", "@lexical/react": "^0.9.0", "@tanstack/react-table": "^8.9.3", + "@vercel/functions": "^1.4.0", "framer-motion": "^10.12.8", "lexical": "^0.9.0", "react-select": "^5.7.0", diff --git a/packages/features/settings/appDir/SettingsLayoutAppDir.tsx b/packages/features/settings/appDir/SettingsLayoutAppDir.tsx index fb2936b4b5..b7d750bb60 100644 --- a/packages/features/settings/appDir/SettingsLayoutAppDir.tsx +++ b/packages/features/settings/appDir/SettingsLayoutAppDir.tsx @@ -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 { OrganizationRepository } from "@calcom/lib/server/repository/organization"; import type { SettingsLayoutProps } from "./SettingsLayoutAppDirClient"; @@ -14,7 +13,7 @@ const SettingsLayoutAppDirClient = dynamic(() => import("./SettingsLayoutAppDirC type SettingsLayoutAppDir = Omit; export default async function SettingsLayoutAppDir(props: SettingsLayoutAppDir) { - const session = await getServerSession(AUTH_OPTIONS); + const session = await getServerSessionForAppDir(); const userId = session?.user?.id ?? -1; const orgId = session?.user?.org?.id ?? -1; let currentOrg = null; diff --git a/packages/features/shell/Shell.tsx b/packages/features/shell/Shell.tsx index a365da4fe5..e9aa9fb172 100644 --- a/packages/features/shell/Shell.tsx +++ b/packages/features/shell/Shell.tsx @@ -42,6 +42,7 @@ import { APP_NAME, DESKTOP_APP_LINK, ENABLE_PROFILE_SWITCHER, + IS_CALCOM, IS_VISUAL_REGRESSION_TESTING, JOIN_COMMUNITY, ROADMAP, @@ -52,6 +53,7 @@ import { getPlaceholderAvatar } from "@calcom/lib/defaultAvatarImage"; import { useFormbricks } from "@calcom/lib/formbricks-client"; import getBrandColours from "@calcom/lib/getBrandColours"; import { useBookerUrl } from "@calcom/lib/hooks/useBookerUrl"; +import { useCopy } from "@calcom/lib/hooks/useCopy"; import { useLocale } from "@calcom/lib/hooks/useLocale"; import { useNotifications, ButtonState } from "@calcom/lib/hooks/useNotifications"; import useTheme from "@calcom/lib/hooks/useTheme"; @@ -927,6 +929,7 @@ function SideBarContainer({ bannersHeight, isPlatformUser = false }: SideBarCont } function SideBar({ bannersHeight, user }: SideBarProps) { + const { isCopied, copyToClipboard, resetCopyStatus } = useCopy(); const { t, isLocaleReady } = useLocale(); const orgBranding = useOrgBranding(); const pathname = usePathname(); @@ -960,12 +963,32 @@ function SideBar({ bannersHeight, user }: SideBarProps) { }, icon: "copy", }, + IS_CALCOM + ? { + name: "copy_referral_link", + href: "", + onClick: async (e: { preventDefault: () => void }) => { + e.preventDefault(); + const res = await fetch("/api/generate-referral-link", { + method: "POST", + }); + const { shortLink } = await res.json(); + copyToClipboard(shortLink); + + if (isCopied) { + showToast(t("link_copied"), "success"); + } + }, + icon: "copy", + } + : null, { name: "settings", href: user?.org ? `/settings/organizations/profile` : "/settings/my-account/profile", icon: "settings", }, - ]; + ].filter(Boolean) as NavigationItemType[]; + return (