fix(review): loop-2 findings — login fallback, proof-band confidence, contrast, content hedges

Code review: login no longer strands visitors with zero sign-in methods when
the providers fetch fails (falls back to SMS + error notice); skeleton while
providers load instead of a blank card.

Design re-audit: proof band flipped from apology to flex ('Don't take our
word for it / Every claim links to its proof') and promoted to the primary
heading tier; unverifiable '60 seconds'/'in minutes' speed claims dropped;
fg-subtle body text bumped to fg-muted (AA contrast); marketplace section
differentiated via border-y + elevated bg (adjacent hairlines removed);
preview frame traffic lights on-palette; header h-12 -> h-14 (hero svh calc
adjusted); emerald-400 -> --color-success token.

Content QA: rest-api article description drift between page and registry
resolved; ChatGPT plan-gating table and Atlassian Rovo SSE-cutoff claims now
carry dated hedges.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SXUwmPVRTD8AKQtio6gCN5
This commit is contained in:
Marco Sadjadi
2026-07-08 23:13:53 +02:00
parent a08f5f05b1
commit c4f0db5719
6 changed files with 57 additions and 32 deletions

View File

@@ -208,6 +208,7 @@ export default function LoginPage() {
// product should never see a phone-number field as the front door. It only
// renders expanded when SMS is the sole configured provider.
const [phoneOpen, setPhoneOpen] = useState(false);
const [providersState, setProvidersState] = useState<'loading' | 'ready' | 'failed'>('loading');
const [error, setError] = useState<string | null>(null);
// Email magic-link
@@ -228,11 +229,21 @@ export default function LoginPage() {
)
.then((p) => {
setProviders(p);
setProvidersState('ready');
// SMS as the only provider → show the phone form directly (no point
// hiding the sole sign-in method behind a toggle).
if (p.sms && !p.email && !p.google && !p.github) setPhoneOpen(true);
})
.catch(() => undefined);
.catch(() => {
// If the providers lookup fails, the page must not strand the visitor
// with zero sign-in methods — fall back to SMS + phone form expanded
// (the one flow that has no provider-specific client config) and say
// why the other options are missing.
setProviders({ google: false, github: false, sms: true, email: false });
setPhoneOpen(true);
setProvidersState('failed');
setError('Some sign-in options could not be loaded. Reload the page to try again.');
});
const err = new URLSearchParams(window.location.search).get('error');
if (err) setError(ERROR_COPY[err] ?? 'Sign-in failed. Please try again.');
}, []);
@@ -296,6 +307,15 @@ export default function LoginPage() {
Passwordless pick whichever is easiest.
</p>
{/* Providers still loading → neutral skeleton instead of a blank card
(previously nothing rendered until the fetch resolved). */}
{providersState === 'loading' && (
<div aria-hidden className="mt-7 space-y-2">
<div className="h-10 w-full animate-pulse rounded-md bg-[--color-bg-elevated]" />
<div className="h-10 w-full animate-pulse rounded-md bg-[--color-bg-elevated]" />
</div>
)}
{hasOAuth && (
<div className="mt-7 space-y-2">
{providers.google && (