Surface: pages/account.tsx — Login, Register, "Save profile", and "Create Key" forms.
Problem (Nielsen #1 Visibility of system status; #5 Error prevention). None of the submit handlers (handleLogin, handleRegister, handleUpdateProfile, handleCreateApiKey) set a pending/submitting state or disable their button while the request is in flight. To the player, clicking Login on a slow connection looks like "nothing happened" — the classic dead-end UX smell — so they click again, firing a second request (a duplicate registration attempt, a second API key, etc.). There is no spinner, no "Signing in…", no disabled state.
Suggested fix. Add a submitting boolean per form (or a shared one), disable the button and show a busy affordance (e.g. MUI <Button disabled={submitting}> with a <CircularProgress size={16}/> start icon or "Signing in…" label) for the duration of the await, mirroring the busy pattern already used well in components/LikeButton.tsx.
Filed during a usability pass (Nielsen heuristics + Don't Make Me Think); verified against pages/account.tsx. Drafted by Claude on behalf of Daniel Stephenson.
Surface:
pages/account.tsx— Login, Register, "Save profile", and "Create Key" forms.Problem (Nielsen #1 Visibility of system status; #5 Error prevention). None of the submit handlers (
handleLogin,handleRegister,handleUpdateProfile,handleCreateApiKey) set a pending/submitting state or disable their button while the request is in flight. To the player, clicking Login on a slow connection looks like "nothing happened" — the classic dead-end UX smell — so they click again, firing a second request (a duplicate registration attempt, a second API key, etc.). There is no spinner, no "Signing in…", no disabled state.Suggested fix. Add a
submittingboolean per form (or a shared one), disable the button and show a busy affordance (e.g. MUI<Button disabled={submitting}>with a<CircularProgress size={16}/>start icon or "Signing in…" label) for the duration of theawait, mirroring thebusypattern already used well incomponents/LikeButton.tsx.Filed during a usability pass (Nielsen heuristics + Don't Make Me Think); verified against
pages/account.tsx. Drafted by Claude on behalf of Daniel Stephenson.