diff --git a/AGENTS.md b/AGENTS.md index 46c8383..45759fb 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -679,6 +679,27 @@ session with **no other memory of this project**. So: `index.css` offsets `.leaflet-top.leaflet-left` by `4.25rem` **only under `max-width:767px`** (desktop toolbar is in flow, no offset). Verified at 390×844: zoom top 135px vs search bottom 108px. +- **Signup & onboarding UX pass (2026-10-01):** hardening the two highest-stakes + first impressions. + - **Signup is one fork.** `LoginArea` also rendered a `SignupMethodDialog` + ("Recovery Phrase vs Secret Key") + `MnemonicSignupDialog`, but + **`setSignupMethodDialogOpen(true)` existed nowhere** — the whole method + branch was DEAD code (unreachable). Removed the wiring (files kept on disk); + the misleading `nsecSignupDialogOpen` state was renamed `signupDialogOpen`. + `SignupDialog` (`welcome → profile → done`) is the only signup path. + - **`SignupDialog` gained a step indicator** (`STEP_ORDER`/`STEP_LABELS`: + Choose → Profile → Save key) and **makes backup a confirmation, not a skip**: + a checkbox ("I've saved my recovery code…") enables "Let's skate"; the + Download button also sets it. The old co-equal "Skip for now, skate" is now a + quiet text link ("I'll save it later from Settings"). Welcome copy no longer + claims "nothing to remember" (it contradicted step 3), the profile step warns + a signer may ask once, and non-Android copy points at signer apps instead of + implying a recommendation. + - **Onboarding adds "Where do you skate?"** (`OnboardingPage`): for a logged-in + skater with no cached fix, "Use my location" calls `getCurrentPosition()` + (which also `saveLastLocation()`s), so `MapPage`'s mount-time + `getLastLocation()` opens centered on their area. The logged-out wallet + section's dead disabled "Log in first" button became a plain line. - **Empty-map nudge (2026-09-28):** `MapPage` distinguishes the two empties — the existing "No spots match" card is for *filters* (`filteredSpots.length === 0 && allLocations.length > 0`) and a new "No spots mapped yet — be the first" card diff --git a/src/components/auth/LoginArea.tsx b/src/components/auth/LoginArea.tsx index f7b7dc3..5463fe9 100644 --- a/src/components/auth/LoginArea.tsx +++ b/src/components/auth/LoginArea.tsx @@ -6,8 +6,6 @@ import { User, UserPlus } from 'lucide-react'; import { Button } from '@/components/ui/button.tsx'; import LoginDialog from './LoginDialog'; import SignupDialog from './SignupDialog'; -import SignupMethodDialog from './SignupMethodDialog'; -import MnemonicSignupDialog from './MnemonicSignupDialog'; import { useLoggedInAccounts } from '@/hooks/useLoggedInAccounts'; import { AccountSwitcher } from './AccountSwitcher'; import { cn } from '@/lib/utils'; @@ -21,15 +19,11 @@ export interface LoginAreaProps { export function LoginArea({ className, compact }: LoginAreaProps) { const { currentUser } = useLoggedInAccounts(); const [loginDialogOpen, setLoginDialogOpen] = useState(false); - const [signupMethodDialogOpen, setSignupMethodDialogOpen] = useState(false); - const [mnemonicSignupDialogOpen, setMnemonicSignupDialogOpen] = useState(false); - const [nsecSignupDialogOpen, setNsecSignupDialogOpen] = useState(false); + const [signupDialogOpen, setSignupDialogOpen] = useState(false); const handleLogin = () => { setLoginDialogOpen(false); - setSignupMethodDialogOpen(false); - setMnemonicSignupDialogOpen(false); - setNsecSignupDialogOpen(false); + setSignupDialogOpen(false); }; return ( @@ -40,7 +34,7 @@ export function LoginArea({ className, compact }: LoginAreaProps) { // Compact mode for mobile headers - icon only
- {/* Reassurance: effortless + safe, no jargon */} + {/* Reassurance: effortless + safe, no jargon. Deliberately does + NOT promise "nothing to remember" — step 3 asks them to save + the key, and the copy must not contradict that. */}

- Takes 5 seconds · stays on this device · nothing to remember + Takes 5 seconds · lives on this device · we'll help you back it up next

+ {/* Platform-aware nudge. On Android the Amber card above already + leads; elsewhere point at signer apps/extensions honestly. */}

- Prefer another signer?{' '} + {onUseAmber && isAndroid ? ( + <>Prefer another signer?{' '} + ) : ( + <>On iOS or desktop? A signer app or browser extension is the most secure option —{' '} + )} See all options

@@ -570,6 +633,14 @@ const SignupDialog: React.FC = ({ isOpen, onClose, onComplete Add a display name to continue.

)} + + {/* Set expectations before it happens: saving publishes a kind-0 + profile event, so an interactive signer (Amber / NIP-07) will + show an approval prompt. Explaining it first avoids the "why + is it asking me to sign?" moment mid-signup. */} +

+ Saving publishes your profile to Nostr — your signer may ask you to approve it once. +

)} @@ -658,28 +729,51 @@ const SignupDialog: React.FC = ({ isOpen, onClose, onComplete - {/* Skate now — clearly available, intentionally quieter than "save". - Copy adapts: once saved, it's a confident go; if not, it's an - honest "you can do this later" so we never trap the user. */} + {/* Backup is a confirmation, not a skip. The primary action stays + locked until the key is saved (download sets it) or explicitly + acknowledged with the checkbox. The escape hatch remains — we + never trap anyone — but it's a quiet text link, never an equal + button competing with "save". */}
+ + - {keySecured !== 'downloaded' && ( -

- No stress — we'll remind you, and you can save it anytime from Settings. -

+ + {!backupAck && ( + )} + + + + +
+ + )} + {/* ── Login saved confirmation ── */} {user && backupConfirmed && (
@@ -399,9 +464,7 @@ export default function OnboardingPage() { ) : ( - +

Log in to connect your own wallet.

)}