diff --git a/apps/web/modules/auth/login-view.tsx b/apps/web/modules/auth/login-view.tsx index 9059a61be3d28d..2ea689b8373dae 100644 --- a/apps/web/modules/auth/login-view.tsx +++ b/apps/web/modules/auth/login-view.tsx @@ -39,7 +39,7 @@ interface LoginValues { } const GoogleIcon = () => ( - + ); export type PageProps = inferSSRProps; export default function Login({ @@ -95,6 +95,12 @@ PageProps & WithNonceProps<{}>) { callbackUrl = safeCallbackUrl || ""; + const LoginFooter = ( + + {t("dont_have_an_account")} + + ); + const TwoFactorFooter = ( <> - )} - - {isGoogleLoginEnabled && ( -
-
-
- - {t("or").toLocaleLowerCase()} - -
-
-
- )} - - )} -
@@ -284,7 +233,7 @@ PageProps & WithNonceProps<{}>) { {errorMessage && }
+ {!twoFactorRequired && ( + <> + {(isGoogleLoginEnabled || displaySSOLogin) &&
} +
+ {isGoogleLoginEnabled && ( + + )} + {displaySSOLogin && ( + + )} +
+ + )} diff --git a/apps/web/modules/signup-view.tsx b/apps/web/modules/signup-view.tsx index 39d773df223099..c77e837262d452 100644 --- a/apps/web/modules/signup-view.tsx +++ b/apps/web/modules/signup-view.tsx @@ -46,9 +46,9 @@ import { TextField, Form, Alert, + showToast, CheckboxField, Icon, - showToast, } from "@calcom/ui"; import type { getServerSideProps } from "@lib/signup/getServerSideProps"; @@ -179,12 +179,9 @@ export default function Signup({ redirectUrl, emailVerificationEnabled, }: SignupProps) { - const isOrgInviteByLink = orgSlug && !prepopulateFormValues?.username; - const displayMiddleDivider = isGoogleLoginEnabled; // Add the isOutlookLoginEnabled flag here when Outlook login is added const [premiumUsername, setPremiumUsername] = useState(false); const [usernameTaken, setUsernameTaken] = useState(false); const [isGoogleLoading, setIsGoogleLoading] = useState(false); - const [displayEmailForm, setDisplayEmailForm] = useState(token); const searchParams = useCompatSearchParams(); const telemetry = useTelemetry(); const { t, i18n } = useLocale(); @@ -213,7 +210,6 @@ export default function Signup({ } const loadingSubmitState = isSubmitSuccessful || isSubmitting; - const displayBackButton = token ? false : displayEmailForm; const handleErrorsAndStripe = async (resp: Response) => { if (!resp.ok) { @@ -233,6 +229,7 @@ export default function Signup({ } }; + const isOrgInviteByLink = orgSlug && !prepopulateFormValues?.username; const isPlatformUser = redirectUrl?.includes("platform") && redirectUrl?.includes("new"); const signUp: SubmitHandler = async (_data) => { @@ -336,19 +333,6 @@ export default function Signup({ {/* Left side */}
- {displayBackButton && ( -
- -
- )}

{IS_CALCOM ? t("create_your_calcom_account") : t("create_your_account")} @@ -363,220 +347,197 @@ export default function Signup({

)}

- {/* Form Container */} - {displayEmailForm && ( -
-
{ - let updatedValues = values; - if (!formMethods.getValues().username && isOrgInviteByLink && orgAutoAcceptEmail) { - updatedValues = { - ...values, - username: getOrgUsernameFromEmail(values.email, orgAutoAcceptEmail), - }; +
+ { + let updatedValues = values; + if (!formMethods.getValues().username && isOrgInviteByLink && orgAutoAcceptEmail) { + updatedValues = { + ...values, + username: getOrgUsernameFromEmail(values.email, orgAutoAcceptEmail), + }; + } + await signUp(updatedValues); + }}> + {/* Username */} + {!isOrgInviteByLink ? ( + setUsernameTaken(value)} + data-testid="signup-usernamefield" + setPremium={(value) => setPremiumUsername(value)} + addOnLeading={ + orgSlug + ? `${getOrgFullOrigin(orgSlug, { protocol: true }).replace(URL_PROTOCOL_REGEX, "")}/` + : `${process.env.NEXT_PUBLIC_WEBSITE_URL.replace(URL_PROTOCOL_REGEX, "")}/` } - await signUp(updatedValues); - }}> - {/* Username */} - {!isOrgInviteByLink ? ( - setUsernameTaken(value)} - data-testid="signup-usernamefield" - setPremium={(value) => setPremiumUsername(value)} - addOnLeading={ - orgSlug - ? `${getOrgFullOrigin(orgSlug, { protocol: true }).replace( - URL_PROTOCOL_REGEX, - "" - )}/` - : `${process.env.NEXT_PUBLIC_WEBSITE_URL.replace(URL_PROTOCOL_REGEX, "")}/` - } - /> - ) : null} - {/* Email */} - - - {/* Password */} - + + {/* Password */} + + {/* Cloudflare Turnstile Captcha */} + {CLOUDFLARE_SITE_ID ? ( + { + formMethods.setValue("cfToken", token); + }} /> - {/* Cloudflare Turnstile Captcha */} - {CLOUDFLARE_SITE_ID ? ( - { - formMethods.setValue("cfToken", token); - }} - /> - ) : null} - - handleConsentChange(COOKIE_CONSENT)} - description={t("cookie_consent_checkbox")} + ) : null} + + handleConsentChange(COOKIE_CONSENT)} + description={t("cookie_consent_checkbox")} + /> + {errors.apiError && ( + - {errors.apiError && ( - - )} + )} + + + {!isGoogleLoginEnabled && !isSAMLLoginEnabled ? null : ( +
+
+
+ + {t("or_continue_with")} + +
+
+
+ )} +
+ {isGoogleLoginEnabled ? ( + + ) : null} + {isSAMLLoginEnabled ? ( - -
- )} - {!displayEmailForm && ( -
- {/* Upper Row */} -
- {isGoogleLoginEnabled ? ( - - ) : null} -
+ if (!formMethods.getValues("email")) { + formMethods.trigger("email"); - {displayMiddleDivider && ( -
-
-
- - {t("or").toLocaleLowerCase()} - -
-
-
- )} - - {/* Lower Row */} -
- - {isSAMLLoginEnabled ? ( - - ) : null} -
+ const username = formMethods.getValues("username"); + if (!username) { + showToast("error", t("username_required")); + return; + } + localStorage.setItem("username", username); + const sp = new URLSearchParams(); + // @NOTE: don't remove username query param as it's required right now for stripe payment page + sp.set("username", username); + sp.set("email", formMethods.getValues("email")); + router.push( + `${process.env.NEXT_PUBLIC_WEBAPP_URL}/auth/sso/saml` + `?${sp.toString()}` + ); + }}> + + {t("saml_sso")} + + ) : null}
- )} - +
{/* Already have an account & T&C */}
diff --git a/apps/web/playwright/organization/organization-invitation.e2e.ts b/apps/web/playwright/organization/organization-invitation.e2e.ts index 79c4bee5d9e3f8..70ab68dd458ad0 100644 --- a/apps/web/playwright/organization/organization-invitation.e2e.ts +++ b/apps/web/playwright/organization/organization-invitation.e2e.ts @@ -297,8 +297,7 @@ test.describe("Organization", () => { await test.step("Signing up with the previous username of the migrated user - shouldn't be allowed", async () => { await page.goto("/signup"); await expect(page.locator("text=Create your account")).toBeVisible(); - await expect(page.locator('[data-testid="continue-with-email-button"]')).toBeVisible(); - await page.locator('[data-testid="continue-with-email-button"]').click(); + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion await page.locator('input[name="username"]').fill(existingUser.username!); await page diff --git a/apps/web/playwright/signup.e2e.ts b/apps/web/playwright/signup.e2e.ts index 19e9f6a4c98d6a..348994717c6dc7 100644 --- a/apps/web/playwright/signup.e2e.ts +++ b/apps/web/playwright/signup.e2e.ts @@ -10,27 +10,7 @@ import { expectInvitationEmailToBeReceived } from "./team/expects"; test.describe.configure({ mode: "parallel" }); -test.describe("Signup Main Page Test", async () => { - test.beforeEach(async ({ features }) => { - features.reset(); - }); - - test("Continue with email button must exist / work", async ({ page }) => { - await page.goto("/signup"); - await expect(page.locator("text=Create your account")).toBeVisible(); - await expect(page.locator('[data-testid="continue-with-email-button"]')).toBeVisible(); - await page.locator('[data-testid="continue-with-email-button"]').click(); - }); - - test("Continue with google button must exist / work", async ({ page }) => { - await page.goto("/signup"); - await expect(page.locator('[data-testid="continue-with-google-button"]')).toBeVisible(); - await page.locator('[data-testid="continue-with-google-button"]').click(); - await page.waitForURL("/auth/sso/google"); - }); -}); - -test.describe("Email Signup Flow Test", async () => { +test.describe("Signup Flow Test", async () => { test.beforeEach(async ({ features }) => { features.reset(); // This resets to the inital state not an empt yarray }); @@ -46,8 +26,6 @@ test.describe("Email Signup Flow Test", async () => { await page.goto("/signup"); await expect(page.locator("text=Create your account")).toBeVisible(); - await expect(page.locator('[data-testid="continue-with-email-button"]')).toBeVisible(); - await page.locator('[data-testid="continue-with-email-button"]').click(); const alertMessage = "Username or email is already taken"; @@ -74,9 +52,8 @@ test.describe("Email Signup Flow Test", async () => { }); await page.goto("/signup"); + await expect(page.locator("text=Create your account")).toBeVisible(); - await expect(page.locator('[data-testid="continue-with-email-button"]')).toBeVisible(); - await page.locator('[data-testid="continue-with-email-button"]').click(); const alertMessage = "Username or email is already taken"; @@ -108,8 +85,6 @@ test.describe("Email Signup Flow Test", async () => { // Signup with premium username name await page.goto("/signup"); await expect(page.locator("text=Create your account")).toBeVisible(); - await expect(page.locator('[data-testid="continue-with-email-button"]')).toBeVisible(); - await page.locator('[data-testid="continue-with-email-button"]').click(); // Fill form await page.locator('input[name="username"]').fill("rock"); @@ -138,8 +113,6 @@ test.describe("Email Signup Flow Test", async () => { await page.goto("/signup"); await expect(page.locator("text=Create your account")).toBeVisible(); - await expect(page.locator('[data-testid="continue-with-email-button"]')).toBeVisible(); - await page.locator('[data-testid="continue-with-email-button"]').click(); // Fill form await page.locator('input[name="username"]').fill(userToCreate.username); @@ -159,8 +132,6 @@ test.describe("Email Signup Flow Test", async () => { const signupUrlWithParams = "/signup?username=rick-jones&email=rick-jones%40example.com"; await page.goto(signupUrlWithParams); await expect(page.locator("text=Create your account")).toBeVisible(); - await expect(page.locator('[data-testid="continue-with-email-button"]')).toBeVisible(); - await page.locator('[data-testid="continue-with-email-button"]').click(); // Fill form const usernameInput = page.locator('input[name="username"]'); @@ -242,8 +213,6 @@ test.describe("Email Signup Flow Test", async () => { await page.goto("/signup"); await expect(page.locator("text=Create your account")).toBeVisible(); - await expect(page.locator('[data-testid="continue-with-email-button"]')).toBeVisible(); - await page.locator('[data-testid="continue-with-email-button"]').click(); // Fill form await page.locator('input[name="username"]').fill(userToCreate.username); @@ -314,8 +283,7 @@ test.describe("Email Signup Flow Test", async () => { const url = new URL(newPage.url()); expect(url.pathname).toBe("/signup"); - await expect(page.locator('[data-testid="continue-with-email-button"]')).toBeVisible(); - await page.locator('[data-testid="continue-with-email-button"]').click(); + // Check required fields await newPage.locator("input[name=password]").fill(`P4ssw0rd!`); await newPage.locator("button[type=submit]").click(); diff --git a/apps/web/public/google-icon-colored.svg b/apps/web/public/google-icon-colored.svg deleted file mode 100644 index 3f8813d5cafd37..00000000000000 --- a/apps/web/public/google-icon-colored.svg +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/packages/features/auth/SAMLLogin.tsx b/packages/features/auth/SAMLLogin.tsx index e8931fcd8f9cf7..b5c196bf04d716 100644 --- a/packages/features/auth/SAMLLogin.tsx +++ b/packages/features/auth/SAMLLogin.tsx @@ -4,7 +4,7 @@ import { useFormContext } from "react-hook-form"; import z from "zod"; import { HOSTED_CAL_FEATURES } from "@calcom/lib/constants"; -import { useLastUsed } from "@calcom/lib/hooks/useLastUsed"; +import { LastUsed, useLastUsed } from "@calcom/lib/hooks/useLastUsed"; import { useLocale } from "@calcom/lib/hooks/useLocale"; import { trpc } from "@calcom/trpc/react"; import { Button } from "@calcom/ui"; @@ -36,9 +36,10 @@ export function SAMLLogin({ samlTenantID, samlProductID, setErrorMessage }: Prop return ( ); }