feat: add data region dropdown to signup page (#25127)

* feat: add data region dropdown to signup page

Add a dropdown to the signup page that allows users to select their data region (United States or European Union). When a region is selected, the user is navigated to the appropriate domain (app.cal.com or app.cal.eu).

- Add SelectField component to signup page below the description text
- Detect current domain and set appropriate default value
- Navigate to correct domain when selection changes
- Add translation strings for data_region, united_states, and european_union

Co-Authored-By: peer@cal.com <peer@cal.com>

* added localhost

* fix: improve data region dropdown - SSR hydration, query params, and self-hosted protection (#25463)

* fix/remove-eu-us-dropdown-from-self-hosted-signup

* fix: remove localhost bypass and fix SSR hydration for data region dropdown

- Remove localhost bypass from IS_CALCOM check to prevent self-hosted instances from seeing Cal.com-specific dropdown
- Fix SSR hydration mismatch by using WEBAPP_URL instead of window.location for region detection
- Fix hostname replacement to preserve query parameters by modifying hostname directly instead of entire URL string

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-authored-by: Dhairyashil Shinde <93669429+dhairyashiil@users.noreply.github.com>
Co-authored-by: Dhairyashil <dhairyashil10101010@gmail.com>
This commit is contained in:
Peer Richelsen
2025-12-04 05:34:24 +00:00
committed by GitHub
co-authored by Devin AI Dhairyashil Shinde Dhairyashil
parent 0605572969
commit af3f44a7f5
2 changed files with 67 additions and 12 deletions
+64 -12
View File
@@ -7,12 +7,12 @@ import dynamic from "next/dynamic";
import Link from "next/link";
import { useRouter } from "next/navigation";
import Script from "next/script";
import posthog from "posthog-js";
import { useState, useEffect } from "react";
import type { SubmitHandler } from "react-hook-form";
import { useForm, useFormContext } from "react-hook-form";
import { Toaster } from "sonner";
import { z } from "zod";
import posthog from "posthog-js";
import getStripe from "@calcom/app-store/stripepayment/lib/client";
import { getPremiumPlanPriceValue } from "@calcom/app-store/stripepayment/lib/utils";
@@ -41,7 +41,7 @@ import type { inferSSRProps } from "@calcom/types/inferSSRProps";
import classNames from "@calcom/ui/classNames";
import { Alert } from "@calcom/ui/components/alert";
import { Button } from "@calcom/ui/components/button";
import { PasswordField, CheckboxField, TextField, Form } from "@calcom/ui/components/form";
import { PasswordField, CheckboxField, TextField, Form, SelectField } from "@calcom/ui/components/form";
import { Icon } from "@calcom/ui/components/icon";
import { showToast } from "@calcom/ui/components/toast";
@@ -337,7 +337,6 @@ export default function Signup({
}}
/>
<noscript
dangerouslySetInnerHTML={{
__html: `<iframe src="https://www.googletagmanager.com/ns.html?id=${process.env.NEXT_PUBLIC_GTM_ID}" height="0" width="0" style="display:none;visibility:hidden"></iframe>`,
}}
@@ -393,6 +392,56 @@ export default function Signup({
})}
</p>
)}
{IS_CALCOM && (
<div className="mt-4">
<SelectField
label={t("data_region")}
value={{
label: t(
// Use WEBAPP_URL for SSR-safe region detection
WEBAPP_URL.includes("cal.eu") ||
(typeof window !== "undefined" &&
window.location.hostname === "localhost" &&
new URL(window.location.href).searchParams.get("region") === "eu")
? "european_union"
: "united_states"
),
value:
// Use WEBAPP_URL for SSR-safe region detection
WEBAPP_URL.includes("cal.eu") ||
(typeof window !== "undefined" &&
window.location.hostname === "localhost" &&
new URL(window.location.href).searchParams.get("region") === "eu")
? "eu"
: "us",
}}
options={[
{ label: t("united_states"), value: "us" },
{ label: t("european_union"), value: "eu" },
]}
onChange={(option) => {
if (option && "value" in option) {
const currentUrl = new URL(window.location.href);
// Handle localhost - add region as URL parameter
if (currentUrl.hostname === "localhost") {
currentUrl.searchParams.set("region", option.value);
window.location.href = currentUrl.toString();
return;
}
// Handle production domains - modify hostname only to preserve query params
if (option.value === "eu") {
currentUrl.hostname = currentUrl.hostname.replace("cal.com", "cal.eu");
} else {
currentUrl.hostname = currentUrl.hostname.replace("cal.eu", "cal.com");
}
window.location.href = currentUrl.toString();
}
}}
/>
</div>
)}
</div>
{/* Form Container */}
@@ -426,14 +475,14 @@ export default function Signup({
addOnLeading={
orgSlug
? truncateDomain(
`${getOrgFullOrigin(orgSlug, { protocol: true }).replace(
URL_PROTOCOL_REGEX,
""
)}/`
)
`${getOrgFullOrigin(orgSlug, { protocol: true }).replace(
URL_PROTOCOL_REGEX,
""
)}/`
)
: truncateDomain(
`${process.env.NEXT_PUBLIC_WEBSITE_URL.replace(URL_PROTOCOL_REGEX, "")}/`
)
`${process.env.NEXT_PUBLIC_WEBSITE_URL.replace(URL_PROTOCOL_REGEX, "")}/`
)
}
/>
) : null}
@@ -565,7 +614,10 @@ export default function Signup({
<>
{/* eslint-disable @next/next/no-img-element */}
<img
className={classNames("text-subtle mr-2 h-4 w-4", premiumUsername && "opacity-50")}
className={classNames(
"text-subtle mr-2 h-4 w-4",
premiumUsername && "opacity-50"
)}
src="/google-icon-colored.svg"
alt="Continue with Google Icon"
/>
@@ -748,7 +800,7 @@ export default function Signup({
</div>
</>
)}
<div className="border-default hidden rounded-bl-2xl rounded-br-none rounded-tl-2xl border border-r-0 border-dashed bg-black/3 dark:bg-white/5 lg:block lg:py-[6px] lg:pl-[6px]">
<div className="border-default bg-black/3 hidden rounded-bl-2xl rounded-br-none rounded-tl-2xl border border-r-0 border-dashed dark:bg-white/5 lg:block lg:py-[6px] lg:pl-[6px]">
<img className="block dark:hidden" src="/mock-event-type-list.svg" alt="Cal.com Booking Page" />
{/* eslint-disable @next/next/no-img-element */}
<img
@@ -1373,6 +1373,9 @@
"user_impersonation_description": "Allows our support team to temporarily sign in as you to help us quickly resolve any issues you report to us.",
"team_impersonation_description": "Allows your team Owners/Admins to temporarily sign in as you.",
"cal_signup_description": "Free for individuals. Team plans for collaborative features.",
"data_region": "Data region",
"united_states": "United States",
"european_union": "European Union",
"make_org_private": "Make organization private",
"make_org_private_description": "Your organization members won't be able to see other organization members when this is turned on.",
"make_team_private": "Make team private",