feat: introduce AuthConnectButton component for streamlined authentication actions
Some checks are pending
E2E / Playwright e2e (push) Waiting to run

- Added AuthConnectButton component to centralize and simplify authentication button rendering across various forms.
- Updated existing authentication components to utilize AuthConnectButton, enhancing code reusability and maintainability.
- Refactored CSS styles for consistent button appearance and layout in authentication flows.
This commit is contained in:
R3D347HR4Y 2026-06-19 22:54:04 +02:00
parent 359931c2f3
commit be9133e220
5 changed files with 112 additions and 42 deletions

View File

@ -936,9 +936,15 @@ html[data-route-scope='drive'] body {
} }
} }
.ultimail-login-connect-action {
display: flex;
width: 100%;
justify-content: center;
}
.ultimail-login .ultimail-login-connect-border { .ultimail-login .ultimail-login-connect-border {
position: relative; position: relative;
display: inline-flex; display: flex;
width: 100%; width: 100%;
padding: 2px; padding: 2px;
border-radius: 9999px; border-radius: 9999px;
@ -1163,6 +1169,11 @@ html[data-route-scope='drive'] body {
.ultimail-login .ultimail-login-connect-border { .ultimail-login .ultimail-login-connect-border {
width: auto; width: auto;
} }
.ultimail-login-connect-action .ultimail-login-connect-border,
.ultimail-login-card-frame .ultimail-login-connect-border {
width: 100%;
}
} }
@media (prefers-reduced-motion: reduce) { @media (prefers-reduced-motion: reduce) {

View File

@ -0,0 +1,66 @@
"use client"
import Link from "next/link"
import { cn } from "@/lib/utils"
type AuthConnectButtonCommon = {
children: React.ReactNode
className?: string
}
type AuthConnectButtonAsButton = AuthConnectButtonCommon &
React.ButtonHTMLAttributes<HTMLButtonElement> & {
href?: undefined
}
type AuthConnectButtonAsAnchor = AuthConnectButtonCommon &
React.AnchorHTMLAttributes<HTMLAnchorElement> & {
href: string
}
type AuthConnectButtonAsLink = AuthConnectButtonCommon &
Omit<React.ComponentProps<typeof Link>, "href"> & {
href: string
as: "link"
}
export type AuthConnectButtonProps =
| AuthConnectButtonAsButton
| AuthConnectButtonAsAnchor
| AuthConnectButtonAsLink
/** UltiSpace gradient CTA — full width, centered in auth flows. */
export function AuthConnectButton(props: AuthConnectButtonProps) {
const { children, className } = props
const btnClass = cn("ultimail-login-connect-btn w-full", className)
let control: React.ReactNode
if ("as" in props && props.as === "link") {
const { as: _as, href, className: _c, children: _ch, ...linkProps } = props
control = (
<Link href={href} className={btnClass} {...linkProps}>
{children}
</Link>
)
} else if ("href" in props && props.href) {
const { href, className: _c, children: _ch, ...anchorProps } = props
control = (
<a href={href} className={btnClass} {...anchorProps}>
{children}
</a>
)
} else {
const { className: _c, children: _ch, ...buttonProps } = props
control = (
<button className={btnClass} {...buttonProps}>
{children}
</button>
)
}
return (
<div className="ultimail-login-connect-action">
<div className="ultimail-login-connect-border">{control}</div>
</div>
)
}

View File

@ -1,9 +1,9 @@
"use client" "use client"
import { useCallback, useEffect, useMemo, useState } from "react" import { useCallback, useEffect, useMemo, useState } from "react"
import Link from "next/link"
import { Loader2 } from "lucide-react" import { Loader2 } from "lucide-react"
import { AuthCard } from "@/components/auth/auth-card" import { AuthCard } from "@/components/auth/auth-card"
import { AuthConnectButton } from "@/components/auth/auth-connect-button"
import { FlowChallengeForm } from "@/components/auth/flow-challenge-form" import { FlowChallengeForm } from "@/components/auth/flow-challenge-form"
import { import {
AUTH_FLOW_SLUGS, AUTH_FLOW_SLUGS,
@ -131,18 +131,16 @@ export function AuthFlowPage({
Redirection en cours Redirection en cours
</p> </p>
) : null} ) : null}
<div className="ultimail-login-connect-border w-full">
{successExternal ? ( {successExternal ? (
<a href={successHref} className="ultimail-login-connect-btn"> <AuthConnectButton href={successHref}>
{successActionLabel} {successActionLabel}
</a> </AuthConnectButton>
) : ( ) : (
<Link href={successHref} className="ultimail-login-connect-btn"> <AuthConnectButton as="link" href={successHref}>
{successActionLabel} {successActionLabel}
</Link> </AuthConnectButton>
)} )}
</div> </div>
</div>
) : ( ) : (
<FlowChallengeForm <FlowChallengeForm
challenge={challenge} challenge={challenge}

View File

@ -2,6 +2,7 @@
import { useEffect, useMemo, useRef, useState } from "react" import { useEffect, useMemo, useRef, useState } from "react"
import { Loader2 } from "lucide-react" import { Loader2 } from "lucide-react"
import { AuthConnectButton } from "@/components/auth/auth-connect-button"
import { Input } from "@/components/ui/input" import { Input } from "@/components/ui/input"
import { Label } from "@/components/ui/label" import { Label } from "@/components/ui/label"
import type { FlowChallenge } from "@/lib/auth/flow-api" import type { FlowChallenge } from "@/lib/auth/flow-api"
@ -151,11 +152,10 @@ export function FlowChallengeForm({
) : null} ) : null}
{isKnownComponent(component) ? ( {isKnownComponent(component) ? (
<div className="ultimail-login-connect-border pt-1"> <AuthConnectButton
<button
type="submit" type="submit"
disabled={submitting} disabled={submitting}
className="ultimail-login-connect-btn w-full disabled:opacity-60" className="disabled:opacity-60"
> >
{submitting ? ( {submitting ? (
<> <>
@ -165,8 +165,7 @@ export function FlowChallengeForm({
) : ( ) : (
primaryAction primaryAction
)} )}
</button> </AuthConnectButton>
</div>
) : null} ) : null}
</form> </form>
) )

View File

@ -1,8 +1,8 @@
"use client" "use client"
import Link from "next/link"
import { Sparkles } from "lucide-react" import { Sparkles } from "lucide-react"
import { AuthCard } from "@/components/auth/auth-card" import { AuthCard } from "@/components/auth/auth-card"
import { AuthConnectButton } from "@/components/auth/auth-connect-button"
type LoginFormProps = { type LoginFormProps = {
loginHref: string loginHref: string
@ -25,26 +25,22 @@ export function LoginForm({
<div className="flex w-full flex-col gap-3 text-center text-sm text-muted-foreground"> <div className="flex w-full flex-col gap-3 text-center text-sm text-muted-foreground">
<p> <p>
Pas encore de compte ?{" "} Pas encore de compte ?{" "}
<Link className="font-medium text-primary underline" href={signupHref}> <a className="font-medium text-primary underline" href={signupHref}>
Créer un compte Créer un compte
</Link> </a>
</p> </p>
<p> <p>
<Link className="font-medium text-primary underline" href={forgotPasswordHref}> <a className="font-medium text-primary underline" href={forgotPasswordHref}>
Mot de passe oublié ? Mot de passe oublié ?
</Link> </a>
</p> </p>
</div> </div>
} }
> >
<div className="flex justify-center"> <AuthConnectButton href={loginHref}>
<div className="ultimail-login-connect-border w-full">
<a href={loginHref} className="ultimail-login-connect-btn">
<Sparkles className="size-4 shrink-0" strokeWidth={2} aria-hidden /> <Sparkles className="size-4 shrink-0" strokeWidth={2} aria-hidden />
Se connecter avec UltiSpace Se connecter avec UltiSpace
</a> </AuthConnectButton>
</div>
</div>
</AuthCard> </AuthCard>
) )
} }