@@ -16,9 +16,11 @@ import { Input } from '@/components/ui/input'
1616import { Label } from '@/components/ui/label'
1717import { client } from '@/lib/auth-client'
1818import { quickValidateEmail } from '@/lib/email/validation'
19+ import { env , isFalsy , isTruthy } from '@/lib/env'
1920import { createLogger } from '@/lib/logs/console/logger'
2021import { cn } from '@/lib/utils'
2122import { SocialLoginButtons } from '@/app/(auth)/components/social-login-buttons'
23+ import { SSOLoginButton } from '@/app/(auth)/components/sso-login-button'
2224import { inter } from '@/app/fonts/inter'
2325import { soehne } from '@/app/fonts/soehne/soehne'
2426
@@ -365,6 +367,14 @@ export default function LoginPage({
365367 }
366368 }
367369
370+ const ssoEnabled = isTruthy ( env . NEXT_PUBLIC_SSO_ENABLED )
371+ const emailEnabled = ! isFalsy ( env . NEXT_PUBLIC_EMAIL_PASSWORD_SIGNUP_ENABLED )
372+ const hasSocial = githubAvailable || googleAvailable
373+ const hasOnlySSO = ssoEnabled && ! emailEnabled && ! hasSocial
374+ const showTopSSO = hasOnlySSO
375+ const showBottomSection = hasSocial || ( ssoEnabled && ! hasOnlySSO )
376+ const showDivider = ( emailEnabled || showTopSSO ) && showBottomSection
377+
368378 return (
369379 < >
370380 < div className = 'space-y-1 text-center' >
@@ -376,96 +386,111 @@ export default function LoginPage({
376386 </ p >
377387 </ div >
378388
379- < form onSubmit = { onSubmit } className = { `${ inter . className } mt-8 space-y-8` } >
380- < div className = 'space-y-6' >
381- < div className = 'space-y-2' >
382- < div className = 'flex items-center justify-between' >
383- < Label htmlFor = 'email' > Email</ Label >
384- </ div >
385- < Input
386- id = 'email'
387- name = 'email'
388- placeholder = 'Enter your email'
389- required
390- autoCapitalize = 'none'
391- autoComplete = 'email'
392- autoCorrect = 'off'
393- value = { email }
394- onChange = { handleEmailChange }
395- className = { cn (
396- 'rounded-[10px] shadow-sm transition-colors focus:border-gray-400 focus:ring-2 focus:ring-gray-100' ,
397- showEmailValidationError &&
398- emailErrors . length > 0 &&
399- 'border-red-500 focus:border-red-500 focus:ring-red-100 focus-visible:ring-red-500'
400- ) }
401- />
402- { showEmailValidationError && emailErrors . length > 0 && (
403- < div className = 'mt-1 space-y-1 text-red-400 text-xs' >
404- { emailErrors . map ( ( error , index ) => (
405- < p key = { index } > { error } </ p >
406- ) ) }
389+ { /* SSO Login Button (primary top-only when it is the only method) */ }
390+ { showTopSSO && (
391+ < div className = { `${ inter . className } mt-8` } >
392+ < SSOLoginButton
393+ callbackURL = { callbackUrl }
394+ variant = 'primary'
395+ primaryClassName = { buttonClass }
396+ />
397+ </ div >
398+ ) }
399+
400+ { /* Email/Password Form - show unless explicitly disabled */ }
401+ { ! isFalsy ( env . NEXT_PUBLIC_EMAIL_PASSWORD_SIGNUP_ENABLED ) && (
402+ < form onSubmit = { onSubmit } className = { `${ inter . className } mt-8 space-y-8` } >
403+ < div className = 'space-y-6' >
404+ < div className = 'space-y-2' >
405+ < div className = 'flex items-center justify-between' >
406+ < Label htmlFor = 'email' > Email</ Label >
407407 </ div >
408- ) }
409- </ div >
410- < div className = 'space-y-2' >
411- < div className = 'flex items-center justify-between' >
412- < Label htmlFor = 'password' > Password</ Label >
413- < button
414- type = 'button'
415- onClick = { ( ) => setForgotPasswordOpen ( true ) }
416- className = 'font-medium text-muted-foreground text-xs transition hover:text-foreground'
417- >
418- Forgot password?
419- </ button >
420- </ div >
421- < div className = 'relative' >
422408 < Input
423- id = 'password'
424- name = 'password'
409+ id = 'email'
410+ name = 'email'
411+ placeholder = 'Enter your email'
425412 required
426- type = { showPassword ? 'text' : 'password' }
427413 autoCapitalize = 'none'
428- autoComplete = 'current-password '
414+ autoComplete = 'email '
429415 autoCorrect = 'off'
430- placeholder = 'Enter your password'
431- value = { password }
432- onChange = { handlePasswordChange }
416+ value = { email }
417+ onChange = { handleEmailChange }
433418 className = { cn (
434- 'rounded-[10px] pr-10 shadow-sm transition-colors focus:border-gray-400 focus:ring-2 focus:ring-gray-100' ,
435- showValidationError &&
436- passwordErrors . length > 0 &&
419+ 'rounded-[10px] shadow-sm transition-colors focus:border-gray-400 focus:ring-2 focus:ring-gray-100' ,
420+ showEmailValidationError &&
421+ emailErrors . length > 0 &&
437422 'border-red-500 focus:border-red-500 focus:ring-red-100 focus-visible:ring-red-500'
438423 ) }
439424 />
440- < button
441- type = 'button'
442- onClick = { ( ) => setShowPassword ( ! showPassword ) }
443- className = '-translate-y-1/2 absolute top-1/2 right-3 text-gray-500 transition hover:text-gray-700'
444- aria-label = { showPassword ? 'Hide password' : 'Show password' }
445- >
446- { showPassword ? < EyeOff size = { 18 } /> : < Eye size = { 18 } /> }
447- </ button >
425+ { showEmailValidationError && emailErrors . length > 0 && (
426+ < div className = 'mt-1 space-y-1 text-red-400 text-xs' >
427+ { emailErrors . map ( ( error , index ) => (
428+ < p key = { index } > { error } </ p >
429+ ) ) }
430+ </ div >
431+ ) }
448432 </ div >
449- { showValidationError && passwordErrors . length > 0 && (
450- < div className = 'mt-1 space-y-1 text-red-400 text-xs' >
451- { passwordErrors . map ( ( error , index ) => (
452- < p key = { index } > { error } </ p >
453- ) ) }
433+ < div className = 'space-y-2' >
434+ < div className = 'flex items-center justify-between' >
435+ < Label htmlFor = 'password' > Password</ Label >
436+ < button
437+ type = 'button'
438+ onClick = { ( ) => setForgotPasswordOpen ( true ) }
439+ className = 'font-medium text-muted-foreground text-xs transition hover:text-foreground'
440+ >
441+ Forgot password?
442+ </ button >
454443 </ div >
455- ) }
444+ < div className = 'relative' >
445+ < Input
446+ id = 'password'
447+ name = 'password'
448+ required
449+ type = { showPassword ? 'text' : 'password' }
450+ autoCapitalize = 'none'
451+ autoComplete = 'current-password'
452+ autoCorrect = 'off'
453+ placeholder = 'Enter your password'
454+ value = { password }
455+ onChange = { handlePasswordChange }
456+ className = { cn (
457+ 'rounded-[10px] pr-10 shadow-sm transition-colors focus:border-gray-400 focus:ring-2 focus:ring-gray-100' ,
458+ showValidationError &&
459+ passwordErrors . length > 0 &&
460+ 'border-red-500 focus:border-red-500 focus:ring-red-100 focus-visible:ring-red-500'
461+ ) }
462+ />
463+ < button
464+ type = 'button'
465+ onClick = { ( ) => setShowPassword ( ! showPassword ) }
466+ className = '-translate-y-1/2 absolute top-1/2 right-3 text-gray-500 transition hover:text-gray-700'
467+ aria-label = { showPassword ? 'Hide password' : 'Show password' }
468+ >
469+ { showPassword ? < EyeOff size = { 18 } /> : < Eye size = { 18 } /> }
470+ </ button >
471+ </ div >
472+ { showValidationError && passwordErrors . length > 0 && (
473+ < div className = 'mt-1 space-y-1 text-red-400 text-xs' >
474+ { passwordErrors . map ( ( error , index ) => (
475+ < p key = { index } > { error } </ p >
476+ ) ) }
477+ </ div >
478+ ) }
479+ </ div >
456480 </ div >
457- </ div >
458481
459- < Button
460- type = 'submit'
461- className = { `${ buttonClass } flex w-full items-center justify-center gap-2 rounded-[10px] border font-medium text-[15px] text-white transition-all duration-200` }
462- disabled = { isLoading }
463- >
464- { isLoading ? 'Signing in...' : 'Sign in' }
465- </ Button >
466- </ form >
482+ < Button
483+ type = 'submit'
484+ className = { `${ buttonClass } flex w-full items-center justify-center gap-2 rounded-[10px] border font-medium text-[15px] text-white transition-all duration-200` }
485+ disabled = { isLoading }
486+ >
487+ { isLoading ? 'Signing in...' : 'Sign in' }
488+ </ Button >
489+ </ form >
490+ ) }
467491
468- { ( githubAvailable || googleAvailable ) && (
492+ { /* Divider - show when we have multiple auth methods */ }
493+ { showDivider && (
469494 < div className = { `${ inter . className } relative my-6 font-light` } >
470495 < div className = 'absolute inset-0 flex items-center' >
471496 < div className = 'auth-divider w-full border-t' />
@@ -476,22 +501,37 @@ export default function LoginPage({
476501 </ div >
477502 ) }
478503
479- < SocialLoginButtons
480- googleAvailable = { googleAvailable }
481- githubAvailable = { githubAvailable }
482- isProduction = { isProduction }
483- callbackURL = { callbackUrl }
484- />
504+ { showBottomSection && (
505+ < div className = { cn ( inter . className , ! emailEnabled ? 'mt-8' : undefined ) } >
506+ < SocialLoginButtons
507+ googleAvailable = { googleAvailable }
508+ githubAvailable = { githubAvailable }
509+ isProduction = { isProduction }
510+ callbackURL = { callbackUrl }
511+ >
512+ { ssoEnabled && ! hasOnlySSO && (
513+ < SSOLoginButton
514+ callbackURL = { callbackUrl }
515+ variant = 'outline'
516+ primaryClassName = { buttonClass }
517+ />
518+ ) }
519+ </ SocialLoginButtons >
520+ </ div >
521+ ) }
485522
486- < div className = { `${ inter . className } pt-6 text-center font-light text-[14px]` } >
487- < span className = 'font-normal' > Don't have an account? </ span >
488- < Link
489- href = { isInviteFlow ? `/signup?invite_flow=true&callbackUrl=${ callbackUrl } ` : '/signup' }
490- className = 'font-medium text-[var(--brand-accent-hex)] underline-offset-4 transition hover:text-[var(--brand-accent-hover-hex)] hover:underline'
491- >
492- Sign up
493- </ Link >
494- </ div >
523+ { /* Only show signup link if email/password signup is enabled */ }
524+ { ! isFalsy ( env . NEXT_PUBLIC_EMAIL_PASSWORD_SIGNUP_ENABLED ) && (
525+ < div className = { `${ inter . className } pt-6 text-center font-light text-[14px]` } >
526+ < span className = 'font-normal' > Don't have an account? </ span >
527+ < Link
528+ href = { isInviteFlow ? `/signup?invite_flow=true&callbackUrl=${ callbackUrl } ` : '/signup' }
529+ className = 'font-medium text-[var(--brand-accent-hex)] underline-offset-4 transition hover:text-[var(--brand-accent-hover-hex)] hover:underline'
530+ >
531+ Sign up
532+ </ Link >
533+ </ div >
534+ ) }
495535
496536 < div
497537 className = { `${ inter . className } auth-text-muted absolute right-0 bottom-0 left-0 px-8 pb-8 text-center font-[340] text-[13px] leading-relaxed sm:px-8 md:px-[44px]` }
0 commit comments