From 622a66fcf85e8f91fa774095d48c825efe74e49d Mon Sep 17 00:00:00 2001 From: Maximilian Kaske Date: Thu, 1 Oct 2026 22:02:34 +0200 Subject: [PATCH] fix: --- .../src/app/login/_components/email-form.tsx | 85 +++++++++++++++++-- .../app/login/_components/login-button.tsx | 7 +- apps/dashboard/src/app/login/page.tsx | 53 ++++++------ 3 files changed, 106 insertions(+), 39 deletions(-) diff --git a/apps/dashboard/src/app/login/_components/email-form.tsx b/apps/dashboard/src/app/login/_components/email-form.tsx index a4eb4972..bb4313c6 100644 --- a/apps/dashboard/src/app/login/_components/email-form.tsx +++ b/apps/dashboard/src/app/login/_components/email-form.tsx @@ -1,18 +1,41 @@ "use client"; +import { Button } from "@openstatus/ui/components/ui/button"; import { Input } from "@openstatus/ui/components/ui/input"; -import { useActionState } from "react"; +import { Separator } from "@openstatus/ui/components/ui/separator"; +import { useActionState, useEffect, useState } from "react"; import { type EmailFormState, continueWithEmail } from "./actions"; -import { LoginButton } from "./login-button"; +import { LoginButton, STORAGE_KEY } from "./login-button"; const initialState: EmailFormState = {}; -export function EmailForm({ redirectTo }: { redirectTo?: string }) { +type Mode = "closed" | "sso" | "email"; + +/** + * One form, two doors: "Continue with SSO" sits with the OAuth buttons, the + * magic link hides behind a text link so OAuth stays the obvious path. Both + * submit the same action, which routes verified SSO domains server-side. + * Reopens by itself for returning email/SSO users. + */ +export function EmailForm({ + redirectTo, + sso, +}: { + redirectTo?: string; + sso: boolean; +}) { const [state, formAction, isPending] = useActionState( continueWithEmail, initialState, ); + const [mode, setMode] = useState("closed"); + + useEffect(() => { + const last = localStorage.getItem(STORAGE_KEY); + if (last === "email") setMode("email"); + if (last === "sso" && sso) setMode("sso"); + }, [sso]); if (state.sent) { return ( @@ -25,7 +48,7 @@ export function EmailForm({ redirectTo }: { redirectTo?: string }) { ); } - return ( + const form = (
{redirectTo ? ( @@ -34,9 +57,12 @@ export function EmailForm({ redirectTo }: { redirectTo?: string }) { name="email" type="email" required + autoFocus autoComplete="email" - placeholder="gilfoyle@piedpiper.dev" - aria-label="Email" + placeholder={ + mode === "sso" ? "you@company.com" : "gilfoyle@piedpiper.dev" + } + aria-label={mode === "sso" ? "Work email" : "Email"} aria-invalid={state.error ? true : undefined} aria-describedby={state.error ? "email-error" : undefined} /> @@ -47,12 +73,53 @@ export function EmailForm({ redirectTo }: { redirectTo?: string }) { ) : null} - {isPending ? "Continuing…" : "Continue"} + {mode === "sso" + ? isPending + ? "Redirecting…" + : "Continue with SSO" + : isPending + ? "Continuing…" + : "Continue with email"}
); + + return ( + <> + {sso ? ( + mode === "sso" ? ( + form + ) : ( + + ) + ) : null} +
+ + or + +
+ {mode === "email" ? ( + form + ) : ( + + )} + + ); } diff --git a/apps/dashboard/src/app/login/_components/login-button.tsx b/apps/dashboard/src/app/login/_components/login-button.tsx index 327cf1dc..2225549e 100644 --- a/apps/dashboard/src/app/login/_components/login-button.tsx +++ b/apps/dashboard/src/app/login/_components/login-button.tsx @@ -5,15 +5,16 @@ import { Button } from "@openstatus/ui/components/ui/button"; import { cn } from "@openstatus/ui/lib/utils"; import { useEffect, useState } from "react"; -const STORAGE_KEY = "openstatus:last-login-provider"; +export const STORAGE_KEY = "openstatus:last-login-provider"; -type Provider = "github" | "google" | "oidc" | "email"; +type Provider = "github" | "google" | "oidc" | "sso" | "email"; export function LoginButton({ provider, children, onClick, className, + variant = "secondary", ...props }: { provider: Provider; @@ -27,7 +28,7 @@ export function LoginButton({ return (