From 863e9e2c45ba3bf53e0b332777b8e0c876103690 Mon Sep 17 00:00:00 2001 From: Kyle Pope Date: Wed, 18 Mar 2026 01:00:42 +0800 Subject: [PATCH] feat: improve account lockout UX with severity-aware error styling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Login errors now distinguish between wrong-password (red), progressive lockout warnings (amber, Lock icon), and temporary lockout (amber, Lock icon) based on the backend detail string. Removes the dead 423 branch from handleCredentialSubmit — account lockout is now returned as 401 with a descriptive detail message. Co-Authored-By: Claude Sonnet 4.6 --- frontend/src/components/auth/LockScreen.tsx | 39 +++++++++++++-------- 1 file changed, 24 insertions(+), 15 deletions(-) diff --git a/frontend/src/components/auth/LockScreen.tsx b/frontend/src/components/auth/LockScreen.tsx index 24b5b9e..0739ed5 100644 --- a/frontend/src/components/auth/LockScreen.tsx +++ b/frontend/src/components/auth/LockScreen.tsx @@ -155,11 +155,10 @@ export default function LockScreen() { // mfaSetupRequired / mfaRequired handled by hook state → activeMode switches automatically } catch (error: any) { const status = error?.response?.status; - if (status === 423) { - setLoginError(error.response.data?.detail || 'Account locked. Try again later.'); - } else if (status === 403) { + if (status === 403) { setLoginError(error.response.data?.detail || 'Account is disabled. Contact an administrator.'); } else { + // 401 covers both wrong password and account lockout (backend embeds detail string) setLoginError(getErrorMessage(error, 'Invalid username or password')); } } @@ -519,18 +518,28 @@ export default function LockScreen() { - {loginError && ( -
-
- )} + {loginError && (() => { + const isLockWarning = + loginError.includes('remaining') || loginError.includes('temporarily locked'); + return ( +
+ {isLockWarning + ?
+ ); + })()}