@@ -24,6 +24,7 @@ import { inter } from '@/app/_styles/fonts/inter/inter'
2424import { soehne } from '@/app/_styles/fonts/soehne/soehne'
2525import { SocialLoginButtons } from '@/app/(auth)/components/social-login-buttons'
2626import { SSOLoginButton } from '@/app/(auth)/components/sso-login-button'
27+ import { useBrandedButtonClass } from '@/hooks/use-branded-button-class'
2728
2829const logger = createLogger ( 'LoginForm' )
2930
@@ -105,7 +106,7 @@ export default function LoginPage({
105106 const [ password , setPassword ] = useState ( '' )
106107 const [ passwordErrors , setPasswordErrors ] = useState < string [ ] > ( [ ] )
107108 const [ showValidationError , setShowValidationError ] = useState ( false )
108- const [ buttonClass , setButtonClass ] = useState ( 'branded-button-gradient' )
109+ const buttonClass = useBrandedButtonClass ( )
109110 const [ isButtonHovered , setIsButtonHovered ] = useState ( false )
110111
111112 const [ callbackUrl , setCallbackUrl ] = useState ( '/workspace' )
@@ -123,6 +124,7 @@ export default function LoginPage({
123124 const [ email , setEmail ] = useState ( '' )
124125 const [ emailErrors , setEmailErrors ] = useState < string [ ] > ( [ ] )
125126 const [ showEmailValidationError , setShowEmailValidationError ] = useState ( false )
127+ const [ resetSuccessMessage , setResetSuccessMessage ] = useState < string | null > ( null )
126128
127129 useEffect ( ( ) => {
128130 setMounted ( true )
@@ -139,32 +141,12 @@ export default function LoginPage({
139141
140142 const inviteFlow = searchParams . get ( 'invite_flow' ) === 'true'
141143 setIsInviteFlow ( inviteFlow )
142- }
143-
144- const checkCustomBrand = ( ) => {
145- const computedStyle = getComputedStyle ( document . documentElement )
146- const brandAccent = computedStyle . getPropertyValue ( '--brand-accent-hex' ) . trim ( )
147144
148- if ( brandAccent && brandAccent !== '#6f3dfa' ) {
149- setButtonClass ( 'branded-button-custom' )
150- } else {
151- setButtonClass ( 'branded-button-gradient' )
145+ const resetSuccess = searchParams . get ( 'resetSuccess' ) === 'true'
146+ if ( resetSuccess ) {
147+ setResetSuccessMessage ( 'Password reset successful. Please sign in with your new password.' )
152148 }
153149 }
154-
155- checkCustomBrand ( )
156-
157- window . addEventListener ( 'resize' , checkCustomBrand )
158- const observer = new MutationObserver ( checkCustomBrand )
159- observer . observe ( document . documentElement , {
160- attributes : true ,
161- attributeFilter : [ 'style' , 'class' ] ,
162- } )
163-
164- return ( ) => {
165- window . removeEventListener ( 'resize' , checkCustomBrand )
166- observer . disconnect ( )
167- }
168150 } , [ searchParams ] )
169151
170152 useEffect ( ( ) => {
@@ -221,6 +203,7 @@ export default function LoginPage({
221203
222204 try {
223205 const safeCallbackUrl = validateCallbackUrl ( callbackUrl ) ? callbackUrl : '/workspace'
206+ let errorHandled = false
224207
225208 const result = await client . signIn . email (
226209 {
@@ -231,11 +214,16 @@ export default function LoginPage({
231214 {
232215 onError : ( ctx ) => {
233216 logger . error ( 'Login error:' , ctx . error )
234- const errorMessage : string [ ] = [ 'Invalid email or password' ]
235217
218+ // EMAIL_NOT_VERIFIED is handled by the catch block which redirects to /verify
236219 if ( ctx . error . code ?. includes ( 'EMAIL_NOT_VERIFIED' ) ) {
220+ errorHandled = true
237221 return
238222 }
223+
224+ errorHandled = true
225+ const errorMessage : string [ ] = [ 'Invalid email or password' ]
226+
239227 if (
240228 ctx . error . code ?. includes ( 'BAD_REQUEST' ) ||
241229 ctx . error . message ?. includes ( 'Email and password sign in is not enabled' )
@@ -271,16 +259,30 @@ export default function LoginPage({
271259 errorMessage . push ( 'Too many requests. Please wait a moment before trying again.' )
272260 }
273261
262+ setResetSuccessMessage ( null )
274263 setPasswordErrors ( errorMessage )
275264 setShowValidationError ( true )
276265 } ,
277266 }
278267 )
279268
280269 if ( ! result || result . error ) {
270+ // Show error if not already handled by onError callback
271+ if ( ! errorHandled ) {
272+ setResetSuccessMessage ( null )
273+ const errorMessage = result ?. error ?. message || 'Login failed. Please try again.'
274+ setPasswordErrors ( [ errorMessage ] )
275+ setShowValidationError ( true )
276+ }
281277 setIsLoading ( false )
282278 return
283279 }
280+
281+ // Clear reset success message on successful login
282+ setResetSuccessMessage ( null )
283+
284+ // Explicit redirect fallback if better-auth doesn't redirect
285+ router . push ( safeCallbackUrl )
284286 } catch ( err : any ) {
285287 if ( err . message ?. includes ( 'not verified' ) || err . code ?. includes ( 'EMAIL_NOT_VERIFIED' ) ) {
286288 if ( typeof window !== 'undefined' ) {
@@ -400,6 +402,13 @@ export default function LoginPage({
400402 </ div >
401403 ) }
402404
405+ { /* Password reset success message */ }
406+ { resetSuccessMessage && (
407+ < div className = { `${ inter . className } mt-1 space-y-1 text-[#4CAF50] text-xs` } >
408+ < p > { resetSuccessMessage } </ p >
409+ </ div >
410+ ) }
411+
403412 { /* Email/Password Form - show unless explicitly disabled */ }
404413 { ! isFalsy ( getEnv ( 'NEXT_PUBLIC_EMAIL_PASSWORD_SIGNUP_ENABLED' ) ) && (
405414 < form onSubmit = { onSubmit } className = { `${ inter . className } mt-8 space-y-8` } >
0 commit comments