Repository: calcom/cal.com
Pull request #20258: feat: dub refer embed
Author: login: Amit91848
Labels: name: ✨ feature
description: New feature or request
name: ❗️ .env changes
description: contains changes to env variables
name: embed
description: area: embed, widget, react embed
name: core
description: area: core, team members only
name: ready-for-e2e
Created: 2025-03-20T14:47:17Z | Merged: 2025-03-26T21:06:21Z

## What does this PR do?

This pull request introduces several changes to integrate the Dub referrals feature into the application. The changes include updates to environment variables, new components for the referrals page, and modifications to existing files to support the new feature.

### Environment Variable Updates:
* [`.env.example`](diffhunk://#diff-a3046da0d15a27e89f2afe639b25748a7ad4d9290af3e7b1b6c1a5533c8f0a8cR120-R124): Added `DUB_API_KEY` and `NEXT_PUBLIC_DUB_PROGRAM_ID` for Dub configuration.

### New Components:
* [`apps/web/app/(use-page-wrapper)/refer/DubReferralsPage.tsx`](diffhunk://#diff-a6480431abc9b86659f08085d2a13532e47dd9633dee2250f13b27e2bfefe363R1-R71): Implemented the `DubReferralsPage` component to fetch and display the referrals token using the Dub embed.
* [`apps/web/app/(use-page-wrapper)/refer/loading.tsx`](diffhunk://#diff-a7c1fb37f643939e49c130a9709f6e47a14e49e8ce573aedb0c8e7c94252e99dR1-R69): Added a loading skeleton component for the referrals page.
* [`apps/web/app/(use-page-wrapper)/refer/page.tsx`](diffhunk://#diff-ceac3265fc14cd3e9310cfe57f88169cbe7d6eb0c690cedefcd0bc92b7a1e5c0R1-R24): Created the main referrals page component that conditionally renders based on the feature flag.

### API Route:
* [`apps/web/app/api/user/referrals-token/route.ts`](diffhunk://#diff-dbbfa91de3c7069c912243e4e1c0eedabdbf8c2f4ed9d776dd27f75bee826fcaR1-R40): Added a new API route to fetch the referrals token using the Dub API and user session data.

### Other Changes:
* [`packages/features/shell/useBottomNavItems.ts`](diffhunk://#diff-dba8875284bda4cc3c11489474345a3d29a50bd13219e1813865288867f6769dL2-R3): Updated the bottom navigation items to include a link to the referrals page when the feature is enabled. [[1]](diffhunk://#diff-dba8875284bda4cc3c11489474345a3d29a50bd13219e1813865288867f6769dL2-R3) [[2]](diffhunk://#diff-dba8875284bda4cc3c11489474345a3d29a50bd13219e1813865288867f6769dL23-L24) [[3]](diffhunk://#diff-dba8875284bda4cc3c11489474345a3d29a50bd13219e1813865288867f6769dL43-L67)
* [`apps/web/package.json`](diffhunk://#diff-14b60f636e1a2b0061da57aaf231cb1ed15a5dc0c592425ed82e58fec95d42d8R48-R49): Added dependencies for `@dub/embed-core` and `@dub/embed-react`.
* [`apps/web/public/static/locales/en/common.json`](diffhunk://#diff-57de4b8e5231f1d699891d98b0381d56e9e24537b0ca5420d1fba4f0597370bcR3031-R3033): Added new localization strings for the referrals feature.
* [`packages/lib/constants.ts`](diffhunk://#diff-84a559b7431271bcf747be80243751e28f9e17100616987cb5776afffe63e1a6R213-R216): Defined a new constant `IS_DUB_REFERRALS_ENABLED` to check if the Dub referrals feature is enabled.
* [`turbo.json`](diffhunk://#diff-f8de965273949793edc0fbfe249bb458c0becde39b2e141db087bcbf5d4ad5e3R281): Updated the list of environment variables to include `NEXT_PUBLIC_DUB_PROGRAM_ID`.

- Created a clean /refer page with proper loading states and dub embed
- Set up the API endpoint to generate user-specific referral tokens
- Implemented theme support so it looks good in both light/dark modes
- This PR adds the ability for users to earn affiliate commissions through a Dub-powered referral system.

## Demo

https://www.loom.com/share/86aadaaf8fef486387fde9ebfae73305
<img width="214" alt="Screenshot 2025-03-06 at 1 35 24 PM" src="https://github.com/user-attachments/assets/69896f02-020f-4522-b062-cdb042f9abb8" />

## Mandatory Tasks (DO NOT REMOVE)

- [x] I have self-reviewed the code (A decent size PR without self-review might be rejected).
- [x] I have updated the developer docs in /docs if this PR makes changes that would require a [documentation change](https://cal.com/docs). If N/A, write N/A here and check the checkbox.
- [x] I confirm automated tests are in place that prove my fix is effective or that my feature works.

## How should this be tested?

<!-- Please describe the tests that you ran to verify your changes. Provide instructions so we can reproduce. Please also list any relevant details for your test configuration. Write details that help to start the tests -->

- Go to /refer (bottom of sidebar)
- See Dub.co embed pop up
- Have a shareable affiliate link



Diff:
diff --git a/.env.example b/.env.example
index 58d941934acc24..de49146b26e893 100644
--- a/.env.example
+++ b/.env.example
@@ -117,6 +117,11 @@ NEXT_PUBLIC_PLAIN_CHAT_ID=
 PLAIN_CHAT_HMAC_SECRET_KEY=
 NEXT_PUBLIC_PLAIN_CHAT_EXCLUDED_PATHS=
 
+
+# Dub Config
+DUB_API_KEY=
+NEXT_PUBLIC_DUB_PROGRAM_ID=
+
 # Zendesk Config
 NEXT_PUBLIC_ZENDESK_KEY=
 
@@ -429,6 +434,4 @@ NEXT_PUBLIC_QUERY_AVAILABLE_SLOTS_INTERVAL_SECONDS=
 # Used to invalidate available slots when navigating to booking form
 NEXT_PUBLIC_INVALIDATE_AVAILABLE_SLOTS_ON_BOOKING_FORM=0
 # Used to enable quick availability checks for x% of all visitors
-NEXT_PUBLIC_QUICK_AVAILABILITY_ROLLOUT=10
-
-
+NEXT_PUBLIC_QUICK_AVAILABILITY_ROLLOUT=10
\ No newline at end of file
diff --git a/apps/web/app/(use-page-wrapper)/refer/DubReferralsPage.tsx b/apps/web/app/(use-page-wrapper)/refer/DubReferralsPage.tsx
new file mode 100644
index 00000000000000..97cab29524b3db
--- /dev/null
+++ b/apps/web/app/(use-page-wrapper)/refer/DubReferralsPage.tsx
@@ -0,0 +1,71 @@
+"use client";
+
+import { DubEmbed } from "@dub/embed-react";
+import { useTheme } from "next-themes";
+import { useState, useEffect } from "react";
+
+import { IS_DUB_REFERRALS_ENABLED } from "@calcom/lib/constants";
+import { useLocale } from "@calcom/lib/hooks/useLocale";
+import { showToast } from "@calcom/ui/components/toast";
+
+const fetchReferralsToken = async () => {
+  try {
+    const response = await fetch("/api/user/referrals-token");
+
+    if (!response.ok) {
+      const { error } = await response.json();
+      showToast(error, "error");
+      return null;
+    }
+
+    const data = await response.json();
+
+    return data.publicToken;
+  } catch (error) {
+    console.error("Error fetching referrals token:", error);
+    return null;
+  }
+};
+
+// The enabled referrals page implementation
+export const DubReferralsPage = () => {
+  const [token, setToken] = useState<string | null>(null);
+  const [loading, setLoading] = useState(true);
+  const { t } = useLocale();
+  const { resolvedTheme } = useTheme();
+
+  useEffect(() => {
+    const getToken = async () => {
+      try {
+        const publicToken = await fetchReferralsToken();
+        setToken(publicToken);
+      } catch (err) {
+        console.error("Error fetching referrals token:", err);
+        showToast(t("unexpected_error_try_again"), "error");
+      } finally {
+        setLoading(false);
+      }
+    };
+
+    getToken();
+  }, []);
+
+  if (!IS_DUB_REFERRALS_ENABLED || !token) {
+    return null;
+  }
+
+  const theme = resolvedTheme === "dark" ? "dark" : "light";
+
+  return (
+    <DubEmbed
+      data="referrals"
+      token={token}
+      options={{
+        theme,
+        themeOptions: {
+          backgroundColor: `${theme === "dark" ? "#0F0F0F" : "#FFFFFF"}`,
+        },
+      }}
+    />
+  );
+};
diff --git a/apps/web/app/(use-page-wrapper)/refer/loading.tsx b/apps/web/app/(use-page-wrapper)/refer/loading.tsx
new file mode 100644
index 00000000000000..a05ce1f0d7d6dc
--- /dev/null
+++ b/apps/web/app/(use-page-wrapper)/refer/loading.tsx
@@ -0,0 +1,69 @@
+"use client";
+
+import {
+  SkeletonAvatar,
+  SkeletonButton,
+  SkeletonContainer,
+  SkeletonText,
+} from "@calcom/ui/components/skeleton";
+
+export default function Loading() {
+  return (
+    <SkeletonContainer className="mx-auto max-w-4xl">
+      <div className="rounded-md p-8">
+        <div className="mb-2 flex items-center">
+          <SkeletonText className="h-5 w-32" />
+        </div>
+
+        <div className="mb-6 space-y-2">
+          <SkeletonText className="h-7 w-3/4" />
+          <SkeletonText className="h-7 w-1/2" />
+        </div>
+
+        <div className="mb-6">
+          <SkeletonText className="mb-2 h-5 w-24" />
+          <div className="flex items-center space-x-2">
+            <SkeletonText className="h-10 w-full rounded-md" />
+            <SkeletonButton className="h-10 w-28 rounded-md" />
+          </div>
+        </div>
+      </div>
+
+      <div className="mt-4 grid grid-cols-3 gap-4 p-4">
+        <div className="col-span-1">
+          <div className="mb-4 grid grid-cols-3 gap-2 p-4">
+            {[...Array(9)].map((_, i) => (
+              <div key={i} className="flex justify-center">
+                <SkeletonAvatar className="h-10 w-10 rounded-md" />
+              </div>
+            ))}
+          </div>
+          <div className="px-4 pb-4">
+            <SkeletonText className="mb-2 h-6 w-full" />
+            <SkeletonButton className="h-10 w-full rounded-md" />
+          </div>
+        </div>
+
+        <div className="col-span-1">
+          <div className="mb-[60px] flex justify-center p-4 md:mb-10">
+            <SkeletonAvatar className="mt-10 h-16 w-16 rounded-full md:mt-7 md:h-24 md:w-24" />
+          </div>
+          <div className="px-4 pb-4">
+            <SkeletonText className="mb-2 h-6 w-full" />
+            <SkeletonButton className="h-10 w-full rounded-md" />
+          </div>
+        </div>
+
+        <div className="col-span-1">
+          <div className="mb-[60px] flex justify-center p-4 md:mb-10">
+            <SkeletonAvatar className="mt-10 h-16 w-16 rounded-md md:mt-7 md:h-24 md:w-24" />
+          </div>
+          <div className="px-4 pb-4">
+            <SkeletonText className="mb-2 h-6 w-full" />
+            <SkeletonButton className="h-10 w-full rounded-md" />
+          </div>
+        </div>
+      </div>
+    </SkeletonContainer>
+  );
+}
diff --git a/apps/web/app/(use-page-wrapper)/refer/page.tsx b/apps/web/app/(use-page-wrapper)/refer/page.tsx
new file mode 100644
index 00000000000000..25d7d7d31300d7
--- /dev/null
+++ b/apps/web/app/(use-page-wrapper)/refer/page.tsx
@@ -0,0 +1,24 @@
+import { getTranslate } from "app/_utils";
+
+import Shell from "@calcom/features/shell/Shell";
+import { IS_DUB_REFERRALS_ENABLED } from "@calcom/lib/constants";
+
+import { DubReferralsPage } from "./DubReferralsPage";
+
+// Export the appropriate component based on the feature flag
+export default async function ReferralsPage() {
+  const t = await getTranslate();
+
+  return (
+    <Shell withoutMain={true}>
+      {IS_DUB_REFERRALS_ENABLED ? (
+        <DubReferralsPage />
+      ) : (
+        <div className="mx-auto max-w-4xl p-8 text-center">
+          <h2 className="mb-4 text-xl font-semibold">{t("referral_program")}</h2>
+          <p>{t("dub_disabled_error_message")}</p>
+        </div>
+      )}
+    </Shell>
+  );
+}
diff --git a/apps/web/app/api/user/referrals-token/route.ts b/apps/web/app/api/user/referrals-token/route.ts
new file mode 100644
index 00000000000000..5fa49b61e96669
--- /dev/null
+++ b/apps/web/app/api/user/referrals-token/route.ts
@@ -0,0 +1,38 @@
+import { defaultResponderForAppDir } from "app/api/defaultResponderForAppDir";
+import { headers, cookies } from "next/headers";
+import { NextResponse } from "next/server";
+
+import { dub } from "@calcom/feature-auth/lib/dub";
+import { getServerSession } from "@calcom/feature-auth/lib/getServerSession";
+import { IS_DUB_REFERRALS_ENABLED } from "@calcom/lib/constants";
+
+import { buildLegacyRequest } from "@lib/buildLegacyCtx";
+
+export const dynamic = "force-dynamic";
+
+const handler = async () => {
+  // Return early if the feature is disabled
+  if (!IS_DUB_REFERRALS_ENABLED) {
+    return NextResponse.json({ error: "Referrals feature is disabled" }, { status: 404 });
+  }
+
+  const session = await getServerSession({ req: buildLegacyRequest(await headers(), await cookies()) });
+  if (!session) {
+    return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
+  }
+  const { publicToken } = await dub.embedTokens.referrals({
+    programId: process.env.NEXT_PUBLIC_DUB_PROGRAM_ID as string,
+    tenantId: session.user.id.toString(),
+    partner: {
+      name: session?.user.name || session?.user.email || "",
+      email: session?.user.email || session?.user.name || "",
+      username: session?.user.username || "",
+      image: session?.user.image || null,
+      tenantId: session?.user.id.toString() || "",
+    },
+  });
+
+  return NextResponse.json({ publicToken });
+};
+
+export const GET = defaultResponderForAppDir(handler);
diff --git a/apps/web/package.json b/apps/web/package.json
index c9873c95d8d797..b66b344f42e959 100644
--- a/apps/web/package.json
+++ b/apps/web/package.json
@@ -45,6 +45,8 @@
     "@daily-co/daily-js": "^0.76.0",
     "@daily-co/daily-react": "^0.22.0",
     "@dub/analytics": "^0.0.15",
+    "@dub/embed-core": "^0.0.10",
+    "@dub/embed-react": "^0.0.10",
     "@formkit/auto-animate": "1.0.0-beta.5",
     "@glidejs/glide": "^3.5.2",
     "@googleapis/admin": "^23.0.0",
diff --git a/apps/web/public/static/locales/en/common.json b/apps/web/public/static/locales/en/common.json
index 281f1cb7a5ac84..514edf42cfc943 100644
--- a/apps/web/public/static/locales/en/common.json
+++ b/apps/web/public/static/locales/en/common.json
@@ -3028,6 +3028,9 @@
   "inactive_team_plan": "Inactive team plan",
   "inactive_team_plan_description": "Your team plan is inactive. Check your subcription or reach out to customer support",
   "limited_access_trial_mode": "Limited access during trial. Feature available after trial ends.",
+  "earn_20_percent_affiliate": "20% Referral",
+  "referral_program": "Referral Program",
+  "dub_disabled_error_message": "You need a Dub API Key and Program Id to use this page.",
   "uid": "UID",
   "link": "Link",
   "rows_per_page": "rows per page",
diff --git a/packages/features/shell/useBottomNavItems.ts b/packages/features/shell/useBottomNavItems.ts
index 56a690b416e3c7..838c13c8ed1dd6 100644
--- a/packages/features/shell/useBottomNavItems.ts
+++ b/packages/features/shell/useBottomNavItems.ts
@@ -1,8 +1,6 @@
 import type { User as UserAuth } from "next-auth";
-import { useState } from "react";
 
-import { IS_CALCOM } from "@calcom/lib/constants";
-import { useCopy } from "@calcom/lib/hooks/useCopy";
+import { IS_DUB_REFERRALS_ENABLED } from "@calcom/lib/constants";
 import { useLocale } from "@calcom/lib/hooks/useLocale";
 import { showToast } from "@calcom/ui/components/toast";
 
@@ -20,8 +18,6 @@ export function useBottomNavItems({
   user,
 }: BottomNavItemsProps): NavigationItemType[] {
   const { t } = useLocale();
-  const [isReferalLoading, setIsReferalLoading] = useState(false);
-  const { fetchAndCopyToClipboard } = useCopy();
 
   return [
     {
@@ -40,31 +36,11 @@ export function useBottomNavItems({
       },
       icon: "copy",
     },
-    IS_CALCOM
+    IS_DUB_REFERRALS_ENABLED
       ? {
-          name: "copy_referral_link",
-          href: "",
-          onClick: (e: { preventDefault: () => void }) => {
-            e.preventDefault();
-            setIsReferalLoading(true);
-            // Create an artificial delay to show the loading state so it doesn't flicker if this request is fast
-            setTimeout(() => {
-              fetchAndCopyToClipboard(
-                fetch("/api/generate-referral-link", {
-                  method: "POST",
-                })
-                  .then((res) => res.json())
-                  .then((res) => res.shortLink),
-                {
-                  onSuccess: () => showToast(t("link_copied"), "success"),
-                  onFailure: () => showToast("Copy to clipboard failed", "error"),
-                }
-              );
-              setIsReferalLoading(false);
-            }, 1000);
-          },
+          name: "earn_20_percent_affiliate",
+          href: "/refer",
           icon: "gift",
-          isLoading: isReferalLoading,
         }
       : null,
     isAdmin
diff --git a/packages/lib/constants.ts b/packages/lib/constants.ts
index 0a8520a28a3b73..06eccea1a48add 100644
--- a/packages/lib/constants.ts
+++ b/packages/lib/constants.ts
@@ -210,4 +210,8 @@ export const DIRECTORY_IDS_TO_LOG = process.env.DIRECTORY_IDS_TO_LOG?.split(",")
 
 export const IS_PLAIN_CHAT_ENABLED =
   !!process.env.NEXT_PUBLIC_PLAIN_CHAT_ID && process.env.NEXT_PUBLIC_PLAIN_CHAT_ID !== "";
+
+export const IS_DUB_REFERRALS_ENABLED =
+  !!process.env.NEXT_PUBLIC_DUB_PROGRAM_ID && process.env.NEXT_PUBLIC_DUB_PROGRAM_ID !== "";
+
 export const CAL_VIDEO_MEETING_LINK_FOR_TESTING = process.env.CAL_VIDEO_MEETING_LINK_FOR_TESTING;
diff --git a/turbo.json b/turbo.json
index 3d7a884969e980..355ab4084634e1 100644
--- a/turbo.json
+++ b/turbo.json
@@ -278,6 +278,7 @@
     "DATABASE_URL",
     "DEBUG",
     "DUB_API_KEY",
+    "NEXT_PUBLIC_DUB_PROGRAM_ID",
     "E2E_TEST_APPLE_CALENDAR_EMAIL",
     "E2E_TEST_APPLE_CALENDAR_PASSWORD",
     "E2E_TEST_CALCOM_QA_EMAIL",
diff --git a/yarn.lock b/yarn.lock
index 4d3e6e4183b7e4..3db63618bcb782 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -3765,6 +3765,8 @@ __metadata:
     "@daily-co/daily-js": ^0.76.0
     "@daily-co/daily-react": ^0.22.0
     "@dub/analytics": ^0.0.15
+    "@dub/embed-core": ^0.0.10
+    "@dub/embed-react": ^0.0.10
     "@formkit/auto-animate": 1.0.0-beta.5
     "@glidejs/glide": ^3.5.2
     "@googleapis/admin": ^23.0.0
@@ -4354,6 +4356,28 @@ __metadata:
   languageName: node
   linkType: hard
 
+"@dub/embed-core@npm:^0.0.10":
+  version: 0.0.10
+  resolution: "@dub/embed-core@npm:0.0.10"
+  dependencies:
+    "@floating-ui/dom": ^1.6.12
+  checksum: 6b423707ea296c7d7e958677c3983eeab8131e59d23bd18be3aa90c7016cb2708a94140122194d7b7074766121bde7e53216cf33532e515bb6834b9e889af87b
+  languageName: node
+  linkType: hard
+
+"@dub/embed-react@npm:^0.0.10":
+  version: 0.0.10
+  resolution: "@dub/embed-react@npm:0.0.10"
+  dependencies:
+    class-variance-authority: ^0.7.0
+    vite: 5.2.9
+  peerDependencies:
+    react: ^18.2.0
+    react-dom: ^18.2.0
+  checksum: 13cce78ab4c11c5c056832b8e92a4f333cce25f094b9da60c2919a414b49c8fc67ea89458f10cb1cdcbd46053e34e6390b3494803d9214f592e6a88dd155cb66
+  languageName: node
+  linkType: hard
+
 "@emnapi/runtime@npm:^1.2.0":
   version: 1.3.1
   resolution: "@emnapi/runtime@npm:1.3.1"
@@ -4514,6 +4538,13 @@ __metadata:
   languageName: node
   linkType: hard
 
+"@esbuild/aix-ppc64@npm:0.20.2":
+  version: 0.20.2
+  resolution: "@esbuild/aix-ppc64@npm:0.20.2"
+  conditions: os=aix & cpu=ppc64
+  languageName: node
+  linkType: hard
+
 "@esbuild/aix-ppc64@npm:0.21.5":
   version: 0.21.5
   resolution: "@esbuild/aix-ppc64@npm:0.21.5"
@@ -4535,6 +4566,13 @@ __metadata:
   languageName: node
   linkType: hard
 
+"@esbuild/android-arm64@npm:0.20.2":
+  version: 0.20.2
+  resolution: "@esbuild/android-arm64@npm:0.20.2"
+  conditions: os=android & cpu=arm64
+  languageName: node
+  linkType: hard
+
 "@esbuild/android-arm64@npm:0.21.5":
   version: 0.21.5
   resolution: "@esbuild/android-arm64@npm:0.21.5"
@@ -4556,6 +4594,13 @@ __metadata:
   languageName: node
   linkType: hard
 
+"@esbuild/android-arm@npm:0.20.2":
+  version: 0.20.2
+  resolution: "@esbuild/android-arm@npm:0.20.2"
+  conditions: os=android & cpu=arm
+  languageName: node
+  linkType: hard
+
 "@esbuild/android-arm@npm:0.21.5":
   version: 0.21.5
   resolution: "@esbuild/android-arm@npm:0.21.5"
@@ -4577,6 +4622,13 @@ __metadata:
   languageName: node
   linkType: hard
 
+"@esbuild/android-x64@npm:0.20.2":
+  version: 0.20.2
+  resolution: "@esbuild/android-x64@npm:0.20.2"
+  conditions: os=android & cpu=x64
+  languageName: node
+  linkType: hard
+
 "@esbuild/android-x64@npm:0.21.5":
   version: 0.21.5
   resolution: "@esbuild/android-x64@npm:0.21.5"
@@ -4598,6 +4650,13 @@ __metadata:
   languageName: node
   linkType: hard
 
+"@esbuild/darwin-arm64@npm:0.20.2":
+  version: 0.20.2
+  resolution: "@esbuild/darwin-arm64@npm:0.20.2"
+  conditions: os=darwin & cpu=arm64
+  languageName: node
+  linkType: hard
+
 "@esbuild/darwin-arm64@npm:0.21.5":
   version: 0.21.5
   resolution: "@esbuild/darwin-arm64@npm:0.21.5"
@@ -4619,6 +4678,13 @@ __metadata:
   languageName: node
   linkType: hard
 
+"@esbuild/darwin-x64@npm:0.20.2":
+  version: 0.20.2
+  resolution: "@esbuild/darwin-x64@npm:0.20.2"
+  conditions: os=darwin & cpu=x64
+  languageName: node
+  linkType: hard
+
 "@esbuild/darwin-x64@npm:0.21.5":
   version: 0.21.5
   resolution: "@esbuild/darwin-x64@npm:0.21.5"
@@ -4640,6 +4706,13 @@ __metadata:
   languageName: node
   linkType: hard
 
+"@esbuild/freebsd-arm64@npm:0.20.2":
+  version: 0.20.2
+  resolution: "@esbuild/freebsd-arm64@npm:0.20.2"
+  conditions: os=freebsd & cpu=arm64
+  languageName: node
+  linkType: hard
+
 "@esbuild/freebsd-arm64@npm:0.21.5":
   version: 0.21.5
   resolution: "@esbuild/freebsd-arm64@npm:0.21.5"
@@ -4661,6 +4734,13 @@ __metadata:
   languageName: node
   linkType: hard
 
+"@esbuild/freebsd-x64@npm:0.20.2":
+  version: 0.20.2
+  resolution: "@esbuild/freebsd-x64@npm:0.20.2"
+  conditions: os=freebsd & cpu=x64
+  languageName: node
+  linkType: hard
+
 "@esbuild/freebsd-x64@npm:0.21.5":
   version: 0.21.5
   resolution: "@esbuild/freebsd-x64@npm:0.21.5"
@@ -4682,6 +4762,13 @@ __metadata:
   languageName: node
   linkType: hard
 
+"@esbuild/linux-arm64@npm:0.20.2":
+  version: 0.20.2
+  resolution: "@esbuild/linux-arm64@npm:0.20.2"
+  conditions: os=linux & cpu=arm64
+  languageName: node
+  linkType: hard
+
 "@esbuild/linux-arm64@npm:0.21.5":
   version: 0.21.5
   resolution: "@esbuild/linux-arm64@npm:0.21.5"
@@ -4703,6 +4790,13 @@ __metadata:
   languageName: node
   linkType: hard
 
+"@esbuild/linux-arm@npm:0.20.2":
+  version: 0.20.2
+  resolution: "@esbuild/linux-arm@npm:0.20.2"
+  conditions: os=linux & cpu=arm
+  languageName: node
+  linkType: hard
+
 "@esbuild/linux-arm@npm:0.21.5":
   version: 0.21.5
   resolution: "@esbuild/linux-arm@npm:0.21.5"
@@ -4724,6 +4818,13 @@ __metadata:
   languageName: node
   linkType: hard
 
+"@esbuild/linux-ia32@npm:0.20.2":
+  version: 0.20.2
+  resolution: "@esbuild/linux-ia32@npm:0.20.2"
+  conditions: os=linux & cpu=ia32
+  languageName: node
+  linkType: hard
+
 "@esbuild/linux-ia32@npm:0.21.5":
   version: 0.21.5
   resolution: "@esbuild/linux-ia32@npm:0.21.5"
@@ -4745,6 +4846,13 @@ __metadata:
   languageName: node
   linkType: hard
 
+"@esbuild/linux-loong64@npm:0.20.2":
+  version: 0.20.2
+  resolution: "@esbuild/linux-loong64@npm:0.20.2"
+  conditions: os=linux & cpu=loong64
+  languageName: node
+  linkType: hard
+
 "@esbuild/linux-loong64@npm:0.21.5":
   version: 0.21.5
   resolution: "@esbuild/linux-loong64@npm:0.21.5"
@@ -4766,6 +4874,13 @@ __metadata:
   languageName: node
   linkType: hard
 
+"@esbuild/linux-mips64el@npm:0.20.2":
+  version: 0.20.2
+  resolution: "@esbuild/linux-mips64el@npm:0.20.2"
+  conditions: os=linux & cpu=mips64el
+  languageName: node
+  linkType: hard
+
 "@esbuild/linux-mips64el@npm:0.21.5":
   version: 0.21.5
   resolution: "@esbuild/linux-mips64el@npm:0.21.5"
@@ -4787,6 +4902,13 @@ __metadata:
   languageName: node
   linkType: hard
 
+"@esbuild/linux-ppc64@npm:0.20.2":
+  version: 0.20.2
+  resolution: "@esbuild/linux-ppc64@npm:0.20.2"
+  conditions: os=linux & cpu=ppc64
+  languageName: node
+  linkType: hard
+
 "@esbuild/linux-ppc64@npm:0.21.5":
   version: 0.21.5
   resolution: "@esbuild/linux-ppc64@npm:0.21.5"
@@ -4808,6 +4930,13 @@ __metadata:
   languageName: node
   linkType: hard
 
+"@esbuild/linux-riscv64@npm:0.20.2":
+  version: 0.20.2
+  resolution: "@esbuild/linux-riscv64@npm:0.20.2"
+  conditions: os=linux & cpu=riscv64
+  languageName: node
+  linkType: hard
+
 "@esbuild/linux-riscv64@npm:0.21.5":
   version: 0.21.5
   resolution: "@esbuild/linux-riscv64@npm:0.21.5"
@@ -4829,6 +4958,13 @@ __metadata:
   languageName: node
   linkType: hard
 
+"@esbuild/linux-s390x@npm:0.20.2":
+  version: 0.20.2
+  resolution: "@esbuild/linux-s390x@npm:0.20.2"
+  conditions: os=linux & cpu=s390x
+  languageName: node
+  linkType: hard
+
 "@esbuild/linux-s390x@npm:0.21.5":
   version: 0.21.5
   resolution: "@esbuild/linux-s390x@npm:0.21.5"
@@ -4850,6 +4986,13 @@ __metadata:
   languageName: node
   linkType: hard
 
+"@esbuild/linux-x64@npm:0.20.2":
+  version: 0.20.2
+  resolution: "@esbuild/linux-x64@npm:0.20.2"
+  conditions: os=linux & cpu=x64
+  languageName: node
+  linkType: hard
+
 "@esbuild/linux-x64@npm:0.21.5":
   version: 0.21.5
   resolution: "@esbuild/linux-x64@npm:0.21.5"
@@ -4871,6 +5014,13 @@ __metadata:
   languageName: node
   linkType: hard
 
+"@esbuild/netbsd-x64@npm:0.20.2":
+  version: 0.20.2
+  resolution: "@esbuild/netbsd-x64@npm:0.20.2"
+  conditions: os=netbsd & cpu=x64
+  languageName: node
+  linkType: hard
+
 "@esbuild/netbsd-x64@npm:0.21.5":
   version: 0.21.5
   resolution: "@esbuild/netbsd-x64@npm:0.21.5"
@@ -4892,6 +5042,13 @@ __metadata:
   languageName: node
   linkType: hard
 
+"@esbuild/openbsd-x64@npm:0.20.2":
+  version: 0.20.2
+  resolution: "@esbuild/openbsd-x64@npm:0.20.2"
+  conditions: os=openbsd & cpu=x64
+  languageName: node
+  linkType: hard
+
 "@esbuild/openbsd-x64@npm:0.21.5":
   version: 0.21.5
   resolution: "@esbuild/openbsd-x64@npm:0.21.5"
@@ -4913,6 +5070,13 @@ __metadata:
   languageName: node
   linkType: hard
 
+"@esbuild/sunos-x64@npm:0.20.2":
+  version: 0.20.2
+  resolution: "@esbuild/sunos-x64@npm:0.20.2"
+  conditions: os=sunos & cpu=x64
+  languageName: node
+  linkType: hard
+
 "@esbuild/sunos-x64@npm:0.21.5":
   version: 0.21.5
   resolution: "@esbuild/sunos-x64@npm:0.21.5"
@@ -4934,6 +5098,13 @@ __metadata:
   languageName: node
   linkType: hard
 
+"@esbuild/win32-arm64@npm:0.20.2":
+  version: 0.20.2
+  resolution: "@esbuild/win32-arm64@npm:0.20.2"
+  conditions: os=win32 & cpu=arm64
+  languageName: node
+  linkType: hard
+
 "@esbuild/win32-arm64@npm:0.21.5":
   version: 0.21.5
   resolution: "@esbuild/win32-arm64@npm:0.21.5"
@@ -4955,6 +5126,13 @@ __metadata:
   languageName: node
   linkType: hard
 
+"@esbuild/win32-ia32@npm:0.20.2":
+  version: 0.20.2
+  resolution: "@esbuild/win32-ia32@npm:0.20.2"
+  conditions: os=win32 & cpu=ia32
+  languageName: node
+  linkType: hard
+
 "@esbuild/win32-ia32@npm:0.21.5":
   version: 0.21.5
   resolution: "@esbuild/win32-ia32@npm:0.21.5"
@@ -4976,6 +5154,13 @@ __metadata:
   languageName: node
   linkType: hard
 
+"@esbuild/win32-x64@npm:0.20.2":
+  version: 0.20.2
+  resolution: "@esbuild/win32-x64@npm:0.20.2"
+  conditions: os=win32 & cpu=x64
+  languageName: node
+  linkType: hard
+
 "@esbuild/win32-x64@npm:0.21.5":
   version: 0.21.5
   resolution: "@esbuild/win32-x64@npm:0.21.5"
@@ -5061,6 +5246,15 @@ __metadata:
   languageName: node
   linkType: hard
 
+"@floating-ui/core@npm:^1.6.0":
+  version: 1.6.9
+  resolution: "@floating-ui/core@npm:1.6.9"
+  dependencies:
+    "@floating-ui/utils": ^0.2.9
+  checksum: 21cbcac72a40172399570dedf0eb96e4f24b0d829980160e8d14edf08c2955ac6feffb7b94e1530c78fb7944635e52669c9257ad08570e0295efead3b5a9af91
+  languageName: node
+  linkType: hard
+
 "@floating-ui/dom@npm:^1.0.1, @floating-ui/dom@npm:^1.2.1":
   version: 1.2.6
   resolution: "@floating-ui/dom@npm:1.2.6"
@@ -5079,6 +5273,16 @@ __metadata:
   languageName: node
   linkType: hard
 
+"@floating-ui/dom@npm:^1.6.12":
+  version: 1.6.13
+  resolution: "@floating-ui/dom@npm:1.6.13"
+  dependencies:
+    "@floating-ui/core": ^1.6.0
+    "@floating-ui/utils": ^0.2.9
+  checksum: eabab9d860d3b5beab1c2d6936287efc4d9ab352de99062380589ef62870d59e8730397489c34a96657e128498001b5672330c4a9da0159fe8b2401ac59fe314
+  languageName: node
+  linkType: hard
+
 "@floating-ui/react-dom@npm:^1.3.0":
   version: 1.3.0
   resolution: "@floating-ui/react-dom@npm:1.3.0"
@@ -5117,6 +5321,13 @@ __metadata:
   languageName: node
   linkType: hard
 
+"@floating-ui/utils@npm:^0.2.9":
+  version: 0.2.9
+  resolution: "@floating-ui/utils@npm:0.2.9"
+  checksum: d518b80cec5a323e54a069a1dd99a20f8221a4853ed98ac16c75275a0cc22f75de4f8ac5b121b4f8990bd45da7ad1fb015b9a1e4bac27bb1cd62444af84e9784
+  languageName: node
+  linkType: hard
+
 "@formatjs/ecma402-abstract@npm:1.11.4":
   version: 1.11.4
   resolution: "@formatjs/ecma402-abstract@npm:1.11.4"
@@ -11853,9 +12064,9 @@ __metadata:
   languageName: node
   linkType: hard
 
-"@rollup/rollup-android-arm-eabi@npm:4.35.0":
-  version: 4.35.0
-  resolution: "@rollup/rollup-android-arm-eabi@npm:4.35.0"
+"@rollup/rollup-android-arm-eabi@npm:4.36.0":
+  version: 4.36.0
+  resolution: "@rollup/rollup-android-arm-eabi@npm:4.36.0"
   conditions: os=android & cpu=arm
   languageName: node
   linkType: hard
@@ -11874,9 +12085,9 @@ __metadata:
   languageName: node
   linkType: hard
 
-"@rollup/rollup-android-arm64@npm:4.35.0":
-  version: 4.35.0
-  resolution: "@rollup/rollup-android-arm64@npm:4.35.0"
+"@rollup/rollup-android-arm64@npm:4.36.0":
+  version: 4.36.0
+  resolution: "@rollup/rollup-android-arm64@npm:4.36.0"
   conditions: os=android & cpu=arm64
   languageName: node
   linkType: hard
@@ -11895,9 +12106,9 @@ __metadata:
   languageName: node
   linkType: hard
 
-"@rollup/rollup-darwin-arm64@npm:4.35.0":
-  version: 4.35.0
-  resolution: "@rollup/rollup-darwin-arm64@npm:4.35.0"
+"@rollup/rollup-darwin-arm64@npm:4.36.0":
+  version: 4.36.0
+  resolution: "@rollup/rollup-darwin-arm64@npm:4.36.0"
   conditions: os=darwin & cpu=arm64
   languageName: node
   linkType: hard
@@ -11916,9 +12127,9 @@ __metadata:
   languageName: node
   linkType: hard
 
-"@rollup/rollup-darwin-x64@npm:4.35.0":
-  version: 4.35.0
-  resolution: "@rollup/rollup-darwin-x64@npm:4.35.0"
+"@rollup/rollup-darwin-x64@npm:4.36.0":
+  version: 4.36.0
+  resolution: "@rollup/rollup-darwin-x64@npm:4.36.0"
   conditions: os=darwin & cpu=x64
   languageName: node
   linkType: hard
@@ -11930,16 +12141,16 @@ __metadata:
   languageName: node
   linkType: hard
 
-"@rollup/rollup-freebsd-arm64@npm:4.35.0":
-  version: 4.35.0
-  resolution: "@rollup/rollup-freebsd-arm64@npm:4.35.0"
+"@rollup/rollup-freebsd-arm64@npm:4.36.0":
+  version: 4.36.0
+  resolution: "@rollup/rollup-freebsd-arm64@npm:4.36.0"
   conditions: os=freebsd & cpu=arm64
   languageName: node
   linkType: hard
 
-"@rollup/rollup-freebsd-x64@npm:4.35.0":
-  version: 4.35.0
-  resolution: "@rollup/rollup-freebsd-x64@npm:4.35.0"
+"@rollup/rollup-freebsd-x64@npm:4.36.0":
+  version: 4.36.0
+  resolution: "@rollup/rollup-freebsd-x64@npm:4.36.0"
   conditions: os=freebsd & cpu=x64
   languageName: node
   linkType: hard
@@ -11951,9 +12162,9 @@ __metadata:
   languageName: node
   linkType: hard
 
-"@rollup/rollup-linux-arm-gnueabihf@npm:4.35.0":
-  version: 4.35.0
-  resolution: "@rollup/rollup-linux-arm-gnueabihf@npm:4.35.0"
+"@rollup/rollup-linux-arm-gnueabihf@npm:4.36.0":
+  version: 4.36.0
+  resolution: "@rollup/rollup-linux-arm-gnueabihf@npm:4.36.0"
   conditions: os=linux & cpu=arm & libc=glibc
   languageName: node
   linkType: hard
@@ -11972,9 +12183,9 @@ __metadata:
   languageName: node
   linkType: hard
 
-"@rollup/rollup-linux-arm-musleabihf@npm:4.35.0":
-  version: 4.35.0
-  resolution: "@rollup/rollup-linux-arm-musleabihf@npm:4.35.0"
+"@rollup/rollup-linux-arm-musleabihf@npm:4.36.0":
+  version: 4.36.0
+  resolution: "@rollup/rollup-linux-arm-musleabihf@npm:4.36.0"
   conditions: os=linux & cpu=arm & libc=musl
   languageName: node
   linkType: hard
@@ -11986,9 +12197,9 @@ __metadata:
   languageName: node
   linkType: hard
 
-"@rollup/rollup-linux-arm64-gnu@npm:4.35.0":
-  version: 4.35.0
-  resolution: "@rollup/rollup-linux-arm64-gnu@npm:4.35.0"
+"@rollup/rollup-linux-arm64-gnu@npm:4.36.0":
+  version: 4.36.0
+  resolution: "@rollup/rollup-linux-arm64-gnu@npm:4.36.0"
   conditions: os=linux & cpu=arm64 & libc=glibc
   languageName: node
   linkType: hard
@@ -12007,9 +12218,9 @@ __metadata:
   languageName: node
   linkType: hard
 
-"@rollup/rollup-linux-arm64-musl@npm:4.35.0":
-  version: 4.35.0
-  resolution: "@rollup/rollup-linux-arm64-musl@npm:4.35.0"
+"@rollup/rollup-linux-arm64-musl@npm:4.36.0":
+  version: 4.36.0
+  resolution: "@rollup/rollup-linux-arm64-musl@npm:4.36.0"
   conditions: os=linux & cpu=arm64 & libc=musl
   languageName: node
   linkType: hard
@@ -12021,9 +12232,9 @@ __metadata:
   languageName: node
   linkType: hard
 
-"@rollup/rollup-linux-loongarch64-gnu@npm:4.35.0":
-  version: 4.35.0
-  resolution: "@rollup/rollup-linux-loongarch64-gnu@npm:4.35.0"
+"@rollup/rollup-linux-loongarch64-gnu@npm:4.36.0":
+  version: 4.36.0
+  resolution: "@rollup/rollup-linux-loongarch64-gnu@npm:4.36.0"
   conditions: os=linux & cpu=loong64 & libc=glibc
   languageName: node
   linkType: hard
@@ -12035,9 +12246,9 @@ __metadata:
   languageName: node
   linkType: hard
 
-"@rollup/rollup-linux-powerpc64le-gnu@npm:4.35.0":
-  version: 4.35.0
-  resolution: "@rollup/rollup-linux-powerpc64le-gnu@npm:4.35.0"
+"@rollup/rollup-linux-powerpc64le-gnu@npm:4.36.0":
+  version: 4.36.0
+  resolution: "@rollup/rollup-linux-powerpc64le-gnu@npm:4.36.0"
   conditions: os=linux & cpu=ppc64 & libc=glibc
   languageName: node
   linkType: hard
@@ -12049,9 +12260,9 @@ __metadata:
   languageName: node
   linkType: hard
 
-"@rollup/rollup-linux-riscv64-gnu@npm:4.35.0":
-  version: 4.35.0
-  resolution: "@rollup/rollup-linux-riscv64-gnu@npm:4.35.0"
+"@rollup/rollup-linux-riscv64-gnu@npm:4.36.0":
+  version: 4.36.0
+  resolution: "@rollup/rollup-linux-riscv64-gnu@npm:4.36.0"
   conditions: os=linux & cpu=riscv64 & libc=glibc
   languageName: node
   linkType: hard
@@ -12063,9 +12274,9 @@ __metadata:
   languageName: node
   linkType: hard
 
-"@rollup/rollup-linux-s390x-gnu@npm:4.35.0":
-  version: 4.35.0
-  resolution: "@rollup/rollup-linux-s390x-gnu@npm:4.35.0"
+"@rollup/rollup-linux-s390x-gnu@npm:4.36.0":
+  version: 4.36.0
+  resolution: "@rollup/rollup-linux-s390x-gnu@npm:4.36.0"
   conditions: os=linux & cpu=s390x & libc=glibc
   languageName: node
   linkType: hard
@@ -12077,9 +12288,9 @@ __metadata:
   languageName: node
   linkType: hard
 
-"@rollup/rollup-linux-x64-gnu@npm:4.35.0":
-  version: 4.35.0
-  resolution: "@rollup/rollup-linux-x64-gnu@npm:4.35.0"
+"@rollup/rollup-linux-x64-gnu@npm:4.36.0":
+  version: 4.36.0
+  resolution: "@rollup/rollup-linux-x64-gnu@npm:4.36.0"
   conditions: os=linux & cpu=x64 & libc=glibc
   languageName: node
   linkType: hard
@@ -12098,9 +12309,9 @@ __metadata:
   languageName: node
   linkType: hard
 
-"@rollup/rollup-linux-x64-musl@npm:4.35.0":
-  version: 4.35.0
-  resolution: "@rollup/rollup-linux-x64-musl@npm:4.35.0"
+"@rollup/rollup-linux-x64-musl@npm:4.36.0":
+  version: 4.36.0
+  resolution: "@rollup/rollup-linux-x64-musl@npm:4.36.0"
   conditions: os=linux & cpu=x64 & libc=musl
   languageName: node
   linkType: hard
@@ -12119,9 +12330,9 @@ __metadata:
   languageName: node
   linkType: hard
 
-"@rollup/rollup-win32-arm64-msvc@npm:4.35.0":
-  version: 4.35.0
-  resolution: "@rollup/rollup-win32-arm64-msvc@npm:4.35.0"
+"@rollup/rollup-win32-arm64-msvc@npm:4.36.0":
+  version: 4.36.0
+  resolution: "@rollup/rollup-win32-arm64-msvc@npm:4.36.0"
   conditions: os=win32 & cpu=arm64
   languageName: node
   linkType: hard
@@ -12140,9 +12351,9 @@ __metadata:
   languageName: node
   linkType: hard
 
-"@rollup/rollup-win32-ia32-msvc@npm:4.35.0":
-  version: 4.35.0
-  resolution: "@rollup/rollup-win32-ia32-msvc@npm:4.35.0"
+"@rollup/rollup-win32-ia32-msvc@npm:4.36.0":
+  version: 4.36.0
+  resolution: "@rollup/rollup-win32-ia32-msvc@npm:4.36.0"
   conditions: os=win32 & cpu=ia32
   languageName: node
   linkType: hard
@@ -12161,9 +12372,9 @@ __metadata:
   languageName: node
   linkType: hard
 
-"@rollup/rollup-win32-x64-msvc@npm:4.35.0":
-  version: 4.35.0
-  resolution: "@rollup/rollup-win32-x64-msvc@npm:4.35.0"
+"@rollup/rollup-win32-x64-msvc@npm:4.36.0":
+  version: 4.36.0
+  resolution: "@rollup/rollup-win32-x64-msvc@npm:4.36.0"
   conditions: os=win32 & cpu=x64
   languageName: node
   linkType: hard
@@ -19380,7 +19591,7 @@ __metadata:
   languageName: node
   linkType: hard
 
-"class-variance-authority@npm:^0.7.1":
+"class-variance-authority@npm:^0.7.0, class-variance-authority@npm:^0.7.1":
   version: 0.7.1
   resolution: "class-variance-authority@npm:0.7.1"
   dependencies:
@@ -22367,6 +22578,86 @@ __metadata:
   languageName: node
   linkType: hard
 
+"esbuild@npm:^0.20.1":
+  version: 0.20.2
+  resolution: "esbuild@npm:0.20.2"
+  dependencies:
+    "@esbuild/aix-ppc64": 0.20.2
+    "@esbuild/android-arm": 0.20.2
+    "@esbuild/android-arm64": 0.20.2
+    "@esbuild/android-x64": 0.20.2
+    "@esbuild/darwin-arm64": 0.20.2
+    "@esbuild/darwin-x64": 0.20.2
+    "@esbuild/freebsd-arm64": 0.20.2
+    "@esbuild/freebsd-x64": 0.20.2
+    "@esbuild/linux-arm": 0.20.2
+    "@esbuild/linux-arm64": 0.20.2
+    "@esbuild/linux-ia32": 0.20.2
+    "@esbuild/linux-loong64": 0.20.2
+    "@esbuild/linux-mips64el": 0.20.2
+    "@esbuild/linux-ppc64": 0.20.2
+    "@esbuild/linux-riscv64": 0.20.2
+    "@esbuild/linux-s390x": 0.20.2
+    "@esbuild/linux-x64": 0.20.2
+    "@esbuild/netbsd-x64": 0.20.2
+    "@esbuild/openbsd-x64": 0.20.2
+    "@esbuild/sunos-x64": 0.20.2
+    "@esbuild/win32-arm64": 0.20.2
+    "@esbuild/win32-ia32": 0.20.2
+    "@esbuild/win32-x64": 0.20.2
+  dependenciesMeta:
+    "@esbuild/aix-ppc64":
+      optional: true
+    "@esbuild/android-arm":
+      optional: true
+    "@esbuild/android-arm64":
+      optional: true
+    "@esbuild/android-x64":
+      optional: true
+    "@esbuild/darwin-arm64":
+      optional: true
+    "@esbuild/darwin-x64":
+      optional: true
+    "@esbuild/freebsd-arm64":
+      optional: true
+    "@esbuild/freebsd-x64":
+      optional: true
+    "@esbuild/linux-arm":
+      optional: true
+    "@esbuild/linux-arm64":
+      optional: true
+    "@esbuild/linux-ia32":
+      optional: true
+    "@esbuild/linux-loong64":
+      optional: true
+    "@esbuild/linux-mips64el":
+      optional: true
+    "@esbuild/linux-ppc64":
+      optional: true
+    "@esbuild/linux-riscv64":
+      optional: true
+    "@esbuild/linux-s390x":
+      optional: true
+    "@esbuild/linux-x64":
+      optional: true
+    "@esbuild/netbsd-x64":
+      optional: true
+    "@esbuild/openbsd-x64":
+      optional: true
+    "@esbuild/sunos-x64":
+      optional: true
+    "@esbuild/win32-arm64":
+      optional: true
+    "@esbuild/win32-ia32":
+      optional: true
+    "@esbuild/win32-x64":
+      optional: true
+  bin:
+    esbuild: bin/esbuild
+  checksum: bc88050fc1ca5c1bd03648f9979e514bdefb956a63aa3974373bb7b9cbac0b3aac9b9da1b5bdca0b3490e39d6b451c72815dbd6b7d7f978c91fbe9c9e9aa4e4c
+  languageName: node
+  linkType: hard
+
 "esbuild@npm:^0.21.3":
   version: 0.21.5
   resolution: "esbuild@npm:0.21.5"
@@ -35684,29 +35975,29 @@ __metadata:
   languageName: node
   linkType: hard
 
-"rollup@npm:4.35.0":
-  version: 4.35.0
-  resolution: "rollup@npm:4.35.0"
-  dependencies:
-    "@rollup/rollup-android-arm-eabi": 4.35.0
-    "@rollup/rollup-android-arm64": 4.35.0
-    "@rollup/rollup-darwin-arm64": 4.35.0
-    "@rollup/rollup-darwin-x64": 4.35.0
-    "@rollup/rollup-freebsd-arm64": 4.35.0
-    "@rollup/rollup-freebsd-x64": 4.35.0
-    "@rollup/rollup-linux-arm-gnueabihf": 4.35.0
-    "@rollup/rollup-linux-arm-musleabihf": 4.35.0
-    "@rollup/rollup-linux-arm64-gnu": 4.35.0
-    "@rollup/rollup-linux-arm64-musl": 4.35.0
-    "@rollup/rollup-linux-loongarch64-gnu": 4.35.0
-    "@rollup/rollup-linux-powerpc64le-gnu": 4.35.0
-    "@rollup/rollup-linux-riscv64-gnu": 4.35.0
-    "@rollup/rollup-linux-s390x-gnu": 4.35.0
-    "@rollup/rollup-linux-x64-gnu": 4.35.0
-    "@rollup/rollup-linux-x64-musl": 4.35.0
-    "@rollup/rollup-win32-arm64-msvc": 4.35.0
-    "@rollup/rollup-win32-ia32-msvc": 4.35.0
-    "@rollup/rollup-win32-x64-msvc": 4.35.0
+"rollup@npm:^4.13.0":
+  version: 4.36.0
+  resolution: "rollup@npm:4.36.0"
+  dependencies:
+    "@rollup/rollup-android-arm-eabi": 4.36.0
+    "@rollup/rollup-android-arm64": 4.36.0
+    "@rollup/rollup-darwin-arm64": 4.36.0
+    "@rollup/rollup-darwin-x64": 4.36.0
+    "@rollup/rollup-freebsd-arm64": 4.36.0
+    "@rollup/rollup-freebsd-x64": 4.36.0
+    "@rollup/rollup-linux-arm-gnueabihf": 4.36.0
+    "@rollup/rollup-linux-arm-musleabihf": 4.36.0
+    "@rollup/rollup-linux-arm64-gnu": 4.36.0
+    "@rollup/rollup-linux-arm64-musl": 4.36.0
+    "@rollup/rollup-linux-loongarch64-gnu": 4.36.0
+    "@rollup/rollup-linux-powerpc64le-gnu": 4.36.0
+    "@rollup/rollup-linux-riscv64-gnu": 4.36.0
+    "@rollup/rollup-linux-s390x-gnu": 4.36.0
+    "@rollup/rollup-linux-x64-gnu": 4.36.0
+    "@rollup/rollup-linux-x64-musl": 4.36.0
+    "@rollup/rollup-win32-arm64-msvc": 4.36.0
+    "@rollup/rollup-win32-ia32-msvc": 4.36.0
+    "@rollup/rollup-win32-x64-msvc": 4.36.0
     "@types/estree": 1.0.6
     fsevents: ~2.3.2
   dependenciesMeta:
@@ -35752,7 +36043,7 @@ __metadata:
       optional: true
   bin:
     rollup: dist/bin/rollup
-  checksum: 1139d35809d1aa4ac8bff49fd0c819bcce86ce6e8e259fd0cacac086998938b5ad44f523d4414b6565ebc0338e7d2de0ad3efa03e26738fe8bd05f1baf72e980
+  checksum: 80a0c2b3641a1204ea90124c89a43f3de279ac2b9e0fc9eee225f04c7657652d255492eb18d987c19d4c819dd8595be766d02daacaf5f6c617e81cd0025258fe
   languageName: node
   linkType: hard
 
@@ -40278,6 +40569,46 @@ __metadata:
   languageName: node
   linkType: hard
 
+"vite@npm:5.2.9":
+  version: 5.2.9
+  resolution: "vite@npm:5.2.9"
+  dependencies:
+    esbuild: ^0.20.1
+    fsevents: ~2.3.3
+    postcss: ^8.4.38
+    rollup: ^4.13.0
+  peerDependencies:
+    "@types/node": ^18.0.0 || >=20.0.0
+    less: "*"
+    lightningcss: ^1.21.0
+    sass: "*"
+    stylus: "*"
+    sugarss: "*"
+    terser: ^5.4.0
+  dependenciesMeta:
+    fsevents:
+      optional: true
+  peerDependenciesMeta:
+    "@types/node":
+      optional: true
+    less:
+      optional: true
+    lightningcss:
+      optional: true
+    sass:
+      optional: true
+    stylus:
+      optional: true
+    sugarss:
+      optional: true
+    terser:
+      optional: true
+  bin:
+    vite: bin/vite.js
+  checksum: 7a97f9547af8550c55bc2529cc6827c1ef0a043a09e9686cf20b615e8d59305cbe917954e806c5fdad6c33bfb883c1ce51325a9c474b5aa5bc13c377a74805fd
+  languageName: node
+  linkType: hard
+
 "vite@npm:^4.1.2":
   version: 4.5.2
   resolution: "vite@npm:4.5.2"


Reviews:
user: login: hbjORbj
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-20T15:00:09Z
user: login: hbjORbj
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-20T15:00:19Z
user: login: hbjORbj
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-20T15:01:11Z
user: login: hbjORbj
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-20T15:01:22Z
user: login: hbjORbj
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-20T15:01:33Z
user: login: hbjORbj
state: DISMISSED
author_association: CONTRIBUTOR
submitted_at: 2025-03-20T21:59:30Z
user: login: zomars
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-21T19:51:21Z
user: login: zomars
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-21T19:52:18Z
user: login: zomars
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-21T19:54:43Z
user: login: Amit91848
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-24T09:08:49Z
user: login: Amit91848
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-24T09:09:23Z
user: login: zomars
state: DISMISSED
author_association: CONTRIBUTOR
submitted_at: 2025-03-26T20:06:57Z
user: login: hbjORbj
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-03-26T20:19:53Z

Review comments:
diff_hunk: @@ -0,0 +1,127 @@
+"use client";
+
+import { useState, useEffect } from "react";
+
+import ReferralClient from "@calcom/features/dub/ReferralClient";
+import { IS_DUB_REFERRALS_ENABLED } from "@calcom/lib/constants";
+import { useLocale } from "@calcom/lib/hooks/useLocale";
+import { SkeletonAvatar, SkeletonButton, SkeletonContainer, SkeletonText } from "@calcom/ui/skeleton";
path: apps/web/app/(use-page-wrapper)/(main-nav)/refer/page.tsx
user: login: hbjORbj
body: ```suggestion
import { SkeletonAvatar, SkeletonButton, SkeletonContainer, SkeletonText } from "@calcom/ui/components/skeleton";
```
created_at: 2025-03-20T15:00:09Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,127 @@
+"use client";
+
+import { useState, useEffect } from "react";
+
+import ReferralClient from "@calcom/features/dub/ReferralClient";
+import { IS_DUB_REFERRALS_ENABLED } from "@calcom/lib/constants";
+import { useLocale } from "@calcom/lib/hooks/useLocale";
+import { SkeletonAvatar, SkeletonButton, SkeletonContainer, SkeletonText } from "@calcom/ui/skeleton";
+import { showToast } from "@calcom/ui/toast";
path: apps/web/app/(use-page-wrapper)/(main-nav)/refer/page.tsx
user: login: hbjORbj
body: ```suggestion
import { showToast } from "@calcom/ui/components/toast";
```
created_at: 2025-03-20T15:00:19Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,127 @@
+"use client";
+
+import { useState, useEffect } from "react";
+
+import ReferralClient from "@calcom/features/dub/ReferralClient";
+import { IS_DUB_REFERRALS_ENABLED } from "@calcom/lib/constants";
+import { useLocale } from "@calcom/lib/hooks/useLocale";
+import { SkeletonAvatar, SkeletonButton, SkeletonContainer, SkeletonText } from "@calcom/ui/skeleton";
+import { showToast } from "@calcom/ui/toast";
+
+const fetchReferralsToken = async () => {
+  try {
+    const response = await fetch("/api/user/referrals-token");
+
+    if (!response.ok) {
+      const { error } = await response.json();
+      showToast(error, "error");
+      return null;
+    }
+
+    const data = await response.json();
+
+    return data.publicToken;
+  } catch (error) {
+    console.error("Error fetching referrals token:", error);
+    return null;
+  }
+};
+
+// The enabled referrals page implementation
+const EnabledReferralsPage = () => {
path: apps/web/app/(use-page-wrapper)/(main-nav)/refer/page.tsx
user: login: hbjORbj
body: i would move this to `refer/EnabledReferralsPage.tsx`
created_at: 2025-03-20T15:01:11Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,127 @@
+"use client";
+
+import { useState, useEffect } from "react";
+
+import ReferralClient from "@calcom/features/dub/ReferralClient";
+import { IS_DUB_REFERRALS_ENABLED } from "@calcom/lib/constants";
+import { useLocale } from "@calcom/lib/hooks/useLocale";
+import { SkeletonAvatar, SkeletonButton, SkeletonContainer, SkeletonText } from "@calcom/ui/skeleton";
+import { showToast } from "@calcom/ui/toast";
+
+const fetchReferralsToken = async () => {
+  try {
+    const response = await fetch("/api/user/referrals-token");
+
+    if (!response.ok) {
+      const { error } = await response.json();
+      showToast(error, "error");
+      return null;
+    }
+
+    const data = await response.json();
+
+    return data.publicToken;
+  } catch (error) {
+    console.error("Error fetching referrals token:", error);
+    return null;
+  }
+};
+
+// The enabled referrals page implementation
+const EnabledReferralsPage = () => {
+  const [token, setToken] = useState<string | null>(null);
+  const [loading, setLoading] = useState(true);
+  const { t } = useLocale();
+
+  useEffect(() => {
+    const getToken = async () => {
+      try {
+        const publicToken = await fetchReferralsToken();
+        setToken(publicToken);
+      } catch (err) {
+        console.error("Error fetching referrals token:", err);
+        showToast(t("unexpected_error_try_again"), "error");
+      } finally {
+        setLoading(false);
+      }
+    };
+
+    getToken();
+  }, []);
+
+  if (loading || !token) {
+    return (
+      <SkeletonContainer className="mx-auto max-w-4xl">
+        <div className="rounded-md p-8">
+          <div className="mb-2 flex items-center">
+            <SkeletonText className="h-5 w-32" />
+          </div>
+
+          <div className="mb-6 space-y-2">
+            <SkeletonText className="h-7 w-3/4" />
+            <SkeletonText className="h-7 w-1/2" />
+          </div>
+
+          <div className="mb-6">
+            <SkeletonText className="mb-2 h-5 w-24" />
+            <div className="flex items-center space-x-2">
+              <SkeletonText className="h-10 w-full rounded-md" />
+              <SkeletonButton className="h-10 w-28 rounded-md" />
+            </div>
+          </div>
+        </div>
+
+        <div className="mt-4 grid grid-cols-3 gap-4 p-4">
+          <div className="col-span-1">
+            <div className="mb-4 grid grid-cols-3 gap-2 p-4">
+              {[...Array(9)].map((_, i) => (
+                <div key={i} className="flex justify-center">
+                  <SkeletonAvatar className="h-10 w-10 rounded-md" />
+                </div>
+              ))}
+            </div>
+            <div className="px-4 pb-4">
+              <SkeletonText className="mb-2 h-6 w-full" />
+              <SkeletonButton className="h-10 w-full rounded-md" />
+            </div>
+          </div>
+
+          <div className="col-span-1">
+            <div className="mb-[60px] flex justify-center p-4 md:mb-10">
+              <SkeletonAvatar className="mt-10 h-16 w-16 rounded-full md:mt-7 md:h-24 md:w-24" />
+            </div>
+            <div className="px-4 pb-4">
+              <SkeletonText className="mb-2 h-6 w-full" />
+              <SkeletonButton className="h-10 w-full rounded-md" />
+            </div>
+          </div>
+
+          <div className="col-span-1">
+            <div className="mb-[60px] flex justify-center p-4 md:mb-10">
+              <SkeletonAvatar className="mt-10 h-16 w-16 rounded-md md:mt-7 md:h-24 md:w-24" />
+            </div>
+            <div className="px-4 pb-4">
+              <SkeletonText className="mb-2 h-6 w-full" />
+              <SkeletonButton className="h-10 w-full rounded-md" />
+            </div>
+          </div>
+        </div>
+      </SkeletonContainer>
+    );
+  }
+
+  return <ReferralClient publicToken={token} />;
+};
+
+// Export the appropriate component based on the feature flag
+export default function ReferralsPage() {
path: apps/web/app/(use-page-wrapper)/(main-nav)/refer/page.tsx
user: login: hbjORbj
body: this can be async
created_at: 2025-03-20T15:01:21Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,127 @@
+"use client";
+
+import { useState, useEffect } from "react";
+
+import ReferralClient from "@calcom/features/dub/ReferralClient";
+import { IS_DUB_REFERRALS_ENABLED } from "@calcom/lib/constants";
+import { useLocale } from "@calcom/lib/hooks/useLocale";
+import { SkeletonAvatar, SkeletonButton, SkeletonContainer, SkeletonText } from "@calcom/ui/skeleton";
+import { showToast } from "@calcom/ui/toast";
+
+const fetchReferralsToken = async () => {
+  try {
+    const response = await fetch("/api/user/referrals-token");
+
+    if (!response.ok) {
+      const { error } = await response.json();
+      showToast(error, "error");
+      return null;
+    }
+
+    const data = await response.json();
+
+    return data.publicToken;
+  } catch (error) {
+    console.error("Error fetching referrals token:", error);
+    return null;
+  }
+};
+
+// The enabled referrals page implementation
+const EnabledReferralsPage = () => {
+  const [token, setToken] = useState<string | null>(null);
+  const [loading, setLoading] = useState(true);
+  const { t } = useLocale();
+
+  useEffect(() => {
+    const getToken = async () => {
+      try {
+        const publicToken = await fetchReferralsToken();
+        setToken(publicToken);
+      } catch (err) {
+        console.error("Error fetching referrals token:", err);
+        showToast(t("unexpected_error_try_again"), "error");
+      } finally {
+        setLoading(false);
+      }
+    };
+
+    getToken();
+  }, []);
+
+  if (loading || !token) {
+    return (
+      <SkeletonContainer className="mx-auto max-w-4xl">
+        <div className="rounded-md p-8">
+          <div className="mb-2 flex items-center">
+            <SkeletonText className="h-5 w-32" />
+          </div>
+
+          <div className="mb-6 space-y-2">
+            <SkeletonText className="h-7 w-3/4" />
+            <SkeletonText className="h-7 w-1/2" />
+          </div>
+
+          <div className="mb-6">
+            <SkeletonText className="mb-2 h-5 w-24" />
+            <div className="flex items-center space-x-2">
+              <SkeletonText className="h-10 w-full rounded-md" />
+              <SkeletonButton className="h-10 w-28 rounded-md" />
+            </div>
+          </div>
+        </div>
+
+        <div className="mt-4 grid grid-cols-3 gap-4 p-4">
+          <div className="col-span-1">
+            <div className="mb-4 grid grid-cols-3 gap-2 p-4">
+              {[...Array(9)].map((_, i) => (
+                <div key={i} className="flex justify-center">
+                  <SkeletonAvatar className="h-10 w-10 rounded-md" />
+                </div>
+              ))}
+            </div>
+            <div className="px-4 pb-4">
+              <SkeletonText className="mb-2 h-6 w-full" />
+              <SkeletonButton className="h-10 w-full rounded-md" />
+            </div>
+          </div>
+
+          <div className="col-span-1">
+            <div className="mb-[60px] flex justify-center p-4 md:mb-10">
+              <SkeletonAvatar className="mt-10 h-16 w-16 rounded-full md:mt-7 md:h-24 md:w-24" />
+            </div>
+            <div className="px-4 pb-4">
+              <SkeletonText className="mb-2 h-6 w-full" />
+              <SkeletonButton className="h-10 w-full rounded-md" />
+            </div>
+          </div>
+
+          <div className="col-span-1">
+            <div className="mb-[60px] flex justify-center p-4 md:mb-10">
+              <SkeletonAvatar className="mt-10 h-16 w-16 rounded-md md:mt-7 md:h-24 md:w-24" />
+            </div>
+            <div className="px-4 pb-4">
+              <SkeletonText className="mb-2 h-6 w-full" />
+              <SkeletonButton className="h-10 w-full rounded-md" />
+            </div>
+          </div>
+        </div>
+      </SkeletonContainer>
+    );
+  }
+
+  return <ReferralClient publicToken={token} />;
+};
+
+// Export the appropriate component based on the feature flag
+export default function ReferralsPage() {
+  const { t } = useLocale();
path: apps/web/app/(use-page-wrapper)/(main-nav)/refer/page.tsx
user: login: hbjORbj
body: this can be `const t = await getTranslate()`;
created_at: 2025-03-20T15:01:32Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,40 @@
+import { headers, cookies } from "next/headers";
+import { NextResponse } from "next/server";
+
+import { dub } from "@calcom/feature-auth/lib/dub";
+import { getServerSession } from "@calcom/feature-auth/lib/getServerSession";
+import { IS_DUB_REFERRALS_ENABLED } from "@calcom/lib/constants";
+
+import { buildLegacyRequest } from "@lib/buildLegacyCtx";
+
+export const dynamic = "force-dynamic";
+
+export const GET = async () => {
+  // Return early if the feature is disabled
+  if (!IS_DUB_REFERRALS_ENABLED) {
+    return NextResponse.json({ error: "Referrals feature is disabled" }, { status: 404 });
+  }
+
+  try {
+    const session = await getServerSession({ req: buildLegacyRequest(headers(), cookies()) });
path: apps/web/app/api/user/referrals-token/route.ts
user: login: hbjORbj
body: ```suggestion
    const session = await getServerSession({ req: buildLegacyRequest(await headers(), await cookies()) });
```
created_at: 2025-03-20T21:56:26Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,27 @@
+"use client";
+
+import { DubEmbed } from "@dub/embed-react";
+import { useTheme } from "next-themes";
+
+import { IS_DUB_REFERRALS_ENABLED } from "@calcom/lib/constants";
+
+const ReferralClientImpl = ({ publicToken }: { publicToken: string }) => {
path: packages/features/dub/ReferralClient.tsx
user: login: hbjORbj
body: - if this is used in apps/web/app only, it can exist there. better be in `refer` dir
- that also means `@dub/embed-react` can only be in `apps/web/package.json` 
created_at: 2025-03-20T21:59:07Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,40 @@
+import { headers, cookies } from "next/headers";
+import { NextResponse } from "next/server";
+
+import { dub } from "@calcom/feature-auth/lib/dub";
+import { getServerSession } from "@calcom/feature-auth/lib/getServerSession";
+import { IS_DUB_REFERRALS_ENABLED } from "@calcom/lib/constants";
+
+import { buildLegacyRequest } from "@lib/buildLegacyCtx";
+
+export const dynamic = "force-dynamic";
+
+export const GET = async () => {
+  // Return early if the feature is disabled
+  if (!IS_DUB_REFERRALS_ENABLED) {
+    return NextResponse.json({ error: "Referrals feature is disabled" }, { status: 404 });
+  }
+
+  try {
+    const session = await getServerSession({ req: buildLegacyRequest(headers(), cookies()) });
path: apps/web/app/api/user/referrals-token/route.ts
user: login: hbjORbj
body: because we're merging Next.js 15 in a moment
created_at: 2025-03-20T21:59:20Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,138 @@
+"use client";
+
+import { DubEmbed } from "@dub/embed-react";
+import { useTheme } from "next-themes";
+import { useState, useEffect } from "react";
+
+import { IS_DUB_REFERRALS_ENABLED } from "@calcom/lib/constants";
+import { useLocale } from "@calcom/lib/hooks/useLocale";
+import {
+  SkeletonAvatar,
+  SkeletonButton,
+  SkeletonContainer,
+  SkeletonText,
+} from "@calcom/ui/components/skeleton";
+import { showToast } from "@calcom/ui/components/toast";
+
+const fetchReferralsToken = async () => {
+  try {
+    const response = await fetch("/api/user/referrals-token");
+
+    if (!response.ok) {
+      const { error } = await response.json();
+      showToast(error, "error");
+      return null;
+    }
+
+    const data = await response.json();
+
+    return data.publicToken;
+  } catch (error) {
+    console.error("Error fetching referrals token:", error);
+    return null;
+  }
+};
+
+// The enabled referrals page implementation
+export const DubReferralsPage = () => {
+  const [token, setToken] = useState<string | null>(null);
+  const [loading, setLoading] = useState(true);
+  const { t } = useLocale();
+  const { resolvedTheme } = useTheme();
+
+  useEffect(() => {
+    const getToken = async () => {
+      try {
+        const publicToken = await fetchReferralsToken();
+        setToken(publicToken);
+      } catch (err) {
+        console.error("Error fetching referrals token:", err);
+        showToast(t("unexpected_error_try_again"), "error");
+      } finally {
+        setLoading(false);
+      }
+    };
+
+    getToken();
+  }, []);
+
+  if (!IS_DUB_REFERRALS_ENABLED) {
+    return null;
+  }
+
+  if (loading || !token) {
path: apps/web/app/(use-page-wrapper)/(main-nav)/refer/DubReferralsPage.tsx
user: login: zomars
body: Can we use loading.tsx Pattern instead?
created_at: 2025-03-21T19:51:21Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,138 @@
+"use client";
+
+import { DubEmbed } from "@dub/embed-react";
+import { useTheme } from "next-themes";
+import { useState, useEffect } from "react";
+
+import { IS_DUB_REFERRALS_ENABLED } from "@calcom/lib/constants";
+import { useLocale } from "@calcom/lib/hooks/useLocale";
+import {
+  SkeletonAvatar,
+  SkeletonButton,
+  SkeletonContainer,
+  SkeletonText,
+} from "@calcom/ui/components/skeleton";
+import { showToast } from "@calcom/ui/components/toast";
+
+const fetchReferralsToken = async () => {
+  try {
+    const response = await fetch("/api/user/referrals-token");
+
+    if (!response.ok) {
+      const { error } = await response.json();
+      showToast(error, "error");
+      return null;
+    }
+
+    const data = await response.json();
+
+    return data.publicToken;
+  } catch (error) {
+    console.error("Error fetching referrals token:", error);
+    return null;
+  }
+};
+
+// The enabled referrals page implementation
+export const DubReferralsPage = () => {
+  const [token, setToken] = useState<string | null>(null);
+  const [loading, setLoading] = useState(true);
+  const { t } = useLocale();
+  const { resolvedTheme } = useTheme();
+
+  useEffect(() => {
+    const getToken = async () => {
+      try {
+        const publicToken = await fetchReferralsToken();
+        setToken(publicToken);
+      } catch (err) {
+        console.error("Error fetching referrals token:", err);
+        showToast(t("unexpected_error_try_again"), "error");
+      } finally {
+        setLoading(false);
+      }
+    };
+
+    getToken();
+  }, []);
+
+  if (!IS_DUB_REFERRALS_ENABLED) {
+    return null;
+  }
+
+  if (loading || !token) {
path: apps/web/app/(use-page-wrapper)/(main-nav)/refer/DubReferralsPage.tsx
user: login: zomars
body: https://nextjs.org/docs/app/building-your-application/routing/route-groups#opting-for-loading-skeletons-on-a-specific-route
created_at: 2025-03-21T19:52:18Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,27 @@
+"use client";
+
+import { DubEmbed } from "@dub/embed-react";
+import { useTheme } from "next-themes";
+
+import { IS_DUB_REFERRALS_ENABLED } from "@calcom/lib/constants";
+
+const ReferralClientImpl = ({ publicToken }: { publicToken: string }) => {
path: packages/features/dub/ReferralClient.tsx
user: login: zomars
body: Agreed
created_at: 2025-03-21T19:54:43Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,138 @@
+"use client";
+
+import { DubEmbed } from "@dub/embed-react";
+import { useTheme } from "next-themes";
+import { useState, useEffect } from "react";
+
+import { IS_DUB_REFERRALS_ENABLED } from "@calcom/lib/constants";
+import { useLocale } from "@calcom/lib/hooks/useLocale";
+import {
+  SkeletonAvatar,
+  SkeletonButton,
+  SkeletonContainer,
+  SkeletonText,
+} from "@calcom/ui/components/skeleton";
+import { showToast } from "@calcom/ui/components/toast";
+
+const fetchReferralsToken = async () => {
+  try {
+    const response = await fetch("/api/user/referrals-token");
+
+    if (!response.ok) {
+      const { error } = await response.json();
+      showToast(error, "error");
+      return null;
+    }
+
+    const data = await response.json();
+
+    return data.publicToken;
+  } catch (error) {
+    console.error("Error fetching referrals token:", error);
+    return null;
+  }
+};
+
+// The enabled referrals page implementation
+export const DubReferralsPage = () => {
+  const [token, setToken] = useState<string | null>(null);
+  const [loading, setLoading] = useState(true);
+  const { t } = useLocale();
+  const { resolvedTheme } = useTheme();
+
+  useEffect(() => {
+    const getToken = async () => {
+      try {
+        const publicToken = await fetchReferralsToken();
+        setToken(publicToken);
+      } catch (err) {
+        console.error("Error fetching referrals token:", err);
+        showToast(t("unexpected_error_try_again"), "error");
+      } finally {
+        setLoading(false);
+      }
+    };
+
+    getToken();
+  }, []);
+
+  if (!IS_DUB_REFERRALS_ENABLED) {
+    return null;
+  }
+
+  if (loading || !token) {
path: apps/web/app/(use-page-wrapper)/(main-nav)/refer/DubReferralsPage.tsx
user: login: Amit91848
body: Loader for Shell Sidebar and Page loads differently so it looks weird??

[Screencast from 2025-03-24 14-28-14.webm](https://github.com/user-attachments/assets/9896b8f4-fd71-4b13-8d0c-4626de9c41f1)

created_at: 2025-03-24T09:08:48Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,138 @@
+"use client";
+
+import { DubEmbed } from "@dub/embed-react";
+import { useTheme } from "next-themes";
+import { useState, useEffect } from "react";
+
+import { IS_DUB_REFERRALS_ENABLED } from "@calcom/lib/constants";
+import { useLocale } from "@calcom/lib/hooks/useLocale";
+import {
+  SkeletonAvatar,
+  SkeletonButton,
+  SkeletonContainer,
+  SkeletonText,
+} from "@calcom/ui/components/skeleton";
+import { showToast } from "@calcom/ui/components/toast";
+
+const fetchReferralsToken = async () => {
+  try {
+    const response = await fetch("/api/user/referrals-token");
+
+    if (!response.ok) {
+      const { error } = await response.json();
+      showToast(error, "error");
+      return null;
+    }
+
+    const data = await response.json();
+
+    return data.publicToken;
+  } catch (error) {
+    console.error("Error fetching referrals token:", error);
+    return null;
+  }
+};
+
+// The enabled referrals page implementation
+export const DubReferralsPage = () => {
+  const [token, setToken] = useState<string | null>(null);
+  const [loading, setLoading] = useState(true);
+  const { t } = useLocale();
+  const { resolvedTheme } = useTheme();
+
+  useEffect(() => {
+    const getToken = async () => {
+      try {
+        const publicToken = await fetchReferralsToken();
+        setToken(publicToken);
+      } catch (err) {
+        console.error("Error fetching referrals token:", err);
+        showToast(t("unexpected_error_try_again"), "error");
+      } finally {
+        setLoading(false);
+      }
+    };
+
+    getToken();
+  }, []);
+
+  if (!IS_DUB_REFERRALS_ENABLED) {
+    return null;
+  }
+
+  if (loading || !token) {
path: apps/web/app/(use-page-wrapper)/(main-nav)/refer/DubReferralsPage.tsx
user: login: Amit91848
body: Instead of loading.tsx, should I wrap the DubReferralsPage is Suspense? @zomars 
created_at: 2025-03-24T09:09:22Z
author_association: MEMBER

PR comments:
user: login: graphite-app[bot]
created_at: 2025-03-20T14:50:11Z
body: ### Graphite Automations
<details><summary><a href="https://app.graphite.dev/automations/?org=calcom&ruleId=qoTwHtX8MnP39HKxIt4V&ref=gt-automation-github-comment">"Add consumer team as reviewer"</a> took an action on this PR • (03/20/25)</summary><p>1 reviewer was added to this PR based on Keith Williams's automation.</p></details>
author_association: NONE
user: login: vercel[bot]
created_at: 2025-03-20T15:35:36Z
body: [vc]: #K94OOPj8+E8w+whh0U/Rr1c5UYXVl2IGM1G70Eys9q8=:eyJpc01vbm9yZXBvIjp0cnVlLCJ0eXBlIjoiZ2l0aHViIiwicHJvamVjdHMiOlt7Im5hbWUiOiJjYWxjb20td2ViLWNhbmFyeSIsInJvb3REaXJlY3RvcnkiOiJhcHBzL3dlYiIsImluc3BlY3RvclVybCI6Imh0dHBzOi8vdmVyY2VsLmNvbS9jYWwvY2FsY29tLXdlYi1jYW5hcnkvSE5NUjh3RkROaGdNc1lDcXBxQmdhZFdRa1FIeSIsInByZXZpZXdVcmwiOiJjYWxjb20td2ViLWNhbmFyeS1naXQtZmVhdC1kdWItcmVmZXJyYWwtZW1iZWQtY2FsLnZlcmNlbC5hcHAiLCJuZXh0Q29tbWl0U3RhdHVzIjoiSUdOT1JFRCIsImxpdmVGZWVkYmFjayI6eyJyZXNvbHZlZCI6MCwidW5yZXNvbHZlZCI6MCwidG90YWwiOjAsImxpbmsiOiIifX0seyJuYW1lIjoiY2FsIiwicm9vdERpcmVjdG9yeSI6ImFwcHMvd2ViIiwiaW5zcGVjdG9yVXJsIjoiaHR0cHM6Ly92ZXJjZWwuY29tL2NhbC9jYWwvQlR2RWF6NnZCNlllRFg5WWpTTENZUm1KRGFmWiIsInByZXZpZXdVcmwiOiJjYWwtZ2l0LWZlYXQtZHViLXJlZmVycmFsLWVtYmVkLWNhbC52ZXJjZWwuYXBwIiwibmV4dENvbW1pdFN0YXR1cyI6IklHTk9SRUQiLCJsaXZlRmVlZGJhY2siOnsicmVzb2x2ZWQiOjAsInVucmVzb2x2ZWQiOjAsInRvdGFsIjowLCJsaW5rIjoiIn19XX0=
**The latest updates on your projects**. Learn more about [Vercel for Git ↗︎](https://vercel.link/github-learn-more)


<details><summary>2 Skipped Deployments</summary>

| Name | Status | Preview | Comments | Updated (UTC) |
| :--- | :----- | :------ | :------- | :------ |
| **cal** | ⬜️ Ignored ([Inspect](https://vercel.com/cal/cal/BTvEaz6vB6YeDX9YjSLCYRmJDafZ)) | [Visit Preview](https://cal-git-feat-dub-referral-embed-cal.vercel.app) |  | Mar 26, 2025 8:10pm |
| **calcom-web-canary** | ⬜️ Ignored ([Inspect](https://vercel.com/cal/calcom-web-canary/HNMR8wFDNhgMsYCqpqBgadWQkQHy)) | [Visit Preview](https://calcom-web-canary-git-feat-dub-referral-embed-cal.vercel.app) |  | Mar 26, 2025 8:10pm |
</details>



author_association: NONE
user: login: github-actions[bot]
created_at: 2025-03-21T08:02:48Z
body: <!-- GENERATED-E2E-RESULTS -->
## E2E results are ready!
- [Workflow #54183.2 latest results](https://calcom.github.io/test-results/reports/feat/dub-referral-embed/14092531548/2)
author_association: CONTRIBUTOR
user: login: socket-security[bot]
created_at: 2025-03-21T19:56:20Z
body: **👍 Dependency issues cleared.** Learn more about [Socket for GitHub ↗︎](https://socket.dev?utm_medium=gh)

This PR previously contained dependency changes with security issues that have been resolved, removed, or ignored.





[**View full report↗︎**](https://socket.dev/dashboard/org/calcom/diff/ded59675-d88e-49c4-99d7-71f1aa65391d/93ae9cd8-b07c-4db7-a430-deb59fe6e440)
author_association: NONE
user: login: socket-security[bot]
created_at: 2025-03-26T17:18:20Z
body: **New, updated, and removed dependencies detected.** Learn more about [Socket for GitHub ↗︎](https://socket.dev?utm_medium=gh)


| Package | New capabilities | Transitives | Size | Publisher |
|:--- |:--- |:--- |:--- |:--- |
| [npm/@formkit/auto-animate@1.0.0-beta.5](https://socket.dev/npm/package/@formkit/auto-animate/overview/1.0.0-beta.5) | None | <a href="https://socket.dev/npm/package/@formkit/auto-animate/dependencies/1.0.0-beta.5">`0`</a> | 35.4 kB | <a href="https://socket.dev/npm/user/justin-schroeder">justin-schroeder</a> |



[**View full report↗︎**](https://socket.dev/dashboard/org/calcom/diff/ded59675-d88e-49c4-99d7-71f1aa65391d/93ae9cd8-b07c-4db7-a430-deb59fe6e440)

<!-- overview-comment -->
author_association: NONE
user: login: hbjORbj
created_at: 2025-03-26T20:16:56Z
body: @Amit91848 let's remove `apps/web/app/api/generate-referral-link/route.ts` since it's no longer needed, I suppose

you can do this in a follow-up PR!
author_association: CONTRIBUTOR
user: login: hbjORbj
created_at: 2025-03-26T20:19:43Z
body: Confirmed it works

<img width="1512" alt="Screenshot 2025-03-26 at 4 19 30 PM" src="https://github.com/user-attachments/assets/56886def-bca5-4999-be70-a1cbbdfd5f7f" />

author_association: CONTRIBUTOR