diff --git a/frontend/components/auth/LoginClient.tsx b/frontend/components/auth/LoginClient.tsx
index 4928ffe1..1e63cd80 100644
--- a/frontend/components/auth/LoginClient.tsx
+++ b/frontend/components/auth/LoginClient.tsx
@@ -64,7 +64,10 @@ export function LoginClient({ nextPath, initialMode }: LoginClientProps) {
? "Set at least 6 characters"
: "设置至少 6 位密码",
loginSubmit: isEn ? "Start your weather decision journey" : "开启气象决策之旅",
+ loginSubmitting: isEn ? "Signing in..." : "正在登录...",
signupSubmit: isEn ? "Create account now" : "立即创建账号",
+ signupSubmitting: isEn ? "Creating account..." : "正在创建账号...",
+ googleSubmitting: isEn ? "Connecting Google..." : "正在连接 Google...",
loginHint: isEn
? "After signing in, your homepage will be personalized."
: "登录后将为您个性化定制首页数据",
@@ -109,6 +112,14 @@ export function LoginClient({ nextPath, initialMode }: LoginClientProps) {
: "提供精准的机场 METAR 实况、先进的 DEB 智能融合预测和实时 AI 决策卡片,助您理清气象风险脉络。",
trusted: isEn ? "Trusted by industry professionals" : "深受行业决策人员信赖",
} as const;
+ const submittingLabel = isLogin ? copy.loginSubmitting : copy.signupSubmitting;
+ const googleSubmittingLabel = copy.googleSubmitting;
+ const loadingSpinner = (
+
+ );
const onResetPassword = async () => {
setErrorText("");
@@ -489,10 +500,12 @@ export function LoginClient({ nextPath, initialMode }: LoginClientProps) {
@@ -508,10 +521,11 @@ export function LoginClient({ nextPath, initialMode }: LoginClientProps) {
type="button"
onClick={() => void onGoogleSignIn()}
disabled={loading}
+ aria-busy={loading}
className="w-full py-3 px-4 rounded-xl border border-slate-200 bg-white text-sm font-semibold text-slate-700 shadow-sm hover:bg-slate-50 active:scale-[0.99] transition-all duration-150 flex items-center justify-center gap-2 disabled:opacity-50"
>
-
{errorText}
: null} diff --git a/frontend/components/auth/__tests__/passwordReset.test.ts b/frontend/components/auth/__tests__/passwordReset.test.ts index 62ac5fad..13c32f1b 100644 --- a/frontend/components/auth/__tests__/passwordReset.test.ts +++ b/frontend/components/auth/__tests__/passwordReset.test.ts @@ -50,6 +50,14 @@ export function runTests() { fs.existsSync(resetClientPath), "password reset page must use a dedicated client component", ); + assert( + loginClientSource.includes("loadingSpinner") && + loginClientSource.includes("submittingLabel") && + loginClientSource.includes("googleSubmittingLabel") && + loginClientSource.includes('aria-busy={loading}') && + loginClientSource.includes("animate-spin"), + "login submit and Google sign-in buttons must show a visible loading spinner and pending label", + ); const resetClientSource = fs.readFileSync(resetClientPath, "utf8"); assert(