From 6e95532e24a27ec4eabef32ed03199f5d3d651ae Mon Sep 17 00:00:00 2001 From: jolah1 Date: Sat, 4 Jul 2026 09:46:33 +0100 Subject: [PATCH] fix(web): no false testnet banner when API is down + Show password toggle Desktop review findings: - AlphaBanner rendered whenever /health had *completed*, including failures. `network` defaults to "testnet", so a mainnet owner whose server was briefly unreachable saw "Alpha: GhostKey is running on Bitcoin testnet. Don't use real-money keys yet" - false and alarming at the worst moment. Banner now renders only when /health succeeds; ServerOfflineBanner already covers the failure case. - Sign-in password field gets a Show/Hide toggle. Mistyped passwords are the top sign-in failure and the field hid every character. Co-Authored-By: Claude Opus 4.8 --- ghostkey-web/src/App.tsx | 14 ++++++------ ghostkey-web/src/SignInPortal.tsx | 36 +++++++++++++++++++++---------- 2 files changed, 32 insertions(+), 18 deletions(-) diff --git a/ghostkey-web/src/App.tsx b/ghostkey-web/src/App.tsx index bab01bc..541e03c 100644 --- a/ghostkey-web/src/App.tsx +++ b/ghostkey-web/src/App.tsx @@ -359,13 +359,13 @@ export default function App() { Skip to content - {/* Wait for the first /health probe before showing the network - banner. `network` defaults to "testnet", so rendering early - flashed an "Alpha: testnet, don't use real money" warning on - every reload of a mainnet vault before flipping to the live - banner. A wrong-network safety warning, even for a moment, - is worse than a brief absence. */} - {health !== "unknown" && } + {/* Only show the network banner once /health has SUCCEEDED. + `network` defaults to "testnet", so rendering before the + probe (or after a failed one) told a mainnet owner + "Alpha: testnet, don't use real-money keys" — false and + alarming at the exact moment the server was already down. + When the probe fails, ServerOfflineBanner below covers it. */} + {health === "ok" && } {demoMode && } {health === "offline" && } {/* diff --git a/ghostkey-web/src/SignInPortal.tsx b/ghostkey-web/src/SignInPortal.tsx index 4866ad2..2679221 100644 --- a/ghostkey-web/src/SignInPortal.tsx +++ b/ghostkey-web/src/SignInPortal.tsx @@ -81,6 +81,10 @@ type Phase = export function SignInPortal({ onNavigate }: Props) { const [email, setEmail] = useState(""); const [password, setPassword] = useState(""); + // Mistyped passwords are the #1 sign-in failure, and the field hides + // every character. A show toggle costs nothing and rescues most of + // them (Bitcoin UX principle: password UX is money UX). + const [showPassword, setShowPassword] = useState(false); const [phase, setPhase] = useState({ kind: "idle" }); const [error, setError] = useState(null); @@ -351,17 +355,27 @@ export function SignInPortal({ onNavigate }: Props) { - { - setPassword(e.target.value); - reset(); - }} - autoComplete="current-password" - className="input" - disabled={phase.kind === "looking" || phase.kind === "unsealing"} - /> +
+ { + setPassword(e.target.value); + reset(); + }} + autoComplete="current-password" + className="input pr-16" + disabled={phase.kind === "looking" || phase.kind === "unsealing"} + /> + +
{phase.kind === "unsealing" ? (